diff --git a/CHANGELOG.md b/CHANGELOG.md index 15f26b5c..590461d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ - Modified Service View page to show data inside cards - Fixed issue with uptime_data sending incorrect start/end timestamps - Modified http cache to bypass if url has a "v" query param +- Added "Static Services" (a fake service that requires you to update the online/offline status) +- Added Update Static Service PATCH route (/api/services/{id}) +- Modified SASS api endpoints (base, layout, forms, mixins, mobile, variables) +- Added additional testing # 0.90.60 (07-15-2020) - Added LETSENCRYPT_ENABLE (boolean) env to enable/disable letsencrypt SSL diff --git a/dev/postman.json b/dev/postman.json index 09052360..ed01b677 100644 --- a/dev/postman.json +++ b/dev/postman.json @@ -840,7 +840,7 @@ "", "pm.test(\"View All Services\", function () {", " var jsonData = pm.response.json();", - " pm.expect(jsonData.length).to.eql(5);", + " pm.expect(jsonData.length).to.eql(6);", "});" ], "type": "text/javascript" @@ -1714,7 +1714,7 @@ "services" ] }, - "description": "Create a new service and begin monitoring." + "description": "View a specific service, this will include the service's failures and checkins.\n\n#### Service Type Field\n- `http` - HTTP Service\n- `tcp` - TCP Service\n- `udp` - UDP Service\n- `icmp` - ICMP Service\n- `grpc` - gRPC Service\n- `static` - Static Service" }, "response": [ { @@ -1876,6 +1876,69 @@ } ] }, + { + "name": "Update Static Service", + "event": [ + { + "listen": "test", + "script": { + "id": "18cfae1e-4025-4338-a734-a552c8ac85ca", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Update Service\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.status).to.eql(\"success\");", + " pm.expect(jsonData.output.type).to.eql(\"static\");", + " pm.expect(jsonData.output.online).to.eql(false);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"online\": false,\n \"latency\": 30500,\n \"issue\": \"This is a failure string you can create\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{endpoint}}/api/services/7", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "services", + "7" + ] + }, + "description": "Update a Static Service by setting it's online status to true or false. If false, you can include a issue string in the `issue` JSON field." + }, + "response": [] + }, { "name": "Delete Service Failures", "event": [ @@ -2026,7 +2089,7 @@ ] } ], - "description": "With the Statping API, you can add, remove, edit all your services fields from the API directly. This includes viewing Service chart data for latency/up-time, and even viewing a log of failures. ", + "description": "With the Statping API, you can add, remove, edit all your services fields from the API directly. This includes viewing Service chart data for latency/up-time, and even viewing a log of failures. \n\n### HTTP Services\nA HTTP service is a basic service that sends a HTTP request (GET, POST, PATCH, DELETE, etc) to check if that web service is online or not. You can expect a specific status code, and response body (including regex). \n\n### TCP and UDP Services\nTCP and UDP Services will send a request to the hostname and port of your choice.\n\n### ICMP Ping Services\nICMP Services will send a ICMP (ping) packet to your server to test if it's online.\n\n### gRPC Services\ngRPC Services will request your gRPC server and check the response\n\n### Static Services\nA Static Service is a \"fake\" service that is set online/offline by you.\n", "auth": { "type": "bearer", "bearer": [ diff --git a/frontend/src/components/Dashboard/ThemeEditor.vue b/frontend/src/components/Dashboard/ThemeEditor.vue index 9b0bec1f..7cbbf733 100644 --- a/frontend/src/components/Dashboard/ThemeEditor.vue +++ b/frontend/src/components/Dashboard/ThemeEditor.vue @@ -6,6 +6,10 @@ {{error}} +
+ Asset Directory: {{directory}} +
+

Enable Local Assets

@@ -24,17 +28,31 @@

Base Theme

+

Layout Theme

+ + +

Forms Theme

+ + +

Mixins

+ +

Mobile Overwrites

- - - -
- Asset Directory: {{directory}} -
+ +
@@ -62,6 +80,9 @@ data () { return { base: null, + layout: null, + forms: null, + mixins: null, vars: null, mobile: null, error: null, @@ -90,6 +111,9 @@ this.$refs.vars.codemirror.refresh() this.$refs.base.codemirror.refresh() this.$refs.mobile.codemirror.refresh() + this.$refs.layout.codemirror.refresh() + this.$refs.forms.codemirror.refresh() + this.$refs.mixins.codemirror.refresh() } }, async fetchTheme() { @@ -101,6 +125,9 @@ this.base = theme.base this.vars = theme.variables this.mobile = theme.mobile + this.layout = theme.layout + this.forms = theme.forms + this.mixins = theme.mixins } this.pending = false this.loaded = true @@ -127,7 +154,14 @@ }, async saveAssets() { this.pending = true - const data = {base: this.base, variables: this.vars, mobile: this.mobile} + const data = { + base: this.base, + layout: this.layout, + forms: this.forms, + mixins: this.mixins, + variables: this.vars, + mobile: this.mobile + } let resp try { resp = await Api.theme_save(data) diff --git a/frontend/src/forms/CoreSettings.vue b/frontend/src/forms/CoreSettings.vue index d8b95dda..7f1cfe84 100644 --- a/frontend/src/forms/CoreSettings.vue +++ b/frontend/src/forms/CoreSettings.vue @@ -1,64 +1,70 @@ diff --git a/frontend/src/forms/Service.vue b/frontend/src/forms/Service.vue index 096acab5..bb633cb1 100644 --- a/frontend/src/forms/Service.vue +++ b/frontend/src/forms/Service.vue @@ -19,6 +19,7 @@ + Use HTTP if you are checking a website or use TCP if you are checking a server @@ -52,7 +53,7 @@ -
+
{{secondsHumanize(service.check_interval)}} @@ -67,7 +68,7 @@
-
+
Request Details
diff --git a/frontend/src/pages/Settings.vue b/frontend/src/pages/Settings.vue index 29fb201a..527cf0c5 100644 --- a/frontend/src/pages/Settings.vue +++ b/frontend/src/pages/Settings.vue @@ -60,12 +60,7 @@
-
-
Statping Settings
-
- -
-
+
API Settings
@@ -82,10 +77,12 @@ API Secret is used for read, create, update and delete routes You can Regenerate API Keys if you need to. -
+
diff --git a/go.mod b/go.mod index 6b2974f5..5f29be9e 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,7 @@ go 1.14 require ( github.com/GeertJohan/go.rice v1.0.0 - github.com/ararog/timeago v0.0.0-20160328174124-e9969cf18b8d github.com/dgrijalva/jwt-go v3.2.0+incompatible - github.com/dustin/go-humanize v1.0.0 github.com/fatih/structs v1.1.0 github.com/foomo/simplecert v1.7.5 github.com/foomo/tlsconfig v0.0.0-20180418120404-b67861b076c9 @@ -15,16 +13,12 @@ require ( github.com/getsentry/sentry-go v0.5.1 github.com/go-mail/mail v2.3.1+incompatible github.com/gorilla/mux v1.7.4 - github.com/gorilla/securecookie v1.1.1 github.com/hako/durafmt v0.0.0-20200605151348-3a43fc422dd9 github.com/jinzhu/gorm v1.9.12 - 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/client_golang v1.1.0 - github.com/russross/blackfriday/v2 v2.0.1 github.com/sirupsen/logrus v1.5.0 github.com/spf13/afero v1.2.2 // indirect github.com/spf13/cast v1.3.1 // indirect @@ -36,10 +30,8 @@ require ( github.com/t-tiger/gorm-bulk-insert/v2 v2.0.1 golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d - golang.org/x/text v0.3.2 // indirect google.golang.org/grpc v1.28.1 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/ini.v1 v1.55.0 // indirect gopkg.in/mail.v2 v2.3.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.2.8 diff --git a/go.sum b/go.sum index b3b94e18..9715f9c4 100755 --- a/go.sum +++ b/go.sum @@ -54,6 +54,7 @@ github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSW github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8= @@ -98,8 +99,6 @@ github.com/aliyun/alibaba-cloud-sdk-go v1.61.112/go.mod h1:pUKYbK5JQ+1Dfxk80P0qx github.com/aliyun/alibaba-cloud-sdk-go v1.61.131 h1:ePFkFbwr/u1HM9/p+azqI5UaxwY1hYKv+H8dkaRCLs4= github.com/aliyun/alibaba-cloud-sdk-go v1.61.131/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -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= github.com/aws/aws-sdk-go v1.30.20 h1:ktsy2vodSZxz/arYqo7DlpkIeNohHL+4Rmjdo7YGtrE= github.com/aws/aws-sdk-go v1.30.20/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= @@ -287,18 +286,18 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 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/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= github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hako/durafmt v0.0.0-20200605151348-3a43fc422dd9 h1:IEhIezS5kcD4ZzOwVl8dAyJ9JCi4Xo6tg44Vj/z7UsI= github.com/hako/durafmt v0.0.0-20200605151348-3a43fc422dd9/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= @@ -368,6 +367,7 @@ github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b h1:DzHy0GlWeF0KAglaTMY github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -439,6 +439,7 @@ github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY 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/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= 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= @@ -561,6 +562,7 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs= github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -613,6 +615,7 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= 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= go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= @@ -714,6 +717,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -753,8 +757,6 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY= -golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -829,6 +831,7 @@ google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO50 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -887,6 +890,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 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= +gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0= gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= diff --git a/handlers/dashboard.go b/handlers/dashboard.go index 915163f8..0f2c7fa9 100644 --- a/handlers/dashboard.go +++ b/handlers/dashboard.go @@ -33,12 +33,15 @@ func logsHandler(w http.ResponseWriter, r *http.Request) { type themeApi struct { Directory string `json:"directory,omitempty"` Base string `json:"base"` - Variables string `json:"variables"` + Forms string `json:"forms"` + Layout string `json:"layout"` + Mixins string `json:"mixins"` Mobile string `json:"mobile"` + Variables string `json:"variables"` } func apiThemeViewHandler(w http.ResponseWriter, r *http.Request) { - var base, variables, mobile, dir string + var base, forms, layout, mixins, variables, mobile, dir string assets := utils.Directory + "/assets" if _, err := os.Stat(assets); err == nil { @@ -49,10 +52,16 @@ func apiThemeViewHandler(w http.ResponseWriter, r *http.Request) { base, _ = utils.OpenFile(dir + "/scss/base.scss") variables, _ = utils.OpenFile(dir + "/scss/variables.scss") mobile, _ = utils.OpenFile(dir + "/scss/mobile.scss") + layout, _ = utils.OpenFile(dir + "/scss/layout.scss") + forms, _ = utils.OpenFile(dir + "/scss/forms.scss") + mixins, _ = utils.OpenFile(dir + "/scss/mixin.scss") } else { base, _ = source.TmplBox.String("scss/base.scss") variables, _ = source.TmplBox.String("scss/variables.scss") mobile, _ = source.TmplBox.String("scss/mobile.scss") + layout, _ = source.TmplBox.String("scss/layout.scss") + forms, _ = source.TmplBox.String("scss/forms.scss") + mixins, _ = source.TmplBox.String("scss/mixin.scss") } resp := &themeApi{ @@ -60,6 +69,9 @@ func apiThemeViewHandler(w http.ResponseWriter, r *http.Request) { Base: base, Variables: variables, Mobile: mobile, + Layout: layout, + Forms: forms, + Mixins: mixins, } returnJson(resp, w, r) } diff --git a/handlers/routes.go b/handlers/routes.go index 45d1bd76..93695ca5 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -128,6 +128,7 @@ func Router() *mux.Router { api.Handle("/api/services/{id}", scoped(apiServiceHandler)).Methods("GET") api.Handle("/api/reorder/services", authenticated(reorderServiceHandler, false)).Methods("POST") api.Handle("/api/services/{id}", authenticated(apiServiceUpdateHandler, false)).Methods("POST") + api.Handle("/api/services/{id}", authenticated(apiServicePatchHandler, false)).Methods("PATCH") api.Handle("/api/services/{id}", authenticated(apiServiceDeleteHandler, false)).Methods("DELETE") api.Handle("/api/services/{id}/failures", scoped(apiServiceFailuresHandler)).Methods("GET") api.Handle("/api/services/{id}/failures", authenticated(servicesDeleteFailuresHandler, false)).Methods("DELETE") diff --git a/handlers/services.go b/handlers/services.go index be1a7b12..38d55e74 100644 --- a/handlers/services.go +++ b/handlers/services.go @@ -74,6 +74,46 @@ func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) { sendJsonAction(service, "create", w, r) } +type servicePatchReq struct { + Online bool `json:"online"` + Issue string `json:"issue,omitempty"` + Latency int64 `json:"latency,omitempty"` +} + +func apiServicePatchHandler(w http.ResponseWriter, r *http.Request) { + service, err := findService(r) + if err != nil { + sendErrorJson(err, w, r) + return + } + var req servicePatchReq + if err := DecodeJSON(r, &req); err != nil { + sendErrorJson(err, w, r) + return + } + + service.Online = req.Online + service.Latency = req.Latency + + issueDefault := "Service was triggered to be offline" + if req.Issue != "" { + issueDefault = req.Issue + } + + if !req.Online { + services.RecordFailure(service, issueDefault) + } else { + services.RecordSuccess(service) + } + + if err := service.Update(); err != nil { + sendErrorJson(err, w, r) + return + } + + sendJsonAction(service, "update", w, r) +} + func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) { service, err := findService(r) if err != nil { @@ -84,9 +124,7 @@ func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) { sendErrorJson(err, w, r) return } - - err = service.Update() - if err != nil { + if err := service.Update(); err != nil { sendErrorJson(err, w, r) return } diff --git a/handlers/services_test.go b/handlers/services_test.go index 5a0afb02..981c8b85 100644 --- a/handlers/services_test.go +++ b/handlers/services_test.go @@ -61,11 +61,11 @@ func TestApiServiceRoutes(t *testing.T) { Method: "GET", ExpectedContains: []string{`"name":"Google"`}, ExpectedStatus: 200, - ResponseLen: 6, + ResponseLen: 7, BeforeTest: SetTestENV, FuncTest: func(t *testing.T) error { count := len(services.Services()) - if count != 6 { + if count != 7 { return errors.Errorf("incorrect services count: %d", count) } return nil @@ -77,11 +77,11 @@ func TestApiServiceRoutes(t *testing.T) { Method: "GET", ExpectedContains: []string{`"name":"Google"`}, ExpectedStatus: 200, - ResponseLen: 5, + ResponseLen: 6, BeforeTest: UnsetTestENV, FuncTest: func(t *testing.T) error { count := len(services.Services()) - if count != 6 { + if count != 7 { return errors.Errorf("incorrect services count: %d", count) } return nil @@ -261,10 +261,10 @@ func TestApiServiceRoutes(t *testing.T) { "order_id": 0 }`, ExpectedStatus: 200, - ExpectedContains: []string{Success, `"type":"service","method":"create"`, `"public":false`, `"group_id":1`}, + ExpectedContains: []string{Success, MethodCreate, `"type":"service",`, `"public":false`, `"group_id":1`}, FuncTest: func(t *testing.T) error { count := len(services.Services()) - if count != 7 { + if count != 8 { return errors.Errorf("incorrect services count: %d", count) } return nil @@ -326,7 +326,27 @@ func TestApiServiceRoutes(t *testing.T) { ExpectedContains: []string{Success, MethodDelete}, FuncTest: func(t *testing.T) error { count := len(services.Services()) - if count != 6 { + if count != 7 { + return errors.Errorf("incorrect services count: %d", count) + } + return nil + }, + SecureRoute: true, + }, + { + Name: "Statping Patch Static Service", + URL: "/api/services/7", + Method: "PATCH", + ExpectedStatus: 200, + Body: `{ + "online": false, + "latency": 30500, + "issue": "This is a failure string you can create" + },`, + ExpectedContains: []string{Success, MethodUpdate}, + FuncTest: func(t *testing.T) error { + count := len(services.Services()) + if count != 7 { return errors.Errorf("incorrect services count: %d", count) } return nil diff --git a/notifiers/notifiers_test.go b/notifiers/notifiers_test.go index e1f25d82..248f4245 100644 --- a/notifiers/notifiers_test.go +++ b/notifiers/notifiers_test.go @@ -1,9 +1,9 @@ package notifiers import ( - "github.com/magiconair/properties/assert" "github.com/statping/statping/types/failures" "github.com/statping/statping/types/services" + "github.com/stretchr/testify/assert" "testing" ) diff --git a/types/configs/config_test.go b/types/configs/config_test.go index 946b052e..ff5da88f 100644 --- a/types/configs/config_test.go +++ b/types/configs/config_test.go @@ -2,6 +2,7 @@ package configs import ( "github.com/statping/statping/utils" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "testing" ) @@ -51,3 +52,9 @@ func TestPostgresConfig(t *testing.T) { err := Connect(postgres, false) require.Nil(t, err) } + +func TestFileSQLFile(t *testing.T) { + file, err := findSQLin(utils.Directory) + require.Nil(t, err) + assert.Equal(t, "statping.db", file) +} diff --git a/types/services/failures.go b/types/services/failures.go index 36027249..75cff278 100644 --- a/types/services/failures.go +++ b/types/services/failures.go @@ -2,7 +2,6 @@ package services import ( "fmt" - humanize "github.com/dustin/go-humanize" "github.com/statping/statping/types/failures" "strings" "time" @@ -20,13 +19,6 @@ func (s *Service) FailuresSince(t time.Time) failures.Failurer { return failures.Since(t, s) } -func (s Service) DowntimeAgo() string { - if s.LastOnline.IsZero() { - return "Never been online" - } - return humanize.Time(s.LastOnline) -} - func (s Service) DowntimeText() string { last := s.AllFailures().Last() if last == nil { diff --git a/types/services/routine.go b/types/services/routine.go index 7860b3c3..da85ffdd 100644 --- a/types/services/routine.go +++ b/types/services/routine.go @@ -94,7 +94,7 @@ func CheckIcmp(s *Service, record bool) (*Service, error) { dur, err := utils.Ping(s.Domain, s.Timeout) if err != nil { if record { - recordFailure(s, fmt.Sprintf("Could not send ICMP to service %v, %v", s.Domain, err)) + RecordFailure(s, fmt.Sprintf("Could not send ICMP to service %v, %v", s.Domain, err)) } return s, err } @@ -104,7 +104,7 @@ func CheckIcmp(s *Service, record bool) (*Service, error) { s.LastResponse = "" s.Online = true if record { - recordSuccess(s) + RecordSuccess(s) } return s, nil } @@ -118,7 +118,7 @@ func CheckGrpc(s *Service, record bool) (*Service, error) { dnsLookup, err := dnsCheck(s) if err != nil { if record { - recordFailure(s, fmt.Sprintf("Could not get IP address for GRPC service %v, %v", s.Domain, err)) + RecordFailure(s, fmt.Sprintf("Could not get IP address for GRPC service %v, %v", s.Domain, err)) } return s, err } @@ -137,13 +137,13 @@ func CheckGrpc(s *Service, record bool) (*Service, error) { } if err != nil { if record { - recordFailure(s, fmt.Sprintf("Dial Error %v", err)) + RecordFailure(s, fmt.Sprintf("Dial Error %v", err)) } 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)) + RecordFailure(s, fmt.Sprintf("%v Socket Close Error %v", strings.ToUpper(s.Type), err)) } return s, err } @@ -151,7 +151,7 @@ func CheckGrpc(s *Service, record bool) (*Service, error) { s.LastResponse = "" s.Online = true if record { - recordSuccess(s) + RecordSuccess(s) } return s, nil } @@ -165,7 +165,7 @@ func CheckTcp(s *Service, record bool) (*Service, error) { dnsLookup, err := dnsCheck(s) if err != nil { if record { - recordFailure(s, fmt.Sprintf("Could not get IP address for TCP service %v, %v", s.Domain, err)) + RecordFailure(s, fmt.Sprintf("Could not get IP address for TCP service %v, %v", s.Domain, err)) } return s, err } @@ -189,7 +189,7 @@ func CheckTcp(s *Service, record bool) (*Service, error) { 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)) + RecordFailure(s, fmt.Sprintf("Dial Error: %v", err)) } return s, err } @@ -203,7 +203,7 @@ func CheckTcp(s *Service, record bool) (*Service, error) { conn, err := tls.DialWithDialer(dialer, s.Type, domain, tlsConfig) if err != nil { if record { - recordFailure(s, fmt.Sprintf("Dial Error: %v", err)) + RecordFailure(s, fmt.Sprintf("Dial Error: %v", err)) } return s, err } @@ -214,7 +214,7 @@ func CheckTcp(s *Service, record bool) (*Service, error) { s.LastResponse = "" s.Online = true if record { - recordSuccess(s) + RecordSuccess(s) } return s, nil } @@ -232,7 +232,7 @@ func CheckHttp(s *Service, record bool) (*Service, error) { dnsLookup, err := dnsCheck(s) if err != nil { if record { - recordFailure(s, fmt.Sprintf("Could not get IP address for domain %v, %v", s.Domain, err)) + RecordFailure(s, fmt.Sprintf("Could not get IP address for domain %v, %v", s.Domain, err)) } return s, err } @@ -284,7 +284,7 @@ func CheckHttp(s *Service, record bool) (*Service, error) { 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)) + RecordFailure(s, fmt.Sprintf("HTTP Error %v", err)) } return s, err } @@ -301,26 +301,26 @@ func CheckHttp(s *Service, record bool) (*Service, error) { } if !match { if record { - recordFailure(s, fmt.Sprintf("HTTP Response Body did not match '%v'", s.Expected)) + RecordFailure(s, fmt.Sprintf("HTTP Response Body did not match '%v'", s.Expected)) } 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)) + RecordFailure(s, fmt.Sprintf("HTTP Status Code %v did not match %v", res.StatusCode, s.ExpectedStatus)) } return s, err } if record { - recordSuccess(s) + RecordSuccess(s) } s.Online = true return s, err } -// recordSuccess will create a new 'hit' record in the database for a successful/online service -func recordSuccess(s *Service) { +// RecordSuccess will create a new 'hit' record in the database for a successful/online service +func RecordSuccess(s *Service) { s.LastOnline = utils.Now() s.Online = true hit := &hits.Hit{ @@ -371,8 +371,8 @@ func sendSuccess(s *Service) { s.notifyAfterCount = 0 } -// recordFailure will create a new 'Failure' record in the database for a offline service -func recordFailure(s *Service, issue string) { +// RecordFailure will create a new 'Failure' record in the database for a offline service +func RecordFailure(s *Service, issue string) { s.LastOffline = utils.Now() fail := &failures.Failure{ diff --git a/types/services/samples.go b/types/services/samples.go index c979ac8c..838eb295 100644 --- a/types/services/samples.go +++ b/types/services/samples.go @@ -176,5 +176,16 @@ func Samples() error { return err } + s7 := &Service{ + Name: "Static Service", + Type: "static", + Order: 7, + Public: null.NewNullBool(true), + CreatedAt: createdOn, + } + if err := s7.Create(); err != nil { + return err + } + return nil }