From eb5e291e5688e8e58a2455210f4d90f01b405001 Mon Sep 17 00:00:00 2001 From: Hunter Long Date: Mon, 2 Mar 2020 22:42:37 -0800 Subject: [PATCH] vue --- Makefile | 4 +- cmd/cli.go | 76 ++++++++-------- cmd/main.go | 46 +++++++--- core/checkin.go | 61 ------------- core/configs.go | 114 ++++++++++++----------- core/core.go | 65 +++----------- core/core_test.go | 22 +++-- core/database.go | 164 ++++++++++++++++------------------ core/failures.go | 6 -- core/incidents.go | 67 -------------- core/messages.go | 50 ----------- core/sample.go | 21 ++--- core/services_checkin_test.go | 9 +- core/users.go | 7 -- core/users_test.go | 2 +- database/crud.go | 4 + database/database.go | 53 ++++++++++- database/routines.go | 6 ++ dev/docker-compose.db.yml | 36 ++------ handlers/api.go | 4 +- handlers/api_test.go | 1 - handlers/incident.go | 12 +-- handlers/index.go | 2 +- handlers/messages.go | 33 +++---- handlers/middleware.go | 2 +- handlers/setup.go | 22 ++--- handlers/users.go | 4 +- source/source_test.go | 9 +- types/core.go | 1 - 29 files changed, 358 insertions(+), 545 deletions(-) diff --git a/Makefile b/Makefile index 14b08da8..783533d8 100644 --- a/Makefile +++ b/Makefile @@ -82,13 +82,13 @@ install: generate: cd source && go generate - cd handlers/graphql && go generate # remove files for a clean compile/build clean: rm -rf ./{logs,assets,plugins,*.db,config.yml,.sass-cache,config.yml,statping,build,.sass-cache,index.html,vendor} rm -rf cmd/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log,*.html,*.json} rm -rf core/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log} + rm -rf core/notifier/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log} rm -rf handlers/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log} rm -rf notifiers/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log} rm -rf source/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log} @@ -104,7 +104,7 @@ clean: find . -name "*.out" -type f -delete find . -name "*.cpu" -type f -delete find . -name "*.mem" -type f -delete - rm -rf {build,tmp,docker} + rm -rf {build,tmp} print_details: @echo \==== Statping Development Instance ==== diff --git a/cmd/cli.go b/cmd/cli.go index ac707da5..0ad52aba 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -19,14 +19,11 @@ import ( "encoding/json" "fmt" "github.com/hunterlong/statping/core" - "github.com/hunterlong/statping/handlers" "github.com/hunterlong/statping/source" - "github.com/hunterlong/statping/types" "github.com/hunterlong/statping/utils" "github.com/joho/godotenv" "github.com/pkg/errors" "io/ioutil" - "net/http/httptest" "time" ) @@ -72,25 +69,25 @@ func catchCLI(args []string) error { updateDisplay() return errors.New("end") case "static": - var err error - if err = runLogs(); err != nil { - return err - } - if err = runAssets(); err != nil { - return err - } - fmt.Printf("Statping v%v Exporting Static 'index.html' page...\n", VERSION) - if _, err = core.LoadConfigFile(dir); err != nil { - log.Errorln("config.yml file not found") - return err - } - indexSource := ExportIndexHTML() - //core.CloseDB() - if err = utils.SaveFile(dir+"/index.html", indexSource); err != nil { - log.Errorln(err) - return err - } - log.Infoln("Exported Statping index page: 'index.html'") + //var err error + //if err = runLogs(); err != nil { + // return err + //} + //if err = runAssets(); err != nil { + // return err + //} + //fmt.Printf("Statping v%v Exporting Static 'index.html' page...\n", VERSION) + //if _, err = core.LoadConfigFile(dir); err != nil { + // log.Errorln("config.yml file not found") + // return err + //} + //indexSource := ExportIndexHTML() + ////core.CloseDB() + //if err = utils.SaveFile(dir+"/index.html", indexSource); err != nil { + // log.Errorln(err) + // return err + //} + //log.Infoln("Exported Statping index page: 'index.html'") case "help": HelpEcho() return errors.New("end") @@ -103,10 +100,11 @@ func catchCLI(args []string) error { if err = runAssets(); err != nil { return err } - if _, err = core.LoadConfigFile(dir); err != nil { + configs, err := core.LoadConfigFile(dir) + if err != nil { return err } - if err = core.CoreApp.Connect(false, dir); err != nil { + if err = core.CoreApp.Connect(configs, false, dir); err != nil { return err } if data, err = core.ExportSettings(); err != nil { @@ -167,19 +165,19 @@ func catchCLI(args []string) error { } // ExportIndexHTML returns the HTML of the index page as a string -func ExportIndexHTML() []byte { - source.Assets() - core.CoreApp.Connect(false, utils.Directory) - core.SelectAllServices(false) - core.CoreApp.UseCdn = types.NewNullBool(true) - for _, srv := range core.Services() { - core.CheckService(srv, true) - } - w := httptest.NewRecorder() - r := httptest.NewRequest("GET", "/", nil) - handlers.ExecuteResponse(w, r, "index.gohtml", nil, nil) - return w.Body.Bytes() -} +//func ExportIndexHTML() []byte { +// source.Assets() +// core.CoreApp.Connect(core.CoreApp., utils.Directory) +// core.SelectAllServices(false) +// core.CoreApp.UseCdn = types.NewNullBool(true) +// for _, srv := range core.Services() { +// core.CheckService(srv, true) +// } +// w := httptest.NewRecorder() +// r := httptest.NewRequest("GET", "/", nil) +// handlers.ExecuteResponse(w, r, "index.gohtml", nil, nil) +// return w.Body.Bytes() +//} func updateDisplay() error { gitCurrent, err := checkGithubUpdates() @@ -202,11 +200,11 @@ func updateDisplay() error { // runOnce will initialize the Statping application and check each service 1 time, will not run HTTP server func runOnce() error { - _, err := core.LoadConfigFile(utils.Directory) + configs, err := core.LoadConfigFile(utils.Directory) if err != nil { return errors.Wrap(err, "config.yml file not found") } - err = core.CoreApp.Connect(false, utils.Directory) + err = core.CoreApp.Connect(configs, false, utils.Directory) if err != nil { return errors.Wrap(err, "issue connecting to database") } diff --git a/cmd/main.go b/cmd/main.go index 6060dd56..194c03fc 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -62,6 +62,13 @@ func parseFlags() { flag.Parse() } +func exit(err error) { + fmt.Printf("%+v", core.Configs()) + panic(err) + //log.Fatalln(err) + //os.Exit(2) +} + // main will run the Statping application func main() { var err error @@ -80,35 +87,54 @@ func main() { if err != nil { if err.Error() == "end" { os.Exit(0) + return } - fmt.Println(err) - os.Exit(1) + exit(err) } } log.Info(fmt.Sprintf("Starting Statping v%v", VERSION)) - updateDisplay() - config, err := core.LoadConfigFile(utils.Directory) + if err := updateDisplay(); err != nil { + log.Warnln(err) + } + + // check if DB_CONN was set, and load config from that + autoConfigDb := utils.Getenv("DB_CONN", "").(string) + if autoConfigDb != "" { + log.Infof("Environment variable 'DB_CONN' was set to %s, loading configs from ENV.", autoConfigDb) + if _, err := core.LoadUsingEnv(); err != nil { + exit(err) + return + } else { + afterConfigLoaded() + } + } + + // attempt to load config.yml file from current directory, if no file, then start in setup mode. + _, err = core.LoadConfigFile(utils.Directory) if err != nil { log.Errorln(err) core.CoreApp.Setup = false writeAble, err := utils.DirWritable(utils.Directory) if err != nil { - log.Fatalln(err) + exit(err) + return } if !writeAble { log.Fatalf("Statping does not have write permissions at: %v\nYou can change this directory by setting the STATPING_DIR environment variable to a dedicated path before starting.", utils.Directory) + return } if err := handlers.RunHTTPServer(ipAddress, port); err != nil { log.Fatalln(err) } + } else { + afterConfigLoaded() } +} - core.CoreApp.Config = config.DbConfig - +func afterConfigLoaded() { if err := mainProcess(); err != nil { - log.Fatalln(err) - os.Exit(2) + exit(err) } } @@ -140,7 +166,7 @@ func loadDotEnvs() error { func mainProcess() error { dir := utils.Directory var err error - err = core.CoreApp.Connect(false, dir) + err = core.CoreApp.Connect(core.Configs(), false, dir) if err != nil { log.Errorln(fmt.Sprintf("could not connect to database: %v", err)) return err diff --git a/core/checkin.go b/core/checkin.go index 8f9e2ff6..a45393fa 100644 --- a/core/checkin.go +++ b/core/checkin.go @@ -17,7 +17,6 @@ package core import ( "fmt" - "github.com/ararog/timeago" "github.com/hunterlong/statping/database" "github.com/hunterlong/statping/types" "github.com/hunterlong/statping/utils" @@ -108,37 +107,6 @@ func SelectCheckin(api string) *Checkin { return nil } -// AllHits returns all of the CheckinHits for a given Checkin -func (c *Checkin) AllHits() []*types.CheckinHit { - var checkins []*types.CheckinHit - Database(&types.CheckinHit{}).Where("checkin = ?", c.Id).Order("id DESC").Find(&checkins) - return checkins -} - -// Hits returns all of the CheckinHits for a given Checkin -func (c *Checkin) AllFailures() []*types.Failure { - var failures []*types.Failure - Database(&types.Failure{}). - Where("checkin = ?", c.Id). - Where("method = 'checkin'"). - Order("id desc"). - Find(&failures) - - return failures -} - -func (c *Checkin) GetFailures(count int) []*types.Failure { - var failures []*types.Failure - Database(&types.Failure{}). - Where("checkin = ?", c.Id). - Where("method = 'checkin'"). - Limit(count). - Order("id desc"). - Find(&failures) - - return failures -} - // Create will create a new Checkin func (c *Checkin) Delete() { c.Close() @@ -171,35 +139,6 @@ func (c *Checkin) Create() (int64, error) { return c.Id, err } -// Update will update a Checkin -func (c *Checkin) Update() (int64, error) { - row := Database(c).Update(&c) - if row.Error() != nil { - log.Warnln(row.Error()) - return 0, row.Error() - } - return c.Id, row.Error() -} - -// Create will create a new successful checkinHit -func (c *CheckinHit) Create() (int64, error) { - if c.CreatedAt.IsZero() { - c.CreatedAt = utils.Now() - } - row := Database(c).Create(&c) - if row.Error() != nil { - log.Warnln(row.Error()) - return 0, row.Error() - } - return c.Id, row.Error() -} - -// Ago returns the duration of time between now and the last successful checkinHit -func (c *CheckinHit) Ago() string { - got, _ := timeago.TimeAgoWithTime(utils.Now(), c.CreatedAt) - return got -} - // RecheckCheckinFailure will check if a Service Checkin has been reported yet func (c *Checkin) RecheckCheckinFailure(guard chan struct{}) { between := utils.Now().Sub(utils.Now()).Seconds() diff --git a/core/configs.go b/core/configs.go index 0ae0458d..7e518b00 100644 --- a/core/configs.go +++ b/core/configs.go @@ -30,15 +30,9 @@ type ErrorResponse struct { } // LoadConfigFile will attempt to load the 'config.yml' file in a specific directory -func LoadConfigFile(directory string) (*DbConfig, error) { - var configs *DbConfig +func LoadConfigFile(directory string) (*types.DbConfig, error) { + var configs *types.DbConfig - dbConn := utils.Getenv("DB_CONN", "").(string) - - if dbConn != "" { - log.Infof("DB_CONN=%s environment variable was found, waiting for database...", dbConn) - return LoadUsingEnv() - } log.Debugln("Attempting to read config file at: " + directory + "/config.yml") file, err := utils.OpenFile(directory + "/config.yml") if err != nil { @@ -50,61 +44,75 @@ func LoadConfigFile(directory string) (*DbConfig, error) { return nil, errors.Wrap(err, "yaml file not formatted correctly") } log.WithFields(utils.ToFields(configs)).Debugln("read config file: " + directory + "/config.yml") - CoreApp.Config = configs.DbConfig + + CoreApp.config = configs + return configs, err } +func Configs() *types.DbConfig { + return CoreApp.config +} + // LoadUsingEnv will attempt to load database configs based on environment variables. If DB_CONN is set if will force this function. -func LoadUsingEnv() (*DbConfig, error) { - Configs, err := EnvToConfig() +func LoadUsingEnv() (*types.DbConfig, error) { + configs, err := EnvToConfig() if err != nil { - return Configs, err + return configs, err } CoreApp.Name = utils.Getenv("NAME", "").(string) - CoreApp.Domain = utils.Getenv("DOMAIN", Configs.LocalIP).(string) + CoreApp.Domain = utils.Getenv("DOMAIN", "").(string) CoreApp.UseCdn = types.NewNullBool(utils.Getenv("USE_CDN", false).(bool)) - err = CoreApp.Connect(true, utils.Directory) + err = CoreApp.Connect(configs, true, utils.Directory) if err != nil { return nil, errors.Wrap(err, "error connecting to database") } - if err := Configs.Save(); err != nil { + if err := SaveConfig(configs); err != nil { return nil, errors.Wrap(err, "error saving configuration") } - exists := DbSession.HasTable("core") + exists := database.Get().HasTable("core") if !exists { - log.Infoln(fmt.Sprintf("Core database does not exist, creating now!")) - if err := CoreApp.DropDatabase(); err != nil { - return nil, errors.Wrap(err, "error dropping database") - } - if err := CoreApp.CreateDatabase(); err != nil { - return nil, errors.Wrap(err, "error creating database") - } - CoreApp, err = Configs.InsertCore() - if err != nil { - return nil, errors.Wrap(err, "error creating the core database") - } - - username := utils.Getenv("ADMIN_USER", "admin").(string) - password := utils.Getenv("ADMIN_PASSWORD", "admin").(string) - - admin := &types.User{ - Username: username, - Password: utils.HashPassword(password), - Email: "info@admin.com", - Admin: types.NewNullBool(true), - } - if _, err := database.Create(admin); err != nil { - return nil, errors.Wrap(err, "error creating admin") - } - - if err := SampleData(); err != nil { - return nil, errors.Wrap(err, "error connecting sample data") - } - return Configs, err + return InitialSetup(configs) } - return Configs, nil + + CoreApp.config = configs + return configs, nil +} + +func InitialSetup(configs *types.DbConfig) (*types.DbConfig, error) { + log.Infoln(fmt.Sprintf("Core database does not exist, creating now!")) + if err := CoreApp.DropDatabase(); err != nil { + return nil, errors.Wrap(err, "error dropping database") + } + if err := CoreApp.CreateDatabase(); err != nil { + return nil, errors.Wrap(err, "error creating database") + } + CoreApp, err := InsertCore(configs) + if err != nil { + return nil, errors.Wrap(err, "error creating the core database") + } + + username := utils.Getenv("ADMIN_USER", "admin").(string) + password := utils.Getenv("ADMIN_PASSWORD", "admin").(string) + + admin := &types.User{ + Username: username, + Password: utils.HashPassword(password), + Email: "info@admin.com", + Admin: types.NewNullBool(true), + } + if _, err := database.Create(admin); err != nil { + return nil, errors.Wrap(err, "error creating admin") + } + + if err := SampleData(); err != nil { + return nil, errors.Wrap(err, "error connecting sample data") + } + + CoreApp.config = configs + return configs, err } // defaultPort accepts a database type and returns its default port @@ -122,7 +130,7 @@ func defaultPort(db string) int { } // EnvToConfig converts environment variables to a DbConfig -func EnvToConfig() (*DbConfig, error) { +func EnvToConfig() (*types.DbConfig, error) { var err error dbConn := utils.Getenv("DB_CONN", "").(string) @@ -173,10 +181,7 @@ func EnvToConfig() (*DbConfig, error) { Location: utils.Directory, SqlFile: sqlFile, } - - CoreApp.Config = config - - return &DbConfig{config}, err + return config, err } // SampleData runs all the sample data for a new Statping installation @@ -202,3 +207,10 @@ func DeleteConfig() error { } return nil } + +func IsSetup() bool { + if CoreApp.config != nil { + return true + } + return false +} diff --git a/core/core.go b/core/core.go index e9fd3882..8cf2fd1a 100644 --- a/core/core.go +++ b/core/core.go @@ -35,6 +35,7 @@ type PluginRepos types.PluginRepos type Core struct { *types.Core services map[int64]*Service + config *types.DbConfig } var ( @@ -93,91 +94,45 @@ func InitApp() error { // InsertNotifierDB inject the Statping database instance to the Notifier package func InsertNotifierDB() error { - if DbSession == nil { - err := CoreApp.Connect(false, utils.Directory) + if !database.Available() { + err := CoreApp.Connect(CoreApp.config, false, utils.Directory) if err != nil { return errors.New("database connection has not been created") } } - notifier.SetDB(DbSession) + notifier.SetDB(database.Get()) return nil } // InsertIntegratorDB inject the Statping database instance to the Integrations package func InsertIntegratorDB() error { - if DbSession == nil { - err := CoreApp.Connect(false, utils.Directory) + if !database.Available() { + err := CoreApp.Connect(CoreApp.config, false, utils.Directory) if err != nil { return errors.New("database connection has not been created") } } - integrations.SetDB(DbSession) + integrations.SetDB(database.Get()) return nil } -// UpdateCore will update the CoreApp variable inside of the 'core' table in database -func UpdateCore(c *Core) (*Core, error) { - db := Database(&Core{}).Update(&c) - return c, db.Error() -} - -// CurrentTime will return the current local time -func (c Core) CurrentTime() string { - t := time.Now().UTC() - current := utils.Timezoner(t, c.Timezone) - ansic := "Monday 03:04:05 PM" - return current.Format(ansic) -} - -// Messages will return the current local time -func (c Core) Messages() []*Message { - var message []*Message - Database(&Message{}).Where("service = ?", 0).Limit(10).Find(&message) - return message -} - // 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 "" - } - return source.OpenAsset("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 "" - } - return source.OpenAsset("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 "" - } - return source.OpenAsset("scss/mobile.scss") -} - // SelectCore will return the CoreApp global variable and the settings/configs for Statping func SelectCore() (*Core, error) { - if DbSession == nil { + if !database.Available() { log.Traceln("database has not been initiated yet.") return nil, errors.New("database has not been initiated yet.") } - exists := DbSession.HasTable("core") + exists := database.Get().HasTable("core") if !exists { log.Errorf("core database has not been setup yet, does not have the 'core' table") return nil, errors.New("core database has not been setup yet.") } - db := Database(&Core{}).First(&CoreApp) + db := database.Core().First(&CoreApp) if db.Error() != nil { return nil, db.Error() } diff --git a/core/core_test.go b/core/core_test.go index 8013b5af..d75a4cc8 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -30,6 +30,8 @@ var ( skipNewDb bool ) +var configs *types.DbConfig + func init() { dir = utils.Directory utils.InitLogs() @@ -50,27 +52,29 @@ func TestDbConfig_Save(t *testing.T) { t.SkipNow() } - config := &DbConfig{&types.DbConfig{ + config := &types.DbConfig{ DbConn: "sqlite", Project: "Tester", Location: dir, - }} + } - err := config.Save() + err := SaveConfig(config) require.Nil(t, err) - assert.Equal(t, "sqlite", CoreApp.Config.DbConn) - assert.NotEmpty(t, CoreApp.Config.ApiKey) - assert.NotEmpty(t, CoreApp.Config.ApiSecret) + assert.Equal(t, "sqlite", config.DbConn) + assert.NotEmpty(t, config.ApiKey) + assert.NotEmpty(t, config.ApiSecret) } func TestLoadDbConfig(t *testing.T) { Configs, err := LoadConfigFile(dir) assert.Nil(t, err) assert.Equal(t, "sqlite", Configs.DbConn) + + configs = Configs } func TestDbConnection(t *testing.T) { - err := CoreApp.Connect(false, dir) + err := CoreApp.Connect(configs, false, dir) assert.Nil(t, err) } @@ -102,9 +106,9 @@ func TestSeedDatabase(t *testing.T) { } func TestReLoadDbConfig(t *testing.T) { - err := CoreApp.Connect(false, dir) + err := CoreApp.Connect(configs, false, dir) assert.Nil(t, err) - assert.Equal(t, "sqlite", CoreApp.Config.DbConn) + assert.Equal(t, "sqlite", CoreApp.config.DbConn) } func TestSelectCore(t *testing.T) { diff --git a/core/database.go b/core/database.go index 53e94d95..367db008 100644 --- a/core/database.go +++ b/core/database.go @@ -18,70 +18,35 @@ package core import ( "bufio" "fmt" + "github.com/pkg/errors" + "os" + "path/filepath" + "time" + + _ "github.com/jinzhu/gorm/dialects/mysql" + _ "github.com/jinzhu/gorm/dialects/postgres" + _ "github.com/jinzhu/gorm/dialects/sqlite" + "github.com/go-yaml/yaml" "github.com/hunterlong/statping/core/notifier" "github.com/hunterlong/statping/database" "github.com/hunterlong/statping/types" "github.com/hunterlong/statping/utils" "github.com/jinzhu/gorm" - _ "github.com/jinzhu/gorm/dialects/mysql" - _ "github.com/jinzhu/gorm/dialects/postgres" - _ "github.com/jinzhu/gorm/dialects/sqlite" - "github.com/pkg/errors" - "os" - "path/filepath" - "time" ) var ( // DbSession stores the Statping database session - DbSession database.Database - DbModels []interface{} + DbModels []interface{} ) func init() { DbModels = []interface{}{&types.Service{}, &types.User{}, &types.Hit{}, &types.Failure{}, &types.Message{}, &types.Group{}, &types.Checkin{}, &types.CheckinHit{}, ¬ifier.Notification{}, &types.Incident{}, &types.IncidentUpdate{}, &types.Integration{}} } -// DbConfig stores the config.yml file for the statup configuration -type DbConfig struct { - *types.DbConfig -} - -func Database(obj interface{}) database.Database { - switch obj.(type) { - case *types.Service, *Service, []*Service: - return DbSession.Model(&types.Service{}) - case *types.Hit, *Hit, []*Hit: - return DbSession.Model(&types.Hit{}) - case *types.Failure, *Failure, []*Failure: - return DbSession.Model(&types.Failure{}) - case *types.Core, *Core: - return DbSession.Table("core").Model(&CoreApp) - case *types.Checkin, *Checkin, []*Checkin: - return DbSession.Model(&types.Checkin{}) - case *types.CheckinHit, *CheckinHit, []*CheckinHit: - return DbSession.Model(&types.CheckinHit{}) - case *types.User, *User, []*User: - return DbSession.Model(&types.User{}) - case *types.Group, *Group, []*Group: - return DbSession.Model(&types.Group{}) - case *types.Incident, *Incident, []*Incident: - return DbSession.Model(&types.Incident{}) - case *types.IncidentUpdate, *IncidentUpdate, []*IncidentUpdate: - return DbSession.Model(&types.IncidentUpdate{}) - case *types.Message, *Message, []*Message: - return DbSession.Model(&types.Message{}) - default: - return DbSession - } -} - // CloseDB will close the database connection if available func CloseDB() { - if DbSession != nil { - DbSession.DB().Close() - } + database.Close() } //// AfterFind for Core will set the timezone @@ -140,11 +105,11 @@ func CloseDB() { //} // InsertCore create the single row for the Core settings in Statping -func (d *DbConfig) InsertCore() (*Core, error) { +func InsertCore(d *types.DbConfig) (*Core, error) { apiKey := utils.Getenv("API_KEY", utils.NewSHA1Hash(40)) apiSecret := utils.Getenv("API_SECRET", utils.NewSHA1Hash(40)) - CoreApp = &Core{Core: &types.Core{ + core := &types.Core{ Name: d.Project, Description: d.Description, ConfigFile: "config.yml", @@ -152,22 +117,34 @@ func (d *DbConfig) InsertCore() (*Core, error) { ApiSecret: apiSecret.(string), Domain: d.Domain, MigrationId: time.Now().Unix(), - Config: d.DbConfig, - }} - query := DbSession.Create(CoreApp.Core) - return CoreApp, query.Error() + } + + CoreApp = &Core{Core: core} + + CoreApp.config = d + + _, err := database.Create(CoreApp.Core) + return CoreApp, err } func findDbFile() string { - if CoreApp.Config.SqlFile != "" { - return CoreApp.Config.SqlFile + if CoreApp.config == nil { + return findSQLin(utils.Directory) } + if CoreApp.config.SqlFile != "" { + return CoreApp.config.SqlFile + } + return utils.Directory + "/" + types.SqliteFilename +} + +func findSQLin(path string) string { filename := types.SqliteFilename - err := filepath.Walk(utils.Directory, func(path string, info os.FileInfo, err error) error { + err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { if info.IsDir() { return nil } if filepath.Ext(path) == ".db" { + fmt.Println("DB file is now: ", info.Name()) filename = info.Name() } return nil @@ -179,20 +156,19 @@ func findDbFile() string { } // Connect will attempt to connect to the sqlite, postgres, or mysql database -func (c *Core) Connect(retry bool, location string) error { +func (c *Core) Connect(configs *types.DbConfig, retry bool, location string) error { postgresSSL := os.Getenv("POSTGRES_SSLMODE") - if DbSession != nil { + if database.Available() { return nil } var conn string var err error - configs := c.Config switch configs.DbConn { - case "sqlite": - sqlFilename := findDbFile() - conn = sqlFilename - log.Infof("SQL database file at: %v/%v", utils.Directory, conn) + case "sqlite", "sqlite3": + conn = findDbFile() + configs.SqlFile = fmt.Sprintf("%s/%s", utils.Directory, conn) + log.Infof("SQL database file at: %s", configs.SqlFile) configs.DbConn = "sqlite3" case "mysql": host := fmt.Sprintf("%v:%v", configs.DbHost, configs.DbPort) @@ -210,10 +186,10 @@ func (c *Core) Connect(retry bool, location string) error { log.WithFields(utils.ToFields(c, conn)).Debugln("attempting to connect to database") dbSession, err := database.Openw(configs.DbConn, conn) if err != nil { - log.Debugln(fmt.Sprintf("Database connection error %v", err)) + log.Debugln(fmt.Sprintf("Database connection error %s", err)) if retry { - log.Errorln(fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", configs.DbHost)) - return c.waitForDb() + log.Errorln(fmt.Sprintf("Database %s connection to '%s' is not available, trying again in 5 seconds...", configs.DbConn, configs.DbHost)) + return c.waitForDb(configs) } else { return err } @@ -229,19 +205,21 @@ func (c *Core) Connect(retry bool, location string) error { dbSession.DB().SetConnMaxLifetime(maxLifeConn.(time.Duration)) if dbSession.DB().Ping() == nil { - DbSession = dbSession if utils.VerboseMode >= 4 { - DbSession.LogMode(true).Debug().SetLogger(gorm.Logger{log}) + database.LogMode(true).Debug().SetLogger(gorm.Logger{log}) } log.Infoln(fmt.Sprintf("Database %v connection was successful.", configs.DbConn)) } + + CoreApp.config = configs + return err } // waitForDb will sleep for 5 seconds and try to connect to the database again -func (c *Core) waitForDb() error { +func (c *Core) waitForDb(configs *types.DbConfig) error { time.Sleep(5 * time.Second) - return c.Connect(true, utils.Directory) + return c.Connect(configs, true, utils.Directory) } // Update will save the config.yml file @@ -252,18 +230,20 @@ func (c *Core) UpdateConfig() error { log.Errorln(err) return err } - data, err := yaml.Marshal(c.Config) + defer config.Close() + + data, err := yaml.Marshal(c.config) if err != nil { log.Errorln(err) return err } config.WriteString(string(data)) - config.Close() + return err } // Save will initially create the config.yml file -func (d *DbConfig) Save() error { +func SaveConfig(d *types.DbConfig) error { config, err := os.Create(utils.Directory + "/config.yml") if err != nil { log.Errorln(err) @@ -271,20 +251,28 @@ func (d *DbConfig) Save() error { } defer config.Close() log.WithFields(utils.ToFields(d)).Debugln("saving config file at: " + utils.Directory + "/config.yml") - CoreApp.Config = d.DbConfig - apiKey := utils.Getenv("API_KEY", utils.NewSHA1Hash(16)) - apiSecret := utils.Getenv("API_SECRET", utils.NewSHA1Hash(16)) + if d.ApiKey == "" || d.ApiSecret == "" { + apiKey := utils.Getenv("API_KEY", utils.NewSHA1Hash(16)) + apiSecret := utils.Getenv("API_SECRET", utils.NewSHA1Hash(16)) + CoreApp.config.ApiKey = apiKey.(string) + CoreApp.config.ApiSecret = apiSecret.(string) + } + if d.DbConn == "sqlite3" { + d.DbConn = "sqlite" + } - CoreApp.Config.ApiKey = apiKey.(string) - CoreApp.Config.ApiSecret = apiSecret.(string) data, err := yaml.Marshal(d) if err != nil { log.Errorln(err) return err } - config.WriteString(string(data)) - log.WithFields(utils.ToFields(d)).Infoln("saved config file at: " + utils.Directory + "/config.yml") + if _, err := config.WriteString(string(data)); err != nil { + return errors.Wrap(err, "error writing to config.yml") + } + log.WithFields(utils.ToFields(d)).Infoln("Saved config file at: " + utils.Directory + "/config.yml") + + CoreApp.config = d return err } @@ -299,8 +287,8 @@ func (c *Core) CreateCore() *Core { Domain: c.Domain, MigrationId: time.Now().Unix(), } - db := Database(newCore).Create(&newCore) - if db.Error() == nil { + _, err := database.Create(&newCore) + if err == nil { CoreApp = &Core{Core: newCore} } CoreApp, err := SelectCore() @@ -313,11 +301,11 @@ func (c *Core) CreateCore() *Core { // DropDatabase will DROP each table Statping created func (c *Core) DropDatabase() error { log.Infoln("Dropping Database Tables...") - tables := []string{"checkins", "checkin_hits", "notifications", "core", "failures", "hits", "services", "users", "messages", "incidents", "incident_updates"} - for _, t := range tables { - if err := DbSession.DropTableIfExists(t); err != nil { + for _, t := range DbModels { + if err := database.Get().DropTableIfExists(t); err != nil { return err.Error() } + log.Infof("Dropped table: %T\n", t) } return nil } @@ -327,11 +315,11 @@ func (c *Core) CreateDatabase() error { var err error log.Infoln("Creating Database Tables...") for _, table := range DbModels { - if err := DbSession.CreateTable(table); err.Error() != nil { + if err := database.Get().CreateTable(table); err.Error() != nil { return err.Error() } } - if err := DbSession.Table("core").CreateTable(&types.Core{}); err.Error() != nil { + if err := database.Get().Table("core").CreateTable(&types.Core{}); err.Error() != nil { return err.Error() } log.Infoln("Statping Database Created") @@ -394,7 +382,7 @@ func (c *Core) ServicesFromEnvFile() error { // If this function has an issue, it will ROLLBACK to the previous state. func (c *Core) MigrateDatabase() error { log.Infoln("Migrating Database Tables...") - tx := DbSession.Begin() + tx := database.Begin("migration") defer func() { if r := recover(); r != nil { tx.Rollback() @@ -412,11 +400,11 @@ func (c *Core) MigrateDatabase() error { log.Errorln(fmt.Sprintf("Statping Database could not be migrated: %v", tx.Error())) return tx.Error() } - log.Infoln("Statping Database Migrated") if err := tx.Commit().Error(); err != nil { return err } + log.Infoln("Statping Database Migrated") return nil } diff --git a/core/failures.go b/core/failures.go index d72faff2..c3693228 100644 --- a/core/failures.go +++ b/core/failures.go @@ -27,9 +27,3 @@ const ( limitedFailures = 32 limitedHits = 32 ) - -// Delete will remove a Failure record from the database -func (f *Failure) Delete() error { - db := Database(&types.Failure{}).Delete(f) - return db.Error() -} diff --git a/core/incidents.go b/core/incidents.go index 125a0bc4..7f319baa 100644 --- a/core/incidents.go +++ b/core/incidents.go @@ -2,7 +2,6 @@ package core import ( "github.com/hunterlong/statping/types" - "time" ) type Incident struct { @@ -17,69 +16,3 @@ type IncidentUpdate struct { func ReturnIncident(u *types.Incident) *Incident { return &Incident{u} } - -// SelectIncident returns the Incident based on the Incident's ID. -func SelectIncident(id int64) (*Incident, error) { - var incident Incident - err := Database(incident).Where("id = ?", id).First(&incident) - return &incident, err.Error() -} - -// AllIncidents will return all incidents and updates recorded -func AllIncidents() []*Incident { - var incidents []*Incident - Database(incidents).Find(&incidents).Order("id desc") - for _, i := range incidents { - var updates []*types.IncidentUpdate - Database(updates).Find(&updates).Order("id desc") - i.Updates = updates - } - return incidents -} - -// Incidents will return the all incidents for a service -func (s *Service) Incidents() []*Incident { - var incidentArr []*Incident - Database(incidentArr).Where("service = ?", s.Id).Order("id desc").Find(&incidentArr) - return incidentArr -} - -// AllUpdates will return the all updates for an incident -func (i *Incident) AllUpdates() []*IncidentUpdate { - var updatesArr []*IncidentUpdate - Database(updatesArr).Where("incident = ?", i.Id).Order("id desc").Find(&updatesArr) - return updatesArr -} - -// Delete will remove a incident -func (i *Incident) Delete() error { - err := Database(i).Delete(i) - return err.Error() -} - -// Create will create a incident and insert it into the database -func (i *Incident) Create() (int64, error) { - i.CreatedAt = time.Now().UTC() - db := Database(i).Create(i) - return i.Id, db.Error() -} - -// Update will update a incident -func (i *Incident) Update() (int64, error) { - i.UpdatedAt = time.Now().UTC() - db := Database(i).Update(i) - return i.Id, db.Error() -} - -// Delete will remove a incident update -func (i *IncidentUpdate) Delete() error { - err := Database(i).Delete(i) - return err.Error() -} - -// Create will create a incident update and insert it into the database -func (i *IncidentUpdate) Create() (int64, error) { - i.CreatedAt = time.Now().UTC() - db := Database(i).Create(i) - return i.Id, db.Error() -} diff --git a/core/messages.go b/core/messages.go index 2c95cd19..4e9ba66c 100644 --- a/core/messages.go +++ b/core/messages.go @@ -16,64 +16,14 @@ package core import ( - "fmt" "github.com/hunterlong/statping/types" - "time" ) type Message struct { *types.Message } -// SelectServiceMessages returns all messages for a service -func SelectServiceMessages(id int64) []*Message { - var message []*Message - Database(&Message{}).Where("service = ?", id).Limit(10).Find(&message) - return message -} - // ReturnMessage will convert *types.Message to *core.Message func ReturnMessage(m *types.Message) *Message { return &Message{m} } - -// SelectMessages returns all messages -func SelectMessages() ([]*Message, error) { - var messages []*Message - db := Database(&Message{}).Find(&messages).Order("id desc") - return messages, db.Error() -} - -// SelectMessage returns a Message based on the ID passed -func SelectMessage(id int64) (*Message, error) { - var message Message - db := Database(&Message{}).Where("id = ?", id).Find(&message) - return &message, db.Error() -} - -// Create will create a Message and insert it into the database -func (m *Message) Create() (int64, error) { - m.CreatedAt = time.Now().UTC() - db := Database(&Message{}).Create(m) - if db.Error() != nil { - log.Errorln(fmt.Sprintf("Failed to create message %v #%v: %v", m.Title, m.Id, db.Error())) - return 0, db.Error() - } - return m.Id, nil -} - -// Delete will delete a Message from database -func (m *Message) Delete() error { - db := Database(&Message{}).Delete(m) - return db.Error() -} - -// Update will update a Message in the database -func (m *Message) Update() (*Message, error) { - db := Database(&Message{}).Update(m) - if db.Error() != nil { - log.Errorln(fmt.Sprintf("Failed to update message %v #%v: %v", m.Title, m.Id, db.Error())) - return nil, db.Error() - } - return m, nil -} diff --git a/core/sample.go b/core/sample.go index 593940b9..0b329e7f 100644 --- a/core/sample.go +++ b/core/sample.go @@ -21,11 +21,12 @@ import ( "github.com/hunterlong/statping/database" "github.com/hunterlong/statping/types" "github.com/hunterlong/statping/utils" + "sync" + "time" + _ "github.com/jinzhu/gorm/dialects/mysql" _ "github.com/jinzhu/gorm/dialects/postgres" _ "github.com/jinzhu/gorm/dialects/sqlite" - "sync" - "time" ) var ( @@ -271,7 +272,7 @@ func insertSampleCheckins() error { // InsertSampleHits will create a couple new hits for the sample services func InsertSampleHits() error { - tx := Database(&Hit{}).Begin() + tx := database.Begin(&types.Hit{}) sg := new(sync.WaitGroup) for i := int64(1); i <= 5; i++ { sg.Add(1) @@ -280,7 +281,7 @@ func InsertSampleHits() error { log.Infoln(fmt.Sprintf("Adding %v sample hit records to service %v", SampleHits, service.Name)) createdAt := sampleStart p := utils.NewPerlin(2., 2., 10, seed) - go func() { + go func(sg *sync.WaitGroup) { defer sg.Done() for hi := 0.; hi <= float64(SampleHits); hi++ { latency := p.Noise1D(hi / 500) @@ -292,7 +293,7 @@ func InsertSampleHits() error { } tx = tx.Create(&hit) } - }() + }(sg) } sg.Wait() if err := tx.Commit().Error(); err != nil { @@ -626,14 +627,14 @@ func TmpRecords(dbFile string) error { CoreApp = NewCore() CoreApp.Name = "Tester" CoreApp.Setup = true - configs := &DbConfig{&types.DbConfig{ + configs := &types.DbConfig{ DbConn: "sqlite", Project: "Tester", Location: utils.Directory, SqlFile: sqlFile, - }} + } log.Infoln("saving config.yml in: " + utils.Directory) - if err := configs.Save(); err != nil { + if err := SaveConfig(configs); err != nil { log.Error(err) } log.Infoln("loading config.yml from: " + utils.Directory) @@ -653,7 +654,7 @@ func TmpRecords(dbFile string) error { } log.Infoln("loading config.yml from: " + utils.Directory) - if err := CoreApp.Connect(false, utils.Directory); err != nil { + if err := CoreApp.Connect(configs, false, utils.Directory); err != nil { log.Error(err) } log.Infoln("selecting the Core variable") @@ -684,7 +685,7 @@ func TmpRecords(dbFile string) error { log.Infoln(tmpSqlFile + " not found, creating a new database...") - if err := CoreApp.Connect(false, utils.Directory); err != nil { + if err := CoreApp.Connect(configs, false, utils.Directory); err != nil { return err } log.Infoln("creating database") diff --git a/core/services_checkin_test.go b/core/services_checkin_test.go index 4b55aab8..177a7ab1 100644 --- a/core/services_checkin_test.go +++ b/core/services_checkin_test.go @@ -58,9 +58,9 @@ func TestSelectCheckin(t *testing.T) { func TestUpdateCheckin(t *testing.T) { testCheckin.Interval = 60 testCheckin.GracePeriod = 15 - id, err := testCheckin.Update() + err := database.Update(testCheckin) assert.Nil(t, err) - assert.NotZero(t, id) + assert.NotZero(t, testCheckin.Id) assert.NotEmpty(t, testCheckin.ApiKey) service := SelectService(1) checkin := service.Checkins()[0] @@ -82,8 +82,9 @@ func TestCreateCheckinHits(t *testing.T) { } _, err := database.Create(hit) require.Nil(t, err) - hits := testCheckin.AllHits() - assert.Equal(t, 1, len(hits)) + + checks := service.Checkins() + assert.Equal(t, 1, len(checks)) } func TestSelectCheckinMethods(t *testing.T) { diff --git a/core/users.go b/core/users.go index cb58b29d..a37ddefa 100644 --- a/core/users.go +++ b/core/users.go @@ -33,13 +33,6 @@ func uwrap(u *database.UserObj) *User { return &User{u} } -// CountUsers returns the amount of users -func CountUsers() int64 { - var amount int64 - Database(&User{}).Count(&amount) - return amount -} - // SelectUser returns the User based on the User's ID. func SelectUser(id int64) (*User, error) { user, err := database.User(id) diff --git a/core/users_test.go b/core/users_test.go index f3d9ab0c..acd8f9d6 100644 --- a/core/users_test.go +++ b/core/users_test.go @@ -112,6 +112,6 @@ func TestDeleteUser(t *testing.T) { } func TestDbConfig_Close(t *testing.T) { - err := DbSession.Close() + err := database.Close() assert.Nil(t, err) } diff --git a/database/crud.go b/database/crud.go index ea39a0d4..0574b6b1 100644 --- a/database/crud.go +++ b/database/crud.go @@ -3,6 +3,10 @@ package database import ( "github.com/hunterlong/statping/types" "reflect" + + _ "github.com/jinzhu/gorm/dialects/mysql" + _ "github.com/jinzhu/gorm/dialects/postgres" + _ "github.com/jinzhu/gorm/dialects/sqlite" ) type CrudObject interface { diff --git a/database/database.go b/database/database.go index 27d43750..0b2201b5 100644 --- a/database/database.go +++ b/database/database.go @@ -4,12 +4,13 @@ import ( "database/sql" "github.com/hunterlong/statping/types" "github.com/jinzhu/gorm" - _ "github.com/jinzhu/gorm/dialects/mysql" - _ "github.com/jinzhu/gorm/dialects/postgres" - _ "github.com/jinzhu/gorm/dialects/sqlite" "net/http" "strings" "time" + + _ "github.com/jinzhu/gorm/dialects/mysql" + _ "github.com/jinzhu/gorm/dialects/postgres" + _ "github.com/jinzhu/gorm/dialects/sqlite" ) const ( @@ -117,6 +118,7 @@ type Database interface { } type Objects interface { + Core() Database Services() Database Users() Database Groups() Database @@ -130,6 +132,51 @@ type Objects interface { Integrations() Database } +func Close() error { + if database == nil { + return nil + } + return database.Close() +} + +func LogMode(b bool) Database { + return database.LogMode(b) +} + +func Begin(model interface{}) Database { + if all, ok := model.(string); ok { + if all == "migration" { + return database.Begin() + } + } + return database.Model(model).Begin() +} + +func Core() Database { + return database.Core() +} + +func Get() Database { + if Available() { + return database + } + return nil +} + +func Available() bool { + if database == nil { + return false + } + if err := database.DB().Ping(); err != nil { + return false + } + return true +} + +func (d *Db) Core() Database { + return d.Table("core").Model(&types.Service{}) +} + func (d *Db) Services() Database { return d.Model(&types.Service{}) } diff --git a/database/routines.go b/database/routines.go index 2ab6ac4f..f39cd5ed 100644 --- a/database/routines.go +++ b/database/routines.go @@ -6,6 +6,10 @@ import ( "github.com/hunterlong/statping/utils" "os" "time" + + _ "github.com/jinzhu/gorm/dialects/mysql" + _ "github.com/jinzhu/gorm/dialects/postgres" + _ "github.com/jinzhu/gorm/dialects/sqlite" ) var ( @@ -39,6 +43,8 @@ func StartMaintenceRoutine() { func databaseMaintence(dur time.Duration) { deleteAfter := time.Now().UTC().Add(dur) + time.Sleep(20 * types.Second) + for range time.Tick(maintenceDuration) { log.Infof("Deleting failures older than %s", dur.String()) DeleteAllSince("failures", deleteAfter) diff --git a/dev/docker-compose.db.yml b/dev/docker-compose.db.yml index 1ad1f208..02011a4b 100644 --- a/dev/docker-compose.db.yml +++ b/dev/docker-compose.db.yml @@ -6,13 +6,13 @@ services: container_name: postgres image: postgres volumes: - - ./docker/databases/postgres:/var/lib/postgresql/data + - ../docker/databases/postgres:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: password123 POSTGRES_DB: statping POSTGRES_USER: root - networks: - - statping + ports: + - 5432:5432 healthcheck: test: ["CMD-SHELL", "pg_isready -U root"] interval: 15s @@ -23,15 +23,15 @@ services: container_name: mysql image: mysql:5.7 volumes: - - ./docker/databases/mysql:/var/lib/mysql + - ../docker/databases/mysql:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: password123 MYSQL_DATABASE: statping MYSQL_USER: root MYSQL_PASSWORD: password - networks: - - statping + ports: + - 3306:3306 healthcheck: test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ] timeout: 20s @@ -55,27 +55,18 @@ services: PMA_USER: root PMA_PASSWORD: password123 PMA_PORT: 3306 - networks: - - statping sqlite-web: container_name: sqlite-web image: coleifer/sqlite-web restart: on-failure command: sqlite_web -H 0.0.0.0 -r -x /data/statping.db - depends_on: - statping: - condition: service_healthy ports: - 6050:8080 - links: - - statping volumes: - - ./docker/statping/sqlite/statping.db:/data/statping.db:ro + - ../docker/statping/sqlite/statping.db:/data/statping.db:ro environment: SQLITE_DATABASE: /data/statping.db - networks: - - statping pgadmin4: container_name: pgadmin4 @@ -91,25 +82,16 @@ services: - 7000:5050 links: - postgres:postgres - networks: - - statping prometheus: container_name: prometheus image: prom/prometheus:v2.0.0 restart: on-failure volumes: - - ./dev/prometheus.yml:/etc/prometheus/prometheus.yml - - ./docker/databases/prometheus:/prometheus - links: - - statping - - statping_mysql - - statping_postgres - - statping_dev + - ./prometheus.yml:/etc/prometheus/prometheus.yml + - ../docker/databases/prometheus:/prometheus ports: - 7050:9090 - networks: - - statping healthcheck: test: "/bin/wget -q -Y off http://localhost:9090/status -O /dev/null > /dev/null 2>&1" interval: 10s diff --git a/handlers/api.go b/handlers/api.go index 669b6ac3..37d901a8 100644 --- a/handlers/api.go +++ b/handlers/api.go @@ -52,7 +52,7 @@ func apiRenewHandler(w http.ResponseWriter, r *http.Request) { var err error core.CoreApp.ApiKey = utils.NewSHA1Hash(40) core.CoreApp.ApiSecret = utils.NewSHA1Hash(40) - core.CoreApp, err = core.UpdateCore(core.CoreApp) + err = database.Update(core.CoreApp) if err != nil { sendErrorJson(err, w, r) return @@ -91,7 +91,7 @@ func apiCoreHandler(w http.ResponseWriter, r *http.Request) { app.Timezone = c.Timezone } app.UseCdn = types.NewNullBool(c.UseCdn.Bool) - core.CoreApp, err = core.UpdateCore(app) + err = database.Update(app) returnJson(core.CoreApp, w, r) } diff --git a/handlers/api_test.go b/handlers/api_test.go index dd29a7b5..a957fb28 100644 --- a/handlers/api_test.go +++ b/handlers/api_test.go @@ -36,7 +36,6 @@ func TestResetDatabase(t *testing.T) { t.Log(err) require.Nil(t, err) require.NotNil(t, core.CoreApp) - require.NotNil(t, core.CoreApp.Config) } func TestFailedHTTPServer(t *testing.T) { diff --git a/handlers/incident.go b/handlers/incident.go index 91c6c201..1dbe855d 100644 --- a/handlers/incident.go +++ b/handlers/incident.go @@ -24,17 +24,17 @@ func apiCreateIncidentHandler(w http.ResponseWriter, r *http.Request) { return } newIncident := core.ReturnIncident(incident) - _, err = newIncident.Create() + obj, err := database.Create(newIncident) if err != nil { sendErrorJson(err, w, r) return } - sendJsonAction(newIncident, "create", w, r) + sendJsonAction(obj, "create", w, r) } func apiIncidentUpdateHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - incident, err := core.SelectIncident(utils.ToInt(vars["id"])) + incident, err := database.Incident(utils.ToInt(vars["id"])) if err != nil { sendErrorJson(err, w, r) return @@ -47,7 +47,7 @@ func apiIncidentUpdateHandler(w http.ResponseWriter, r *http.Request) { return } - _, err = incident.Update() + err = database.Update(&incident) if err != nil { sendErrorJson(err, w, r) return @@ -57,12 +57,12 @@ func apiIncidentUpdateHandler(w http.ResponseWriter, r *http.Request) { func apiDeleteIncidentHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - incident, err := core.SelectIncident(utils.ToInt(vars["id"])) + incident, err := database.Incident(utils.ToInt(vars["id"])) if err != nil { sendErrorJson(err, w, r) return } - err = incident.Delete() + err = database.Delete(incident) if err != nil { sendErrorJson(err, w, r) return diff --git a/handlers/index.go b/handlers/index.go index 37ddf804..14a76a51 100644 --- a/handlers/index.go +++ b/handlers/index.go @@ -32,7 +32,7 @@ func healthCheckHandler(w http.ResponseWriter, r *http.Request) { health := map[string]interface{}{ "services": len(core.Services()), "online": true, - "setup": core.CoreApp.Config != nil, + "setup": core.IsSetup(), } returnJson(health, w, r) } diff --git a/handlers/messages.go b/handlers/messages.go index 4bea0ae4..532fc22f 100644 --- a/handlers/messages.go +++ b/handlers/messages.go @@ -19,27 +19,15 @@ import ( "encoding/json" "fmt" "github.com/gorilla/mux" - "github.com/hunterlong/statping/core" + "github.com/hunterlong/statping/database" "github.com/hunterlong/statping/types" "github.com/hunterlong/statping/utils" "net/http" ) func apiAllMessagesHandler(r *http.Request) interface{} { - messages, err := core.SelectMessages() - if err != nil { - log.Error(err) - return nil - } - return joinMessages(messages) -} - -func joinMessages(messages []*core.Message) []*types.Message { - var m []*types.Message - for _, v := range messages { - m = append(m, v.Message) - } - return m + messages := database.AllMessages() + return messages } func apiMessageCreateHandler(w http.ResponseWriter, r *http.Request) { @@ -50,18 +38,17 @@ func apiMessageCreateHandler(w http.ResponseWriter, r *http.Request) { sendErrorJson(err, w, r) return } - msg := core.ReturnMessage(message) - _, err = msg.Create() + _, err = database.Create(message) if err != nil { sendErrorJson(err, w, r) return } - sendJsonAction(msg, "create", w, r) + sendJsonAction(message, "create", w, r) } func apiMessageGetHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - message, err := core.SelectMessage(utils.ToInt(vars["id"])) + message, err := database.Message(utils.ToInt(vars["id"])) if err != nil { sendErrorJson(err, w, r) return @@ -71,12 +58,12 @@ func apiMessageGetHandler(w http.ResponseWriter, r *http.Request) { func apiMessageDeleteHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - message, err := core.SelectMessage(utils.ToInt(vars["id"])) + message, err := database.Message(utils.ToInt(vars["id"])) if err != nil { sendErrorJson(err, w, r) return } - err = message.Delete() + err = database.Delete(message) if err != nil { sendErrorJson(err, w, r) return @@ -86,7 +73,7 @@ func apiMessageDeleteHandler(w http.ResponseWriter, r *http.Request) { func apiMessageUpdateHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - message, err := core.SelectMessage(utils.ToInt(vars["id"])) + message, err := database.Message(utils.ToInt(vars["id"])) if err != nil { sendErrorJson(fmt.Errorf("message #%v was not found", vars["id"]), w, r) return @@ -97,7 +84,7 @@ func apiMessageUpdateHandler(w http.ResponseWriter, r *http.Request) { sendErrorJson(err, w, r) return } - _, err = message.Update() + err = database.Update(message) if err != nil { sendErrorJson(err, w, r) return diff --git a/handlers/middleware.go b/handlers/middleware.go index 8557ce18..699f9700 100644 --- a/handlers/middleware.go +++ b/handlers/middleware.go @@ -135,7 +135,7 @@ func cached(duration, contentType string, handler func(w http.ResponseWriter, r content := CacheStorage.Get(r.RequestURI) w.Header().Set("Content-Type", contentType) w.Header().Set("Access-Control-Allow-Origin", "*") - if core.CoreApp.Config == nil { + if !core.IsSetup() { handler(w, r) return } diff --git a/handlers/setup.go b/handlers/setup.go index 2ce9fb5f..0c49190d 100644 --- a/handlers/setup.go +++ b/handlers/setup.go @@ -52,7 +52,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { sample, _ := strconv.ParseBool(r.PostForm.Get("sample_data")) dir := utils.Directory - config := &core.DbConfig{DbConfig: &types.DbConfig{ + configs := &types.DbConfig{ DbConn: dbConn, DbHost: dbHost, DbUser: dbUser, @@ -67,11 +67,11 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { Email: email, Error: nil, Location: utils.Directory, - }} + } - log.WithFields(utils.ToFields(core.CoreApp, config)).Debugln("new configs posted") + log.WithFields(utils.ToFields(core.CoreApp, configs)).Debugln("new configs posted") - if err := config.Save(); err != nil { + if err := core.SaveConfig(configs); err != nil { log.Errorln(err) sendErrorJson(err, w, r) return @@ -83,7 +83,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { return } - if err = core.CoreApp.Connect(false, dir); err != nil { + if err = core.CoreApp.Connect(configs, false, dir); err != nil { log.Errorln(err) core.DeleteConfig() sendErrorJson(err, w, r) @@ -100,7 +100,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { return } - core.CoreApp, err = config.InsertCore() + core.CoreApp, err = core.InsertCore(configs) if err != nil { log.Errorln(err) sendErrorJson(err, w, r) @@ -108,9 +108,9 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { } admin := &types.User{ - Username: config.Username, - Password: config.Password, - Email: config.Email, + Username: configs.Username, + Password: configs.Password, + Email: configs.Email, Admin: types.NewNullBool(true), } database.Create(admin) @@ -129,8 +129,8 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { Message string `json:"message"` Config *types.DbConfig `json:"config"` }{ - "okokok", - config.DbConfig, + "success", + configs, } returnJson(out, w, r) } diff --git a/handlers/users.go b/handlers/users.go index c3bb355f..d24276dd 100644 --- a/handlers/users.go +++ b/handlers/users.go @@ -60,8 +60,8 @@ func apiUserUpdateHandler(w http.ResponseWriter, r *http.Request) { func apiUserDeleteHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - users := core.CountUsers() - if users == 1 { + users := database.AllUsers() + if len(users) == 1 { sendErrorJson(errors.New("cannot delete the last user"), w, r) return } diff --git a/source/source_test.go b/source/source_test.go index f405c30c..bf60aaa7 100644 --- a/source/source_test.go +++ b/source/source_test.go @@ -78,7 +78,7 @@ func TestSaveAndCompileAsset(t *testing.T) { themeCSS, err := utils.OpenFile(dir + "/assets/css/theme.css") require.Nil(t, err) - assert.Equal(t, scssData, themeCSS) + assert.Contains(t, themeCSS, `color: #333;`) } func TestOpenAsset(t *testing.T) { @@ -88,12 +88,7 @@ func TestOpenAsset(t *testing.T) { func TestDeleteAssets(t *testing.T) { assert.True(t, UsingAssets(dir)) - //assert.Nil(t, DeleteAllAssets(dir)) - assert.False(t, UsingAssets(dir)) -} - -func TestCopyToPluginFailed(t *testing.T) { - //assert.Nil(t, DeleteAllAssets(dir)) + assert.Nil(t, DeleteAllAssets(dir)) assert.False(t, UsingAssets(dir)) } diff --git a/types/core.go b/types/core.go index c3d235f8..ddf66c98 100644 --- a/types/core.go +++ b/types/core.go @@ -48,7 +48,6 @@ type Core struct { Started time.Time `gorm:"-" json:"started_on"` Plugins []*Info `gorm:"-" json:"-"` Notifications []AllNotifiers `gorm:"-" json:"-"` - Config *DbConfig `gorm:"-" json:"-"` Integrations []Integrator `gorm:"-" json:"-"` }