From 93d9dc9915914b3e7511bdd1a0e18e1f15e2fd7e Mon Sep 17 00:00:00 2001 From: Hunter Long Date: Fri, 18 Sep 2020 10:53:34 -0700 Subject: [PATCH] 0.90.68 (#821) - Added DB_DSN env for mysql, postgres or sqlite DSN database connection string - Added READ_ONLY env for a read only connection to the database - Added Custom OAuth OpenID toggle switch in settings (appends 'openid' in scope) - Fixed Custom OAuth response_type issue - Added Configs tab in Settings to edit the config.yml from frontend --- CHANGELOG.md | 7 ++ cmd/cli.go | 18 +++- database/database.go | 93 ++++++++++++++++++- database/routines.go | 2 + dev/kubernetes.yml | 42 +++++++++ frontend/src/API.js | 12 ++- frontend/src/assets/scss/layout.scss | 4 - frontend/src/components/Dashboard/Configs.vue | 67 +++++++++++++ .../src/components/Dashboard/Importer.vue | 52 ++++++++--- frontend/src/forms/Login.vue | 22 ++++- frontend/src/forms/OAuth.vue | 28 ++++-- frontend/src/languages/chinese.js | 1 + frontend/src/languages/data.csv | 1 + frontend/src/languages/english.js | 1 + frontend/src/languages/french.js | 1 + frontend/src/languages/german.js | 1 + frontend/src/languages/italian.js | 1 + frontend/src/languages/japanese.js | 1 + frontend/src/languages/korean.js | 1 + frontend/src/languages/russian.js | 1 + frontend/src/languages/spanish.js | 1 + frontend/src/pages/Help.vue | 6 +- frontend/src/pages/Settings.vue | 27 ++++-- go.mod | 4 +- go.sum | 6 ++ handlers/dashboard.go | 58 ++++++++++-- handlers/oauth_custom.go | 2 - handlers/routes.go | 2 + handlers/setup.go | 2 +- notifiers/discord.go | 2 +- notifiers/slack.go | 2 +- types/configs/connection.go | 9 +- types/configs/file.go | 6 +- types/configs/methods.go | 31 +++++++ types/configs/migration.go | 2 +- types/configs/struct.go | 36 +++---- types/core/struct.go | 37 ++++---- utils/env.go | 2 + version.txt | 2 +- 39 files changed, 489 insertions(+), 104 deletions(-) create mode 100644 dev/kubernetes.yml create mode 100644 frontend/src/components/Dashboard/Configs.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e8eef57..21c48215 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# 0.90.68 (09-17-2020) +- Added DB_DSN env for mysql, postgres or sqlite DSN database connection string +- Added READ_ONLY env for a read only connection to the database +- Added Custom OAuth OpenID toggle switch in settings (appends 'openid' in scope) +- Fixed Custom OAuth response_type issue +- Added Configs tab in Settings to edit the config.yml from frontend + # 0.90.67 (09-14-2020) - Modified core settings to update config.yml on save - Modified Theme Editor to restart the HTTP router on create/delete (fixing 404's) diff --git a/cmd/cli.go b/cmd/cli.go index 0dd2c966..4f06b8e1 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -18,6 +18,10 @@ import ( "time" ) +var ( + importAll *bool +) + func assetsCli() error { dir := utils.Directory if err := utils.InitLogs(); err != nil { @@ -254,6 +258,9 @@ func importCli(args []string) error { if len(exportData.Messages) > 0 { log.Printf("Messages: %d\n", len(exportData.Messages)) } + if len(exportData.Incidents) > 0 { + log.Printf("Incidents: %d\n", len(exportData.Incidents)) + } if len(exportData.Users) > 0 { log.Printf("Users: %d\n", len(exportData.Users)) } @@ -285,14 +292,14 @@ func importCli(args []string) error { if ask("Import Core settings?") { c := exportData.Core if err := c.Update(); err != nil { - return err + log.Errorln(err) } } for _, s := range exportData.Groups { if ask(fmt.Sprintf("Import Group '%s'?", s.Name)) { s.Id = 0 if err := s.Create(); err != nil { - return err + log.Errorln(err) } } } @@ -300,7 +307,7 @@ func importCli(args []string) error { if ask(fmt.Sprintf("Import Service '%s'?", s.Name)) { s.Id = 0 if err := s.Create(); err != nil { - return err + log.Errorln(err) } } } @@ -308,7 +315,7 @@ func importCli(args []string) error { if ask(fmt.Sprintf("Import Checkin '%s'?", s.Name)) { s.Id = 0 if err := s.Create(); err != nil { - return err + log.Errorln(err) } } } @@ -316,7 +323,7 @@ func importCli(args []string) error { if ask(fmt.Sprintf("Import Message '%s'?", s.Title)) { s.Id = 0 if err := s.Create(); err != nil { - return err + log.Errorln(err) } } } @@ -333,6 +340,7 @@ func importCli(args []string) error { } func ask(format string) bool { + fmt.Printf(fmt.Sprintf(format + " [y/N]: ")) reader := bufio.NewReader(os.Stdin) text, _ := reader.ReadString('\n') diff --git a/database/database.go b/database/database.go index c6136cfc..79b6fc2a 100644 --- a/database/database.go +++ b/database/database.go @@ -169,10 +169,6 @@ func Available(db Database) bool { return true } -func AmountGreaterThan1000(db *gorm.DB) *gorm.DB { - return db.Where("service = ?", 1000) -} - func (it *Db) MultipleSelects(args ...string) Database { joined := strings.Join(args, ", ") return it.Select(joined) @@ -181,6 +177,7 @@ func (it *Db) MultipleSelects(args ...string) Database { type Db struct { Database *gorm.DB Type string + ReadOnly bool } // Openw is a drop-in replacement for Open() @@ -223,6 +220,9 @@ func OpenTester() (Database, error) { default: dbString = fmt.Sprintf("file:%s?mode=memory&cache=shared", utils.RandomString(12)) } + if utils.Params.IsSet("DB_DSN") { + dbString = utils.Params.GetString("DB_DSN") + } newDb, err := Openw(testDB, dbString) if err != nil { return nil, err @@ -239,6 +239,7 @@ func Wrap(db *gorm.DB) Database { return &Db{ Database: db, Type: db.Dialect().GetName(), + ReadOnly: utils.Params.GetBool("READ_ONLY"), } } @@ -379,14 +380,26 @@ func (it *Db) Related(value interface{}, foreignKeys ...string) Database { } func (it *Db) FirstOrInit(out interface{}, where ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.FirstOrInit(out, where...)) } func (it *Db) FirstOrCreate(out interface{}, where ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.FirstOrCreate(out, where...)) } func (it *Db) Update(attrs ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Update(attrs...)) } @@ -395,22 +408,42 @@ func (it *Db) Updates(values interface{}, ignoreProtectedAttrs ...bool) Database } func (it *Db) UpdateColumn(attrs ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.UpdateColumn(attrs...)) } func (it *Db) UpdateColumns(values interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.UpdateColumns(values)) } func (it *Db) Save(value interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Save(value)) } func (it *Db) Create(value interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Create(value)) } func (it *Db) Delete(value interface{}, where ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Delete(value, where...)) } @@ -435,14 +468,26 @@ func (it *Db) Debug() Database { } func (it *Db) Begin() Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Begin()) } func (it *Db) Commit() Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Commit()) } func (it *Db) Rollback() Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Rollback()) } @@ -455,14 +500,26 @@ func (it *Db) RecordNotFound() bool { } func (it *Db) CreateTable(values ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.CreateTable(values...)) } func (it *Db) DropTable(values ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.DropTable(values...)) } func (it *Db) DropTableIfExists(values ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.DropTableIfExists(values...)) } @@ -471,26 +528,50 @@ func (it *Db) HasTable(value interface{}) bool { } func (it *Db) AutoMigrate(values ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.AutoMigrate(values...)) } func (it *Db) ModifyColumn(column string, typ string) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.ModifyColumn(column, typ)) } func (it *Db) DropColumn(column string) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.DropColumn(column)) } func (it *Db) AddIndex(indexName string, columns ...string) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.AddIndex(indexName, columns...)) } func (it *Db) AddUniqueIndex(indexName string, columns ...string) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.AddUniqueIndex(indexName, columns...)) } func (it *Db) RemoveIndex(indexName string) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.RemoveIndex(indexName)) } @@ -519,6 +600,10 @@ func (it *Db) SetJoinTableHandler(source interface{}, column string, handler gor } func (it *Db) AddForeignKey(field string, dest string, onDelete string, onUpdate string) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.AddForeignKey(field, dest, onDelete, onUpdate)) } diff --git a/database/routines.go b/database/routines.go index 92583e64..591277da 100644 --- a/database/routines.go +++ b/database/routines.go @@ -16,6 +16,8 @@ var ( // Maintenance will automatically delete old records from 'failures' and 'hits' // this function is currently set to delete records 7+ days old every 60 minutes +// env: REMOVE_AFTER - golang duration parsed time for deleting records older than REMOVE_AFTER duration from now +// env: CLEANUP_INTERVAL - golang duration parsed time for checking old records routine func Maintenance() { dur := utils.Params.GetDuration("REMOVE_AFTER") interval := utils.Params.GetDuration("CLEANUP_INTERVAL") diff --git a/dev/kubernetes.yml b/dev/kubernetes.yml new file mode 100644 index 00000000..15033baa --- /dev/null +++ b/dev/kubernetes.yml @@ -0,0 +1,42 @@ +apiVersion: v1 +kind: Service +metadata: + name: statping +spec: + ports: + - port: 8080 + selector: + app: statping + clusterIP: None +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: statping +spec: + selector: + matchLabels: + app: statping + strategy: + type: Recreate + template: + metadata: + labels: + app: statping + spec: + containers: + - image: statping/statping + name: statping + env: + - name: ALLOW_REPORTS + value: "true" + ports: + - containerPort: 8080 + name: statping + volumeMounts: + - name: statping-storage + mountPath: /app + volumes: + - name: statping-storage + persistentVolumeClaim: + claimName: statping-claim diff --git a/frontend/src/API.js b/frontend/src/API.js index 8a0d3fcc..3edd8702 100644 --- a/frontend/src/API.js +++ b/frontend/src/API.js @@ -7,8 +7,8 @@ const tokenKey = "statping_auth"; class Api { constructor() { - this.version = "0.90.66"; - this.commit = "a3ce4124f654b13c7f2af88b8410f998bd57fcef"; + this.version = "0.90.67"; + this.commit = "7e121335791d2143a2eefd404dbcce83b8f46f61"; } async oauth() { @@ -261,6 +261,14 @@ class Api { }) } + async configs() { + return axios.get('api/settings/configs').then(response => (response.data)) || [] + } + + async configs_save(data) { + return axios.post('api/settings/configs', data).then(response => (response.data)) || [] + } + token() { return $cookies.get(tokenKey); } diff --git a/frontend/src/assets/scss/layout.scss b/frontend/src/assets/scss/layout.scss index acb16334..59b82352 100644 --- a/frontend/src/assets/scss/layout.scss +++ b/frontend/src/assets/scss/layout.scss @@ -10,10 +10,6 @@ A { color: $text-color; } -A:HOVER { - color: lighten($text-color, 12%) !important; -} - .modal-backdrop { position: absolute; top: 0; diff --git a/frontend/src/components/Dashboard/Configs.vue b/frontend/src/components/Dashboard/Configs.vue new file mode 100644 index 00000000..0d2977b6 --- /dev/null +++ b/frontend/src/components/Dashboard/Configs.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/frontend/src/components/Dashboard/Importer.vue b/frontend/src/components/Dashboard/Importer.vue index 0f65c056..c131806b 100644 --- a/frontend/src/components/Dashboard/Importer.vue +++ b/frontend/src/components/Dashboard/Importer.vue @@ -6,14 +6,16 @@

-
- +
+
- Export +
+ Export +
-
+

Core Settings @@ -21,13 +23,13 @@

-
Name{{file.core.name}}
-
Description{{file.core.description}}
-
Domain{{file.core.domain}}
+
Name{{file.core.name}}
+
Description{{file.core.description}}
+
Domain{{file.core.domain}}
-
+

Users

@@ -51,7 +53,7 @@
-
+

Checkins

@@ -60,10 +62,10 @@
- {{checkin.id}} + {{checkin.name}}
- {{checkin.service_id}} + Service #{{checkin.service_id}}
@@ -74,7 +76,7 @@
-
+

Services

@@ -97,7 +99,7 @@
-
+

Groups

@@ -117,6 +119,26 @@
+
+

Incidents + +

+ +
+
+ {{incident.name}} +
+
+ + + + +
+
+
+

Notifiers @@ -141,7 +163,9 @@ {{error}}

- +
+ +
diff --git a/frontend/src/forms/Login.vue b/frontend/src/forms/Login.vue index 64ce8cf6..b84c2d68 100644 --- a/frontend/src/forms/Login.vue +++ b/frontend/src/forms/Login.vue @@ -95,17 +95,31 @@ } this.loading = false }, + encode(val) { + return encodeURI(val) + }, + custom_scopes() { + let scopes = [] + if (this.oauth.custom_open_id) { + scopes.push("openid") + } + scopes.push(this.oauth.custom_scopes.split(",")) + if (scopes.length !== 0) { + return "&scopes="+scopes.join(",") + } + return "" + }, GHlogin() { - window.location = `https://github.com/login/oauth/authorize?client_id=${this.oauth.gh_client_id}&redirect_uri=${this.core.domain}/oauth/github&scope=user,repo` + window.location = `https://github.com/login/oauth/authorize?client_id=${this.oauth.gh_client_id}&redirect_uri=${this.encode(this.core.domain+"/oauth/github")}&scope=user,repo` }, Slacklogin() { - window.location = `https://slack.com/oauth/authorize?client_id=${this.oauth.slack_client_id}&redirect_uri=${this.core.domain}/oauth/slack&scope=identity.basic` + window.location = `https://slack.com/oauth/authorize?client_id=${this.oauth.slack_client_id}&redirect_uri=${this.encode(this.core.domain+"/oauth/slack")}&scope=identity.basic` }, Googlelogin() { - window.location = `https://accounts.google.com/signin/oauth?client_id=${this.oauth.google_client_id}&redirect_uri=${this.core.domain}/oauth/google&response_type=code&scope=https://www.googleapis.com/auth/userinfo.profile+https://www.googleapis.com/auth/userinfo.email` + window.location = `https://accounts.google.com/signin/oauth?client_id=${this.oauth.google_client_id}&redirect_uri=${this.encode(this.core.domain+"/oauth/google")}&response_type=code&scope=https://www.googleapis.com/auth/userinfo.profile+https://www.googleapis.com/auth/userinfo.email` }, Customlogin() { - window.location = `${this.oauth.custom_endpoint_auth}?client_id=${this.oauth.custom_client_id}&redirect_uri=${this.core.domain}/oauth/custom${this.oauth.custom_scopes !== "" ? "&scope="+this.oauth.custom_scopes : "" }` + window.location = `${this.oauth.custom_endpoint_auth}?client_id=${this.oauth.custom_client_id}&redirect_uri=${this.encode(this.core.domain+"/oauth/custom")}&response_type=code${this.custom_scopes()}` } } } diff --git a/frontend/src/forms/OAuth.vue b/frontend/src/forms/OAuth.vue index 4bc385a6..646429a8 100644 --- a/frontend/src/forms/OAuth.vue +++ b/frontend/src/forms/OAuth.vue @@ -168,8 +168,8 @@
-
-
+
+
@@ -199,13 +199,24 @@
-
- -
- - Optional comma delimited list of oauth scopes -
+
+ +
+ + Optional comma delimited list of oauth scopes
+
+
+ +
+ + + + + Enable if provider is OpenID +
+
+
@@ -271,6 +282,7 @@ custom_endpoint_auth: "", custom_endpoint_token: "", custom_scopes: "", + custom_open_id: false, } } }, diff --git a/frontend/src/languages/chinese.js b/frontend/src/languages/chinese.js index 162e6d58..e594cf48 100755 --- a/frontend/src/languages/chinese.js +++ b/frontend/src/languages/chinese.js @@ -9,6 +9,7 @@ const chinese = { logout: "注销", online: "在线", offline: "离线", + configs: "配置", username: "用户名", password: "密码", email: "电子邮件", diff --git a/frontend/src/languages/data.csv b/frontend/src/languages/data.csv index 60d8250f..cc8aa51b 100644 --- a/frontend/src/languages/data.csv +++ b/frontend/src/languages/data.csv @@ -9,6 +9,7 @@ login,Login logout,Logout online,Online offline,Offline +configs,Configuration username,Username password,Password email,Email diff --git a/frontend/src/languages/english.js b/frontend/src/languages/english.js index c737223f..cd34b643 100644 --- a/frontend/src/languages/english.js +++ b/frontend/src/languages/english.js @@ -9,6 +9,7 @@ const english = { logout: "Logout", online: "Online", offline: "Offline", + configs: "Configuration", username: "Username", password: "Password", email: "Email", diff --git a/frontend/src/languages/french.js b/frontend/src/languages/french.js index d448af30..4115f01c 100644 --- a/frontend/src/languages/french.js +++ b/frontend/src/languages/french.js @@ -9,6 +9,7 @@ const french = { logout: "Déconnexion", online: "En ligne", offline: "Offline", + configs: "Configuration", username: "Nom d'utilisateur", password: "mot de passe", email: "Email", diff --git a/frontend/src/languages/german.js b/frontend/src/languages/german.js index aabba35f..e9f80593 100644 --- a/frontend/src/languages/german.js +++ b/frontend/src/languages/german.js @@ -9,6 +9,7 @@ const german = { logout: "Abmelden", online: "Online", offline: "Offline", + configs: "Konfiguration", username: "Benutzername", password: "Kennwort", email: "Mail", diff --git a/frontend/src/languages/italian.js b/frontend/src/languages/italian.js index 90cff78d..ccf9a417 100755 --- a/frontend/src/languages/italian.js +++ b/frontend/src/languages/italian.js @@ -9,6 +9,7 @@ const italian = { logout: "Disconnetti", online: "Online", offline: "Offline", + configs: "Configurazione", username: "Nome utente", password: "Password", email: "E-mail", diff --git a/frontend/src/languages/japanese.js b/frontend/src/languages/japanese.js index 8e1c9cbf..eed5a90c 100755 --- a/frontend/src/languages/japanese.js +++ b/frontend/src/languages/japanese.js @@ -9,6 +9,7 @@ const japanese = { logout: "ログアウト", online: "オンライン", offline: "オフライン", + configs: "構成", username: "ユーザ名", password: "パスワード", email: "Eメール", diff --git a/frontend/src/languages/korean.js b/frontend/src/languages/korean.js index 6939dec7..2cba872f 100755 --- a/frontend/src/languages/korean.js +++ b/frontend/src/languages/korean.js @@ -9,6 +9,7 @@ const korean = { logout: "로그아웃", online: "온라인", offline: "오프라인", + configs: "구성", username: "사용자 이름", password: "비밀번호", email: "이메일", diff --git a/frontend/src/languages/russian.js b/frontend/src/languages/russian.js index 4f9d89e9..4a578938 100644 --- a/frontend/src/languages/russian.js +++ b/frontend/src/languages/russian.js @@ -9,6 +9,7 @@ const russian = { logout: "Выход из системы", online: "Онлайн", offline: "Оффлайн", + configs: "Конфигурация", username: "Имя пользователя", password: "Пароль", email: "Электронная почта", diff --git a/frontend/src/languages/spanish.js b/frontend/src/languages/spanish.js index aa7457b6..ea6e4293 100644 --- a/frontend/src/languages/spanish.js +++ b/frontend/src/languages/spanish.js @@ -9,6 +9,7 @@ const spanish = { logout: "Cerrar sesión", online: "En línea", offline: "Offline", + configs: "Configuración", username: "Nombre de usuario", password: "Contraseña", email: "Correo", diff --git a/frontend/src/pages/Help.vue b/frontend/src/pages/Help.vue index 55639c5b..61654a40 100755 --- a/frontend/src/pages/Help.vue +++ b/frontend/src/pages/Help.vue @@ -1545,8 +1545,8 @@ systemctl start statping

You can even run Statping on your Raspberry Pi by installing the precompiled binary from Latest Releases. For the Raspberry Pi 3 you’ll want to download the statping-linux-arm7.tar.gz file. Be sure to change VERSION to the latest version in Releases, and include the ‘v’.

VERSION=$(curl -sL "https://github.com/statping/statping/releases/latest" | grep -o 'tag/[v.0-9]*' | awk -F/ '{print $2}' | head -n1)
-wget https://github.com/statping/statping/releases/download/$VERSION/statping-linux-arm7.tar.gz
-tar -xvzf statping-linux-arm7.tar.gz
+wget https://github.com/statping/statping/releases/download/$VERSION/statping-linux-arm-7.tar.gz
+tar -xvzf statping-linux-arm-7.tar.gz
 chmod +x statping
 mv statping /usr/local/bin/statping
 
@@ -2275,7 +2275,7 @@ OluFxewsEO0QNDrfFb+0gnjYlnGqOFcZjUMXbDdY5oLSPtXohynuTK1qyQ==
 
-Automatically generated from Statping's Wiki on 2020-09-09 01:24:21.649582 +0000 UTC +Automatically generated from Statping's Wiki on 2020-09-15 19:09:14.703237 +0000 UTC
diff --git a/frontend/src/pages/Settings.vue b/frontend/src/pages/Settings.vue index ae8331a3..1f8a8016 100644 --- a/frontend/src/pages/Settings.vue +++ b/frontend/src/pages/Settings.vue @@ -4,10 +4,16 @@