diff --git a/Makefile b/Makefile index 002ecd09..458b0376 100644 --- a/Makefile +++ b/Makefile @@ -164,6 +164,10 @@ install: build install-local: build mv $(BINARY_NAME) /usr/local/bin/$(BINARY_NAME) +install-darwin: + go build -a -ldflags "-X main.VERSION=${VERSION}" -o statping --tags "netgo darwin" ./cmd + mv $(BINARY_NAME) /usr/local/bin/$(BINARY_NAME) + generate: cd source && go generate @@ -399,5 +403,5 @@ check: @echo "yarn: $(shell yarn --version) - $(shell which yarn)" && yarn --version >/dev/null 2>&1 || (echo "ERROR: yarn is required."; exit 1) @echo "All required programs are installed!" -.PHONY: all check build certs multiarch go-build build-all buildx-base buildx-dev buildx-latest build-alpine test-all test test-api docker frontend up down print_details lite sentry-release snapcraft build-linux build-mac build-win build-all postman +.PHONY: all check build certs multiarch install-darwin go-build build-all buildx-base buildx-dev buildx-latest build-alpine test-all test test-api docker frontend up down print_details lite sentry-release snapcraft build-linux build-mac build-win build-all postman .SILENT: travis_s3_creds diff --git a/cmd/cli.go b/cmd/cli.go index 4673318c..90a56144 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -16,6 +16,7 @@ import ( "github.com/statping/statping/utils" "io/ioutil" "os" + "path/filepath" "strings" "time" ) @@ -67,8 +68,8 @@ After=network-online.target [Service] Type=simple Restart=always -Environment=STATPING_DIR=` + dir + ` -Environment=ALLOW_REPORTS=true +Environment="STATPING_DIR=` + dir + `" +Environment="ALLOW_REPORTS=true" ExecStart=` + binPath + ` --port=` + utils.ToString(port) + ` WorkingDirectory=` + dir + ` @@ -97,7 +98,7 @@ WantedBy=multi-user.target" } func exportCli(args []string) error { - filename := fmt.Sprintf("%s/statping-%s.json", utils.Directory, time.Now().Format("01-02-2006-1504")) + filename := filepath.Join(utils.Directory, time.Now().Format("01-02-2006-1504")+".json") if len(args) == 1 { filename = fmt.Sprintf("%s/%s", utils.Directory, args) } diff --git a/cmd/cli_test.go b/cmd/cli_test.go index 94de537d..586db178 100644 --- a/cmd/cli_test.go +++ b/cmd/cli_test.go @@ -2,10 +2,12 @@ package main import ( "bytes" + "github.com/statping/statping/source" "github.com/statping/statping/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "io/ioutil" + "os" "testing" ) @@ -18,16 +20,15 @@ func init() { } func TestStatpingDirectory(t *testing.T) { - dir := utils.Directory - require.NotContains(t, dir, "/cmd") - require.NotEmpty(t, dir) - dir = utils.Params.GetString("STATPING_DIR") require.NotContains(t, dir, "/cmd") require.NotEmpty(t, dir) } func TestEnvCLI(t *testing.T) { + os.Setenv("API_SECRET", "demoapisecret123") + os.Setenv("SASS", "/usr/local/bin/sass") + cmd := rootCmd b := bytes.NewBufferString("") cmd.SetOut(b) @@ -39,6 +40,12 @@ func TestEnvCLI(t *testing.T) { assert.Contains(t, string(out), VERSION) assert.Contains(t, utils.Directory, string(out)) assert.Contains(t, "SAMPLE_DATA=true", string(out)) + assert.Contains(t, "API_SECRET=demoapisecret123", string(out)) + assert.Contains(t, "STATPING_DIR="+dir, string(out)) + assert.Contains(t, "SASS=/usr/local/bin/sass", string(out)) + + os.Unsetenv("API_SECRET") + os.Unsetenv("SASS") } func TestVersionCLI(t *testing.T) { @@ -58,16 +65,26 @@ func TestAssetsCLI(t *testing.T) { b := bytes.NewBufferString("") cmd.SetOut(b) cmd.SetArgs([]string{"assets"}) - cmd.Execute() + err := cmd.Execute() + require.Nil(t, err) out, err := ioutil.ReadAll(b) assert.Nil(t, err) assert.Contains(t, string(out), VERSION) - assert.FileExists(t, utils.Directory+"/assets/css/main.css") - assert.FileExists(t, utils.Directory+"/assets/css/style.css") - assert.FileExists(t, utils.Directory+"/assets/css/vendor.css") - assert.FileExists(t, utils.Directory+"/assets/scss/base.scss") - assert.FileExists(t, utils.Directory+"/assets/scss/mobile.scss") - assert.FileExists(t, utils.Directory+"/assets/scss/variables.scss") + for _, f := range source.RequiredFiles { + assert.FileExists(t, utils.Directory+"/assets/"+f) + } +} + +func TestUpdateCLI(t *testing.T) { + cmd := rootCmd + b := bytes.NewBufferString("") + cmd.SetOut(b) + cmd.SetArgs([]string{"update"}) + err := cmd.Execute() + require.Nil(t, err) + out, err := ioutil.ReadAll(b) + require.Nil(t, err) + assert.Contains(t, string(out), VERSION) } func TestHelpCLI(t *testing.T) { diff --git a/cmd/commands.go b/cmd/commands.go index 19d2b59c..f6829649 100644 --- a/cmd/commands.go +++ b/cmd/commands.go @@ -12,16 +12,18 @@ import ( ) var rootCmd = &cobra.Command{ - Use: "statping", - Short: "A simple Application Status Monitor that is opensource and lightweight.", + Use: "statping", + Version: VERSION, + Short: "A simple Application Status Monitor that is opensource and lightweight.", Run: func(cmd *cobra.Command, args []string) { start() }, } var updateCmd = &cobra.Command{ - Use: "update", - Short: "Update to the latest version", + Use: "update", + Example: "statping update", + Short: "Update to the latest version", RunE: func(cmd *cobra.Command, args []string) error { log.Infoln("Updating Statping to the latest version...") curl, err := exec.LookPath("curl") @@ -59,8 +61,9 @@ var updateCmd = &cobra.Command{ } var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print the version number of Statping", + Use: "version", + Example: "statping version", + Short: "Print the version number of Statping", Run: func(cmd *cobra.Command, args []string) { if COMMIT != "" { fmt.Printf("%s (%s)\n", VERSION, COMMIT) @@ -72,8 +75,9 @@ var versionCmd = &cobra.Command{ } var systemctlCmd = &cobra.Command{ - Use: "systemctl [install/uninstall]", - Short: "Install or Uninstall systemctl services", + Use: "systemctl [install/uninstall]", + Example: "statping systemctl install", + Short: "Install or Uninstall systemctl services", RunE: func(cmd *cobra.Command, args []string) error { if args[1] == "install" { if len(args) < 3 { @@ -99,8 +103,9 @@ var systemctlCmd = &cobra.Command{ } var assetsCmd = &cobra.Command{ - Use: "assets", - Short: "Dump all assets used locally to be edited", + Use: "assets", + Example: "statping assets", + Short: "Dump all assets used locally to be edited", RunE: func(cmd *cobra.Command, args []string) error { if err := assetsCli(); err != nil { return err @@ -111,8 +116,9 @@ var assetsCmd = &cobra.Command{ } var exportCmd = &cobra.Command{ - Use: "export", - Short: "Exports your Statping settings to a 'statping-export.json' file.", + Use: "export", + Example: "statping export", + Short: "Exports your Statping settings to a 'statping-export.json' file.", RunE: func(cmd *cobra.Command, args []string) error { if err := exportCli(args); err != nil { return err @@ -123,8 +129,9 @@ var exportCmd = &cobra.Command{ } var sassCmd = &cobra.Command{ - Use: "sass", - Short: "Compile .scss files into the css directory", + Use: "sass", + Example: "statping sass", + Short: "Compile .scss files into the css directory", RunE: func(cmd *cobra.Command, args []string) error { if err := sassCli(); err != nil { return err @@ -135,8 +142,9 @@ var sassCmd = &cobra.Command{ } var envCmd = &cobra.Command{ - Use: "env", - Short: "Return the configs that will be ran", + Use: "env", + Example: "statping env", + Short: "Return the configs that will be ran", RunE: func(cmd *cobra.Command, args []string) error { if err := envCli(); err != nil { return err @@ -147,8 +155,9 @@ var envCmd = &cobra.Command{ } var resetCmd = &cobra.Command{ - Use: "reset", - Short: "Start a fresh copy of Statping", + Use: "reset", + Example: "statping reset", + Short: "Start a fresh copy of Statping", RunE: func(cmd *cobra.Command, args []string) error { if err := resetCli(); err != nil { return err @@ -159,8 +168,9 @@ var resetCmd = &cobra.Command{ } var onceCmd = &cobra.Command{ - Use: "once", - Short: "Check all services 1 time and then quit", + Use: "once", + Example: "statping once", + Short: "Check all services 1 time and then quit", RunE: func(cmd *cobra.Command, args []string) error { if err := onceCli(); err != nil { return err @@ -171,8 +181,9 @@ var onceCmd = &cobra.Command{ } var importCmd = &cobra.Command{ - Use: "import [.json file]", - Short: "Imports settings from a previously saved JSON file.", + Use: "import [.json file]", + Example: "statping import backup.json", + Short: "Imports settings from a previously saved JSON file.", RunE: func(cmd *cobra.Command, args []string) error { if err := importCli(args); err != nil { return err diff --git a/frontend/src/assets/scss/forms.scss b/frontend/src/assets/scss/forms.scss index 6ddaf46f..9413f9d4 100644 --- a/frontend/src/assets/scss/forms.scss +++ b/frontend/src/assets/scss/forms.scss @@ -31,7 +31,7 @@ .form-control[readonly] { background-color: lighten($background-color, 12%) !important; - color: lighten($input-color, 40%) !important; + color: lighten($input-color, 30%) !important; } /* The slider itself */ diff --git a/frontend/src/pages/Settings.vue b/frontend/src/pages/Settings.vue index 4f43c733..89cc46a4 100644 --- a/frontend/src/pages/Settings.vue +++ b/frontend/src/pages/Settings.vue @@ -20,8 +20,6 @@
Notifiers
- {{notifiers}} -
{{notifier.title}} diff --git a/go.mod b/go.mod index 5f29be9e..a8c549c2 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/getsentry/sentry-go v0.5.1 github.com/go-mail/mail v2.3.1+incompatible + github.com/golang/protobuf v1.4.0 github.com/gorilla/mux v1.7.4 github.com/hako/durafmt v0.0.0-20200605151348-3a43fc422dd9 github.com/jinzhu/gorm v1.9.12 diff --git a/handlers/notifications.go b/handlers/notifications.go index 7d1e9b86..6af69258 100644 --- a/handlers/notifications.go +++ b/handlers/notifications.go @@ -67,9 +67,9 @@ type testNotificationReq struct { func testNotificationHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - n, err := notifications.Find(vars["notifier"]) - if err != nil { - sendErrorJson(err, w, r) + n := services.FindNotifier(vars["notifier"]) + if n == nil { + sendErrorJson(errors.New("unknown notifier"), w, r) return } @@ -82,6 +82,7 @@ func testNotificationHandler(w http.ResponseWriter, r *http.Request) { notif := services.ReturnNotifier(n.Method) var out string + var err error if req.Method == "success" { out, err = notif.OnSuccess(services.Example(true)) } else { diff --git a/source/source.go b/source/source.go index 6aa5f03b..b124e37d 100644 --- a/source/source.go +++ b/source/source.go @@ -14,8 +14,27 @@ import ( ) var ( - log = utils.Log.WithField("type", "source") - TmplBox *rice.Box // HTML and other small files from the 'source/tmpl' directory, this will be loaded into '/assets' + log = utils.Log.WithField("type", "source") + TmplBox *rice.Box // HTML and other small files from the 'source/tmpl' directory, this will be loaded into '/assets' + RequiredFiles = []string{ + "css/style.css", + "css/style.css.gz", + "css/main.css", + "scss/main.scss", + "scss/base.scss", + "scss/forms.scss", + "scss/layout.scss", + "scss/mixin.scss", + "scss/mobile.scss", + "scss/variables.scss", + "js/bundle.js", + "js/main.chunk.js", + "js/polyfill.chunk.js", + "js/style.chunk.js", + "banner.png", + "favicon.ico", + "robots.txt", + } ) // Assets will load the Rice boxes containing the CSS, SCSS, JS, and HTML files. diff --git a/source/source_test.go b/source/source_test.go index 053934b6..564e905d 100644 --- a/source/source_test.go +++ b/source/source_test.go @@ -8,26 +8,7 @@ import ( ) var ( - dir string - requiredFiles = []string{ - "css/style.css", - "css/style.css.gz", - "css/main.css", - "scss/main.scss", - "scss/base.scss", - "scss/forms.scss", - "scss/layout.scss", - "scss/mixin.scss", - "scss/mobile.scss", - "scss/variables.scss", - "js/bundle.js", - "js/main.chunk.js", - "js/polyfill.chunk.js", - "js/style.chunk.js", - "banner.png", - "favicon.ico", - "robots.txt", - } + dir string ) func init() { @@ -38,8 +19,8 @@ func init() { dir = utils.Params.GetString("STATPING_DIR") } -func assetFiles(t *testing.T, exist bool) { - for _, f := range requiredFiles { +func assertFiles(t *testing.T, exist bool) { + for _, f := range RequiredFiles { if exist { assert.FileExists(t, dir+"/assets/"+f) } else { @@ -50,54 +31,65 @@ func assetFiles(t *testing.T, exist bool) { func TestCore_UsingAssets(t *testing.T) { assert.False(t, UsingAssets(dir)) - assetFiles(t, false) + assertFiles(t, false) } func TestCreateAssets(t *testing.T) { assert.Nil(t, CreateAllAssets(dir)) assert.True(t, UsingAssets(dir)) assert.Nil(t, CompileSASS()) - assetFiles(t, true) + assertFiles(t, true) } func TestCopyAllToPublic(t *testing.T) { err := CopyAllToPublic(TmplBox) require.Nil(t, err) - assetFiles(t, true) + assertFiles(t, true) } func TestCompileSASS(t *testing.T) { err := CompileSASS() require.Nil(t, err) assert.True(t, UsingAssets(dir)) - assetFiles(t, true) + assertFiles(t, true) } func TestSaveAndCompileAsset(t *testing.T) { - scssData := "$bodycolor: #333; BODY { color: $bodycolor; }" + vars := OpenAsset("scss/variables.scss") + vars += "$testingcolor: #b1b2b3;" - err := SaveAsset([]byte(scssData), "scss/base.scss") + err := SaveAsset([]byte(vars), "scss/variables.scss") + require.Nil(t, err) + assert.FileExists(t, dir+"/assets/scss/variables.scss") + + scssData := OpenAsset("scss/base.scss") + scssData += "BODY { color: $testingcolor; }" + err = SaveAsset([]byte(scssData), "scss/base.scss") require.Nil(t, err) assert.FileExists(t, dir+"/assets/scss/base.scss") - asset := OpenAsset("scss/base.scss") + asset := OpenAsset("scss/variables.scss") + assert.NotEmpty(t, asset) + assert.Equal(t, vars, asset) + + asset = OpenAsset("scss/base.scss") assert.NotEmpty(t, asset) assert.Equal(t, scssData, asset) err = CompileSASS() require.Nil(t, err) - assert.FileExists(t, dir+"/assets/css/main.css") + assertFiles(t, true) themeCSS, err := utils.OpenFile(dir + "/assets/css/main.css") require.Nil(t, err) - assert.Contains(t, themeCSS, `color: #333;`) + assert.Contains(t, themeCSS, `color: #b1b2b3;`) } func TestOpenAsset(t *testing.T) { - for _, f := range requiredFiles { - asset := OpenAsset(f) - assert.NotEmpty(t, asset) + for _, f := range RequiredFiles { + assert.FileExists(t, dir+"/assets/"+f) + assert.NotEmpty(t, OpenAsset(f)) } } @@ -105,6 +97,7 @@ func TestDeleteAssets(t *testing.T) { assert.True(t, UsingAssets(dir)) assert.Nil(t, DeleteAllAssets(dir)) assert.False(t, UsingAssets(dir)) + assertFiles(t, false) } func ExampleSaveAsset() { diff --git a/types/configs/connection.go b/types/configs/connection.go index 9f795864..c2fb2d96 100644 --- a/types/configs/connection.go +++ b/types/configs/connection.go @@ -20,6 +20,19 @@ import ( "time" ) +func initModels(db database.Database) { + core.SetDB(db) + services.SetDB(db) + hits.SetDB(db) + failures.SetDB(db) + checkins.SetDB(db) + notifications.SetDB(db) + incidents.SetDB(db) + users.SetDB(db) + messages.SetDB(db) + groups.SetDB(db) +} + // Connect will attempt to connect to the sqlite, postgres, or mysql database func Connect(configs *DbConfig, retry bool) error { conn := configs.ConnectionString() @@ -61,19 +74,6 @@ func Connect(configs *DbConfig, retry bool) error { return err } -func initModels(db database.Database) { - core.SetDB(db) - services.SetDB(db) - hits.SetDB(db) - failures.SetDB(db) - checkins.SetDB(db) - notifications.SetDB(db) - incidents.SetDB(db) - users.SetDB(db) - messages.SetDB(db) - groups.SetDB(db) -} - func CreateAdminUser(c *DbConfig) error { adminUser := utils.Params.GetString("ADMIN_USER") adminPass := utils.Params.GetString("ADMIN_PASSWORD") diff --git a/types/configs/load.go b/types/configs/load.go index 4de36ab2..0258c80c 100644 --- a/types/configs/load.go +++ b/types/configs/load.go @@ -53,7 +53,7 @@ func LoadConfigs(cfgFile string) (*DbConfig, error) { if db.Location != "" { p.Set("LOCATION", db.Location) } - if db.ApiSecret != "" { + if db.ApiSecret != "" && p.GetString("API_SECRET") == "" { p.Set("API_SECRET", db.ApiSecret) } if db.Language != "" { @@ -90,10 +90,9 @@ func LoadConfigs(cfgFile string) (*DbConfig, error) { Language: p.GetString("LANGUAGE"), SendReports: p.GetBool("ALLOW_REPORTS"), LetsEncryptEnable: p.GetBool("LETSENCRYPT_ENABLE"), - } - if configs.LetsEncryptEnable { - configs.LetsEncryptHost = p.GetString("LETSENCRYPT_HOST") - configs.LetsEncryptEmail = p.GetString("LETSENCRYPT_EMAIL") + LetsEncryptHost: p.GetString("LETSENCRYPT_HOST"), + LetsEncryptEmail: p.GetString("LETSENCRYPT_EMAIL"), + ApiSecret: p.GetString("API_SECRET"), } log.WithFields(utils.ToFields(configs)).Debugln("read config file: " + cfgFile) diff --git a/types/configs/struct.go b/types/configs/struct.go index 2b10f317..166fd986 100644 --- a/types/configs/struct.go +++ b/types/configs/struct.go @@ -28,7 +28,6 @@ type DbConfig struct { LetsEncryptEmail string `yaml:"letsencrypt_email,omitempty" json:"letsencrypt_email"` LetsEncryptEnable bool `yaml:"letsencrypt_enable" json:"letsencrypt_enable"` LocalIP string `yaml:"-" json:"-"` - filename string `yaml:"-" json:"-"` Db database.Database `yaml:"-" json:"-"` } diff --git a/types/core/database.go b/types/core/database.go index 40197f91..83ff9c5f 100644 --- a/types/core/database.go +++ b/types/core/database.go @@ -12,6 +12,18 @@ var db database.Database func SetDB(database database.Database) { db = database.Model(&Core{}) + c, err := Select() + if err != nil { + utils.Log.Errorln(err) + return + } + apiEnv := utils.Params.GetString("API_SECRET") + if c.ApiSecret != apiEnv && apiEnv != "" { + c.ApiSecret = apiEnv + if err := c.Update(); err != nil { + utils.Log.Errorln(err) + } + } } func (c *Core) AfterFind() { @@ -42,6 +54,9 @@ func Select() (*Core, error) { if utils.Params.GetString("LANGUAGE") != "" { App.Language = utils.Params.GetString("LANGUAGE") } + if utils.Params.GetString("API_SECRET") != "" { + App.ApiSecret = utils.Params.GetString("API_SECRET") + } return App, q.Error() }