sentry optional

pull/490/head
hunterlong 2020-04-11 15:18:43 -07:00
parent 74d77b6300
commit bbd36d3698
28 changed files with 225 additions and 155 deletions

View File

@ -42,6 +42,7 @@ notifications:
os: os:
- linux - linux
script: script:
- "cd frontend && yarn test"
- "travis_retry make clean test-ci" - "travis_retry make clean test-ci"
- "if [[ \"$TRAVIS_BRANCH\" == \"master\" && \"$TRAVIS_PULL_REQUEST\" = \"false\" ]]; then make coverage; fi" - "if [[ \"$TRAVIS_BRANCH\" == \"master\" && \"$TRAVIS_PULL_REQUEST\" = \"false\" ]]; then make coverage; fi"
services: services:

View File

@ -28,8 +28,7 @@ var (
verboseMode int verboseMode int
port int port int
log = utils.Log.WithField("type", "cmd") log = utils.Log.WithField("type", "cmd")
confgs *configs.DbConfig
confgs *configs.DbConfig
) )
// parseFlags will parse the application flags // parseFlags will parse the application flags
@ -75,8 +74,6 @@ func main() {
parseFlags() parseFlags()
utils.SentryInit(VERSION)
if err := source.Assets(); err != nil { if err := source.Assets(); err != nil {
exit(err) exit(err)
} }
@ -202,18 +199,14 @@ func InitApp() error {
if _, err := core.Select(); err != nil { if _, err := core.Select(); err != nil {
return err return err
} }
if _, err := services.SelectAllServices(true); err != nil { if _, err := services.SelectAllServices(true); err != nil {
return err return err
} }
go services.CheckServices() go services.CheckServices()
notifiers.InitNotifiers() notifiers.InitNotifiers()
go database.Maintenance()
utils.SentryInit(&VERSION, core.App.AllowReports.Bool)
core.App.Setup = true core.App.Setup = true
core.App.Started = utils.Now() core.App.Started = utils.Now()
go database.Maintenance()
return nil return nil
} }

View File

@ -19,6 +19,8 @@ context('Setup Process', () => {
it('should have sample data', () => { it('should have sample data', () => {
cy.visit('/') cy.visit('/')
cy.get('#title').should('contain', 'Demo Tester')
cy.get('#description').should('contain', 'This is a test from Crypress!')
cy.get('.card').should('have.length', 5) cy.get('.card').should('have.length', 5)
cy.get('.group_header').should('have.length', 2) cy.get('.group_header').should('have.length', 2)
}) })

View File

@ -34,17 +34,17 @@ context('Notifier Tests', () => {
cy.get('#api_secret').should('not.have.value', '') cy.get('#api_secret').should('not.have.value', '')
}) })
it('should test and save notifier', () => { // it('should test and save notifier', () => {
cy.visit('/dashboard/settings') // cy.visit('/dashboard/settings')
cy.get('#notifiers_tabs > a').should('have.length', 10) // cy.get('#notifiers_tabs > a').should('have.length', 10)
cy.get('#notifiers_tabs > #v-pills-command-tab').click() // cy.get('#notifiers_tabs > #v-pills-command-tab').click()
//
cy.get('#v-pills-command-tab > .form-control').eq(0).clear().type('/bin/sh') // cy.get('#v-pills-command-tab > .form-control').eq(0).clear().type('/bin/echo')
cy.get('#v-pills-command-tab > .form-control').eq(1).clear().type('echo "success"') // cy.get('#v-pills-command-tab > .form-control').eq(1).clear().type('"success"')
cy.get('#v-pills-command-tab > .form-control').eq(2).clear().type('echo "failure"') // cy.get('#v-pills-command-tab > .form-control').eq(2).clear().type('"failure"')
//
cy.get('#v-pills-command-tab > .card-body > .btn').eq(0).click() // cy.get('#v-pills-command-tab').find(".save-notifier").click()
cy.get('#v-pills-command-tab > .card-body > .btn').eq(1).click() // cy.get('#v-pills-command-tab').find(".test-notifier").click()
}) // })
}) })

View File

@ -98,9 +98,13 @@ context('Services Tests', () => {
it('should delete new services', () => { it('should delete new services', () => {
cy.visit('/dashboard/services') cy.visit('/dashboard/services')
cy.get('#services_list > tr').should('have.length', 10)
cy.get('#services_list > tr').eq(0).find('a.btn-danger').click() cy.get('#services_list > tr').eq(0).find('a.btn-danger').click()
cy.get('#services_list > tr').should('have.length', 9)
cy.get('#services_list > tr').eq(1).find('a.btn-danger').click() cy.get('#services_list > tr').eq(1).find('a.btn-danger').click()
cy.get('#services_list > tr').should('have.length', 8)
cy.get('#services_list > tr').eq(2).find('a.btn-danger').click() cy.get('#services_list > tr').eq(2).find('a.btn-danger').click()
cy.get('#services_list > tr').should('have.length', 7)
cy.get('#services_list > tr').eq(3).find('a.btn-danger').click() cy.get('#services_list > tr').eq(3).find('a.btn-danger').click()
cy.get('#services_list > tr').should('have.length', 6) cy.get('#services_list > tr').should('have.length', 6)
}) })

View File

@ -66,19 +66,6 @@ context('Users Tests', () => {
cy.get('#users_table > tr').eq(2).contains('ADMIN') cy.get('#users_table > tr').eq(2).contains('ADMIN')
}) })
it('should confirm edit user', () => {
cy.visit('/dashboard/users')
cy.get('#users_table > tr').should('have.length', 3)
cy.get('#users_table > tr').eq(2).find('a.edit-user').click()
cy.get('#email').should('have.value', 'info@admin3.com')
cy.get('#email').clear().type('info@updated.com')
cy.get('#password').type('password123')
cy.get('#password_confirm').type('password123')
cy.get('button[type="submit"]').click()
cy.get('#users_table > tr').should('have.length', 3)
})
it('should delete new users', () => { it('should delete new users', () => {
cy.visit('/dashboard/users') cy.visit('/dashboard/users')
cy.get('#users_table > tr').should('have.length', 3) cy.get('#users_table > tr').should('have.length', 3)

View File

@ -1,7 +1,11 @@
import Vue from "vue";
import axios from 'axios' import axios from 'axios'
import * as Sentry from "@sentry/browser";
import * as Integrations from "@sentry/integrations";
const qs = require('querystring');
const qs = require('querystring')
const tokenKey = "statping_user"; const tokenKey = "statping_user";
const errorReporter = "https://bed4d75404924cb3a799e370733a1b64@sentry.statping.com/3"
class Api { class Api {
constructor() { constructor() {
@ -9,7 +13,11 @@ class Api {
} }
async core() { async core() {
return axios.get('api').then(response => (response.data)) const core = axios.get('api').then(response => (response.data))
if (core.allow_reports) {
await this.sentry_init()
}
return core
} }
async core_save(obj) { async core_save(obj) {
@ -258,6 +266,13 @@ class Api {
await axios.all([all]) await axios.all([all])
} }
async sentry_init() {
Sentry.init({
dsn: errorReporter,
integrations: [new Integrations.Vue({Vue, attachProps: true})],
});
}
} }
const api = new Api() const api = new Api()
export default api export default api

View File

@ -1,7 +1,7 @@
<template> <template>
<div id="app"> <div id="app">
<router-view :app="app" :loaded="loaded"/> <router-view :loaded="loaded"/>
<Footer :logged_in="logged_in" :version="version" v-if="$route.path !== '/setup'"/> <Footer v-if="$route.path !== '/setup'"/>
</div> </div>
</template> </template>
@ -18,8 +18,6 @@
return { return {
loaded: false, loaded: false,
version: "", version: "",
logged_in: false,
app: null
} }
}, },
computed: { computed: {
@ -27,18 +25,22 @@
return this.$store.getters.core return this.$store.getters.core
} }
}, },
async created() { async beforeMount() {
this.app = await this.$store.dispatch('loadRequired') await this.$store.dispatch('loadCore')
this.app = {...this.$store.state}
if (this.core.logged_in) {
await this.$store.dispatch('loadAdmin')
}
this.loaded = true
if (!this.core.setup) { if (!this.core.setup) {
this.$router.push('/setup') this.$router.push('/setup')
} }
if (this.$route.path !== '/setup') {
if (this.core.logged_in) {
await this.$store.dispatch('loadAdmin')
} else {
await this.$store.dispatch('loadRequired')
}
this.loaded = true
}
}, },
async mounted() { async mounted() {
if (this.$route.path !== '/setup') { if (this.$route.path !== '/setup') {

View File

@ -347,6 +347,7 @@ HTML,BODY {
.card { .card {
background-color: $service-background; background-color: $service-background;
border: $service-border; border: $service-border;
//box-shadow: 0px 2px 11px 1px rgba(0, 0, 0, 0.13);
} }
.card-body { .card-body {

View File

@ -30,12 +30,18 @@
components: { components: {
ServiceInfo ServiceInfo
}, },
data() {
return {
visible: false
}
},
computed: { computed: {
services() { services() {
return this.$store.getters.services return this.$store.getters.services
} }
}, },
methods: { methods: {
failuresLast24Hours() { failuresLast24Hours() {
let total = 0; let total = 0;
this.services.map((s) => { this.services.map((s) => {

View File

@ -24,10 +24,10 @@
<td class="d-none d-md-table-cell">{{niceDate(user.updated_at)}}</td> <td class="d-none d-md-table-cell">{{niceDate(user.updated_at)}}</td>
<td class="text-right"> <td class="text-right">
<div class="btn-group"> <div class="btn-group">
<a @click.prevent="editUser(user, edit)" class="btn btn-outline-secondary edit-user"> <a @click.prevent="editUser(user, edit)" href="#" class="btn btn-outline-secondary edit-user">
<font-awesome-icon icon="user" /> Edit <font-awesome-icon icon="user" /> Edit
</a> </a>
<a @click.prevent="deleteUser(user)" v-if="index !== 0" class="btn btn-danger delete-user"> <a @click.prevent="deleteUser(user)" v-if="index !== 0" href="#" class="btn btn-danger delete-user">
<font-awesome-icon icon="times" /> <font-awesome-icon icon="times" />
</a> </a>
</div> </div>

View File

@ -18,10 +18,6 @@
components: { components: {
Dashboard Dashboard
}, },
props: {
version: String,
logged_in: Boolean
},
computed: { computed: {
core() { core() {
return this.$store.getters.core return this.$store.getters.core

View File

@ -1,23 +1,28 @@
<template v-if="service"> <template>
<div class="col-12 card mb-4" style="min-height: 280px;" :class="{'offline-card': !service.online}"> <div class="card mb-4" :class="{'offline-card': !service.online}">
<div class="card-body p-3 p-md-1 pt-md-3 pb-md-1"> <div class="card-title px-4 pt-3">
<h4 class="card-title mb-4"> <h4 v-observe-visibility="setVisible">
<router-link :to="serviceLink(service)">{{service.name}}</router-link> <router-link :to="serviceLink(service)">{{service.name}}</router-link>
<span class="badge float-right" :class="{'badge-success': service.online, 'badge-danger': !service.online}"> <span class="badge float-right" :class="{'badge-success': service.online, 'badge-danger': !service.online}">
{{service.online ? "ONLINE" : "OFFLINE"}} {{service.online ? "ONLINE" : "OFFLINE"}}
</span> </span>
</h4> </h4>
</div>
<div class="card-body p-3 p-md-1 pt-md-3 pb-md-1">
<transition name="fade"> <transition name="fade">
<div v-if="loaded && service.online" class="row pb-3"> <div v-if="loaded && service.online" class="col-12 pb-2">
<div class="col-md-6 col-sm-12 mt-2 mt-md-0 mb-3"> <div class="row">
<ServiceSparkLine :title="set2_name" subtitle="Latency Last 24 Hours" :series="set2"/> <div class="col-md-6 col-sm-12 mt-2 mt-md-0 mb-3">
</div> <ServiceSparkLine :title="set2_name" subtitle="Latency Last 24 Hours" :series="set2"/>
<div class="col-md-6 col-sm-12 mt-4 mt-md-0 mb-3"> </div>
<ServiceSparkLine :title="set1_name" subtitle="Latency Last 7 Days" :series="set1"/> <div class="col-md-6 col-sm-12 mt-4 mt-md-0 mb-3">
<ServiceSparkLine :title="set1_name" subtitle="Latency Last 7 Days" :series="set1"/>
</div>
</div> </div>
<div class="d-none row col-12 mt-4 pt-1 mb-3 align-content-center"> <div v-if="false" class="row mt-4 pt-1 mb-3 align-content-center">
<StatsGen :service="service" <StatsGen :service="service"
title="Since Yesterday" title="Since Yesterday"
@ -44,16 +49,26 @@
group="24h" expression="latencyPercent"/> group="24h" expression="latencyPercent"/>
</div> </div>
<div class="col-4"> </div>
<button @click.prevent="Tab('incident')" class="btn btn-block btn-outline-secondary incident" :class="{'text-white btn-secondary': openTab==='incident'}" >Incidents</button> </transition>
</div> </div>
<div class="col-4">
<div class="card-footer">
<div class="row">
<div class="col-3">
<button @click.prevent="Tab('incident')" class="btn btn-block btn-outline-secondary incident" :class="{'text-white btn-secondary': openTab==='incident'}" >Incidents</button>
</div>
<div class="col-3">
<button @click.prevent="Tab('checkin')" class="btn btn-block btn-outline-secondary checkin" :class="{'text-white btn-secondary': openTab==='checkin'}" >Checkins</button> <button @click.prevent="Tab('checkin')" class="btn btn-block btn-outline-secondary checkin" :class="{'text-white btn-secondary': openTab==='checkin'}" >Checkins</button>
</div> </div>
<div class="col-4"> <div class="col-3">
<button @click.prevent="Tab('failures')" class="btn btn-block btn-outline-secondary failures" :disabled="service.stats.failures === 0" :class="{'text-white btn-secondary': openTab==='failures'}"> <button @click.prevent="Tab('failures')" class="btn btn-block btn-outline-secondary failures" :disabled="service.stats.failures === 0" :class="{'text-white btn-secondary': openTab==='failures'}">
Failures <span class="badge badge-danger float-right mt-1">{{service.stats.failures}}</span></button> Failures <span class="badge badge-danger float-right mt-1">{{service.stats.failures}}</span></button>
</div> </div>
<div class="col-3 pt-2">
<span class="text-black-50 float-right">{{service.online_7_days}}% Uptime</span>
</div>
<div v-if="openTab === 'incident'" class="col-12 mt-4"> <div v-if="openTab === 'incident'" class="col-12 mt-4">
<FormIncident :service="service" /> <FormIncident :service="service" />
@ -70,8 +85,6 @@
</div> </div>
</div> </div>
</transition>
</div> </div>
<span v-for="(failure, index) in failures" v-bind:key="index" class="alert alert-light"> <span v-for="(failure, index) in failures" v-bind:key="index" class="alert alert-light">
@ -115,17 +128,27 @@
loaded: false, loaded: false,
set1_name: "", set1_name: "",
set2_name: "", set2_name: "",
failures: null failures: null,
visible: false
} }
}, },
async mounted() { watch: {
},
methods: {
async setVisible(isVisible, entry) {
if (isVisible && !this.visible) {
await this.loadInfo()
this.visible = true
}
},
async loadInfo() {
this.set1 = await this.getHits(24 * 7, "6h") this.set1 = await this.getHits(24 * 7, "6h")
this.set1_name = this.calc(this.set1) this.set1_name = this.calc(this.set1)
this.set2 = await this.getHits(24, "1h") this.set2 = await this.getHits(24, "1h")
this.set2_name = this.calc(this.set2) this.set2_name = this.calc(this.set2)
this.loaded = true this.loaded = true
}, },
methods: {
async deleteFailures() { async deleteFailures() {
const c = confirm('Are you sure you want to delete all failures?') const c = confirm('Are you sure you want to delete all failures?')
if (c) { if (c) {

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<div v-for="(checkin, i) in checkins" class="col-12 alert dim" role="alert"> <div v-for="(checkin, i) in checkins" class="col-12 alert alert-light" role="alert">
<span class="badge badge-pill badge-info text-uppercase">{{checkin.name}}</span> <span class="badge badge-pill badge-info text-uppercase">{{checkin.name}}</span>
<span class="float-right font-2">Last checkin {{ago(checkin.last_hit)}}</span> <span class="float-right font-2">Last checkin {{ago(checkin.last_hit)}}</span>
<span class="float-right font-2 mr-3">Check Every {{checkin.interval}} seconds</span> <span class="float-right font-2 mr-3">Check Every {{checkin.interval}} seconds</span>
@ -13,7 +13,7 @@
</span> </span>
</div> </div>
<div class="col-12 alert dim"> <div class="col-12 alert alert-light">
<form @submit.prevent="saveCheckin"> <form @submit.prevent="saveCheckin">
<div class="form-group row"> <div class="form-group row">
<div class="col-5"> <div class="col-5">

View File

@ -31,7 +31,20 @@
<small class="form-text text-muted">HTML is allowed inside the footer</small> <small class="form-text text-muted">HTML is allowed inside the footer</small>
</div> </div>
<button @click.prevent="saveSettings" id="save_core" type="submit" class="btn btn-primary btn-block">Save Settings</button> <div class="form-group row mt-3">
<label class="col-sm-10 col-form-label">Enable Error Reporting</label>
<div class="col-sm-2 float-right">
<span @click="core.allow_reports = !!core.allow_reports" class="switch" id="allow_report">
<input v-model="core.allow_reports" type="checkbox" name="allow_report" class="switch" id="switch_allow_report" :checked="core.allow_reports">
<label for="switch_allow_report"></label>
</span>
</div>
<div class="col-12">
<small>Help the Statping project out by sending anonymous error logs back to our server.</small>
</div>
</div>
<button @click.prevent="saveSettings" id="save_core" type="submit" class="btn btn-primary btn-block mt-3">Save Settings</button>
</form> </form>
</template> </template>

View File

@ -48,12 +48,12 @@
<div class="row"> <div class="row">
<div class="col-6 col-sm-6 mb-2 mb-sm-0 mt-2 mt-sm-0"> <div class="col-6 col-sm-6 mb-2 mb-sm-0 mt-2 mt-sm-0">
<button @click.prevent="saveNotifier" type="submit" class="btn btn-block text-capitalize btn-primary"> <button @click.prevent="saveNotifier" type="submit" class="btn btn-block text-capitalize btn-primary save-notifier">
<i class="fa fa-check-circle"></i> {{loading ? "Loading..." : saved ? "Saved" : "Save Settings"}} <i class="fa fa-check-circle"></i> {{loading ? "Loading..." : saved ? "Saved" : "Save Settings"}}
</button> </button>
</div> </div>
<div class="col-6 col-sm-6 mb-2 mb-sm-0 mt-2 mt-sm-0"> <div class="col-6 col-sm-6 mb-2 mb-sm-0 mt-2 mt-sm-0">
<button @click.prevent="testNotifier" class="btn btn-outline-dark btn-block text-capitalize"><i class="fa fa-vial"></i> <button @click.prevent="testNotifier" class="btn btn-outline-dark btn-block text-capitalize test-notifier"><i class="fa fa-vial"></i>
{{loadingTest ? "Loading..." : "Test Notifier"}}</button> {{loadingTest ? "Loading..." : "Test Notifier"}}</button>
</div> </div>
</div> </div>

View File

@ -6,8 +6,8 @@
<div class="form-group row"> <div class="form-group row">
<label for="switch-gh-oauth" class="col-sm-4 col-form-label">OAuth Login Settings</label> <label for="switch-gh-oauth" class="col-sm-4 col-form-label">OAuth Login Settings</label>
<div class="col-md-8 col-xs-12 mt-1"> <div class="col-md-8 col-xs-12 mt-1">
<span @click="internal_enabled = !!internal_enabled" class="switch float-left"> <span @click="oauth.internal_enabled = !!core.oauth.internal_enabled" class="switch float-left">
<input v-model="internal_enabled" type="checkbox" class="switch" id="switch-local-oauth" :checked="internal_enabled"> <input v-model="oauth.internal_enabled" type="checkbox" class="switch" id="switch-local-oauth" :checked="oauth.internal_enabled">
<label for="switch-local-oauth">Use email/password Authentication</label> <label for="switch-local-oauth">Use email/password Authentication</label>
</span> </span>
</div> </div>
@ -15,7 +15,7 @@
<div class="form-group row"> <div class="form-group row">
<label for="whitelist_domains" class="col-sm-4 col-form-label">Whitelist Domains</label> <label for="whitelist_domains" class="col-sm-4 col-form-label">Whitelist Domains</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input v-model="oauth.oauth_domains" type="text" class="form-control" placeholder="domain.com" id="whitelist_domains"> <input v-model="oauth.oauth.oauth_domains" type="text" class="form-control" placeholder="domain.com" id="whitelist_domains">
</div> </div>
</div> </div>
</div> </div>
@ -28,20 +28,20 @@
<div class="form-group row mt-3"> <div class="form-group row mt-3">
<label for="github_client" class="col-sm-4 col-form-label">Github Client ID</label> <label for="github_client" class="col-sm-4 col-form-label">Github Client ID</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input v-model="oauth.gh_client_id" type="text" class="form-control" id="github_client" required> <input v-model="oauth.oauth.gh_client_id" type="text" class="form-control" id="github_client" required>
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label for="github_secret" class="col-sm-4 col-form-label">Github Client Secret</label> <label for="github_secret" class="col-sm-4 col-form-label">Github Client Secret</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input v-model="oauth.gh_client_secret" type="text" class="form-control" id="github_secret" required> <input v-model="oauth.oauth.gh_client_secret" type="text" class="form-control" id="github_secret" required>
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label for="switch-gh-oauth" class="col-sm-4 col-form-label">Enable Github Login</label> <label for="switch-gh-oauth" class="col-sm-4 col-form-label">Enable Github Login</label>
<div class="col-md-8 col-xs-12 mt-1"> <div class="col-md-8 col-xs-12 mt-1">
<span @click="github_enabled = !!github_enabled" class="switch float-left"> <span @click="oauth.github_enabled = !!oauth.github_enabled" class="switch float-left">
<input v-model="github_enabled" type="checkbox" class="switch" id="switch-gh-oauth" :checked="github_enabled"> <input v-model="oauth.github_enabled" type="checkbox" class="switch" id="switch-gh-oauth" :checked="oauth.github_enabled">
<label for="switch-gh-oauth"> </label> <label for="switch-gh-oauth"> </label>
</span> </span>
</div> </div>
@ -145,8 +145,6 @@
</div> </div>
</div> </div>
{{providers()}}
<button class="btn btn-primary btn-block" @click.prevent="saveOAuth" type="submit"> <button class="btn btn-primary btn-block" @click.prevent="saveOAuth" type="submit">
Save OAuth Settings Save OAuth Settings
</button> </button>
@ -159,30 +157,34 @@
export default { export default {
name: 'OAuth', name: 'OAuth',
props: {
oauth: {
type: Object
}
},
computed: { computed: {
core() { oauth() {
return this.$store.getters.core return this.$store.getters.core.oauth
} }
}, },
data() { data() {
return { return {
internal_enabled: this.$store.getters.core.oauth.oauth_providers.split(",").includes('local'), internal_enabled: this.has('local'),
google_enabled: this.$store.getters.core.oauth.oauth_providers.split(",").includes('google'), google_enabled: this.has('google'),
github_enabled: this.$store.getters.core.oauth.oauth_providers.split(",").includes('github'), github_enabled: this.has('github'),
slack_enabled: this.$store.getters.core.oauth.oauth_providers.split(",").includes('slack') slack_enabled: this.has('slack')
} }
}, },
mounted() {
window.console.log(this.core.oauth)
},
beforeCreate() { beforeCreate() {
// this.github_enabled = this.$store.getters.core.oauth.oauth_providers.split(",").includes('github') // this.github_enabled = this.$store.getters.core.oauth.oauth_providers.split(",").includes('github')
// const c = await Api.core() // const c = await Api.core()
// this.auth = c.auth // this.auth = c.auth
}, },
methods: { methods: {
has(val) {
if (!this.core.oauth.oauth_providers) {
return false
}
return this.core.oauth.oauth_providers.split(",").includes(val)
},
providers() { providers() {
let providers = []; let providers = [];
if (this.github_enabled) { if (this.github_enabled) {
@ -206,7 +208,6 @@
await Api.core_save(c) await Api.core_save(c)
const core = await Api.core() const core = await Api.core()
this.$store.commit('setCore', core) this.$store.commit('setCore', core)
this.core = core
} }
} }
} }

View File

@ -162,6 +162,7 @@
return return
} }
await this.$store.dispatch('loadCore')
await this.$store.dispatch('loadRequired') await this.$store.dispatch('loadRequired')
this.loading = false this.loading = false

View File

@ -84,6 +84,7 @@
in_user() { in_user() {
let u = this.in_user let u = this.in_user
u.password = null u.password = null
u.password_confirm = null
this.user = u this.user = u
} }
}, },

View File

@ -1,9 +1,10 @@
import {library} from '@fortawesome/fontawesome-svg-core' import {library} from '@fortawesome/fontawesome-svg-core'
import {fas} from '@fortawesome/fontawesome-free-solid'; import {fas} from '@fortawesome/fontawesome-free-solid';
import {fab} from '@fortawesome/free-brands-svg-icons'; import {fab} from '@fortawesome/free-brands-svg-icons';
import {far} from '@fortawesome/fontawesome-svg-core';
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome' import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome'
import Vue from "vue"; import Vue from "vue";
library.add(fas, fab) library.add(fas, fab)
Vue.component('font-awesome-icon', FontAwesomeIcon) Vue.component('font-awesome-icon', FontAwesomeIcon)

View File

@ -6,9 +6,7 @@ import VueClipboard from 'vue-clipboard2'
import App from '@/App.vue' import App from '@/App.vue'
import store from './store' import store from './store'
import * as Sentry from '@sentry/browser';
import * as Integrations from '@sentry/integrations';
const errorReporter = "https://bed4d75404924cb3a799e370733a1b64@sentry.statping.com/3"
import router from './routes' import router from './routes'
import "./mixin" import "./mixin"
import "./icons" import "./icons"
@ -19,12 +17,6 @@ Vue.use(VueClipboard);
Vue.use(VueRouter); Vue.use(VueRouter);
Vue.use(VueObserveVisibility); Vue.use(VueObserveVisibility);
Sentry.init({
dsn: errorReporter,
integrations: [new Integrations.Vue({Vue, attachProps: true})],
});
Vue.config.productionTip = false Vue.config.productionTip = false
new Vue({ new Vue({
router, router,

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="container col-md-7 col-sm-12 mt-md-5 bg-light"> <div class="container col-md-7 col-sm-12 mt-md-5 bg-light">
<TopNav :admin="$store.state.admin"/> <TopNav :admin="admin"/>
<router-view :admin="$store.state.admin"/> <router-view :admin="admin"/>
</div> </div>
</template> </template>
@ -17,14 +17,23 @@
data () { data () {
return { return {
authenticated: false, authenticated: false,
loaded: false,
} }
}, },
async mounted() { computed: {
const core = await Api.core() admin() {
this.$store.commit('setAdmin', core.admin) return this.$store.getters.admin
this.$store.commit('setCore', core) },
user() {
return this.$store.getters.user
}
},
mounted() {
// if (!this.user || !this.admin) {
// this.$router.push('/login')
// }
}
} }
}
</script> </script>
<!-- Add "scoped" attribute to limit CSS to this component only --> <!-- Add "scoped" attribute to limit CSS to this component only -->

View File

@ -126,7 +126,7 @@
</div> </div>
<div class="tab-pane fade" v-bind:class="{active: liClass('v-pills-oauth-tab'), show: liClass('v-pills-oauth-tab')}" id="v-pills-oauth" role="tabpanel" aria-labelledby="v-pills-oauth-tab"> <div class="tab-pane fade" v-bind:class="{active: liClass('v-pills-oauth-tab'), show: liClass('v-pills-oauth-tab')}" id="v-pills-oauth" role="tabpanel" aria-labelledby="v-pills-oauth-tab">
<OAuth :oauth="core.oauth"/> <OAuth/>
</div> </div>
<div v-for="(notifier, index) in notifiers" v-bind:key="`${notifier.method}_${index}`" class="tab-pane fade" v-bind:class="{active: liClass(`v-pills-${notifier.method.toLowerCase()}-tab`), show: liClass(`v-pills-${notifier.method.toLowerCase()}-tab`)}" v-bind:id="`v-pills-${notifier.method.toLowerCase()}-tab`" role="tabpanel" v-bind:aria-labelledby="`v-pills-${notifier.method.toLowerCase()}-tab`"> <div v-for="(notifier, index) in notifiers" v-bind:key="`${notifier.method}_${index}`" class="tab-pane fade" v-bind:class="{active: liClass(`v-pills-${notifier.method.toLowerCase()}-tab`), show: liClass(`v-pills-${notifier.method.toLowerCase()}-tab`)}" v-bind:id="`v-pills-${notifier.method.toLowerCase()}-tab`" role="tabpanel" v-bind:aria-labelledby="`v-pills-${notifier.method.toLowerCase()}-tab`">

View File

@ -27,7 +27,8 @@ export default new Vuex.Store({
users: [], users: [],
notifiers: [], notifiers: [],
checkins: [], checkins: [],
admin: false admin: false,
user: false
}, },
getters: { getters: {
hasAllData: state => state.hasAllData, hasAllData: state => state.hasAllData,
@ -43,6 +44,7 @@ export default new Vuex.Store({
checkins: state => state.checkins, checkins: state => state.checkins,
isAdmin: state => state.admin, isAdmin: state => state.admin,
isUser: state => state.user,
servicesInOrder: state => state.services.sort((a, b) => a.order_id - b.order_id), servicesInOrder: state => state.services.sort((a, b) => a.order_id - b.order_id),
servicesNoGroup: state => state.services.filter(g => g.group_id === 0).sort((a, b) => a.order_id - b.order_id), servicesNoGroup: state => state.services.filter(g => g.group_id === 0).sort((a, b) => a.order_id - b.order_id),
@ -96,6 +98,7 @@ export default new Vuex.Store({
state.hasPublicData = bool state.hasPublicData = bool
}, },
setCore (state, core) { setCore (state, core) {
window.console.log('GETTING CORE')
state.core = core state.core = core
}, },
setToken (state, token) { setToken (state, token) {
@ -122,15 +125,23 @@ export default new Vuex.Store({
setAdmin (state, admin) { setAdmin (state, admin) {
state.admin = admin state.admin = admin
}, },
setUser (state, user) {
state.user = user
},
}, },
actions: { actions: {
async getAllServices(context) { async getAllServices(context) {
const services = await Api.services() const services = await Api.services()
context.commit("setServices", services); context.commit("setServices", services);
}, },
async loadCore(context) {
const core = await Api.core()
context.commit("setCore", core);
context.commit('setAdmin', core.admin)
context.commit('setCore', core)
context.commit('setUser', core.logged_in)
},
async loadRequired(context) { async loadRequired(context) {
const core = await Api.core()
context.commit("setCore", core);
const groups = await Api.groups() const groups = await Api.groups()
context.commit("setGroups", groups); context.commit("setGroups", groups);
const services = await Api.services() const services = await Api.services()
@ -138,19 +149,9 @@ export default new Vuex.Store({
const messages = await Api.messages() const messages = await Api.messages()
context.commit("setMessages", messages) context.commit("setMessages", messages)
context.commit("setHasPublicData", true) context.commit("setHasPublicData", true)
// if (core.logged_in) {
// const notifiers = await Api.notifiers()
// context.commit("setNotifiers", notifiers);
// const users = await Api.users()
// context.commit("setUsers", users);
// const integrations = await Api.integrations()
// context.commit("setIntegrations", integrations);
// }
window.console.log('finished loading required data') window.console.log('finished loading required data')
}, },
async loadAdmin(context) { async loadAdmin(context) {
const core = await Api.core()
context.commit("setCore", core);
const groups = await Api.groups() const groups = await Api.groups()
context.commit("setGroups", groups); context.commit("setGroups", groups);
const services = await Api.services() const services = await Api.services()

View File

@ -81,6 +81,8 @@ func apiCoreHandler(w http.ResponseWriter, r *http.Request) {
} }
app.OAuth = c.OAuth app.OAuth = c.OAuth
app.UseCdn = null.NewNullBool(c.UseCdn.Bool) app.UseCdn = null.NewNullBool(c.UseCdn.Bool)
app.AllowReports = null.NewNullBool(c.AllowReports.Bool)
utils.SentryInit(nil, app.AllowReports.Bool)
err = app.Update() err = app.Update()
returnJson(core.App, w, r) returnJson(core.App, w, r)
} }

View File

@ -30,7 +30,13 @@ func Select() (*Core, error) {
return nil, db.Error() return nil, db.Error()
} }
App = &c App = &c
App.UseCdn = null.NewNullBool(os.Getenv("USE_CDN") == "true")
if os.Getenv("USE_CDN") == "true" {
App.UseCdn = null.NewNullBool(true)
}
if os.Getenv("ALLOW_REPORTS") == "true" {
App.AllowReports = null.NewNullBool(true)
}
return App, q.Error() return App, q.Error()
} }

View File

@ -35,6 +35,7 @@ type Core struct {
Timezone float32 `gorm:"column:timezone;default:-8.0" json:"timezone,omitempty"` Timezone float32 `gorm:"column:timezone;default:-8.0" json:"timezone,omitempty"`
LoggedIn bool `gorm:"-" json:"logged_in"` LoggedIn bool `gorm:"-" json:"logged_in"`
IsAdmin bool `gorm:"-" json:"admin"` IsAdmin bool `gorm:"-" json:"admin"`
AllowReports null.NullBool `gorm:"column:allow_reports;default:false" json:"allow_reports"`
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"` UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
Started time.Time `gorm:"-" json:"started_on"` Started time.Time `gorm:"-" json:"started_on"`

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/fatih/structs" "github.com/fatih/structs"
"github.com/getsentry/sentry-go" "github.com/getsentry/sentry-go"
"github.com/prometheus/common/log"
Logger "github.com/sirupsen/logrus" Logger "github.com/sirupsen/logrus"
"github.com/statping/statping/types/null" "github.com/statping/statping/types/null"
"gopkg.in/natefinch/lumberjack.v2" "gopkg.in/natefinch/lumberjack.v2"
@ -16,12 +17,13 @@ import (
) )
var ( var (
Log = Logger.StandardLogger() Log = Logger.StandardLogger()
ljLogger *lumberjack.Logger ljLogger *lumberjack.Logger
LastLines []*logRow LastLines []*logRow
LockLines sync.Mutex LockLines sync.Mutex
VerboseMode int VerboseMode int
version string version string
allowReports bool
) )
const ( const (
@ -29,22 +31,32 @@ const (
errorReporter = "https://ddf2784201134d51a20c3440e222cebe@sentry.statping.com/4" errorReporter = "https://ddf2784201134d51a20c3440e222cebe@sentry.statping.com/4"
) )
func SentryInit(v string) { func SentryInit(v *string, allow bool) {
if v == "" { allowReports = allow
v = "development" if v != nil {
if *v == "" {
*v = "development"
}
version = *v
} }
version = v goEnv := Getenv("GO_ENV", "production").(string)
errorEnv := Getenv("GO_ENV", "production").(string) allowReports := Getenv("ALLOW_REPORTS", false).(bool)
if err := sentry.Init(sentry.ClientOptions{ if allowReports || allow {
Dsn: errorReporter, if err := sentry.Init(sentry.ClientOptions{
Environment: errorEnv, Dsn: errorReporter,
Release: v, Environment: goEnv,
}); err != nil { Release: version,
Log.Errorln(err) }); err != nil {
log.Errorln(err)
}
Log.Infoln("Error Reporting initiated, thank you!")
} }
} }
func SentryErr(err error) { func SentryErr(err error) {
if !allowReports {
return
}
sentry.CaptureException(err) sentry.CaptureException(err)
} }
@ -63,7 +75,7 @@ type hook struct {
func (t *hook) Fire(e *Logger.Entry) error { func (t *hook) Fire(e *Logger.Entry) error {
pushLastLine(e.Message) pushLastLine(e.Message)
if e.Level == Logger.ErrorLevel { if e.Level == Logger.ErrorLevel && allowReports {
SentryLogEntry(e) SentryLogEntry(e)
} }
return nil return nil