diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index e1de9143..7ad19d81 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -319,7 +319,7 @@ jobs: dockerfile: Dockerfile.base tags: "base" - - name: Latest/Version Docker Image + - name: Dev Docker Image uses: elgohr/Publish-Docker-Github-Action@master env: VERSION: ${{ env.VERSION }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 0d3c67c0..7602ac04 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -5,10 +5,9 @@ on: - '*' # matches every branch - '*/*' # matches every branch containing a single '/' - '!master' # excludes master - - '!dev' # excludes dev pull_request: branches: - - master + - dev jobs: compile: diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index b5ba5fda..bb4f79b3 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -13,6 +13,6 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: "This issue hasn't had any updates in a while. If this is still a problem, please create a new issue." stale-issue-label: "stale" - days-before-stale: 30 - days-before-close: 7 + days-before-stale: 45 + days-before-close: 14 exempt-issue-label: "bug,urgent,feature,pinned,locked" diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c830809..cf99f370 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +# 0.90.56 (06-25-2020) +- Modified metrics now include service name for each service metric +- Added switch for true/false notifier values +- Added list for notifiers that have static values (in drop down) +- Fixed oAuth form saving +- Fixed some HTTP Cookie issues +- Added error if Theme Editor returns an error from API +- Added Pushover priority and sounds +- Added HTTP headers for outgoing requests (includes User-Agent=Statping and Statping-Version=0.90.55) +- Fixed Google oAuth handling +- Added Google oAuth email/domain user restrictions +- Modified notifiers to use dereferenced services and failures +- Added core.Example() function for testing +- Added Custom oAuth Authentication method +- Fixed setup form not creating user from values inputted in form +- Fixed issues with Telegram Notifier +- Modified notifier test handler to return notifier based on URL, not JSON payload + # 0.90.55 (06-18-2020) - Added 404 page - Modified Statping's PR process, dev -> master diff --git a/dev/postman.json b/dev/postman.json index 6bd364fb..1f6b4ba6 100644 --- a/dev/postman.json +++ b/dev/postman.json @@ -3391,7 +3391,7 @@ " var user = jsonData[0];", " pm.expect(user.id).to.eql(1);", " pm.expect(user.username).to.eql(\"admin\");", - " pm.expect(user.email).to.eql(\"info@admin.com\");", + " pm.expect(user.email).to.eql(\"info@domain.com\");", "});" ], "type": "text/javascript" @@ -4233,7 +4233,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"method\": \"success\",\n \"notifier\": {\n \"enabled\": false,\n \"limits\": 60,\n \"method\": \"slack\",\n \"host\": \"https://webhooksurl.slack.com/***\",\n \"success_data\": \"{\\n \\\"blocks\\\": [{\\n \\\"type\\\": \\\"section\\\",\\n \\\"text\\\": {\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\"The service {{.Service.Name}} is back online.\\\"\\n }\\n }, {\\n \\\"type\\\": \\\"actions\\\",\\n \\\"elements\\\": [{\\n \\\"type\\\": \\\"button\\\",\\n \\\"text\\\": {\\n \\\"type\\\": \\\"plain_text\\\",\\n \\\"text\\\": \\\"View Service\\\",\\n \\\"emoji\\\": true\\n },\\n \\\"style\\\": \\\"primary\\\",\\n \\\"url\\\": \\\"{{.Core.Domain}}/service/{{.Service.Id}}\\\"\\n }, {\\n \\\"type\\\": \\\"button\\\",\\n \\\"text\\\": {\\n \\\"type\\\": \\\"plain_text\\\",\\n \\\"text\\\": \\\"Go to Statping\\\",\\n \\\"emoji\\\": true\\n },\\n \\\"url\\\": \\\"{{.Core.Domain}}\\\"\\n }]\\n }]\\n}\",\n \"failure_data\": \"{\\n \\\"blocks\\\": [{\\n \\\"type\\\": \\\"section\\\",\\n \\\"text\\\": {\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\":warning: The service {{.Service.Name}} is currently offline! :warning:\\\"\\n }\\n }, {\\n \\\"type\\\": \\\"divider\\\"\\n }, {\\n \\\"type\\\": \\\"section\\\",\\n \\\"fields\\\": [{\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\"*Service:*\\\\n{{.Service.Name}}\\\"\\n }, {\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\"*URL:*\\\\n{{.Service.Domain}}\\\"\\n }, {\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\"*Status Code:*\\\\n{{.Service.LastStatusCode}}\\\"\\n }, {\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\"*When:*\\\\n{{.Failure.CreatedAt}}\\\"\\n }, {\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\"*Downtime:*\\\\n{{.Service.DowntimeAgo}}\\\"\\n }, {\\n \\\"type\\\": \\\"plain_text\\\",\\n \\\"text\\\": \\\"*Error:*\\\\n{{.Failure.Issue}}\\\"\\n }]\\n }, {\\n \\\"type\\\": \\\"divider\\\"\\n }, {\\n \\\"type\\\": \\\"actions\\\",\\n \\\"elements\\\": [{\\n \\\"type\\\": \\\"button\\\",\\n \\\"text\\\": {\\n \\\"type\\\": \\\"plain_text\\\",\\n \\\"text\\\": \\\"View Offline Service\\\",\\n \\\"emoji\\\": true\\n },\\n \\\"style\\\": \\\"danger\\\",\\n \\\"url\\\": \\\"{{.Core.Domain}}/service/{{.Service.Id}}\\\"\\n }, {\\n \\\"type\\\": \\\"button\\\",\\n \\\"text\\\": {\\n \\\"type\\\": \\\"plain_text\\\",\\n \\\"text\\\": \\\"Go to Statping\\\",\\n \\\"emoji\\\": true\\n },\\n \\\"url\\\": \\\"{{.Core.Domain}}\\\"\\n }]\\n }]\\n}\"\n }\n}", + "raw": "{\n \"method\": \"success\",\n \"notifier\": {\n \"enabled\": false,\n \"limits\": 60,\n \"method\": \"slack\",\n \"host\": \"https://webhooksurl.slack.com/***\",\n \"success_data\": \"{\\n \\\"blocks\\\": [{\\n \\\"type\\\": \\\"section\\\",\\n \\\"text\\\": {\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\"The service {{.Service.Name}} is back online.\\\"\\n }\\n }, {\\n \\\"type\\\": \\\"actions\\\",\\n \\\"elements\\\": [{\\n \\\"type\\\": \\\"button\\\",\\n \\\"text\\\": {\\n \\\"type\\\": \\\"plain_text\\\",\\n \\\"text\\\": \\\"View Service\\\",\\n \\\"emoji\\\": true\\n },\\n \\\"style\\\": \\\"primary\\\",\\n \\\"url\\\": \\\"{{.Core.Domain}}/service/{{.Service.Id}}\\\"\\n }, {\\n \\\"type\\\": \\\"button\\\",\\n \\\"text\\\": {\\n \\\"type\\\": \\\"plain_text\\\",\\n \\\"text\\\": \\\"Go to Statping\\\",\\n \\\"emoji\\\": true\\n },\\n \\\"url\\\": \\\"{{.Core.Domain}}\\\"\\n }]\\n }]\\n}\",\n \"failure_data\": \"{\\n \\\"blocks\\\": [{\\n \\\"type\\\": \\\"section\\\",\\n \\\"text\\\": {\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\":warning: The service {{.Service.Name}} is currently offline! :warning:\\\"\\n }\\n }, {\\n \\\"type\\\": \\\"divider\\\"\\n }, {\\n \\\"type\\\": \\\"section\\\",\\n \\\"fields\\\": [{\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\"*Service:*\\\\n{{.Service.Name}}\\\"\\n }, {\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\"*URL:*\\\\n{{.Service.Domain}}\\\"\\n }, {\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\"*Status Code:*\\\\n{{.Service.LastStatusCode}}\\\"\\n }, {\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\"*When:*\\\\n{{.Failure.CreatedAt}}\\\"\\n }, {\\n \\\"type\\\": \\\"mrkdwn\\\",\\n \\\"text\\\": \\\"*Downtime:*\\\\n{{.Service.DowntimeAgo}}\\\"\\n }, {\\n \\\"type\\\": \\\"plain_text\\\",\\n \\\"text\\\": \\\"*Error:*\\\\n{{.Failure.Issue}}\\\"\\n }]\\n }, {\\n \\\"type\\\": \\\"divider\\\"\\n }, {\\n \\\"type\\\": \\\"actions\\\",\\n \\\"elements\\\": [{\\n \\\"type\\\": \\\"button\\\",\\n \\\"text\\\": {\\n \\\"type\\\": \\\"plain_text\\\",\\n \\\"text\\\": \\\"View Offline Service\\\",\\n \\\"emoji\\\": true\\n },\\n \\\"style\\\": \\\"danger\\\",\\n \\\"url\\\": \\\"{{.Core.Domain}}/service/{{.Service.Id}}\\\"\\n }, {\\n \\\"type\\\": \\\"button\\\",\\n \\\"text\\\": {\\n \\\"type\\\": \\\"plain_text\\\",\\n \\\"text\\\": \\\"Go to Statping\\\",\\n \\\"emoji\\\": true\\n },\\n \\\"url\\\": \\\"{{.Core.Domain}}\\\"\\n }]\\n }]\\n}\"\n }\n}", "options": { "raw": {} } diff --git a/frontend/src/API.js b/frontend/src/API.js index 1adbbacc..aed0c464 100644 --- a/frontend/src/API.js +++ b/frontend/src/API.js @@ -9,7 +9,7 @@ const errorReporter = "https://bed4d75404924cb3a799e370733a1b64@sentry.statping. class Api { constructor() { - + axios.defaults.withCredentials = true } async oauth() { @@ -251,17 +251,13 @@ class Api { } token() { - const tk = $cookies.get(tokenKey) - if (!tk) { - return {admin: false}; - } - return tk; + return $cookies.get(tokenKey); } authToken() { const tk = $cookies.get(tokenKey) - if (tk.token) { - return {'Authorization': 'Bearer ' + tk.token}; + if (tk) { + return {'Authorization': 'Bearer ' + tk}; } else { return {}; } diff --git a/frontend/src/components/Dashboard/ThemeEditor.vue b/frontend/src/components/Dashboard/ThemeEditor.vue index 5d402f16..bf0f6d1a 100644 --- a/frontend/src/components/Dashboard/ThemeEditor.vue +++ b/frontend/src/components/Dashboard/ThemeEditor.vue @@ -107,9 +107,14 @@ }, async createAssets() { this.pending = true - const resp = await Api.theme_generate(true) + let resp + try { + resp = await Api.theme_generate(true) + } catch(e) { + this.error = e.response.data.error + } this.pending = false - await this.fetchTheme() + await this.fetchTheme() }, async deleteAssets() { this.pending = true diff --git a/frontend/src/components/Dashboard/TopNav.vue b/frontend/src/components/Dashboard/TopNav.vue index 8b887f89..3129592a 100644 --- a/frontend/src/components/Dashboard/TopNav.vue +++ b/frontend/src/components/Dashboard/TopNav.vue @@ -52,7 +52,7 @@ this.$store.commit('setHasAllData', false) this.$store.commit('setToken', null) this.$store.commit('setAdmin', false) - this.$cookies.remove("statping_auth") + // this.$cookies.remove("statping_auth") await this.$router.push('/logout') } } diff --git a/frontend/src/components/Dashboard/Variables.vue b/frontend/src/components/Dashboard/Variables.vue index 57393818..3dc1ec9d 100644 --- a/frontend/src/components/Dashboard/Variables.vue +++ b/frontend/src/components/Dashboard/Variables.vue @@ -38,8 +38,16 @@ 8080 - {{"\{\{.Service.DowntimeAgo\}\}"}} - 35 minutes ago + {{"\{\{.Service.Downtime.Human\}\}"}} + 2 minutes + + + {{"\{\{.Service.Uptime.Human\}\}"}} + 13 hours + + + {{"\{\{.Service.Online\}\}"}} + true/false {{"\{\{.Service.LastStatusCode\}\}"}} @@ -49,6 +57,22 @@ {{"\{\{.Service.FailuresLast24Hours\}\}"}} 38 + + {{"\{\{.Service.LastOnline\}\}"}} + 2020-11-05T13:15:30Z + + + {{"\{\{.Service.LastOffline\}\}"}} + 2020-10-01T13:15:30Z + + + {{"\{\{.Service.Online24Hours\}\}"}} + 0.99 + + + {{"\{\{.Service.Online7Days\}\}"}} + 0.97 + Additional variables within the Service struct diff --git a/frontend/src/forms/Login.vue b/frontend/src/forms/Login.vue index dd0fce1d..cea8eee3 100644 --- a/frontend/src/forms/Login.vue +++ b/frontend/src/forms/Login.vue @@ -37,6 +37,10 @@ Login with Google + + Login with {{oauth.custom_name}} + + @@ -80,9 +84,8 @@ if (auth.error) { this.error = true } else if (auth.token) { - const u = {username: this.username, admin: auth.admin, token: auth.token} - this.$cookies.set("statping_auth", JSON.stringify(u)) - this.$store.dispatch('loadAdmin') + // this.$cookies.set("statping_auth", auth.token) + await this.$store.dispatch('loadAdmin') this.$store.commit('setAdmin', auth.admin) this.$router.push('/dashboard') } @@ -96,6 +99,9 @@ }, 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` + }, + 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 : "" }` } } } diff --git a/frontend/src/forms/Notifier.vue b/frontend/src/forms/Notifier.vue index a071dbeb..53cd3fef 100644 --- a/frontend/src/forms/Notifier.vue +++ b/frontend/src/forms/Notifier.vue @@ -12,9 +12,23 @@

-

+
+ + Scan this QR Code on the Statping Mobile App for quick setup +
+ +
- + + + + + + + +
@@ -155,17 +169,26 @@ export default { theme: 'neat', mode: "mymode", lineWrapping: true, - json: true, + json: this.notifier.data_type === "json", autoRefresh: true, mime: this.notifier.data_type === "json" ? "application/json" : "text/plain" }, beautifySettings: { indent_size: 2, space_in_empty_paren: true }, } }, - computed: { - - }, + computed: { + core() { + return this.$store.getters.core + }, + qrcode() { + const u = `statping://setup?domain=${this.core.domain}&api=${this.core.api_secret}` + return "https://chart.googleapis.com/chart?chs=500x500&cht=qr&chl=" + encodeURIComponent(u) + } + }, methods: { + formVisible(want, form) { + return !!want.includes(form.type); + }, visible(isVisible, entry) { if (isVisible) { this.$refs.cmfailure.codemirror.refresh() @@ -173,13 +196,19 @@ export default { } }, onCmSuccessReady(cm) { - this.success_data = beautify(this.notifier.success_data, this.beautifySettings) + this.success_data = this.notifier.success_data + if (this.notifier.data_type === "json") { + this.success_data = beautify(this.notifier.success_data, this.beautifySettings) + } setTimeout(function() { cm.refresh(); },1); }, onCmFailureReady(cm) { - this.failure_data = beautify(this.notifier.failure_data, this.beautifySettings) + this.failure_data = this.notifier.failure_data + if (this.notifier.data_type === "json") { + this.failure_data = beautify(this.notifier.failure_data, this.beautifySettings) + } setTimeout(function() { cm.refresh(); },1); diff --git a/frontend/src/forms/OAuth.vue b/frontend/src/forms/OAuth.vue index ca0c7a5d..8c3e3904 100644 --- a/frontend/src/forms/OAuth.vue +++ b/frontend/src/forms/OAuth.vue @@ -1,24 +1,18 @@