diff --git a/cmd/main.go b/cmd/main.go index e442396e..0259d350 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -96,7 +96,6 @@ func main() { configs, err := core.LoadConfigFile(utils.Directory) if err != nil { log.Errorln(err) - core.SetupMode = true writeAble, err := utils.DirWritable(utils.Directory) if err != nil { log.Fatalln(err) @@ -104,6 +103,7 @@ func main() { 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) } + core.CoreApp.Setup = false if err := handlers.RunHTTPServer(ipAddress, port); err != nil { log.Fatalln(err) } @@ -149,7 +149,7 @@ func mainProcess() error { } core.CoreApp.MigrateDatabase() core.InitApp() - if !core.SetupMode { + if !core.CoreApp.Setup { plugin.LoadPlugins() if err := handlers.RunHTTPServer(ipAddress, port); err != nil { log.Fatalln(err) diff --git a/core/configs.go b/core/configs.go index e16ffa42..974d7fc9 100644 --- a/core/configs.go +++ b/core/configs.go @@ -40,6 +40,7 @@ func LoadConfigFile(directory string) (*types.DbConfig, error) { log.Debugln("attempting to read config file at: " + directory + "/config.yml") file, err := ioutil.ReadFile(directory + "/config.yml") if err != nil { + CoreApp.Setup = false return nil, errors.New("config.yml file not found at " + directory + "/config.yml - starting in setup mode") } err = yaml.Unmarshal(file, &configs) diff --git a/core/core.go b/core/core.go index 79d2014f..c59eb00a 100644 --- a/core/core.go +++ b/core/core.go @@ -37,10 +37,9 @@ type Core struct { } var ( - CoreApp *Core // CoreApp is a global variable that contains many elements - SetupMode bool // SetupMode will be true if Statping does not have a database connection - VERSION string // VERSION is set on build automatically by setting a -ldflag - log = utils.Log.WithField("type", "core") + CoreApp *Core // CoreApp is a global variable that contains many elements + VERSION string // VERSION is set on build automatically by setting a -ldflag + log = utils.Log.WithField("type", "core") ) func init() { @@ -71,7 +70,7 @@ func InitApp() { CoreApp.Notifications = notifier.AllCommunications CoreApp.Integrations = integrations.Integrations go DatabaseMaintence() - SetupMode = false + CoreApp.Setup = true } // InsertNotifierDB inject the Statping database instance to the Notifier package diff --git a/frontend/src/App.vue b/frontend/src/App.vue index f53db808..d281594c 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,12 +1,11 @@ diff --git a/frontend/src/assets/scss/base.scss b/frontend/src/assets/scss/base.scss index 9e839c08..36878049 100644 --- a/frontend/src/assets/scss/base.scss +++ b/frontend/src/assets/scss/base.scss @@ -134,7 +134,7 @@ HTML,BODY { .chart-container { position: relative; - height: 190px; + height: 200px; width: 100%; overflow: hidden; } diff --git a/frontend/src/components/API.js b/frontend/src/components/API.js index 542be0ee..1a5e9a55 100644 --- a/frontend/src/components/API.js +++ b/frontend/src/components/API.js @@ -16,6 +16,10 @@ class Api { return axios.post('/api/core', obj).then(response => (response.data)) } + async setup_save (data) { + return axios.post('/api/setup', qs.stringify(data)).then(response => (response.data)) + } + async services () { return axios.get('/api/services').then(response => (response.data)) } diff --git a/frontend/src/components/Dashboard/DashboardIndex.vue b/frontend/src/components/Dashboard/DashboardIndex.vue index ae48b821..f79a1804 100644 --- a/frontend/src/components/Dashboard/DashboardIndex.vue +++ b/frontend/src/components/Dashboard/DashboardIndex.vue @@ -16,7 +16,7 @@ -
+
@@ -32,7 +32,6 @@ }, data () { return { - services: this.$store.getters.servicesInOrder() } }, methods: { diff --git a/frontend/src/components/Dashboard/DashboardMessages.vue b/frontend/src/components/Dashboard/DashboardMessages.vue index a8ee60de..8a5d0363 100644 --- a/frontend/src/components/Dashboard/DashboardMessages.vue +++ b/frontend/src/components/Dashboard/DashboardMessages.vue @@ -54,9 +54,6 @@ return { } - }, - created() { - }, methods: { service (id) { diff --git a/frontend/src/components/Dashboard/DashboardServices.vue b/frontend/src/components/Dashboard/DashboardServices.vue index 6baa922c..ba88429a 100644 --- a/frontend/src/components/Dashboard/DashboardServices.vue +++ b/frontend/src/components/Dashboard/DashboardServices.vue @@ -16,8 +16,8 @@ - - + + @@ -65,7 +65,7 @@ - + {{group.name}} {{$store.getters.servicesInGroup(group.id).length}} @@ -74,7 +74,7 @@
- Edit + Edit @@ -112,14 +112,9 @@ }, data () { return { - services: [] + } }, - async created() { - const services = await Api.services() - this.$store.commit('setServices', services) - this.services = this.$store.getters.servicesInOrder() - }, computed: { servicesList: { get() { diff --git a/frontend/src/components/Dashboard/DashboardUsers.vue b/frontend/src/components/Dashboard/DashboardUsers.vue index 4df9eef1..8ca9ef02 100644 --- a/frontend/src/components/Dashboard/DashboardUsers.vue +++ b/frontend/src/components/Dashboard/DashboardUsers.vue @@ -44,10 +44,6 @@ } }, - async created() { - const users = await Api.users() - this.$store.commit('setUsers', users) - }, methods: { async deleteUser(u) { let c = confirm(`Are you sure you want to delete user '${u.username}'?`) diff --git a/frontend/src/forms/Setup.vue b/frontend/src/forms/Setup.vue new file mode 100644 index 00000000..17f576b5 --- /dev/null +++ b/frontend/src/forms/Setup.vue @@ -0,0 +1,166 @@ + + + + + + diff --git a/frontend/src/pages/Dashboard.vue b/frontend/src/pages/Dashboard.vue index 754f3490..126d905b 100644 --- a/frontend/src/pages/Dashboard.vue +++ b/frontend/src/pages/Dashboard.vue @@ -6,31 +6,17 @@ diff --git a/frontend/src/pages/Login.vue b/frontend/src/pages/Login.vue index 4cbf8cbc..50f04fe8 100644 --- a/frontend/src/pages/Login.vue +++ b/frontend/src/pages/Login.vue @@ -60,7 +60,7 @@ this.error = true } else if (auth.token) { this.auth = Api.saveToken(this.username, auth.token) - this.$store.commit('setToken', auth) + await this.$store.dispatch('loadRequired') this.$router.push('/dashboard') } this.loading = false diff --git a/frontend/src/pages/Settings.vue b/frontend/src/pages/Settings.vue index 3aec647a..e54fbdfd 100644 --- a/frontend/src/pages/Settings.vue +++ b/frontend/src/pages/Settings.vue @@ -50,7 +50,7 @@

Additional Settings

-
+
@@ -265,7 +265,8 @@ data () { return { tab: "v-pills-home-tab", - qrcode: "" + qrcode: "", + core: this.$store.getters.core } }, async created() { diff --git a/frontend/src/routes.js b/frontend/src/routes.js index 36c81a8e..4f22047f 100644 --- a/frontend/src/routes.js +++ b/frontend/src/routes.js @@ -9,13 +9,18 @@ import Settings from "./pages/Settings"; import Login from "./pages/Login"; import Service from "./pages/Service"; import VueRouter from "vue-router"; -import Api from "./components/API"; +import Setup from "./forms/Setup"; const routes = [ + { + path: '/setup', + name: 'Setup', + component: Setup + }, { path: '/', name: 'Index', - component: Index + component: Index, }, { path: '/dashboard', diff --git a/frontend/src/store.js b/frontend/src/store.js index f1456749..34d6451a 100644 --- a/frontend/src/store.js +++ b/frontend/src/store.js @@ -1,5 +1,6 @@ import Vuex from 'vuex' import Vue from 'vue' +import Api from "./components/API" Vue.use(Vuex) @@ -37,6 +38,9 @@ export default new Vuex.Store({ users: state => state.users, notifiers: state => state.notifiers, + servicesInOrder: state => state.services, + groupsCleaned: state => state.groups.filter(g => g.name !== ''), + serviceById: (state) => (id) => { return state.services.find(s => s.id === id) }, @@ -46,9 +50,6 @@ export default new Vuex.Store({ servicesInGroup: (state) => (id) => { return state.services.filter(s => s.group_id === id) }, - servicesInOrder: (state) => () => { - return state.services - }, onlineServices: (state) => (online) => { return state.services.filter(s => s.online === online) }, @@ -79,7 +80,7 @@ export default new Vuex.Store({ state.token = token }, setServices(state, services) { - state.services = services.sort((a, b) => a.order_id - b.order_id) + state.services = services }, setGroups(state, groups) { state.groups = groups @@ -95,6 +96,23 @@ export default new Vuex.Store({ } }, actions: { - + async loadRequired(context) { + const core = await Api.core() + context.commit("setCore", core); + const services = await Api.services() + context.commit("setServices", services); + const groups = await Api.groups() + context.commit("setGroups", groups); + const messages = await Api.messages() + context.commit("setMessages", messages) + context.commit("setHasPublicData", true) + }, + async loadAdmin(context) { + await context.dispatch('loadRequired') + const notifiers = await Api.notifiers() + context.commit("setNotifiers", notifiers); + const users = await Api.users() + context.commit("setUsers", users); + } } }); diff --git a/go.mod b/go.mod index dd11d6cc..0fc09925 100644 --- a/go.mod +++ b/go.mod @@ -18,9 +18,9 @@ require ( github.com/go-mail/mail v2.3.1+incompatible github.com/go-yaml/yaml v2.1.0+incompatible github.com/gorilla/mux v1.7.3 - github.com/gorilla/sessions v1.2.0 github.com/gorilla/websocket v1.4.1 // indirect github.com/hashicorp/golang-lru v0.5.3 // indirect + github.com/hunterlong/scopr v0.0.0 github.com/jinzhu/gorm v1.9.11 github.com/joho/godotenv v1.3.0 github.com/lib/pq v1.2.0 // indirect @@ -41,3 +41,5 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.2.7 // indirect ) + +replace github.com/hunterlong/scopr v0.0.0 => ../scopr diff --git a/go.sum b/go.sum index 0a61bd40..a5e63d52 100644 --- a/go.sum +++ b/go.sum @@ -85,10 +85,6 @@ github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= -github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= diff --git a/handlers/handlers.go b/handlers/handlers.go index efb8daad..730e870d 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -103,7 +103,7 @@ func RunHTTPServer(ip string, port int) error { // IsReadAuthenticated will allow Read Only authentication for some routes func IsReadAuthenticated(r *http.Request) bool { - if core.SetupMode { + if !core.CoreApp.Setup { return false } var token string @@ -132,7 +132,7 @@ func IsFullAuthenticated(r *http.Request) bool { if core.CoreApp == nil { return true } - if core.SetupMode { + if !core.CoreApp.Setup { return false } var token string @@ -185,7 +185,7 @@ func ScopeName(r *http.Request) string { // IsAdmin returns true if the user session is an administrator func IsAdmin(r *http.Request) bool { - if core.SetupMode { + if !core.CoreApp.Setup { return false } if os.Getenv("GO_ENV") == "test" { @@ -201,7 +201,7 @@ func IsAdmin(r *http.Request) bool { // IsUser returns true if the user is registered func IsUser(r *http.Request) bool { - if core.SetupMode { + if !core.CoreApp.Setup { return false } if os.Getenv("GO_ENV") == "test" { diff --git a/handlers/setup.go b/handlers/setup.go index d5fa009d..8f8f1ab0 100644 --- a/handlers/setup.go +++ b/handlers/setup.go @@ -16,11 +16,13 @@ package handlers import ( + "errors" "github.com/hunterlong/statping/core" "github.com/hunterlong/statping/types" "github.com/hunterlong/statping/utils" "net/http" "os" + "strconv" "time" ) @@ -39,11 +41,15 @@ func setupHandler(w http.ResponseWriter, r *http.Request) { func processSetupHandler(w http.ResponseWriter, r *http.Request) { var err error - if !core.SetupMode { - http.Redirect(w, r, basePath, http.StatusSeeOther) + if core.CoreApp.Setup { + sendErrorJson(errors.New("Statping has already been setup"), w, r) + return + } + if err = r.ParseForm(); err != nil { + log.Errorln(err) + sendErrorJson(err, w, r) return } - r.ParseForm() dbHost := r.PostForm.Get("db_host") dbUser := r.PostForm.Get("db_user") dbPass := r.PostForm.Get("db_password") @@ -56,7 +62,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { description := r.PostForm.Get("description") domain := r.PostForm.Get("domain") email := r.PostForm.Get("email") - sample := r.PostForm.Get("sample_data") == "on" + sample, _ := strconv.ParseBool(r.PostForm.Get("sample_data")) dir := utils.Directory config := &types.DbConfig{ @@ -80,34 +86,37 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { if _, err := core.CoreApp.SaveConfig(config); err != nil { log.Errorln(err) - config.Error = err - setupResponseError(w, r, config) + sendErrorJson(err, w, r) return } if _, err = core.LoadConfigFile(dir); err != nil { log.Errorln(err) - config.Error = err - setupResponseError(w, r, config) + sendErrorJson(err, w, r) return } if err = core.CoreApp.Connect(false, dir); err != nil { log.Errorln(err) core.DeleteConfig() - config.Error = err - setupResponseError(w, r, config) + sendErrorJson(err, w, r) return } - core.CoreApp.DropDatabase() - core.CoreApp.CreateDatabase() + if err = core.CoreApp.DropDatabase(); err != nil { + sendErrorJson(err, w, r) + return + } + + if err = core.CoreApp.CreateDatabase(); err != nil { + sendErrorJson(err, w, r) + return + } core.CoreApp, err = core.CoreApp.InsertCore(config) if err != nil { log.Errorln(err) - config.Error = err - setupResponseError(w, r, config) + sendErrorJson(err, w, r) return } @@ -120,13 +129,23 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { admin.Create() if sample { - core.SampleData() + if err = core.SampleData(); err != nil { + sendErrorJson(err, w, r) + return + } } core.InitApp() CacheStorage.Delete("/") resetCookies() - time.Sleep(2 * time.Second) - http.Redirect(w, r, basePath, http.StatusSeeOther) + time.Sleep(1 * time.Second) + out := struct { + Message string `json:"message"` + Config *types.DbConfig `json:"config"` + }{ + "okokok", + config, + } + returnJson(out, w, r) } func setupResponseError(w http.ResponseWriter, r *http.Request, a interface{}) { diff --git a/types/core.go b/types/core.go index 53706dd5..6b87626f 100644 --- a/types/core.go +++ b/types/core.go @@ -38,6 +38,7 @@ type Core struct { Footer NullString `gorm:"column:footer" json:"footer"` Domain string `gorm:"not null;column:domain" json:"domain"` Version string `gorm:"column:version" json:"version"` + Setup bool `gorm:"-" json:"setup"` MigrationId int64 `gorm:"column:migration_id" json:"migration_id,omitempty"` UseCdn NullBool `gorm:"column:use_cdn;default:false" json:"using_cdn,omitempty"` UpdateNotify NullBool `gorm:"column:update_notify;default:true" json:"update_notify,omitempty"`