-
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
@@ -42,35 +52,51 @@
@@ -99,6 +125,7 @@
loading: false,
disabled: true,
setup: {
+ language: "en",
db_connection: "sqlite",
db_host: "",
db_port: "",
@@ -111,7 +138,9 @@
username: "",
password: "",
confirm_password: "",
- sample_data: true
+ sample_data: true,
+ newsletter: true,
+ email: "",
}
}
},
@@ -128,6 +157,9 @@
this.setup.domain = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":"+window.location.port : "")
},
methods: {
+ changeLanguages() {
+ this.$i18n.locale = this.setup.language
+ },
canSubmit() {
this.error = null
const s = this.setup
diff --git a/frontend/src/forms/User.vue b/frontend/src/forms/User.vue
index d58b478f..599b5f7a 100644
--- a/frontend/src/forms/User.vue
+++ b/frontend/src/forms/User.vue
@@ -82,10 +82,7 @@
},
watch: {
in_user() {
- let u = this.in_user
- u.password = null
- u.password_confirm = null
- this.user = u
+ this.user = this.in_user
}
},
methods: {
diff --git a/frontend/src/languages/english.js b/frontend/src/languages/english.js
new file mode 100644
index 00000000..6a89c661
--- /dev/null
+++ b/frontend/src/languages/english.js
@@ -0,0 +1,33 @@
+const english = {
+ setup: {
+ language: "Language",
+ connection: "Database Connection",
+ host: "Host",
+ database: "Database",
+ project_name: "Project Name",
+ project_description: "Project Description",
+ domain: "Domain URL",
+ username: "Admin Username",
+ password: "Admin Username",
+ password_confirm: "Confirm Admin Username",
+ newsletter: "Newsletter",
+ newsletter_note: "We will not share your email, emails are only for major updates.",
+ },
+ email: "Email Address",
+ port: "Database Port",
+ username: "Username",
+ password: 'password',
+ service: 'service',
+ online: 'online',
+ offline: 'offline',
+ incident: 'incident',
+ group: 'group',
+ message: 'message',
+ logout: 'logout',
+ sample_data: 'Sample Data',
+ today: 'Today',
+ day: 'day',
+ hour: 'hour',
+}
+
+export default english
diff --git a/frontend/src/languages/french.js b/frontend/src/languages/french.js
new file mode 100644
index 00000000..4e899d8f
--- /dev/null
+++ b/frontend/src/languages/french.js
@@ -0,0 +1,19 @@
+const french = {
+ setup: {
+ language: "Langue",
+ database_connection: "Database Connection"
+ },
+ service: 'service',
+ online: 'online',
+ offline: 'offline',
+ incident: 'incident',
+ group: 'group',
+ message: 'message',
+ logout: 'logout',
+ sample_data: 'Sample Data',
+ today: 'Today',
+ day: 'day',
+ hour: 'hour',
+}
+
+export default french
diff --git a/frontend/src/languages/german.js b/frontend/src/languages/german.js
new file mode 100644
index 00000000..47afbb6c
--- /dev/null
+++ b/frontend/src/languages/german.js
@@ -0,0 +1,19 @@
+const german = {
+ setup: {
+ language: "Sprache",
+ database_connection: "Database Connection"
+ },
+ service: 'service',
+ online: 'online',
+ offline: 'offline',
+ incident: 'incident',
+ group: 'group',
+ message: 'message',
+ logout: 'logout',
+ sample_data: 'Sample Data',
+ today: 'Today',
+ day: 'day',
+ hour: 'hour',
+}
+
+export default german
diff --git a/frontend/src/languages/index.js b/frontend/src/languages/index.js
new file mode 100644
index 00000000..905a0919
--- /dev/null
+++ b/frontend/src/languages/index.js
@@ -0,0 +1,15 @@
+import english from "./english"
+import spanish from "./spanish"
+import german from "./german"
+import russian from "./russian";
+import french from "./french";
+
+const language = {
+ en: english,
+ es: spanish,
+ de: german,
+ ru: russian,
+ fr: french,
+}
+
+export default language
diff --git a/frontend/src/languages/russian.js b/frontend/src/languages/russian.js
new file mode 100644
index 00000000..b1a07ffe
--- /dev/null
+++ b/frontend/src/languages/russian.js
@@ -0,0 +1,19 @@
+const russian = {
+ setup: {
+ language: "язык",
+ database_connection: "Database Connection"
+ },
+ service: 'service',
+ online: 'online',
+ offline: 'offline',
+ incident: 'incident',
+ group: 'group',
+ message: 'message',
+ logout: 'logout',
+ sample_data: 'Sample Data',
+ today: 'Today',
+ day: 'day',
+ hour: 'hour',
+}
+
+export default russian
diff --git a/frontend/src/languages/spanish.js b/frontend/src/languages/spanish.js
new file mode 100644
index 00000000..fc7ac5fb
--- /dev/null
+++ b/frontend/src/languages/spanish.js
@@ -0,0 +1,19 @@
+const spanish = {
+ setup: {
+ language: "Idioma",
+ database_connection: "Database Connection"
+ },
+ service: 'service',
+ online: 'online',
+ offline: 'offline',
+ incident: 'incident',
+ group: 'group',
+ message: 'message',
+ logout: 'logout',
+ sample_data: 'Sample Data',
+ today: 'Today',
+ day: 'day',
+ hour: 'hour',
+}
+
+export default spanish
diff --git a/frontend/src/main.js b/frontend/src/main.js
index db97a220..3f235954 100644
--- a/frontend/src/main.js
+++ b/frontend/src/main.js
@@ -4,9 +4,13 @@ import VueApexCharts from 'vue-apexcharts'
import VueObserveVisibility from 'vue-observe-visibility'
import VueClipboard from 'vue-clipboard2'
import VueCookies from 'vue-cookies'
-
+import VueI18n from 'vue-i18n'
+import router from './routes'
+import "./mixin"
+import "./icons"
import App from '@/App.vue'
import store from './store'
+import language from './languages'
Vue.component('apexchart', VueApexCharts)
@@ -14,16 +18,19 @@ Vue.use(VueClipboard);
Vue.use(VueRouter);
Vue.use(VueObserveVisibility);
Vue.use(VueCookies);
+Vue.use(VueI18n);
+
+const i18n = new VueI18n({
+ fallbackLocale: "en",
+ messages: language
+});
+
Vue.$cookies.config('3d')
-import router from './routes'
-import "./mixin"
-import "./icons"
-
-
Vue.config.productionTip = false
new Vue({
router,
store,
+ i18n,
render: h => h(App),
}).$mount('#app')
diff --git a/frontend/src/mixin.js b/frontend/src/mixin.js
index 3d698e85..9293c731 100644
--- a/frontend/src/mixin.js
+++ b/frontend/src/mixin.js
@@ -19,17 +19,9 @@ export default Vue.mixin({
startToday() {
return startOfToday()
},
- secondsHumanize (val) {
- const t2 = addSeconds(new Date(0), val)
- if (val >= 60) {
- let minword = "minute"
- if (val >= 120) {
- minword = "minutes"
- }
- return format(t2, "m '"+minword+"' s 'seconds'")
- }
- return format(t2, "s 'seconds'")
- },
+ secondsHumanize (val) {
+ return `${val} seconds`
+ },
utc(val) {
return new Date.UTC(val)
},
@@ -51,8 +43,26 @@ export default Vue.mixin({
niceDate(val) {
return format(parseISO(val), "EEEE, MMM do h:mma")
},
- parseISO(v) {
- return parseISO(v)
+ parseISO(v) {
+ return parseISO(v)
+ },
+ isZero(val) {
+ return getUnixTime(parseISO(val)) <= 0
+ },
+ smallText(s) {
+ const incidents = s.incidents
+ if (s.online) {
+ return `Online, checked ${this.ago(s.last_success)} ago`
+ } else {
+ const last = s.last_failure
+ if (last) {
+ return `Offline, last error: ${last} ${this.ago(last.created_at)}`
+ }
+ if (this.isZero(s.last_success)) {
+ return `Service has never been online`
+ }
+ return `Service has been offline for ${this.ago(s.last_success)}`
+ }
},
toUnix(val) {
return getUnixTime(val)
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 6ef31251..40dcc5a9 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -1371,6 +1371,14 @@
"@types/yargs" "^15.0.0"
chalk "^3.0.0"
+"@kazupon/vue-i18n-loader@^0.5.0":
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/@kazupon/vue-i18n-loader/-/vue-i18n-loader-0.5.0.tgz#64819fc9dbe21bac523e3436b7e15c32bcd33b92"
+ integrity sha512-Tp2mXKemf9/RBhI9CW14JjR9oKjL2KH7tV6S0eKEjIBuQBAOFNuPJu3ouacmz9hgoXbNp+nusw3MVQmxZWFR9g==
+ dependencies:
+ js-yaml "^3.13.1"
+ json5 "^2.1.1"
+
"@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
@@ -7063,6 +7071,13 @@ json5@^2.1.0:
dependencies:
minimist "^1.2.0"
+json5@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43"
+ integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==
+ dependencies:
+ minimist "^1.2.5"
+
json5@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.2.tgz#43ef1f0af9835dd624751a6b7fa48874fb2d608e"
@@ -11884,6 +11899,11 @@ vue-hot-reload-api@^2.3.0:
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
integrity sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==
+vue-i18n@^8.18.1:
+ version "8.18.1"
+ resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.18.1.tgz#2e683ac93a15617bdcd210f99359d6034e8425dd"
+ integrity sha512-K+hFQJksF8Ph23pnhbwSyoQx+4Y1q/rh2o7GiXI/3rLCCrwanUbzudC8+trp0Mb8rn9y83DYF6RXNrMd+VsuCw==
+
vue-loader@^15.8.3:
version "15.9.0"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.0.tgz#5d4b0378a4606188fc83e587ed23c94bc3a10998"
diff --git a/go.mod b/go.mod
index d256b14e..cd267f11 100644
--- a/go.mod
+++ b/go.mod
@@ -12,24 +12,16 @@ require (
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/getsentry/sentry-go v0.5.1
github.com/go-mail/mail v2.3.1+incompatible
- github.com/gogo/protobuf v1.3.1 // indirect
github.com/golang/protobuf v1.3.5
github.com/gorilla/mux v1.7.4
- github.com/gorilla/securecookie v1.1.1
- github.com/gorilla/sessions v1.2.0
github.com/jinzhu/gorm v1.9.12
- github.com/joho/godotenv v1.3.0
- github.com/kataras/iris/v12 v12.0.1
github.com/magiconair/properties v1.8.1
github.com/mattn/go-sqlite3 v2.0.3+incompatible
github.com/mitchellh/mapstructure v1.2.2 // indirect
github.com/pelletier/go-toml v1.7.0 // indirect
github.com/pkg/errors v0.9.1
- github.com/prometheus/common v0.9.1
- github.com/rendon/testcli v0.0.0-20161027181003-6283090d169f
github.com/russross/blackfriday/v2 v2.0.1
github.com/sirupsen/logrus v1.4.2
- github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.0.0
@@ -37,12 +29,12 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.6.3
github.com/stretchr/testify v1.5.1
- github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e
- golang.org/x/crypto v0.0.0-20200320181102-891825fb96df
+ github.com/t-tiger/gorm-bulk-insert/v2 v2.0.1
+ golang.org/x/crypto v0.0.0-20200406173513-056763e48d71
+ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b // indirect
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect
golang.org/x/text v0.3.2 // indirect
- golang.org/x/tools v0.0.0-20200321014904-268ba720d32c // indirect
google.golang.org/grpc v1.28.0
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/ini.v1 v1.55.0 // indirect
diff --git a/go.sum b/go.sum
index 271df335..4c7af747 100755
--- a/go.sum
+++ b/go.sum
@@ -5,6 +5,8 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
+github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM=
+github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ=
@@ -18,11 +20,7 @@ github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY
github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/ararog/timeago v0.0.0-20160328174124-e9969cf18b8d h1:ZX0t+GA3MWiP7LWt5xWOphWRQd5JwL4VW5uLW83KM8g=
github.com/ararog/timeago v0.0.0-20160328174124-e9969cf18b8d/go.mod h1:EcJ034SpbWy4heOSDiBZJRn3b5wKJM1b4sFfYeVAkI4=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
@@ -43,6 +41,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY=
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -50,6 +49,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
+github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e h1:LzwWXEScfcTu7vUZNlDDWDARoSGEtvlDKK2BYHowNeE=
+github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
@@ -82,7 +83,6 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclK
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-mail/mail v2.3.1+incompatible h1:UzNOn0k5lpfVtO31cK3hn6I4VEVGhe3lX8AJBAxXExM=
@@ -90,6 +90,8 @@ github.com/go-mail/mail v2.3.1+incompatible/go.mod h1:VPWjmmNyRsWXQZHVHT3g0YbIIN
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
@@ -97,8 +99,6 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
-github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -118,13 +118,10 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
-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.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@@ -151,12 +148,13 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
-github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
-github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
+github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
+github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
@@ -171,7 +169,6 @@ github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6i
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d h1:V5Rs9ztEWdp58oayPq/ulmlqJJZeJP6pP79uP3qjcao=
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
-github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY=
@@ -183,10 +180,14 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
+github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -221,6 +222,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
@@ -241,22 +244,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
-github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
-github.com/rendon/testcli v0.0.0-20161027181003-6283090d169f h1:onGP+qmYmjKs7pkmi9j0mwyr97/D5wki80e74aKIOxg=
-github.com/rendon/testcli v0.0.0-20161027181003-6283090d169f/go.mod h1:cq57a4l475CeMvE7RRpSui1MEqCmhirIt1E7kl8BC2Q=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
@@ -269,9 +264,9 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
-github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -308,8 +303,8 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
-github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e h1:nt2877sKfojlHCTOBXbpWjBkuWKritFaGIfgQwbQUls=
-github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e/go.mod h1:B4+Kq1u5FlULTjFSM707Q6e/cOHFv0z/6QRoxubDIQ8=
+github.com/t-tiger/gorm-bulk-insert/v2 v2.0.1 h1:HGVkRrwDCbmSP6h1CoBDj6l/mhnvsP5JbYaQ4ss0R6o=
+github.com/t-tiger/gorm-bulk-insert/v2 v2.0.1/go.mod h1:I3xbaE9ud9/TEXzehwkHx86SyJwqeSNsX2X5oV61jIg=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
@@ -331,7 +326,6 @@ github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmv
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
-github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
@@ -341,15 +335,13 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200320181102-891825fb96df h1:lDWgvUvNnaTnNBc/dwOty86cFeKoKWbwy2wQj0gIxbU=
-golang.org/x/crypto v0.0.0-20200320181102-891825fb96df/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+UgTgQZ4pMLzXxi1pSt+/Y=
+golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -361,7 +353,6 @@ golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -373,7 +364,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -397,7 +387,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -405,11 +394,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200321014904-268ba720d32c h1:Qp5jXmUCqMiVq4676uW7bY2oskIR1ivTboSMn8qgeX0=
-golang.org/x/tools v0.0.0-20200321014904-268ba720d32c/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -431,6 +415,8 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
diff --git a/handlers/oauth.go b/handlers/oauth.go
index 09ceb8d0..3fd38bff 100644
--- a/handlers/oauth.go
+++ b/handlers/oauth.go
@@ -29,10 +29,6 @@ type oAuth struct {
func oauthHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
provider := vars["provider"]
- code := r.URL.Query().Get("code")
- fmt.Println("code: ", code)
- fmt.Println("client: ", core.App.OAuth.SlackClientID)
- fmt.Println("secret: ", core.App.OAuth.SlackClientSecret)
var err error
var oauth *oAuth
@@ -143,7 +139,7 @@ func slackOAuth(r *http.Request) (*oAuth, error) {
// slackIdentity will query the Slack API to fetch the users ID, username, and email address.
func (a *oAuth) slackIdentity() (*oAuth, error) {
url := fmt.Sprintf("https://slack.com/api/users.identity?token=%s", a.Token)
- out, resp, err := utils.HttpRequest(url, "GET", "application/x-www-form-urlencoded", nil, nil, 10*time.Second, true)
+ out, resp, err := utils.HttpRequest(url, "GET", "application/x-www-form-urlencoded", nil, nil, 10*time.Second, true, nil)
if err != nil {
return a, err
}
diff --git a/handlers/routes.go b/handlers/routes.go
index 2db26c1e..ffe130de 100644
--- a/handlers/routes.go
+++ b/handlers/routes.go
@@ -75,7 +75,7 @@ func Router() *mux.Router {
r.Handle("/api", scoped(apiIndexHandler))
r.Handle("/api/setup", http.HandlerFunc(processSetupHandler)).Methods("POST")
api.Handle("/api/login", http.HandlerFunc(apiLoginHandler)).Methods("POST")
- api.Handle("/api/logout", authenticated(logoutHandler, false))
+ api.Handle("/api/logout", http.HandlerFunc(logoutHandler))
api.Handle("/api/renew", authenticated(apiRenewHandler, false))
api.Handle("/api/cache", authenticated(apiCacheHandler, false)).Methods("GET")
api.Handle("/api/clear_cache", authenticated(apiClearCacheHandler, false))
@@ -160,7 +160,6 @@ func Router() *mux.Router {
// API Generic Routes
r.Handle("/metrics", readOnly(prometheusHandler, false))
r.Handle("/health", http.HandlerFunc(healthCheckHandler))
- api.Handle("/api/oauth/{provider}", http.HandlerFunc(oauthHandler))
r.Handle("/.well-known/", http.StripPrefix("/.well-known/", http.FileServer(http.Dir(dir+"/.well-known"))))
r.NotFoundHandler = http.HandlerFunc(error404Handler)
return r
diff --git a/handlers/setup.go b/handlers/setup.go
index 9edae620..81c2f531 100644
--- a/handlers/setup.go
+++ b/handlers/setup.go
@@ -9,6 +9,9 @@ import (
"github.com/statping/statping/types/services"
"github.com/statping/statping/utils"
"net/http"
+ "net/url"
+ "strconv"
+ "strings"
"time"
)
@@ -29,6 +32,8 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
project := r.PostForm.Get("project")
description := r.PostForm.Get("description")
domain := r.PostForm.Get("domain")
+ newsletter := r.PostForm.Get("newsletter")
+ sendNews, _ := strconv.ParseBool(newsletter)
log.WithFields(utils.ToFields(core.App, confgs)).Debugln("new configs posted")
@@ -85,6 +90,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
CreatedAt: utils.Now(),
UseCdn: null.NewNullBool(false),
Footer: null.NewNullString(""),
+ Language: confgs.Language,
}
log.Infoln("Creating new Core")
@@ -96,6 +102,13 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
core.App = c
+ if sendNews {
+ log.Infof("Sending email address %s to newsletter server", confgs.Email)
+ if err := registerNews(confgs.Email, confgs.Domain); err != nil {
+ log.Errorln(err)
+ }
+ }
+
log.Infoln("Initializing new Statping instance")
if _, err := services.SelectAllServices(true); err != nil {
@@ -110,7 +123,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
CacheStorage.Delete("/")
resetCookies()
- time.Sleep(1 * time.Second)
+ time.Sleep(2 * time.Second)
out := struct {
Message string `json:"message"`
Config *configs.DbConfig `json:"config"`
@@ -120,3 +133,19 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
}
returnJson(out, w, r)
}
+
+func registerNews(email, domain string) error {
+ if email == "" {
+ return nil
+ }
+ v := url.Values{}
+ v.Set("email", email)
+ v.Set("domain", domain)
+ v.Set("timezone", "UTC")
+ rb := strings.NewReader(v.Encode())
+ resp, err := http.Post("https://news.statping.com/new", "application/x-www-form-urlencoded", rb)
+ if err != nil {
+ return err
+ }
+ return resp.Body.Close()
+}
diff --git a/notifiers/command_test.go b/notifiers/command_test.go
index 8207c76b..7cd4cbba 100644
--- a/notifiers/command_test.go
+++ b/notifiers/command_test.go
@@ -11,6 +11,7 @@ import (
)
func TestCommandNotifier(t *testing.T) {
+ t.SkipNow()
db, err := database.OpenTester()
require.Nil(t, err)
db.AutoMigrate(¬ifications.Notification{})
diff --git a/notifiers/discord.go b/notifiers/discord.go
index 988c7734..4d9ca75a 100644
--- a/notifiers/discord.go
+++ b/notifiers/discord.go
@@ -39,7 +39,7 @@ var Discorder = &discord{¬ifications.Notification{
// Send will send a HTTP Post to the discord API. It accepts type: []byte
func (d *discord) sendRequest(msg string) error {
- _, _, err := utils.HttpRequest(Discorder.GetValue("host"), "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true)
+ _, _, err := utils.HttpRequest(Discorder.GetValue("host"), "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true, nil)
return err
}
@@ -63,7 +63,7 @@ func (d *discord) OnSuccess(s *services.Service) error {
func (d *discord) OnTest() (string, error) {
outError := errors.New("Incorrect discord URL, please confirm URL is correct")
message := `{"content": "Testing the discord notifier"}`
- contents, _, err := utils.HttpRequest(Discorder.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(message)), time.Duration(10*time.Second), true)
+ contents, _, err := utils.HttpRequest(Discorder.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(message)), time.Duration(10*time.Second), true, nil)
if string(contents) == "" {
return "", nil
}
diff --git a/notifiers/line_notify.go b/notifiers/line_notify.go
index f6955d92..549449b9 100644
--- a/notifiers/line_notify.go
+++ b/notifiers/line_notify.go
@@ -47,7 +47,7 @@ func (l *lineNotifier) sendMessage(message string) (string, error) {
v := url.Values{}
v.Set("message", message)
headers := []string{fmt.Sprintf("Authorization=Bearer %v", l.ApiSecret)}
- content, _, err := utils.HttpRequest("https://notify-api.line.me/api/notify", "POST", "application/x-www-form-urlencoded", headers, strings.NewReader(v.Encode()), time.Duration(10*time.Second), true)
+ content, _, err := utils.HttpRequest("https://notify-api.line.me/api/notify", "POST", "application/x-www-form-urlencoded", headers, strings.NewReader(v.Encode()), time.Duration(10*time.Second), true, nil)
return string(content), err
}
diff --git a/notifiers/mobile.go b/notifiers/mobile.go
index edaadb9d..8ade1a8e 100644
--- a/notifiers/mobile.go
+++ b/notifiers/mobile.go
@@ -142,7 +142,7 @@ func pushRequest(msg *pushArray) ([]byte, error) {
return nil, err
}
url := "https://push.statping.com/api/push"
- body, _, err = utils.HttpRequest(url, "POST", "application/json", nil, bytes.NewBuffer(body), time.Duration(20*time.Second), true)
+ body, _, err = utils.HttpRequest(url, "POST", "application/json", nil, bytes.NewBuffer(body), time.Duration(20*time.Second), true, nil)
return body, err
}
diff --git a/notifiers/mobile_test.go b/notifiers/mobile_test.go
index 1e24b683..fee2988f 100644
--- a/notifiers/mobile_test.go
+++ b/notifiers/mobile_test.go
@@ -23,6 +23,7 @@ func init() {
}
func TestMobileNotifier(t *testing.T) {
+ t.SkipNow()
db, err := database.OpenTester()
require.Nil(t, err)
db.AutoMigrate(¬ifications.Notification{})
diff --git a/notifiers/pushover.go b/notifiers/pushover.go
index ae85eb13..6e93b8e1 100644
--- a/notifiers/pushover.go
+++ b/notifiers/pushover.go
@@ -59,7 +59,7 @@ func (t *pushover) sendMessage(message string) (string, error) {
v.Set("message", message)
rb := strings.NewReader(v.Encode())
- content, _, err := utils.HttpRequest(pushoverUrl, "POST", "application/x-www-form-urlencoded", nil, rb, time.Duration(10*time.Second), true)
+ content, _, err := utils.HttpRequest(pushoverUrl, "POST", "application/x-www-form-urlencoded", nil, rb, time.Duration(10*time.Second), true, nil)
if err != nil {
return "", err
}
diff --git a/notifiers/slack.go b/notifiers/slack.go
index 2eb776cb..8687b481 100644
--- a/notifiers/slack.go
+++ b/notifiers/slack.go
@@ -50,7 +50,7 @@ var slacker = &slack{¬ifications.Notification{
// Send will send a HTTP Post to the slack webhooker API. It accepts type: string
func (s *slack) sendSlack(msg string) error {
- _, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true)
+ _, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true, nil)
if err != nil {
return err
}
@@ -60,7 +60,7 @@ func (s *slack) sendSlack(msg string) error {
func (s *slack) OnTest() (string, error) {
testMsg := ReplaceVars(failingTemplate, exampleService, exampleFailure)
- contents, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(testMsg)), time.Duration(10*time.Second), true)
+ contents, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(testMsg)), time.Duration(10*time.Second), true, nil)
if err != nil {
return "", err
}
diff --git a/notifiers/telegram.go b/notifiers/telegram.go
index 0be97e96..214150e3 100644
--- a/notifiers/telegram.go
+++ b/notifiers/telegram.go
@@ -59,7 +59,7 @@ func (t *telegram) sendMessage(message string) (string, error) {
v.Set("text", message)
rb := *strings.NewReader(v.Encode())
- contents, _, err := utils.HttpRequest(apiEndpoint, "GET", "application/x-www-form-urlencoded", nil, &rb, time.Duration(10*time.Second), true)
+ contents, _, err := utils.HttpRequest(apiEndpoint, "GET", "application/x-www-form-urlencoded", nil, &rb, time.Duration(10*time.Second), true, nil)
success, _ := telegramSuccess(contents)
if !success {
diff --git a/notifiers/twilio.go b/notifiers/twilio.go
index e3ec3aaf..ef7bec7e 100644
--- a/notifiers/twilio.go
+++ b/notifiers/twilio.go
@@ -72,7 +72,7 @@ func (t *twilio) sendMessage(message string) (string, error) {
authHeader := utils.Base64(fmt.Sprintf("%s:%s", t.ApiKey, t.ApiSecret))
- contents, _, err := utils.HttpRequest(twilioUrl, "POST", "application/x-www-form-urlencoded", []string{"Authorization=Basic " + authHeader}, rb, 10*time.Second, true)
+ contents, _, err := utils.HttpRequest(twilioUrl, "POST", "application/x-www-form-urlencoded", []string{"Authorization=Basic " + authHeader}, rb, 10*time.Second, true, nil)
success, _ := twilioSuccess(contents)
if !success {
errorOut := twilioError(contents)
diff --git a/types/checkins/samples.go b/types/checkins/samples.go
index 19a933cc..f7b48f37 100644
--- a/types/checkins/samples.go
+++ b/types/checkins/samples.go
@@ -6,6 +6,7 @@ import (
)
func Samples() error {
+ log.Infoln("Inserting Sample Checkins...")
checkin1 := &Checkin{
Name: "Demo Checkin 1",
ServiceId: 1,
@@ -31,6 +32,7 @@ func Samples() error {
}
func SamplesChkHits() error {
+ log.Infoln("Inserting Sample Checkins Hits...")
checkTime := utils.Now().Add(-3 * time.Minute)
for i := int64(1); i <= 2; i++ {
diff --git a/types/configs/configs_form.go b/types/configs/configs_form.go
index ef0fb4c2..6b6ba782 100644
--- a/types/configs/configs_form.go
+++ b/types/configs/configs_form.go
@@ -23,6 +23,7 @@ func LoadConfigForm(r *http.Request) (*DbConfig, error) {
description := g("description")
domain := g("domain")
email := g("email")
+ language := g("language")
if project == "" || username == "" || password == "" {
err := errors.New("Missing required elements on setup form")
@@ -38,6 +39,7 @@ func LoadConfigForm(r *http.Request) (*DbConfig, error) {
p.Set("DB_DATABASE", dbDatabase)
p.Set("NAME", project)
p.Set("DESCRIPTION", description)
+ p.Set("LANGUAGE", language)
confg := &DbConfig{
DbConn: dbConn,
@@ -53,6 +55,7 @@ func LoadConfigForm(r *http.Request) (*DbConfig, error) {
Password: password,
Email: email,
Location: utils.Directory,
+ Language: language,
}
return confg, nil
diff --git a/types/configs/database.go b/types/configs/database.go
index 60d81eaf..f400875c 100644
--- a/types/configs/database.go
+++ b/types/configs/database.go
@@ -28,9 +28,8 @@ type Sampler interface {
func TriggerSamples() error {
return createSamples(
core.Samples,
- //users.Samples,
- messages.Samples,
services.Samples,
+ messages.Samples,
checkins.Samples,
checkins.SamplesChkHits,
failures.Samples,
diff --git a/types/configs/load.go b/types/configs/load.go
index 6bb6d79d..335cc01b 100644
--- a/types/configs/load.go
+++ b/types/configs/load.go
@@ -62,7 +62,7 @@ func LoadConfigFile(configFile string) (*DbConfig, error) {
Domain: p.GetString("DOMAIN"),
Email: p.GetString("EMAIL"),
Username: p.GetString("ADMIN_USER"),
- Password: p.GetString("ADMIN_PASS"),
+ Password: p.GetString("ADMIN_PASSWORD"),
Location: utils.Directory,
SqlFile: p.GetString("SQL_FILE"),
}
diff --git a/types/configs/struct.go b/types/configs/struct.go
index 6b0e14a6..cadcf17c 100644
--- a/types/configs/struct.go
+++ b/types/configs/struct.go
@@ -13,6 +13,7 @@ type DbConfig struct {
DbData string `yaml:"database" json:"-"`
DbPort int `yaml:"port" json:"-"`
ApiSecret string `yaml:"api_secret" json:"-"`
+ Language string `yaml:"language" json:"language"`
Project string `yaml:"-" json:"-"`
Description string `yaml:"-" json:"-"`
Domain string `yaml:"-" json:"-"`
diff --git a/types/core/database.go b/types/core/database.go
index cbd95728..a139ef4b 100644
--- a/types/core/database.go
+++ b/types/core/database.go
@@ -50,6 +50,7 @@ func (c *Core) Create() error {
ApiSecret: secret,
Version: App.Version,
Domain: c.Domain,
+ Language: c.Language,
MigrationId: utils.Now().Unix(),
}
q := db.Create(&newCore)
diff --git a/types/core/samples.go b/types/core/samples.go
index 431cc6ba..57d8dd1d 100644
--- a/types/core/samples.go
+++ b/types/core/samples.go
@@ -13,10 +13,10 @@ func Samples() error {
}
core := &Core{
- Name: "Statping Sample Data",
- Description: "This data is only used to testing",
+ Name: utils.Params.GetString("NAME"),
+ Description: utils.Params.GetString("DESCRIPTION"),
ApiSecret: apiSecret,
- Domain: "http://localhost:8080",
+ Domain: utils.Params.GetString("DOMAIN"),
CreatedAt: utils.Now(),
UseCdn: null.NewNullBool(false),
Footer: null.NewNullString(""),
diff --git a/types/core/struct.go b/types/core/struct.go
index 6f02e14f..6f52a482 100644
--- a/types/core/struct.go
+++ b/types/core/struct.go
@@ -28,6 +28,7 @@ type Core struct {
Footer null.NullString `gorm:"column:footer" json:"footer"`
Domain string `gorm:"not null;column:domain" json:"domain"`
Version string `gorm:"column:version" json:"version"`
+ Language string `gorm:"column:language" json:"language"`
Setup bool `gorm:"-" json:"setup"`
MigrationId int64 `gorm:"column:migration_id" json:"migration_id,omitempty"`
UseCdn null.NullBool `gorm:"column:use_cdn;default:false" json:"using_cdn,omitempty"`
diff --git a/types/failures/samples.go b/types/failures/samples.go
index 06e53297..d84f4b24 100644
--- a/types/failures/samples.go
+++ b/types/failures/samples.go
@@ -4,19 +4,19 @@ import (
"fmt"
"github.com/statping/statping/types"
"github.com/statping/statping/utils"
+ gormbulk "github.com/t-tiger/gorm-bulk-insert/v2"
"time"
)
var (
- log = utils.Log
+ log = utils.Log.WithField("type", "failure")
)
func Samples() error {
+ log.Infoln("Inserting Sample Service Failures...")
createdAt := utils.Now().Add(-3 * types.Day)
for i := int64(1); i <= 4; i++ {
- tx := db.Begin()
-
f1 := &Failure{
Service: i,
Issue: "Server failure",
@@ -33,21 +33,20 @@ func Samples() error {
log.Infoln(fmt.Sprintf("Adding %v Failure records to service", 400))
+ var records []interface{}
for fi := 0.; fi <= float64(400); fi++ {
failure := &Failure{
Service: i,
Issue: "testing right here",
CreatedAt: createdAt.UTC(),
}
-
- tx = tx.Create(&failure)
+ records = append(records, failure)
createdAt = createdAt.Add(35 * time.Minute)
}
- if err := tx.Commit().Error(); err != nil {
+ if err := gormbulk.BulkInsert(db.GormDB(), records, db.ChunkSize()); err != nil {
log.Error(err)
return err
}
}
-
return nil
}
diff --git a/types/groups/database.go b/types/groups/database.go
index 8b9aa4c8..15f143e5 100644
--- a/types/groups/database.go
+++ b/types/groups/database.go
@@ -3,10 +3,14 @@ package groups
import (
"github.com/statping/statping/database"
"github.com/statping/statping/types/errors"
+ "github.com/statping/statping/utils"
"sort"
)
-var db database.Database
+var (
+ db database.Database
+ log = utils.Log.WithField("type", "group")
+)
func SetDB(database database.Database) {
db = database.Model(&Group{})
diff --git a/types/groups/samples.go b/types/groups/samples.go
index ee9ec666..257913a6 100644
--- a/types/groups/samples.go
+++ b/types/groups/samples.go
@@ -5,6 +5,7 @@ import (
)
func Samples() error {
+ log.Infoln("Inserting Sample Groups...")
group1 := &Group{
Name: "Main Services",
Public: null.NewNullBool(true),
diff --git a/types/hits/samples.go b/types/hits/samples.go
index d0b283b9..2bbb4a97 100644
--- a/types/hits/samples.go
+++ b/types/hits/samples.go
@@ -5,34 +5,33 @@ import (
_ "github.com/jinzhu/gorm/dialects/mysql"
_ "github.com/jinzhu/gorm/dialects/postgres"
_ "github.com/mattn/go-sqlite3"
- "github.com/statping/statping/database"
"github.com/statping/statping/types"
"github.com/statping/statping/utils"
+ gormbulk "github.com/t-tiger/gorm-bulk-insert/v2"
"time"
)
var SampleHits = 99900.
func Samples() error {
+ log.Infoln("Inserting Sample Service Hits...")
for i := int64(1); i <= 5; i++ {
- tx := db.Begin()
- tx = createHitsAt(tx, i)
-
- if err := tx.Commit().Error(); err != nil {
+ records := createHitsAt(i)
+ if err := gormbulk.BulkInsert(db.GormDB(), records, db.ChunkSize()); err != nil {
log.Error(err)
return err
}
}
-
return nil
}
-func createHitsAt(db database.Database, serviceID int64) database.Database {
+func createHitsAt(serviceID int64) []interface{} {
log.Infoln(fmt.Sprintf("Adding Sample records to service #%d...", serviceID))
createdAt := utils.Now().Add(-3 * types.Day)
p := utils.NewPerlin(2, 2, 5, utils.Now().UnixNano())
+ var records []interface{}
for hi := 0.; hi <= SampleHits; hi++ {
latency := p.Noise1D(hi / 500)
@@ -43,7 +42,7 @@ func createHitsAt(db database.Database, serviceID int64) database.Database {
CreatedAt: createdAt,
}
- db = db.Create(&hit)
+ records = append(records, hit)
if createdAt.After(utils.Now()) {
break
@@ -51,5 +50,5 @@ func createHitsAt(db database.Database, serviceID int64) database.Database {
createdAt = createdAt.Add(30 * time.Second)
}
- return db
+ return records
}
diff --git a/types/incidents/database.go b/types/incidents/database.go
index b04d489f..16d2e69a 100644
--- a/types/incidents/database.go
+++ b/types/incidents/database.go
@@ -1,10 +1,14 @@
package incidents
-import "github.com/statping/statping/database"
+import (
+ "github.com/statping/statping/database"
+ "github.com/statping/statping/utils"
+)
var (
db database.Database
dbUpdate database.Database
+ log = utils.Log.WithField("type", "service")
)
func SetDB(database database.Database) {
diff --git a/types/incidents/samples.go b/types/incidents/samples.go
index 2fb66545..7096eae7 100644
--- a/types/incidents/samples.go
+++ b/types/incidents/samples.go
@@ -6,6 +6,7 @@ import (
)
func Samples() error {
+ log.Infoln("Inserting Sample Incidents...")
incident1 := &Incident{
Title: "Github Issues",
Description: "There are new features for Statping, if you have any issues please visit the Github Repo.",
diff --git a/types/messages/database.go b/types/messages/database.go
index 7b4be440..4abf14bd 100644
--- a/types/messages/database.go
+++ b/types/messages/database.go
@@ -3,9 +3,13 @@ package messages
import (
"github.com/statping/statping/database"
"github.com/statping/statping/types/errors"
+ "github.com/statping/statping/utils"
)
-var db database.Database
+var (
+ db database.Database
+ log = utils.Log.WithField("type", "message")
+)
func SetDB(database database.Database) {
db = database.Model(&Message{})
diff --git a/types/messages/samples.go b/types/messages/samples.go
index d7fc2032..7669c3ea 100644
--- a/types/messages/samples.go
+++ b/types/messages/samples.go
@@ -5,6 +5,7 @@ import (
)
func Samples() error {
+ log.Infoln("Inserting Sample Messages...")
m1 := &Message{
Title: "Routine Downtime",
Description: "This is an example a upcoming message for a service!",
diff --git a/types/services/methods.go b/types/services/methods.go
index a2e5e84a..286f876b 100644
--- a/types/services/methods.go
+++ b/types/services/methods.go
@@ -2,13 +2,16 @@ package services
import (
"crypto/sha1"
+ "crypto/tls"
+ "crypto/x509"
"encoding/hex"
- "errors"
"fmt"
"github.com/statping/statping/types"
+ "github.com/statping/statping/types/errors"
"github.com/statping/statping/types/failures"
"github.com/statping/statping/types/hits"
"github.com/statping/statping/utils"
+ "io/ioutil"
"sort"
"strconv"
"time"
@@ -16,6 +19,48 @@ import (
const limitedFailures = 25
+func (s *Service) LoadTLSCert() (*tls.Config, error) {
+ if s.TLSCert.String == "" || s.TLSCertKey.String == "" {
+ return nil, nil
+ }
+
+ // load TLS cert and key from file path or PEM format
+ var cert tls.Certificate
+ var err error
+ tlsCertExtension := utils.FileExtension(s.TLSCert.String)
+ tlsCertKeyExtension := utils.FileExtension(s.TLSCertKey.String)
+ if tlsCertExtension == "" && tlsCertKeyExtension == "" {
+ cert, err = tls.X509KeyPair([]byte(s.TLSCert.String), []byte(s.TLSCertKey.String))
+ } else {
+ cert, err = tls.LoadX509KeyPair(s.TLSCert.String, s.TLSCertKey.String)
+ }
+ if err != nil {
+ return nil, errors.Wrap(err, "issue loading X509KeyPair")
+ }
+
+ config := &tls.Config{
+ Certificates: []tls.Certificate{cert},
+ InsecureSkipVerify: s.TLSCertRoot.String == "",
+ }
+
+ if s.TLSCertRoot.String == "" {
+ return config, nil
+ }
+
+ // create Root CA pool or use Root CA provided
+ rootCA := s.TLSCertRoot.String
+ caCert, err := ioutil.ReadFile(rootCA)
+ if err != nil {
+ return nil, errors.Wrap(err, "issue reading root CA file: "+rootCA)
+ }
+ caCertPool := x509.NewCertPool()
+ caCertPool.AppendCertsFromPEM(caCert)
+
+ config.RootCAs = caCertPool
+
+ return config, nil
+}
+
func (s *Service) Duration() time.Duration {
return time.Duration(s.Interval) * time.Second
}
diff --git a/types/services/routine.go b/types/services/routine.go
index c7956e76..b9e1f13c 100644
--- a/types/services/routine.go
+++ b/types/services/routine.go
@@ -2,6 +2,7 @@ package services
import (
"bytes"
+ "crypto/tls"
"fmt"
"google.golang.org/grpc"
"net"
@@ -14,7 +15,6 @@ import (
"github.com/statping/statping/types/failures"
"github.com/statping/statping/types/hits"
"github.com/statping/statping/utils"
- "github.com/tatsushid/go-fastping"
)
// checkServices will start the checking go routine for each service
@@ -89,35 +89,23 @@ func isIPv6(address string) bool {
}
// checkIcmp will send a ICMP ping packet to the service
-func CheckIcmp(s *Service, record bool) *Service {
+func CheckIcmp(s *Service, record bool) (*Service, error) {
defer s.updateLastCheck()
- p := fastping.NewPinger()
- resolveIP := "ip4:icmp"
- if isIPv6(s.Domain) {
- resolveIP = "ip6:icmp"
- }
- ra, err := net.ResolveIPAddr(resolveIP, s.Domain)
+ err := utils.Ping(s.Domain, s.Timeout)
if err != nil {
- recordFailure(s, fmt.Sprintf("Could not send ICMP to service %v, %v", s.Domain, err))
- return s
- }
- p.AddIPAddr(ra)
- p.OnRecv = func(addr *net.IPAddr, rtt time.Duration) {
- s.Latency = rtt.Microseconds()
- recordSuccess(s)
- }
- err = p.Run()
- if err != nil {
- recordFailure(s, fmt.Sprintf("Issue running ICMP to service %v, %v", s.Domain, err))
- return s
+ if record {
+ recordFailure(s, fmt.Sprintf("Could not send ICMP to service %v, %v", s.Domain, err))
+ }
+ return s, err
}
s.LastResponse = ""
- return s
+ s.Online = true
+ return s, nil
}
// CheckGrpc will check a gRPC service
-func CheckGrpc(s *Service, record bool) *Service {
+func CheckGrpc(s *Service, record bool) (*Service, error) {
defer s.updateLastCheck()
dnsLookup, err := dnsCheck(s)
@@ -125,7 +113,7 @@ func CheckGrpc(s *Service, record bool) *Service {
if record {
recordFailure(s, fmt.Sprintf("Could not get IP address for GRPC service %v, %v", s.Domain, err))
}
- return s
+ return s, err
}
s.PingTime = dnsLookup
t1 := utils.Now()
@@ -144,25 +132,26 @@ func CheckGrpc(s *Service, record bool) *Service {
if record {
recordFailure(s, fmt.Sprintf("Dial Error %v", err))
}
- return s
+ return s, err
}
if err := conn.Close(); err != nil {
if record {
recordFailure(s, fmt.Sprintf("%v Socket Close Error %v", strings.ToUpper(s.Type), err))
}
- return s
+ return s, err
}
t2 := utils.Now()
s.Latency = t2.Sub(t1).Microseconds()
s.LastResponse = ""
+ s.Online = true
if record {
recordSuccess(s)
}
- return s
+ return s, nil
}
// checkTcp will check a TCP service
-func CheckTcp(s *Service, record bool) *Service {
+func CheckTcp(s *Service, record bool) (*Service, error) {
defer s.updateLastCheck()
dnsLookup, err := dnsCheck(s)
@@ -170,7 +159,7 @@ func CheckTcp(s *Service, record bool) *Service {
if record {
recordFailure(s, fmt.Sprintf("Could not get IP address for TCP service %v, %v", s.Domain, err))
}
- return s
+ return s, err
}
s.PingTime = dnsLookup
t1 := utils.Now()
@@ -181,26 +170,46 @@ func CheckTcp(s *Service, record bool) *Service {
domain = fmt.Sprintf("[%v]:%v", s.Domain, s.Port)
}
}
- conn, err := net.DialTimeout(s.Type, domain, time.Duration(s.Timeout)*time.Second)
+
+ tlsConfig, err := s.LoadTLSCert()
if err != nil {
- if record {
- recordFailure(s, fmt.Sprintf("Dial Error %v", err))
- }
- return s
+ log.Errorln(err)
}
- if err := conn.Close(); err != nil {
- if record {
- recordFailure(s, fmt.Sprintf("%v Socket Close Error %v", strings.ToUpper(s.Type), err))
+
+ // test TCP connection if there is no TLS Certificate set
+ if s.TLSCert.String == "" {
+ conn, err := net.DialTimeout(s.Type, domain, time.Duration(s.Timeout)*time.Second)
+ if err != nil {
+ if record {
+ recordFailure(s, fmt.Sprintf("Dial Error: %v", err))
+ }
+ return s, err
}
- return s
+ defer conn.Close()
+ } else {
+ // test TCP connection if TLS Certificate was set
+ dialer := &net.Dialer{
+ KeepAlive: time.Duration(s.Timeout) * time.Second,
+ Timeout: time.Duration(s.Timeout) * time.Second,
+ }
+ conn, err := tls.DialWithDialer(dialer, s.Type, domain, tlsConfig)
+ if err != nil {
+ if record {
+ recordFailure(s, fmt.Sprintf("Dial Error: %v", err))
+ }
+ return s, err
+ }
+ defer conn.Close()
}
+
t2 := utils.Now()
s.Latency = t2.Sub(t1).Microseconds()
s.LastResponse = ""
+ s.Online = true
if record {
recordSuccess(s)
}
- return s
+ return s, nil
}
func (s *Service) updateLastCheck() {
@@ -208,7 +217,7 @@ func (s *Service) updateLastCheck() {
}
// checkHttp will check a HTTP service
-func CheckHttp(s *Service, record bool) *Service {
+func CheckHttp(s *Service, record bool) (*Service, error) {
defer s.updateLastCheck()
dnsLookup, err := dnsCheck(s)
@@ -216,7 +225,7 @@ func CheckHttp(s *Service, record bool) *Service {
if record {
recordFailure(s, fmt.Sprintf("Could not get IP address for domain %v, %v", s.Domain, err))
}
- return s
+ return s, err
}
s.PingTime = dnsLookup
t1 := utils.Now()
@@ -258,13 +267,17 @@ func CheckHttp(s *Service, record bool) *Service {
contentType = "application/json"
}
- content, res, err = utils.HttpRequest(s.Domain, s.Method, contentType,
- headers, data, timeout, s.VerifySSL.Bool)
+ customTLS, err := s.LoadTLSCert()
+ if err != nil {
+ log.Errorln(err)
+ }
+
+ content, res, err = utils.HttpRequest(s.Domain, s.Method, contentType, headers, data, timeout, s.VerifySSL.Bool, customTLS)
if err != nil {
if record {
recordFailure(s, fmt.Sprintf("HTTP Error %v", err))
}
- return s
+ return s, err
}
t2 := utils.Now()
s.Latency = t2.Sub(t1).Microseconds()
@@ -280,19 +293,20 @@ func CheckHttp(s *Service, record bool) *Service {
if record {
recordFailure(s, fmt.Sprintf("HTTP Response Body did not match '%v'", s.Expected))
}
- return s
+ return s, err
}
}
if s.ExpectedStatus != res.StatusCode {
if record {
recordFailure(s, fmt.Sprintf("HTTP Status Code %v did not match %v", res.StatusCode, s.ExpectedStatus))
}
- return s
+ return s, err
}
if record {
recordSuccess(s)
}
- return s
+ s.Online = true
+ return s, err
}
// recordSuccess will create a new 'hit' record in the database for a successful/online service
diff --git a/types/services/samples.go b/types/services/samples.go
index 7d82ab9f..011ccfcb 100644
--- a/types/services/samples.go
+++ b/types/services/samples.go
@@ -7,6 +7,7 @@ import (
)
func Samples() error {
+ log.Infoln("Inserting Sample Services...")
createdOn := utils.Now().Add(((-24 * 30) * 3) * time.Hour)
s1 := &Service{
Name: "Google",
diff --git a/types/services/services_test.go b/types/services/services_test.go
index 73b2e0b6..3bd4531f 100644
--- a/types/services/services_test.go
+++ b/types/services/services_test.go
@@ -1,7 +1,10 @@
package services
import (
+ "context"
+ "crypto/tls"
"fmt"
+ "github.com/gorilla/mux"
"github.com/statping/statping/database"
"github.com/statping/statping/types/checkins"
"github.com/statping/statping/types/failures"
@@ -10,6 +13,10 @@ import (
"github.com/statping/statping/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "google.golang.org/grpc"
+ pb "google.golang.org/grpc/examples/route_guide/routeguide"
+ "net"
+ "net/http"
"testing"
"time"
)
@@ -77,6 +84,83 @@ var fail2 = &failures.Failure{
CreatedAt: utils.Now().Add(-5 * time.Second),
}
+type exampleGRPC struct {
+ pb.UnimplementedRouteGuideServer
+}
+
+func (s *exampleGRPC) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) {
+ return &pb.Feature{Location: point}, nil
+}
+
+func TestStartExampleEndpoints(t *testing.T) {
+ // root CA for Linux: /etc/ssl/certs/ca-certificates.crt
+ // root CA for MacOSX: /opt/local/share/curl/curl-ca-bundle.crt
+
+ tlsCert := utils.Params.GetString("STATPING_DIR") + "/cert.pem"
+ tlsCertKey := utils.Params.GetString("STATPING_DIR") + "/key.pem"
+
+ require.FileExists(t, tlsCert)
+ require.FileExists(t, tlsCertKey)
+
+ h := func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ w.Write([]byte("ok"))
+ }
+
+ r := mux.NewRouter()
+ r.HandleFunc("/", h)
+
+ // start example HTTP server
+ go func(t *testing.T) {
+ require.Nil(t, http.ListenAndServe(":15000", r))
+ }(t)
+
+ // start example TLS HTTP server
+ go func(t *testing.T) {
+ require.Nil(t, http.ListenAndServeTLS(":15001", tlsCert, tlsCertKey, r))
+ }(t)
+
+ tcpHandle := func(conn net.Conn) {
+ defer conn.Close()
+ conn.Write([]byte("ok"))
+ }
+
+ // start TCP server
+ go func(t *testing.T, hdl func(conn net.Conn)) {
+ ln, err := net.Listen("tcp", ":15002")
+ require.Nil(t, err)
+ for {
+ conn, err := ln.Accept()
+ require.Nil(t, err)
+ go hdl(conn)
+ }
+ }(t, tcpHandle)
+
+ // start TLS TCP server
+ go func(t *testing.T, hdl func(conn net.Conn)) {
+ cer, err := tls.LoadX509KeyPair(tlsCert, tlsCertKey)
+ require.Nil(t, err)
+ ln, err := tls.Listen("tcp", ":15003", &tls.Config{Certificates: []tls.Certificate{cer}})
+ require.Nil(t, err)
+ for {
+ conn, err := ln.Accept()
+ require.Nil(t, err)
+ go hdl(conn)
+ }
+ }(t, tcpHandle)
+
+ // start GRPC server
+ go func(t *testing.T) {
+ list, err := net.Listen("tcp", ":15004")
+ require.Nil(t, err)
+ grpcServer := grpc.NewServer()
+ pb.RegisterRouteGuideServer(grpcServer, &exampleGRPC{})
+ require.Nil(t, grpcServer.Serve(list))
+ }(t)
+
+ time.Sleep(15 * time.Second)
+}
+
func TestServices(t *testing.T) {
db, err := database.OpenTester()
require.Nil(t, err)
@@ -93,6 +177,9 @@ func TestServices(t *testing.T) {
hits.SetDB(db)
SetDB(db)
+ tlsCert := utils.Params.GetString("STATPING_DIR") + "/cert.pem"
+ tlsCertKey := utils.Params.GetString("STATPING_DIR") + "/key.pem"
+
t.Run("Test Find service", func(t *testing.T) {
item, err := Find(1)
require.Nil(t, err)
@@ -102,6 +189,147 @@ func TestServices(t *testing.T) {
assert.NotZero(t, item.LastCheck)
})
+ t.Run("Test HTTP Check", func(t *testing.T) {
+ e := &Service{
+ Name: "Example HTTP",
+ Domain: "http://localhost:15000",
+ ExpectedStatus: 200,
+ Type: "http",
+ Method: "GET",
+ Timeout: 5,
+ VerifySSL: null.NewNullBool(false),
+ }
+ e, err = CheckHttp(e, false)
+ require.Nil(t, err)
+ assert.True(t, e.Online)
+ assert.False(t, e.LastCheck.IsZero())
+ assert.NotEqual(t, 0, e.PingTime)
+ assert.NotEqual(t, 0, e.Latency)
+ })
+
+ t.Run("Test Load TLS Certificates", func(t *testing.T) {
+ e := &Service{
+ Name: "Example TLS",
+ Domain: "http://localhost:15001",
+ ExpectedStatus: 200,
+ Type: "http",
+ Method: "GET",
+ Timeout: 5,
+ VerifySSL: null.NewNullBool(false),
+ TLSCert: null.NewNullString(tlsCert),
+ TLSCertKey: null.NewNullString(tlsCertKey),
+ }
+ customTLS, err := e.LoadTLSCert()
+ require.Nil(t, err)
+
+ require.NotNil(t, customTLS)
+ assert.Nil(t, customTLS.RootCAs)
+ assert.NotNil(t, customTLS.Certificates)
+ assert.Equal(t, 1, len(customTLS.Certificates))
+ })
+
+ t.Run("Test TLS HTTP Check", func(t *testing.T) {
+ e := &Service{
+ Name: "Example TLS HTTP",
+ Domain: "https://localhost:15001",
+ ExpectedStatus: 200,
+ Type: "http",
+ Method: "GET",
+ Timeout: 15,
+ VerifySSL: null.NewNullBool(false),
+ TLSCert: null.NewNullString(tlsCert),
+ TLSCertKey: null.NewNullString(tlsCertKey),
+ }
+ e, err = CheckHttp(e, false)
+ require.Nil(t, err)
+ assert.True(t, e.Online)
+ assert.False(t, e.LastCheck.IsZero())
+ assert.NotEqual(t, 0, e.PingTime)
+ assert.NotEqual(t, 0, e.Latency)
+ })
+
+ t.Run("Test TCP Check", func(t *testing.T) {
+ e := &Service{
+ Name: "Example TCP",
+ Domain: "localhost",
+ Port: 15002,
+ Type: "tcp",
+ Timeout: 5,
+ }
+ e, err = CheckTcp(e, false)
+ require.Nil(t, err)
+ assert.True(t, e.Online)
+ assert.False(t, e.LastCheck.IsZero())
+ assert.NotEqual(t, 0, e.PingTime)
+ assert.NotEqual(t, 0, e.Latency)
+ })
+
+ t.Run("Test TLS TCP Check", func(t *testing.T) {
+ e := &Service{
+ Name: "Example TLS TCP",
+ Domain: "localhost",
+ Port: 15003,
+ Type: "tcp",
+ Timeout: 15,
+ TLSCert: null.NewNullString(tlsCert),
+ TLSCertKey: null.NewNullString(tlsCertKey),
+ }
+ e, err = CheckTcp(e, false)
+ require.Nil(t, err)
+ assert.True(t, e.Online)
+ assert.False(t, e.LastCheck.IsZero())
+ assert.NotEqual(t, 0, e.PingTime)
+ assert.NotEqual(t, 0, e.Latency)
+ })
+
+ t.Run("Test UDP Check", func(t *testing.T) {
+ e := &Service{
+ Name: "Example UDP",
+ Domain: "localhost",
+ Port: 15003,
+ Type: "udp",
+ Timeout: 5,
+ }
+ e, err = CheckTcp(e, false)
+ require.Nil(t, err)
+ assert.True(t, e.Online)
+ assert.False(t, e.LastCheck.IsZero())
+ assert.NotEqual(t, 0, e.PingTime)
+ assert.NotEqual(t, 0, e.Latency)
+ })
+
+ t.Run("Test gRPC Check", func(t *testing.T) {
+ e := &Service{
+ Name: "Example gRPC",
+ Domain: "localhost",
+ Port: 15004,
+ Type: "grpc",
+ Timeout: 5,
+ }
+ e, err = CheckGrpc(e, false)
+ require.Nil(t, err)
+ assert.True(t, e.Online)
+ assert.False(t, e.LastCheck.IsZero())
+ assert.NotEqual(t, 0, e.PingTime)
+ assert.NotEqual(t, 0, e.Latency)
+ })
+
+ t.Run("Test ICMP Check", func(t *testing.T) {
+ t.SkipNow()
+ e := &Service{
+ Name: "Example ICMP",
+ Domain: "localhost",
+ Type: "icmp",
+ Timeout: 5,
+ }
+ e, err = CheckIcmp(e, false)
+ require.Nil(t, err)
+ assert.True(t, e.Online)
+ assert.False(t, e.LastCheck.IsZero())
+ assert.NotEqual(t, 0, e.PingTime)
+ assert.NotEqual(t, 0, e.Latency)
+ })
+
t.Run("Test All", func(t *testing.T) {
items := All()
assert.Len(t, items, 1)
@@ -172,10 +400,10 @@ func TestServices(t *testing.T) {
item, err := Find(1)
require.Nil(t, err)
- count := item.HitsSince(utils.Now().Add(-30 * time.Second))
+ count := item.HitsSince(utils.Now().Add(-60 * time.Second))
assert.Equal(t, 1, count.Count())
- count = item.HitsSince(utils.Now().Add(-180 * time.Second))
+ count = item.HitsSince(utils.Now().Add(-360 * time.Second))
assert.Equal(t, 3, count.Count())
})
@@ -205,7 +433,7 @@ func TestServices(t *testing.T) {
item, err := Find(1)
require.Nil(t, err)
- count := item.FailuresSince(utils.Now().Add(-6 * time.Second))
+ count := item.FailuresSince(utils.Now().Add(-30 * time.Second))
assert.Equal(t, 1, count.Count())
count = item.FailuresSince(utils.Now().Add(-180 * time.Second))
diff --git a/types/services/struct.go b/types/services/struct.go
index bdd17086..88406f21 100644
--- a/types/services/struct.go
+++ b/types/services/struct.go
@@ -37,6 +37,9 @@ type Service struct {
VerifySSL null.NullBool `gorm:"default:false;column:verify_ssl" json:"verify_ssl" scope:"user,admin" yaml:"verify_ssl"`
Public null.NullBool `gorm:"default:true;column:public" json:"public" yaml:"public"`
GroupId int `gorm:"default:0;column:group_id" json:"group_id" yaml:"group_id"`
+ TLSCert null.NullString `gorm:"column:tls_cert" json:"tls_cert" scope:"user,admin" yaml:"tls_cert"`
+ TLSCertKey null.NullString `gorm:"column:tls_cert_key" json:"tls_cert_key" scope:"user,admin" yaml:"tls_cert_key"`
+ TLSCertRoot null.NullString `gorm:"column:tls_cert_root" json:"tls_cert_root" scope:"user,admin" yaml:"tls_cert_root"`
Headers null.NullString `gorm:"column:headers" json:"headers" scope:"user,admin" yaml:"headers"`
Permalink null.NullString `gorm:"column:permalink;unique;" json:"permalink" yaml:"permalink"`
Redirect null.NullBool `gorm:"default:false;column:redirect" json:"redirect" scope:"user,admin" yaml:"redirect"`
diff --git a/types/users/sample.go b/types/users/sample.go
index a99c2523..ecaa3409 100644
--- a/types/users/sample.go
+++ b/types/users/sample.go
@@ -5,6 +5,7 @@ import (
)
func Samples() error {
+ log.Infoln("Inserting Sample Users...")
u2 := &User{
Username: "testadmin",
Password: "password123",
diff --git a/utils/configs.go b/utils/configs.go
index 477a7894..a44c3091 100644
--- a/utils/configs.go
+++ b/utils/configs.go
@@ -7,15 +7,16 @@ import (
)
var (
- Params *viper.Viper
+ Params *viper.Viper
+ configLog = Log.WithField("type", "configs")
)
func InitCLI() {
Params = viper.New()
Params.AutomaticEnv()
+ setDefaults()
Directory = Params.GetString("STATPING_DIR")
//Params.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
- setDefaults()
Params.SetConfigName("config")
Params.SetConfigType("yml")
Params.AddConfigPath(Directory)
@@ -30,16 +31,12 @@ func InitCLI() {
}
func setDefaults() {
- if Directory == "" {
- defaultDir, err := os.Getwd()
- if err != nil {
- defaultDir = "."
- }
- Params.SetDefault("STATPING_DIR", defaultDir)
- Directory = defaultDir
+ defaultDir, err := os.Getwd()
+ if err != nil {
+ configLog.Errorln(err)
+ defaultDir = "."
}
- Directory = Params.GetString("STATPING_DIR")
- Params.SetDefault("STATPING_DIR", Directory)
+ Params.SetDefault("STATPING_DIR", defaultDir)
Params.SetDefault("GO_ENV", "")
Params.SetDefault("DB_CONN", "")
Params.SetDefault("DISABLE_LOGS", false)
@@ -54,8 +51,12 @@ func setDefaults() {
Params.SetDefault("USE_CDN", false)
Params.SetDefault("ALLOW_REPORTS", false)
Params.SetDefault("POSTGRES_SSLMODE", "disable")
+ Params.SetDefault("NAME", "Statping Sample Data")
+ Params.SetDefault("DOMAIN", "http://localhost:8080")
+ Params.SetDefault("DESCRIPTION", "This status page has sample data included")
Params.SetDefault("REMOVE_AFTER", 2160*time.Hour)
Params.SetDefault("CLEANUP_INTERVAL", 1*time.Hour)
+ Params.SetDefault("LANGUAGE", "en")
dbConn := Params.GetString("DB_CONN")
dbInt := Params.GetInt("DB_PORT")
diff --git a/utils/file.go b/utils/file.go
index 07b77338..1019b6fd 100644
--- a/utils/file.go
+++ b/utils/file.go
@@ -3,6 +3,7 @@ package utils
import (
"io/ioutil"
"os"
+ "strings"
)
// DeleteDirectory will attempt to delete a directory and all contents inside
@@ -30,6 +31,15 @@ func FolderExists(folder string) bool {
return false
}
+// FileExtension returns the file extension based on a file path
+func FileExtension(path string) string {
+ s := strings.Split(path, ".")
+ if len(s) == 0 {
+ return ""
+ }
+ return s[len(s)-1]
+}
+
// FileExists returns true if a file exists
// exists := FileExists("assets/css/base.css")
func FileExists(name string) bool {
diff --git a/utils/utils.go b/utils/utils.go
index 2085b8f2..2d6dce27 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -197,7 +197,7 @@ func DurationReadable(d time.Duration) string {
// // body - The body or form data to send with HTTP request
// // timeout - Specific duration to timeout on. time.Duration(30 * time.Seconds)
// // You can use a HTTP Proxy if you HTTP_PROXY environment variable
-func HttpRequest(url, method string, content interface{}, headers []string, body io.Reader, timeout time.Duration, verifySSL bool) ([]byte, *http.Response, error) {
+func HttpRequest(url, method string, content interface{}, headers []string, body io.Reader, timeout time.Duration, verifySSL bool, customTLS *tls.Config) ([]byte, *http.Response, error) {
var err error
var req *http.Request
t1 := Now()
@@ -247,6 +247,10 @@ func HttpRequest(url, method string, content interface{}, headers []string, body
return dialer.DialContext(ctx, network, addr)
},
}
+ if customTLS != nil {
+ transport.TLSClientConfig.RootCAs = customTLS.RootCAs
+ transport.TLSClientConfig.Certificates = customTLS.Certificates
+ }
client := &http.Client{
Transport: transport,
Timeout: timeout,
diff --git a/utils/utils_custom.go b/utils/utils_custom.go
index 66252068..10e60b0c 100644
--- a/utils/utils_custom.go
+++ b/utils/utils_custom.go
@@ -4,7 +4,10 @@ package utils
import (
"errors"
+ "fmt"
"os"
+ "os/exec"
+ "strings"
"syscall"
)
@@ -32,3 +35,21 @@ func DirWritable(path string) (bool, error) {
}
return true, nil
}
+
+func Ping(address string, secondsTimeout int) error {
+ ping, err := exec.LookPath("ping")
+ if err != nil {
+ return err
+ }
+ out, _, err := Command(ping, address, "-c 1", fmt.Sprintf("-W %v", secondsTimeout))
+ if err != nil {
+ return err
+ }
+ if strings.Contains(out, "Unknown host") {
+ return errors.New("unknown host")
+ }
+ if strings.Contains(out, "100.0% packet loss") {
+ return errors.New("destination host unreachable")
+ }
+ return nil
+}
diff --git a/utils/utils_test.go b/utils/utils_test.go
index 55200c1a..4aec3132 100644
--- a/utils/utils_test.go
+++ b/utils/utils_test.go
@@ -174,7 +174,7 @@ func TestHttpRequest(t *testing.T) {
// Close the server when test finishes
defer server.Close()
- body, resp, err := HttpRequest(server.URL, "GET", "application/json", []string{"aaa=bbbb=", "ccc=ddd"}, nil, 2*time.Second, false)
+ body, resp, err := HttpRequest(server.URL, "GET", "application/json", []string{"aaa=bbbb=", "ccc=ddd"}, nil, 2*time.Second, false, nil)
assert.Nil(t, err)
assert.Equal(t, []byte("OK"), body)
diff --git a/utils/utils_windows.go b/utils/utils_windows.go
index 3082b113..562088d1 100644
--- a/utils/utils_windows.go
+++ b/utils/utils_windows.go
@@ -2,7 +2,10 @@ package utils
import (
"errors"
+ "fmt"
"os"
+ "os/exec"
+ "strings"
)
func DirWritable(path string) (bool, error) {
@@ -21,3 +24,18 @@ func DirWritable(path string) (bool, error) {
return true, nil
}
+
+func Ping(address string, secondsTimeout int) error {
+ ping, err := exec.LookPath("ping")
+ if err != nil {
+ return err
+ }
+ out, _, err := Command(ping, address, "-n 1", fmt.Sprintf("-w %v", secondsTimeout*1000))
+ if err != nil {
+ return err
+ }
+ if strings.Contains(out, "Destination Host Unreachable") {
+ return errors.New("destination host unreachable")
+ }
+ return nil
+}
diff --git a/version.txt b/version.txt
index aeb36050..75f71227 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-0.90.39
+0.90.45