error handling, tests, fixes

pull/508/head
hunterlong 2020-04-16 20:21:17 -07:00
parent 03e490afb9
commit 25d6f3b66a
32 changed files with 447 additions and 277 deletions

View File

@ -72,6 +72,8 @@ jobs:
DB_CONN: sqlite3 DB_CONN: sqlite3
STATPING_DIR: /home/runner/work/statping/statping STATPING_DIR: /home/runner/work/statping/statping
API_KEY: demopassword123 API_KEY: demopassword123
DISABLE_LOGS: true
ALLOW_REPORTS: true
DISCORD_URL: ${{ secrets.DISCORD_URL }} DISCORD_URL: ${{ secrets.DISCORD_URL }}
EMAIL_HOST: ${{ secrets.EMAIL_HOST }} EMAIL_HOST: ${{ secrets.EMAIL_HOST }}
EMAIL_USER: ${{ secrets.EMAIL_USER }} EMAIL_USER: ${{ secrets.EMAIL_USER }}
@ -90,7 +92,7 @@ jobs:
TWILIO_SECRET: ${{ secrets.TWILIO_SECRET }} TWILIO_SECRET: ${{ secrets.TWILIO_SECRET }}
TWILIO_FROM: ${{ secrets.TWILIO_FROM }} TWILIO_FROM: ${{ secrets.TWILIO_FROM }}
TWILIO_TO: ${{ secrets.TWILIO_TO }} TWILIO_TO: ${{ secrets.TWILIO_TO }}
run: SASS=`which sass` go test -v -covermode=count -coverprofile=coverage.out -p=1 ./... run: go test -v -covermode=count -coverprofile=coverage.out -p=1 ./...
- name: Build Binaries - name: Build Binaries
run: make build-bin build-win run: make build-bin build-win

View File

@ -4,6 +4,10 @@
- Added Viper and Cobra config/env parsing package - Added Viper and Cobra config/env parsing package
- Added more golang tests - Added more golang tests
- Modified handlers to use a more generic find method - Modified handlers to use a more generic find method
- Added 'env' command to show variables used in config
- Added 'reset' command that will delete files and backup .db file for a fresh install
- Added error type that has common errors with http status code based on error
# 0.90.27 (04-15-2020) # 0.90.27 (04-15-2020)
- Fixed postgres database table creation process - Fixed postgres database table creation process

View File

@ -79,6 +79,61 @@ func sassCli() error {
return nil return nil
} }
func resetCli() error {
d := utils.Directory
fmt.Println("Statping directory: ", d)
assets := d + "/assets"
if utils.FolderExists(assets) {
fmt.Printf("Deleting %s folder.\n", assets)
if err := utils.DeleteDirectory(assets); err != nil {
return err
}
} else {
fmt.Printf("Assets folder does not exist %s\n", assets)
}
logDir := d + "/logs"
if utils.FolderExists(logDir) {
fmt.Printf("Deleting %s directory.\n", logDir)
if err := utils.DeleteDirectory(logDir); err != nil {
return err
}
} else {
fmt.Printf("Logs folder does not exist %s\n", logDir)
}
c := d + "/config.yml"
if utils.FileExists(c) {
fmt.Printf("Deleting %s file.\n", c)
if err := utils.DeleteFile(c); err != nil {
return err
}
} else {
fmt.Printf("Config file does not exist %s\n", c)
}
dbFile := d + "/statping.db"
if utils.FileExists(dbFile) {
fmt.Printf("Backuping up %s file.\n", dbFile)
if err := utils.RenameDirectory(dbFile, d+"/statping.db.backup"); err != nil {
return err
}
} else {
fmt.Printf("Statping SQL Database file does not exist %s\n", dbFile)
}
fmt.Println("Statping has been reset")
return nil
}
func envCli() error {
fmt.Println("Statping Configuration")
for k, v := range utils.Params.AllSettings() {
fmt.Printf("%s=%v\n", strings.ToUpper(k), v)
}
return nil
}
func onceCli() error { func onceCli() error {
if err := utils.InitLogs(); err != nil { if err := utils.InitLogs(); err != nil {
return err return err
@ -182,21 +237,6 @@ func ask(format string) bool {
return strings.ToLower(text) == "y" return strings.ToLower(text) == "y"
} }
// ExportIndexHTML returns the HTML of the index page as a string
//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 { func updateDisplay() error {
gitCurrent, err := checkGithubUpdates() gitCurrent, err := checkGithubUpdates()
if err != nil { if err != nil {
@ -426,3 +466,18 @@ func ExportSettings() ([]byte, error) {
export, err := json.Marshal(data) export, err := json.Marshal(data)
return export, err return export, err
} }
// ExportIndexHTML returns the HTML of the index page as a string
//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()
//}

View File

@ -2,15 +2,11 @@ package main
import ( import (
"bytes" "bytes"
"github.com/rendon/testcli"
"github.com/statping/statping/utils" "github.com/statping/statping/utils"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"io/ioutil" "io/ioutil"
"os"
"os/exec"
"testing" "testing"
"time"
) )
var ( var (
@ -18,102 +14,31 @@ var (
) )
func init() { func init() {
dir = utils.Directory utils.InitCLI()
//core.SampleHits = 480
} }
func TestStartServerCommand(t *testing.T) { func TestStatpingDirectory(t *testing.T) {
t.SkipNow() dir := utils.Directory
cmd := helperCommand(nil, "") require.NotContains(t, dir, "/cmd")
var got = make(chan string) require.NotEmpty(t, dir)
commandAndSleep(cmd, time.Duration(60*time.Second), got)
os.Unsetenv("DB_CONN") dir = utils.Params.GetString("STATPING_DIR")
gg, _ := <-got require.NotContains(t, dir, "/cmd")
assert.Contains(t, gg, "DB_CONN environment variable was found") require.NotEmpty(t, dir)
assert.Contains(t, gg, "Core database does not exist, creating now!")
assert.Contains(t, gg, "Starting monitoring process for 5 Services")
} }
func TestVersionCommand(t *testing.T) { func TestEnvCLI(t *testing.T) {
c := testcli.Command("statping", "version") cmd := rootCmd
c.Run() b := bytes.NewBufferString("")
assert.True(t, c.StdoutContains(VERSION)) cmd.SetOut(b)
} cmd.SetArgs([]string{"env"})
err := cmd.Execute()
func TestHelpCommand(t *testing.T) {
c := testcli.Command("statping", "help")
c.Run()
t.Log(c.Stdout())
assert.True(t, c.StdoutContains("statping help - Shows the user basic information about Statping"))
}
func TestStaticCommand(t *testing.T) {
t.SkipNow()
cmd := helperCommand(nil, "static")
var got = make(chan string)
commandAndSleep(cmd, time.Duration(10*time.Second), got)
gg, _ := <-got
t.Log(gg)
assert.Contains(t, gg, "Exporting Static 'index.html' page...")
assert.Contains(t, gg, "Exported Statping index page: 'index.html'")
assert.FileExists(t, dir+"/index.html")
}
func TestExportCommand(t *testing.T) {
t.SkipNow()
cmd := helperCommand(nil, "export")
var got = make(chan string)
commandAndSleep(cmd, time.Duration(10*time.Second), got)
gg, _ := <-got
t.Log(gg)
assert.FileExists(t, dir+"/statping-export.json")
}
func TestUpdateCommand(t *testing.T) {
t.SkipNow()
cmd := helperCommand(nil, "version")
var got = make(chan string)
commandAndSleep(cmd, time.Duration(15*time.Second), got)
gg, _ := <-got
t.Log(gg)
assert.Contains(t, gg, VERSION)
}
func TestAssetsCommand(t *testing.T) {
t.SkipNow()
c := testcli.Command("statping", "assets")
c.Run()
t.Log(c.Stdout())
t.Log("Directory for Assets: ", dir)
time.Sleep(1 * time.Second)
err := utils.DeleteDirectory(dir + "/assets")
require.Nil(t, err) require.Nil(t, err)
assert.FileExists(t, dir+"/assets/robots.txt") out, err := ioutil.ReadAll(b)
assert.FileExists(t, dir+"/assets/scss/base.scss")
assert.FileExists(t, dir+"/assets/scss/main.scss")
assert.FileExists(t, dir+"/assets/scss/variables.scss")
assert.FileExists(t, dir+"/assets/css/main.css")
assert.FileExists(t, dir+"/assets/css/vendor.css")
assert.FileExists(t, dir+"/assets/css/style.css")
err = utils.DeleteDirectory(dir + "/assets")
require.Nil(t, err) require.Nil(t, err)
} assert.Contains(t, string(out), VERSION)
assert.Contains(t, utils.Directory, string(out))
func TestRunCommand(t *testing.T) { assert.Contains(t, "SAMPLE_DATA=true", string(out))
t.SkipNow()
cmd := helperCommand(nil, "run")
var got = make(chan string)
commandAndSleep(cmd, time.Duration(15*time.Second), got)
gg, _ := <-got
t.Log(gg)
assert.Contains(t, gg, "Running 1 time and saving to database...")
assert.Contains(t, gg, "Check is complete.")
}
func TestEnvironmentVarsCommand(t *testing.T) {
c := testcli.Command("statping", "env")
c.Run()
assert.True(t, c.StdoutContains("Statping Environment Variable"))
} }
func TestVersionCLI(t *testing.T) { func TestVersionCLI(t *testing.T) {
@ -121,10 +46,11 @@ func TestVersionCLI(t *testing.T) {
b := bytes.NewBufferString("") b := bytes.NewBufferString("")
cmd.SetOut(b) cmd.SetOut(b)
cmd.SetArgs([]string{"version"}) cmd.SetArgs([]string{"version"})
cmd.Execute() err := cmd.Execute()
require.Nil(t, err)
out, err := ioutil.ReadAll(b) out, err := ioutil.ReadAll(b)
assert.Nil(t, err) require.Nil(t, err)
assert.Contains(t, string(out), VERSION) assert.Contains(t, VERSION, string(out))
} }
func TestAssetsCLI(t *testing.T) { func TestAssetsCLI(t *testing.T) {
@ -132,51 +58,51 @@ func TestAssetsCLI(t *testing.T) {
b := bytes.NewBufferString("") b := bytes.NewBufferString("")
cmd.SetOut(b) cmd.SetOut(b)
cmd.SetArgs([]string{"assets"}) cmd.SetArgs([]string{"assets"})
cmd.Execute() err := cmd.Execute()
require.Nil(t, err)
out, err := ioutil.ReadAll(b) out, err := ioutil.ReadAll(b)
assert.Nil(t, err) assert.Nil(t, err)
assert.Contains(t, string(out), VERSION) assert.Contains(t, string(out), VERSION)
assert.FileExists(t, dir+"/assets/css/main.css") assert.FileExists(t, utils.Directory+"/assets/css/main.css")
assert.FileExists(t, dir+"/assets/css/style.css") assert.FileExists(t, utils.Directory+"/assets/css/style.css")
assert.FileExists(t, dir+"/assets/css/vendor.css") assert.FileExists(t, utils.Directory+"/assets/css/vendor.css")
assert.FileExists(t, dir+"/assets/scss/base.scss") assert.FileExists(t, utils.Directory+"/assets/scss/base.scss")
assert.FileExists(t, dir+"/assets/scss/mobile.scss") assert.FileExists(t, utils.Directory+"/assets/scss/mobile.scss")
assert.FileExists(t, dir+"/assets/scss/variables.scss") assert.FileExists(t, utils.Directory+"/assets/scss/variables.scss")
} }
func TestSassCLI(t *testing.T) { func TestHelpCLI(t *testing.T) {
c := testcli.Command("statping", "assets") cmd := rootCmd
c.Run() b := bytes.NewBufferString("")
t.Log(c.Stdout()) cmd.SetOut(b)
assert.FileExists(t, dir+"/assets/css/main.css") cmd.SetArgs([]string{"help"})
assert.FileExists(t, dir+"/assets/css/style.css") err := cmd.Execute()
assert.FileExists(t, dir+"/assets/css/vendor.css") require.Nil(t, err)
out, err := ioutil.ReadAll(b)
require.Nil(t, err)
assert.Contains(t, string(out), VERSION)
} }
func TestUpdateCLI(t *testing.T) { func TestResetCLI(t *testing.T) {
t.SkipNow() err := utils.SaveFile(utils.Directory+"/statping.db", []byte("test data"))
cmd := helperCommand(nil, "update") require.Nil(t, err)
var got = make(chan string)
commandAndSleep(cmd, time.Duration(15*time.Second), got)
gg, _ := <-got
t.Log(gg)
assert.Contains(t, gg, "version")
}
func commandAndSleep(cmd *exec.Cmd, duration time.Duration, out chan<- string) { cmd := rootCmd
go func(out chan<- string) { b := bytes.NewBufferString("")
runCommand(cmd, out) cmd.SetOut(b)
}(out) cmd.SetArgs([]string{"reset"})
time.Sleep(duration) err = cmd.Execute()
cmd.Process.Kill() require.Nil(t, err)
} out, err := ioutil.ReadAll(b)
require.Nil(t, err)
assert.Contains(t, string(out), VERSION)
func helperCommand(envs []string, s ...string) *exec.Cmd { assert.NoDirExists(t, utils.Directory+"/assets")
cmd := exec.Command("statping", s...) assert.NoDirExists(t, utils.Directory+"/logs")
return cmd assert.NoFileExists(t, utils.Directory+"/config.yml")
} assert.NoFileExists(t, utils.Directory+"/statping.db")
assert.FileExists(t, utils.Directory+"/statping.db.backup")
func runCommand(c *exec.Cmd, out chan<- string) { err = utils.DeleteFile(utils.Directory + "/statping.db.backup")
bout, _ := c.CombinedOutput() require.Nil(t, err)
out <- string(bout)
} }

View File

@ -50,6 +50,22 @@ var sassCmd = &cobra.Command{
}, },
} }
var envCmd = &cobra.Command{
Use: "env",
Short: "Return the configs that will be ran",
RunE: func(cmd *cobra.Command, args []string) error {
return envCli()
},
}
var resetCmd = &cobra.Command{
Use: "reset",
Short: "Start a fresh copy of Statping",
RunE: func(cmd *cobra.Command, args []string) error {
return resetCli()
},
}
var onceCmd = &cobra.Command{ var onceCmd = &cobra.Command{
Use: "once", Use: "once",
Short: "Check all services 1 time and then quit", Short: "Check all services 1 time and then quit",

View File

@ -32,14 +32,16 @@ var (
func init() { func init() {
core.New(VERSION) core.New(VERSION)
utils.InitCLI()
parseFlags(rootCmd)
rootCmd.AddCommand(versionCmd) rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(assetsCmd) rootCmd.AddCommand(assetsCmd)
rootCmd.AddCommand(exportCmd) rootCmd.AddCommand(exportCmd)
rootCmd.AddCommand(importCmd) rootCmd.AddCommand(importCmd)
rootCmd.AddCommand(sassCmd) rootCmd.AddCommand(sassCmd)
rootCmd.AddCommand(onceCmd) rootCmd.AddCommand(onceCmd)
rootCmd.AddCommand(envCmd)
rootCmd.AddCommand(resetCmd)
utils.InitCLI()
parseFlags(rootCmd)
} }
// exit will return an error and return an exit code 1 due to this error // exit will return an error and return an exit code 1 due to this error

View File

@ -92,6 +92,7 @@ type Database interface {
// extra // extra
Error() error Error() error
Status() int
RowsAffected() int64 RowsAffected() int64
Since(time.Time) Database Since(time.Time) Database
@ -504,6 +505,34 @@ func (it *Db) Error() error {
return it.Database.Error return it.Database.Error
} }
func (it *Db) Status() int {
switch it.Database.Error {
case gorm.ErrRecordNotFound:
return 404
case gorm.ErrCantStartTransaction:
return 422
case gorm.ErrInvalidSQL:
return 500
case gorm.ErrUnaddressable:
return 500
default:
return 500
}
}
func (it *Db) Loggable() bool {
switch it.Database.Error {
case gorm.ErrCantStartTransaction:
return true
case gorm.ErrInvalidSQL:
return true
case gorm.ErrUnaddressable:
return true
default:
return false
}
}
func (it *Db) Since(ago time.Time) Database { func (it *Db) Since(ago time.Time) Database {
return it.Where("created_at > ?", it.FormatTime(ago)) return it.Where("created_at > ?", it.FormatTime(ago))
} }

View File

@ -1,11 +1,10 @@
package handlers package handlers
import ( import (
"encoding/json"
"errors"
"fmt" "fmt"
"github.com/statping/statping/types/checkins" "github.com/statping/statping/types/checkins"
"github.com/statping/statping/types/core" "github.com/statping/statping/types/core"
"github.com/statping/statping/types/errors"
"github.com/statping/statping/types/groups" "github.com/statping/statping/types/groups"
"github.com/statping/statping/types/incidents" "github.com/statping/statping/types/incidents"
"github.com/statping/statping/types/messages" "github.com/statping/statping/types/messages"
@ -22,7 +21,7 @@ type apiResponse struct {
Status string `json:"status"` Status string `json:"status"`
Object string `json:"type,omitempty"` Object string `json:"type,omitempty"`
Method string `json:"method,omitempty"` Method string `json:"method,omitempty"`
Error string `json:"error,omitempty"` Error error `json:"error,omitempty"`
Id int64 `json:"id,omitempty"` Id int64 `json:"id,omitempty"`
Output interface{} `json:"output,omitempty"` Output interface{} `json:"output,omitempty"`
} }
@ -54,8 +53,7 @@ func apiRenewHandler(w http.ResponseWriter, r *http.Request) {
func apiCoreHandler(w http.ResponseWriter, r *http.Request) { func apiCoreHandler(w http.ResponseWriter, r *http.Request) {
var c *core.Core var c *core.Core
decoder := json.NewDecoder(r.Body) err := DecodeJSON(r, &c)
err := decoder.Decode(&c)
if err != nil { if err != nil {
sendErrorJson(err, w, r) sendErrorJson(err, w, r)
return return
@ -111,17 +109,18 @@ func apiClearCacheHandler(w http.ResponseWriter, r *http.Request) {
returnJson(output, w, r) returnJson(output, w, r)
} }
func sendErrorJson(err error, w http.ResponseWriter, r *http.Request, statusCode ...int) { func sendErrorJson(err error, w http.ResponseWriter, r *http.Request) {
errCode := 0
e, ok := err.(errors.Error)
if ok {
errCode = e.Status()
}
log.WithField("url", r.URL.String()). log.WithField("url", r.URL.String()).
WithField("method", r.Method). WithField("method", r.Method).
WithField("code", statusCode). WithField("code", errCode).
Errorln(fmt.Errorf("sending error response for %s: %s", r.URL.String(), err.Error())) Errorln(fmt.Errorf("sending error response for %s: %s", r.URL.String(), err.Error()))
output := apiResponse{ returnJson(err, w, r)
Status: "error",
Error: err.Error(),
}
returnJson(output, w, r, statusCode...)
} }
func sendJsonAction(obj interface{}, method string, w http.ResponseWriter, r *http.Request) { func sendJsonAction(obj interface{}, method string, w http.ResponseWriter, r *http.Request) {
@ -173,11 +172,6 @@ func sendJsonAction(obj interface{}, method string, w http.ResponseWriter, r *ht
} }
func sendUnauthorizedJson(w http.ResponseWriter, r *http.Request) { func sendUnauthorizedJson(w http.ResponseWriter, r *http.Request) {
output := apiResponse{
Status: "error",
Error: errors.New("not authorized").Error(),
}
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized) returnJson(errors.NotAuthenticated, w, r)
returnJson(output, w, r)
} }

View File

@ -106,7 +106,7 @@ func TestSetupRoutes(t *testing.T) {
} }
func TestMainApiRoutes(t *testing.T) { func TestMainApiRoutes(t *testing.T) {
date := utils.Now().Format("2006-01-02") date := utils.Now().Format("2006-01")
tests := []HTTPTest{ tests := []HTTPTest{
{ {
Name: "Statping Details", Name: "Statping Details",

View File

@ -1,10 +1,10 @@
package handlers package handlers
import ( import (
"errors"
"fmt" "fmt"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/statping/statping/types/checkins" "github.com/statping/statping/types/checkins"
"github.com/statping/statping/types/errors"
"github.com/statping/statping/types/services" "github.com/statping/statping/types/services"
"github.com/statping/statping/utils" "github.com/statping/statping/utils"
"net" "net"
@ -13,14 +13,15 @@ import (
func findCheckin(r *http.Request) (*checkins.Checkin, string, error) { func findCheckin(r *http.Request) (*checkins.Checkin, string, error) {
vars := mux.Vars(r) vars := mux.Vars(r)
if vars["api"] == "" { id := vars["api"]
return nil, "", errors.New("missing checkin API in URL") if id == "" {
return nil, "", errors.IDMissing
} }
checkin, err := checkins.FindByAPI(vars["api"]) checkin, err := checkins.FindByAPI(id)
if err != nil { if err != nil {
return nil, vars["api"], err return nil, id, errors.Missing(checkins.Checkin{}, id)
} }
return checkin, vars["api"], nil return checkin, id, nil
} }
func apiAllCheckinsHandler(w http.ResponseWriter, r *http.Request) { func apiAllCheckinsHandler(w http.ResponseWriter, r *http.Request) {
@ -29,9 +30,9 @@ func apiAllCheckinsHandler(w http.ResponseWriter, r *http.Request) {
} }
func apiCheckinHandler(w http.ResponseWriter, r *http.Request) { func apiCheckinHandler(w http.ResponseWriter, r *http.Request) {
checkin, id, err := findCheckin(r) checkin, _, err := findCheckin(r)
if err != nil { if err != nil {
sendErrorJson(fmt.Errorf("checkin %v was not found", id), w, r) sendErrorJson(err, w, r)
return return
} }
returnJson(checkin, w, r) returnJson(checkin, w, r)

View File

@ -73,6 +73,20 @@ func TestApiCheckinRoutes(t *testing.T) {
BeforeTest: SetTestENV, BeforeTest: SetTestENV,
Skip: true, Skip: true,
}, },
{
Name: "Statping Missing Trigger Checkin",
URL: "/checkin/" + apiToken,
Method: "GET",
BeforeTest: SetTestENV,
ExpectedStatus: 404,
},
{
Name: "Statping Missing Checkin",
URL: "/api/checkins/missing123",
Method: "GET",
BeforeTest: SetTestENV,
ExpectedStatus: 404,
},
} }
for _, v := range tests { for _, v := range tests {

View File

@ -2,7 +2,7 @@ package handlers
import ( import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/pkg/errors" "github.com/statping/statping/types/errors"
"github.com/statping/statping/types/groups" "github.com/statping/statping/types/groups"
"github.com/statping/statping/utils" "github.com/statping/statping/utils"
"net/http" "net/http"
@ -10,14 +10,22 @@ import (
func findGroup(r *http.Request) (*groups.Group, error) { func findGroup(r *http.Request) (*groups.Group, error) {
vars := mux.Vars(r) vars := mux.Vars(r)
if utils.NotNumber(vars["id"]) {
return nil, errors.NotNumber
}
id := utils.ToInt(vars["id"]) id := utils.ToInt(vars["id"])
if id == 0 { if id == 0 {
return nil, errors.New("missing group id") return nil, errors.IDMissing
} }
g, err := groups.Find(id) g, err := groups.Find(id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !g.Public.Bool {
if !IsReadAuthenticated(r) {
return nil, errors.NotAuthenticated
}
}
return g, nil return g, nil
} }
@ -31,7 +39,7 @@ func apiAllGroupHandler(r *http.Request) interface{} {
func apiGroupHandler(w http.ResponseWriter, r *http.Request) { func apiGroupHandler(w http.ResponseWriter, r *http.Request) {
group, err := findGroup(r) group, err := findGroup(r)
if err != nil { if err != nil {
sendErrorJson(errors.Wrap(err, "group not found"), w, r, http.StatusNotFound) sendErrorJson(err, w, r)
return return
} }
returnJson(group, w, r) returnJson(group, w, r)
@ -41,8 +49,7 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request) {
func apiGroupUpdateHandler(w http.ResponseWriter, r *http.Request) { func apiGroupUpdateHandler(w http.ResponseWriter, r *http.Request) {
group, err := findGroup(r) group, err := findGroup(r)
if err != nil { if err != nil {
w.WriteHeader(http.StatusNotFound) sendErrorJson(err, w, r)
sendErrorJson(errors.Wrap(err, "group not found"), w, r)
return return
} }
@ -79,7 +86,7 @@ func apiCreateGroupHandler(w http.ResponseWriter, r *http.Request) {
func apiGroupDeleteHandler(w http.ResponseWriter, r *http.Request) { func apiGroupDeleteHandler(w http.ResponseWriter, r *http.Request) {
group, err := findGroup(r) group, err := findGroup(r)
if err != nil { if err != nil {
sendErrorJson(errors.Wrap(err, "group not found"), w, r) sendErrorJson(err, w, r)
return return
} }

View File

@ -4,10 +4,10 @@ import (
"crypto/subtle" "crypto/subtle"
"crypto/tls" "crypto/tls"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go"
"github.com/statping/statping/types/core" "github.com/statping/statping/types/core"
"github.com/statping/statping/types/errors"
"html/template" "html/template"
"net/http" "net/http"
"os" "os"
@ -248,12 +248,14 @@ func ExecuteResponse(w http.ResponseWriter, r *http.Request, file string, data i
} }
} }
func returnJson(d interface{}, w http.ResponseWriter, r *http.Request, statusCode ...int) { func returnJson(d interface{}, w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if len(statusCode) != 0 { if e, ok := d.(errors.Error); ok {
code := statusCode[0] w.WriteHeader(e.Status())
w.WriteHeader(code) json.NewEncoder(w).Encode(e)
return
} }
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(d) json.NewEncoder(w).Encode(d)
} }
@ -263,5 +265,5 @@ func error404Handler(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains") w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
} }
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
ExecuteResponse(w, r, "index.html", nil, nil) ExecuteResponse(w, r, "base.gohtml", nil, nil)
} }

View File

@ -2,7 +2,7 @@ package handlers
import ( import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/pkg/errors" "github.com/statping/statping/types/errors"
"github.com/statping/statping/types/incidents" "github.com/statping/statping/types/incidents"
"github.com/statping/statping/utils" "github.com/statping/statping/utils"
"net/http" "net/http"
@ -10,13 +10,16 @@ import (
func findIncident(r *http.Request) (*incidents.Incident, int64, error) { func findIncident(r *http.Request) (*incidents.Incident, int64, error) {
vars := mux.Vars(r) vars := mux.Vars(r)
if utils.NotNumber(vars["id"]) {
return nil, 0, errors.NotNumber
}
id := utils.ToInt(vars["id"]) id := utils.ToInt(vars["id"])
if id == 0 { if id == 0 {
return nil, id, errors.New("missing checkin API in URL") return nil, id, errors.IDMissing
} }
checkin, err := incidents.Find(id) checkin, err := incidents.Find(id)
if err != nil { if err != nil {
return nil, id, err return nil, id, errors.Missing(&incidents.Incident{}, id)
} }
return checkin, id, nil return checkin, id, nil
} }

View File

@ -1,8 +1,8 @@
package handlers package handlers
import ( import (
"fmt"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/statping/statping/types/errors"
"github.com/statping/statping/types/messages" "github.com/statping/statping/types/messages"
"github.com/statping/statping/utils" "github.com/statping/statping/utils"
"net/http" "net/http"
@ -10,12 +10,15 @@ import (
func findMessage(r *http.Request) (*messages.Message, int64, error) { func findMessage(r *http.Request) (*messages.Message, int64, error) {
vars := mux.Vars(r) vars := mux.Vars(r)
num := utils.ToInt(vars["id"]) if utils.NotNumber(vars["id"]) {
message, err := messages.Find(num) return nil, 0, errors.NotNumber
if err != nil {
return nil, num, err
} }
return message, num, nil id := utils.ToInt(vars["id"])
message, err := messages.Find(id)
if err != nil {
return nil, id, err
}
return message, id, nil
} }
func apiAllMessagesHandler(r *http.Request) interface{} { func apiAllMessagesHandler(r *http.Request) interface{} {
@ -37,17 +40,17 @@ func apiMessageCreateHandler(w http.ResponseWriter, r *http.Request) {
} }
func apiMessageGetHandler(r *http.Request) interface{} { func apiMessageGetHandler(r *http.Request) interface{} {
message, id, err := findMessage(r) message, _, err := findMessage(r)
if err != nil { if err != nil {
return fmt.Errorf("message #%d was not found", id) return err
} }
return message return message
} }
func apiMessageDeleteHandler(w http.ResponseWriter, r *http.Request) { func apiMessageDeleteHandler(w http.ResponseWriter, r *http.Request) {
message, id, err := findMessage(r) message, _, err := findMessage(r)
if err != nil { if err != nil {
sendErrorJson(fmt.Errorf("message #%d was not found", id), w, r) sendErrorJson(err, w, r)
return return
} }
err = message.Delete() err = message.Delete()
@ -59,9 +62,9 @@ func apiMessageDeleteHandler(w http.ResponseWriter, r *http.Request) {
} }
func apiMessageUpdateHandler(w http.ResponseWriter, r *http.Request) { func apiMessageUpdateHandler(w http.ResponseWriter, r *http.Request) {
message, id, err := findMessage(r) message, _, err := findMessage(r)
if err != nil { if err != nil {
sendErrorJson(fmt.Errorf("message #%d was not found", id), w, r) sendErrorJson(err, w, r)
return return
} }
if err := DecodeJSON(r, &message); err != nil { if err := DecodeJSON(r, &message); err != nil {

View File

@ -29,7 +29,7 @@ func TestMessagesApiRoutes(t *testing.T) {
"notify_before_scale": "hour" "notify_before_scale": "hour"
}`, }`,
ExpectedStatus: 200, ExpectedStatus: 200,
ExpectedContains: []string{`"status":"success"`, `"type":"message"`, `"method":"create"`, `"title":"API Message"`}, ExpectedContains: []string{Success, `"type":"message"`, `"method":"create"`, `"title":"API Message"`},
BeforeTest: SetTestENV, BeforeTest: SetTestENV,
AfterTest: UnsetTestENV, AfterTest: UnsetTestENV,
SecureRoute: true, SecureRoute: true,
@ -40,7 +40,8 @@ func TestMessagesApiRoutes(t *testing.T) {
Method: "GET", Method: "GET",
ExpectedStatus: 200, ExpectedStatus: 200,
ExpectedContains: []string{`"title":"Routine Downtime"`}, ExpectedContains: []string{`"title":"Routine Downtime"`},
}, { },
{
Name: "Statping Update Message", Name: "Statping Update Message",
URL: "/api/messages/1", URL: "/api/messages/1",
Method: "POST", Method: "POST",
@ -68,7 +69,14 @@ func TestMessagesApiRoutes(t *testing.T) {
ExpectedContains: []string{`"status":"success"`, `"method":"delete"`}, ExpectedContains: []string{`"status":"success"`, `"method":"delete"`},
BeforeTest: SetTestENV, BeforeTest: SetTestENV,
SecureRoute: true, SecureRoute: true,
}} },
{
Name: "Statping Missing Message",
URL: "/api/messages/999999",
Method: "GET",
ExpectedStatus: 404,
},
}
for _, v := range tests { for _, v := range tests {
t.Run(v.Name, func(t *testing.T) { t.Run(v.Name, func(t *testing.T) {

View File

@ -4,9 +4,9 @@ import (
"compress/gzip" "compress/gzip"
"crypto/subtle" "crypto/subtle"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"github.com/statping/statping/types/core" "github.com/statping/statping/types/core"
"github.com/statping/statping/types/errors"
"github.com/statping/statping/utils" "github.com/statping/statping/utils"
"io" "io"
"net/http" "net/http"
@ -167,7 +167,7 @@ func DecodeJSON(r *http.Request, obj interface{}) error {
decoder := json.NewDecoder(r.Body) decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&obj) err := decoder.Decode(&obj)
if err != nil { if err != nil {
return err return errors.DecodeJSON
} }
defer r.Body.Close() defer r.Body.Close()
return nil return nil

View File

@ -2,8 +2,8 @@ package handlers
import ( import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/statping/statping/database" "github.com/statping/statping/database"
"github.com/statping/statping/types/errors"
"github.com/statping/statping/types/failures" "github.com/statping/statping/types/failures"
"github.com/statping/statping/types/hits" "github.com/statping/statping/types/hits"
"github.com/statping/statping/types/services" "github.com/statping/statping/types/services"
@ -21,7 +21,11 @@ func findService(r *http.Request) (*services.Service, error) {
id := utils.ToInt(vars["id"]) id := utils.ToInt(vars["id"])
servicer, err := services.Find(id) servicer, err := services.Find(id)
if err != nil { if err != nil {
return nil, errors.Errorf("service %d not found", id) return nil, err
}
user := IsUser(r)
if !servicer.Public.Bool && !user {
return nil, errors.NotAuthenticated
} }
return servicer, nil return servicer, nil
} }
@ -37,7 +41,7 @@ func reorderServiceHandler(w http.ResponseWriter, r *http.Request) {
for _, s := range newOrder { for _, s := range newOrder {
service, err := services.Find(s.Id) service, err := services.Find(s.Id)
if err != nil { if err != nil {
sendErrorJson(errors.Errorf("service %d not found", s.Id), w, r) sendErrorJson(err, w, r)
return return
} }
service.Order = s.Order service.Order = s.Order
@ -51,10 +55,6 @@ func apiServiceHandler(r *http.Request) interface{} {
if err != nil { if err != nil {
return err return err
} }
user := IsUser(r)
if !srv.Public.Bool && !user {
return errors.New("not authenticated")
}
srv = srv.UpdateStats() srv = srv.UpdateStats()
return *srv return *srv
} }
@ -78,11 +78,11 @@ func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) {
func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) { func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) {
service, err := findService(r) service, err := findService(r)
if err != nil { if err != nil {
sendErrorJson(err, w, r, http.StatusNotFound) sendErrorJson(err, w, r)
return return
} }
if err := DecodeJSON(r, &service); err != nil { if err := DecodeJSON(r, &service); err != nil {
sendErrorJson(err, w, r, http.StatusBadRequest) sendErrorJson(err, w, r)
return return
} }
@ -110,10 +110,9 @@ func apiServiceRunningHandler(w http.ResponseWriter, r *http.Request) {
} }
func apiServiceDataHandler(w http.ResponseWriter, r *http.Request) { func apiServiceDataHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) service, err := findService(r)
service, err := services.Find(utils.ToInt(vars["id"]))
if err != nil { if err != nil {
sendErrorJson(errors.New("service data not found"), w, r) sendErrorJson(err, w, r)
return return
} }
@ -132,10 +131,9 @@ func apiServiceDataHandler(w http.ResponseWriter, r *http.Request) {
} }
func apiServiceFailureDataHandler(w http.ResponseWriter, r *http.Request) { func apiServiceFailureDataHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) service, err := findService(r)
service, err := services.Find(utils.ToInt(vars["id"]))
if err != nil { if err != nil {
sendErrorJson(errors.New("service data not found"), w, r) sendErrorJson(err, w, r)
return return
} }
@ -157,7 +155,7 @@ func apiServiceFailureDataHandler(w http.ResponseWriter, r *http.Request) {
func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) { func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) {
service, err := findService(r) service, err := findService(r)
if err != nil { if err != nil {
sendErrorJson(errors.New("service data not found"), w, r) sendErrorJson(err, w, r)
return return
} }
@ -179,7 +177,7 @@ func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) {
func apiServiceTimeDataHandler(w http.ResponseWriter, r *http.Request) { func apiServiceTimeDataHandler(w http.ResponseWriter, r *http.Request) {
service, err := findService(r) service, err := findService(r)
if err != nil { if err != nil {
sendErrorJson(errors.New("service data not found"), w, r) sendErrorJson(err, w, r)
return return
} }
@ -258,12 +256,10 @@ func servicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
} }
func apiServiceFailuresHandler(r *http.Request) interface{} { func apiServiceFailuresHandler(r *http.Request) interface{} {
vars := mux.Vars(r) service, err := findService(r)
service, err := services.Find(utils.ToInt(vars["id"]))
if err != nil { if err != nil {
return errors.New("service not found") return err
} }
var fails []*failures.Failure var fails []*failures.Failure
query, err := database.ParseQueries(r, service.AllFailures()) query, err := database.ParseQueries(r, service.AllFailures())
if err != nil { if err != nil {
@ -274,12 +270,10 @@ func apiServiceFailuresHandler(r *http.Request) interface{} {
} }
func apiServiceHitsHandler(r *http.Request) interface{} { func apiServiceHitsHandler(r *http.Request) interface{} {
vars := mux.Vars(r) service, err := findService(r)
service, err := services.Find(utils.ToInt(vars["id"]))
if err != nil { if err != nil {
return errors.New("service not found") return err
} }
var hts []*hits.Hit var hts []*hits.Hit
query, err := database.ParseQueries(r, service.AllHits()) query, err := database.ParseQueries(r, service.AllHits())
if err != nil { if err != nil {

View File

@ -60,13 +60,20 @@ func TestApiServiceRoutes(t *testing.T) {
BeforeTest: UnsetTestENV, BeforeTest: UnsetTestENV,
}, },
{ {
Name: "Statping Private Service 1", Name: "Statping Private Service 6",
URL: "/api/services/6", URL: "/api/services/6",
Method: "GET", Method: "GET",
ExpectedContains: []string{`"error":"not authenticated"`}, ExpectedContains: []string{`"error":"user not authenticated"`},
ExpectedStatus: 200, ExpectedStatus: 401,
BeforeTest: UnsetTestENV, BeforeTest: UnsetTestENV,
}, },
{
Name: "Statping Authenticated Private Service 6",
URL: "/api/services/6",
Method: "GET",
ExpectedStatus: 200,
BeforeTest: SetTestENV,
},
{ {
Name: "Statping Service 1 with Private responses", Name: "Statping Service 1 with Private responses",
URL: "/api/services/1", URL: "/api/services/1",
@ -122,14 +129,14 @@ func TestApiServiceRoutes(t *testing.T) {
URL: "/api/services/1/failure_data" + startEndQuery + "&group=24h", URL: "/api/services/1/failure_data" + startEndQuery + "&group=24h",
Method: "GET", Method: "GET",
ExpectedStatus: 200, ExpectedStatus: 200,
GreaterThan: 4, GreaterThan: 3,
}, },
{ {
Name: "Statping Service 1 Failure Data - 12 Hour", Name: "Statping Service 1 Failure Data - 12 Hour",
URL: "/api/services/1/failure_data" + startEndQuery + "&group=12h", URL: "/api/services/1/failure_data" + startEndQuery + "&group=12h",
Method: "GET", Method: "GET",
ExpectedStatus: 200, ExpectedStatus: 200,
GreaterThan: 7, GreaterThan: 6,
}, },
{ {
Name: "Statping Service 1 Failure Data - 1 Hour", Name: "Statping Service 1 Failure Data - 1 Hour",
@ -162,7 +169,7 @@ func TestApiServiceRoutes(t *testing.T) {
if err := json.Unmarshal(resp, &uptime); err != nil { if err := json.Unmarshal(resp, &uptime); err != nil {
return err return err
} }
assert.GreaterOrEqual(t, uptime.Uptime, int64(259100000)) assert.GreaterOrEqual(t, uptime.Uptime, int64(200000000))
return nil return nil
}, },
}, },

View File

@ -1,9 +1,9 @@
package handlers package handlers
import ( import (
"errors"
"fmt" "fmt"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/statping/statping/types/errors"
"github.com/statping/statping/types/users" "github.com/statping/statping/types/users"
"github.com/statping/statping/utils" "github.com/statping/statping/utils"
"net/http" "net/http"
@ -11,10 +11,13 @@ import (
func findUser(r *http.Request) (*users.User, int64, error) { func findUser(r *http.Request) (*users.User, int64, error) {
vars := mux.Vars(r) vars := mux.Vars(r)
if utils.NotNumber(vars["id"]) {
return nil, 0, errors.NotNumber
}
num := utils.ToInt(vars["id"]) num := utils.ToInt(vars["id"])
user, err := users.Find(num) user, err := users.Find(num)
if err != nil { if err != nil {
return nil, num, err return nil, num, errors.Missing(&users.User{}, num)
} }
return user, num, nil return user, num, nil
} }
@ -22,7 +25,7 @@ func findUser(r *http.Request) (*users.User, int64, error) {
func apiUserHandler(w http.ResponseWriter, r *http.Request) { func apiUserHandler(w http.ResponseWriter, r *http.Request) {
user, _, err := findUser(r) user, _, err := findUser(r)
if err != nil { if err != nil {
sendErrorJson(err, w, r, http.StatusNotFound) sendErrorJson(err, w, r)
return return
} }
user.Password = "" user.Password = ""
@ -30,15 +33,15 @@ func apiUserHandler(w http.ResponseWriter, r *http.Request) {
} }
func apiUserUpdateHandler(w http.ResponseWriter, r *http.Request) { func apiUserUpdateHandler(w http.ResponseWriter, r *http.Request) {
user, id, err := findUser(r) user, _, err := findUser(r)
if err != nil { if err != nil {
sendErrorJson(fmt.Errorf("user #%d was not found", id), w, r) sendErrorJson(err, w, r)
return return
} }
err = DecodeJSON(r, &user) err = DecodeJSON(r, &user)
if err != nil { if err != nil {
sendErrorJson(fmt.Errorf("user #%d was not found", id), w, r) sendErrorJson(err, w, r)
return return
} }

View File

@ -42,7 +42,7 @@ func scssRendered(name string) string {
// CompileSASS will attempt to compile the SASS files into CSS // CompileSASS will attempt to compile the SASS files into CSS
func CompileSASS(files ...string) error { func CompileSASS(files ...string) error {
sassBin := utils.Getenv("SASS", "sass").(string) sassBin := utils.Params.GetString("SASS")
for _, file := range files { for _, file := range files {
scssFile := fmt.Sprintf("%v/assets/%v", utils.Directory, file) scssFile := fmt.Sprintf("%v/assets/%v", utils.Directory, file)

View File

@ -16,6 +16,9 @@ func (c *Checkin) Expected() time.Duration {
func (c *Checkin) Period() time.Duration { func (c *Checkin) Period() time.Duration {
duration, _ := time.ParseDuration(fmt.Sprintf("%ds", c.Interval)) duration, _ := time.ParseDuration(fmt.Sprintf("%ds", c.Interval))
if duration.Seconds() <= 15 {
return 15 * time.Second
}
return duration return duration
} }

38
types/errors/common.go Normal file
View File

@ -0,0 +1,38 @@
package errors
import (
"fmt"
"strings"
)
var (
NotAuthenticated = &appError{
Err: "user not authenticated",
Code: 401,
}
DecodeJSON = &appError{
Err: "could not decode incoming JSON",
Code: 422,
}
IDMissing = &appError{
Err: "ID missing in URL",
Code: 422,
}
NotNumber = &appError{
Err: "ID needs to be an integer",
Code: 422,
}
)
func Missing(object interface{}, id interface{}) error {
outErr := fmt.Errorf("%s with id %v was not found", splitVar(object), id)
return &appError{
Err: outErr.Error(),
Code: 404,
}
}
func splitVar(val interface{}) string {
s := strings.Split(fmt.Sprintf("%T", val), ".")
return strings.ToLower(s[len(s)-1])
}

48
types/errors/struct.go Normal file
View File

@ -0,0 +1,48 @@
package errors
import (
"github.com/pkg/errors"
)
type appError struct {
Err string `json:"error"`
Code int `json:"-"`
DbCode int `json:"code,omitempty"`
Id int64 `json:"id,omitempty"`
loggable bool `json:"-"`
}
type Error interface {
Error() string
Status() int
}
func New(err string) Error {
return &appError{
Err: err,
}
}
func Err(err Error) Error {
return &appError{
Err: err.Error(),
Code: err.Status(),
}
}
func Wrap(err error, message string) Error {
return &appError{
Err: errors.Wrap(err, message).Error(),
}
}
func (e *appError) Error() string {
return e.Err
}
func (e appError) Status() int {
if e.Code == 0 {
return 200
}
return e.Code
}

View File

@ -2,6 +2,7 @@ package groups
import ( import (
"github.com/statping/statping/database" "github.com/statping/statping/database"
"github.com/statping/statping/types/errors"
"sort" "sort"
) )
@ -14,6 +15,9 @@ func SetDB(database database.Database) {
func Find(id int64) (*Group, error) { func Find(id int64) (*Group, error) {
var group Group var group Group
q := db.Where("id = ?", id).Find(&group) q := db.Where("id = ?", id).Find(&group)
if q.Error() != nil {
return nil, errors.Missing(group, id)
}
return &group, q.Error() return &group, q.Error()
} }

View File

@ -1,6 +1,9 @@
package messages package messages
import "github.com/statping/statping/database" import (
"github.com/statping/statping/database"
"github.com/statping/statping/types/errors"
)
var db database.Database var db database.Database
@ -11,6 +14,9 @@ func SetDB(database database.Database) {
func Find(id int64) (*Message, error) { func Find(id int64) (*Message, error) {
var message Message var message Message
q := db.Where("id = ?", id).Find(&message) q := db.Where("id = ?", id).Find(&message)
if q.Error() != nil {
return nil, errors.Missing(message, id)
}
return &message, q.Error() return &message, q.Error()
} }

View File

@ -1,9 +1,9 @@
package services package services
import ( import (
"errors"
"fmt" "fmt"
"github.com/statping/statping/database" "github.com/statping/statping/database"
"github.com/statping/statping/types/errors"
"github.com/statping/statping/utils" "github.com/statping/statping/utils"
"sort" "sort"
) )
@ -20,7 +20,7 @@ func SetDB(database database.Database) {
func Find(id int64) (*Service, error) { func Find(id int64) (*Service, error) {
srv := allServices[id] srv := allServices[id]
if srv == nil { if srv == nil {
return nil, errors.New("service not found") return nil, errors.Missing(&Service{}, id)
} }
return srv, nil return srv, nil
} }

View File

@ -1,7 +1,6 @@
package utils package utils
import ( import (
"github.com/prometheus/common/log"
"github.com/spf13/viper" "github.com/spf13/viper"
"os" "os"
"time" "time"
@ -13,35 +12,34 @@ var (
func InitCLI() { func InitCLI() {
Params = viper.New() Params = viper.New()
Params.AutomaticEnv()
Directory = Params.GetString("STATPING_DIR")
//Params.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
setDefaults() setDefaults()
Params.SetConfigName("config") Params.SetConfigName("config")
Params.SetConfigType("yml") Params.SetConfigType("yml")
Params.AddConfigPath(".") Params.AddConfigPath(Directory)
err := Params.ReadInConfig()
if err != nil {
log.Debugf("config.yml Fatal error config file: %s", err)
}
Params.AddConfigPath(".") Params.ReadInConfig()
Params.AddConfigPath(Directory)
Params.SetConfigFile(".env") Params.SetConfigFile(".env")
err = Params.ReadInConfig() Params.ReadInConfig()
if err != nil {
log.Debugf(".env Fatal error config file: %s", err)
}
Params.AutomaticEnv() Params.Set("VERSION", version)
if err != nil {
log.Debugf("No environment variables found: %s", err)
}
} }
func setDefaults() { func setDefaults() {
defaultDir, err := os.Getwd() if Directory == "" {
if err != nil { defaultDir, err := os.Getwd()
defaultDir = "." if err != nil {
defaultDir = "."
}
Params.SetDefault("STATPING_DIR", defaultDir)
Directory = defaultDir
} }
Params.SetDefault("STATPING_DIR", defaultDir)
Directory = Params.GetString("STATPING_DIR") Directory = Params.GetString("STATPING_DIR")
Params.SetDefault("STATPING_DIR", Directory)
Params.SetDefault("GO_ENV", "") Params.SetDefault("GO_ENV", "")
Params.SetDefault("DISABLE_LOGS", false) Params.SetDefault("DISABLE_LOGS", false)
Params.SetDefault("BASE_PATH", "") Params.SetDefault("BASE_PATH", "")
@ -51,9 +49,8 @@ func setDefaults() {
Params.SetDefault("SAMPLE_DATA", true) Params.SetDefault("SAMPLE_DATA", true)
Params.SetDefault("USE_CDN", false) Params.SetDefault("USE_CDN", false)
Params.SetDefault("ALLOW_REPORTS", false) Params.SetDefault("ALLOW_REPORTS", false)
Params.SetDefault("AUTH_USERNAME", "")
Params.SetDefault("AUTH_PASSWORD", "")
Params.SetDefault("POSTGRES_SSLMODE", "disable") Params.SetDefault("POSTGRES_SSLMODE", "disable")
Params.SetDefault("SASS", "sass")
dbConn := Params.GetString("DB_CONN") dbConn := Params.GetString("DB_CONN")
dbInt := Params.GetInt("DB_PORT") dbInt := Params.GetInt("DB_PORT")

View File

@ -24,7 +24,7 @@ func CreateDirectory(directory string) error {
// FolderExists will return true if the folder exists // FolderExists will return true if the folder exists
func FolderExists(folder string) bool { func FolderExists(folder string) bool {
if _, err := os.Stat(folder); os.IsExist(err) { if stat, err := os.Stat(folder); err == nil && stat.IsDir() {
return true return true
} }
return false return false
@ -45,13 +45,13 @@ func FileExists(name string) bool {
// DeleteFile will attempt to delete a file // DeleteFile will attempt to delete a file
// DeleteFile("newfile.json") // DeleteFile("newfile.json")
func DeleteFile(file string) error { func DeleteFile(file string) error {
Log.Debugln("deleting file: " + file) Log.Warn("deleting file: " + file)
return os.Remove(file) return os.Remove(file)
} }
// RenameDirectory will attempt rename a directory to a new name // RenameDirectory will attempt rename a directory to a new name
func RenameDirectory(fromDir string, toDir string) error { func RenameDirectory(fromDir string, toDir string) error {
Log.Debugln("renaming directory: " + fromDir + "to: " + toDir) Log.Warn("renaming directory: " + fromDir + "to: " + toDir)
return os.Rename(fromDir, toDir) return os.Rename(fromDir, toDir)
} }

View File

@ -42,6 +42,11 @@ type env struct {
data interface{} data interface{}
} }
func NotNumber(val string) bool {
_, err := strconv.ParseInt(val, 10, 64)
return err != nil
}
func GetenvAs(key string, defaultValue interface{}) *env { func GetenvAs(key string, defaultValue interface{}) *env {
return &env{ return &env{
data: Getenv(key, defaultValue), data: Getenv(key, defaultValue),

View File

@ -201,6 +201,5 @@ func TestConfigLoad(t *testing.T) {
assert.Equal(t, "sqlite", s("DB_CONN")) assert.Equal(t, "sqlite", s("DB_CONN"))
assert.Equal(t, Directory, s("STATPING_DIR")) assert.Equal(t, Directory, s("STATPING_DIR"))
assert.True(t, b("SAMPLE_DATA")) assert.True(t, b("SAMPLE_DATA"))
assert.False(t, b("DISABLE_LOGS"))
assert.False(t, b("ALLOW_REPORTS")) assert.False(t, b("ALLOW_REPORTS"))
} }