pull/429/head
Hunter Long 2020-03-02 22:42:37 -08:00
parent d5ffa3a851
commit eb5e291e56
29 changed files with 358 additions and 545 deletions

View File

@ -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 ====

View File

@ -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")
}

View File

@ -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

View File

@ -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()

View File

@ -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,30 +44,44 @@ 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 {
return InitialSetup(configs)
}
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")
@ -81,7 +89,7 @@ func LoadUsingEnv() (*DbConfig, error) {
if err := CoreApp.CreateDatabase(); err != nil {
return nil, errors.Wrap(err, "error creating database")
}
CoreApp, err = Configs.InsertCore()
CoreApp, err := InsertCore(configs)
if err != nil {
return nil, errors.Wrap(err, "error creating the core database")
}
@ -102,9 +110,9 @@ func LoadUsingEnv() (*DbConfig, error) {
if err := SampleData(); err != nil {
return nil, errors.Wrap(err, "error connecting sample data")
}
return Configs, err
}
return Configs, nil
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
}

View File

@ -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()
}

View File

@ -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) {

View File

@ -18,24 +18,25 @@ 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{}
)
@ -43,45 +44,9 @@ func init() {
DbModels = []interface{}{&types.Service{}, &types.User{}, &types.Hit{}, &types.Failure{}, &types.Message{}, &types.Group{}, &types.Checkin{}, &types.CheckinHit{}, &notifier.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
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
}

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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
}

View File

@ -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")

View File

@ -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) {

View File

@ -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)

View File

@ -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)
}

View File

@ -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 {

View File

@ -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{})
}

View File

@ -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)

View File

@ -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

View File

@ -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)
}

View File

@ -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) {

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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))
}

View File

@ -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:"-"`
}