From 41e35ae444e9fa2216ab3c246b33136ecdfb8bef Mon Sep 17 00:00:00 2001
From: Hunter Long
Date: Thu, 15 Nov 2018 18:52:51 -0800
Subject: [PATCH] new service patch
---
Makefile | 2 +-
core/checker.go | 15 +-
core/database.go | 2 +-
handlers/api.go | 16 +-
handlers/routes.go | 4 +
notifiers/mobile.go | 15 +-
source/source.go | 4 +
source/tmpl/form_service.html | 6 +-
source/tmpl/grafana.json | 583 ++++++++++++++++++++++++++++++
source/tmpl/help.md | 285 ++-------------
{dev => source/tmpl}/postman.json | 0
{dev => source/tmpl}/swagger.json | 0
types/user.go | 4 +-
13 files changed, 663 insertions(+), 273 deletions(-)
create mode 100644 source/tmpl/grafana.json
rename {dev => source/tmpl}/postman.json (100%)
rename {dev => source/tmpl}/swagger.json (100%)
diff --git a/Makefile b/Makefile
index 6e25cd2d..c0a5d9c2 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION=0.79.8
+VERSION=0.79.81
BINARY_NAME=statup
GOPATH:=$(GOPATH)
GOCMD=go
diff --git a/core/checker.go b/core/checker.go
index 6b8ccbe9..384f293c 100644
--- a/core/checker.go
+++ b/core/checker.go
@@ -17,6 +17,7 @@ package core
import (
"bytes"
+ "crypto/tls"
"fmt"
"github.com/hunterlong/statup/core/notifier"
"github.com/hunterlong/statup/types"
@@ -158,11 +159,17 @@ func (s *Service) checkHttp(record bool) *Service {
}
s.PingTime = dnsLookup
t1 := time.Now()
- timeout := time.Duration(s.Timeout)
- client := http.Client{
- Timeout: timeout * time.Second,
+ timeout := time.Duration(time.Duration(s.Timeout) * time.Second)
+ transport := &http.Transport{
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ },
+ TLSHandshakeTimeout: timeout,
+ }
+ client := &http.Client{
+ Transport: transport,
+ Timeout: timeout,
}
-
var response *http.Response
if s.Method == "POST" {
response, err = client.Post(s.Domain, "application/json", bytes.NewBuffer([]byte(s.PostData.String)))
diff --git a/core/database.go b/core/database.go
index 83fa1df4..b72e3786 100644
--- a/core/database.go
+++ b/core/database.go
@@ -235,7 +235,7 @@ func (db *DbConfig) Connect(retry bool, location string) error {
err = dbSession.DB().Ping()
if err == nil {
DbSession = dbSession
- utils.Log(1, fmt.Sprintf("Database %v connection '%v@%v' at %v was successful.", dbType, Configs.DbUser, Configs.DbHost, Configs.DbData))
+ utils.Log(1, fmt.Sprintf("Database %v connection '%v@%v:%v' at %v was successful.", dbType, Configs.DbUser, Configs.DbHost, Configs.DbPort, Configs.DbData))
}
return err
}
diff --git a/handlers/api.go b/handlers/api.go
index 0df59c96..cc4bf4b0 100644
--- a/handlers/api.go
+++ b/handlers/api.go
@@ -157,24 +157,24 @@ func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) {
return
}
vars := mux.Vars(r)
- service := core.SelectService(utils.StringInt(vars["id"]))
- if service == nil {
+ srv := core.SelectServicer(utils.StringInt(vars["id"]))
+ if srv.Select() == nil {
sendErrorJson(errors.New("service not found"), w, r)
return
}
- var updatedService *types.Service
+ var updatedService *core.Service
decoder := json.NewDecoder(r.Body)
decoder.Decode(&updatedService)
- updatedService.Id = service.Id
- service = core.ReturnService(updatedService)
- err := service.Update(true)
+ updatedService.Id = srv.Select().Id
+
+ err := updatedService.Update(true)
if err != nil {
sendErrorJson(err, w, r)
return
}
- go service.Check(true)
+ go updatedService.Check(true)
w.Header().Set("Content-Type", "application/json")
- json.NewEncoder(w).Encode(service)
+ json.NewEncoder(w).Encode(updatedService)
}
func apiServiceDeleteHandler(w http.ResponseWriter, r *http.Request) {
diff --git a/handlers/routes.go b/handlers/routes.go
index cf6d3200..258fbd5e 100644
--- a/handlers/routes.go
+++ b/handlers/routes.go
@@ -125,6 +125,10 @@ func Router() *mux.Router {
r.Handle("/api/messages/{id}", http.HandlerFunc(apiMessageUpdateHandler)).Methods("POST")
r.Handle("/api/messages/{id}", http.HandlerFunc(apiMessageDeleteHandler)).Methods("DELETE")
+ r.PathPrefix("/files/postman.json").Handler(http.StripPrefix("/files/", http.FileServer(source.TmplBox.HTTPBox())))
+ r.PathPrefix("/files/swagger.json").Handler(http.StripPrefix("/files/", http.FileServer(source.TmplBox.HTTPBox())))
+ r.PathPrefix("/files/grafana.json").Handler(http.StripPrefix("/files/", http.FileServer(source.TmplBox.HTTPBox())))
+
// API Generic Routes
r.Handle("/metrics", http.HandlerFunc(prometheusHandler))
r.Handle("/health", http.HandlerFunc(healthCheckHandler))
diff --git a/notifiers/mobile.go b/notifiers/mobile.go
index 5f383db7..0f8f44d1 100644
--- a/notifiers/mobile.go
+++ b/notifiers/mobile.go
@@ -29,13 +29,14 @@ type mobilePush struct {
}
var mobile = &mobilePush{¬ifier.Notification{
- Method: "mobile",
- Title: "Mobile Notifications",
- Description: "Receive push notifications on your Android or iPhone devices using the Statup App. You can scan the Authentication QR Code found in Settings to get the mobile app setup in seconds.",
- Author: "Hunter Long",
- AuthorUrl: "https://github.com/hunterlong",
- Delay: time.Duration(5 * time.Second),
- Icon: "fas fa-mobile-alt",
+ Method: "mobile",
+ Title: "Mobile Notifications",
+ Description: `Receive push notifications on your Android or iPhone devices using the Statup App. You can scan the Authentication QR Code found in Settings to get the mobile app setup in seconds.
+
`,
+ Author: "Hunter Long",
+ AuthorUrl: "https://github.com/hunterlong",
+ Delay: time.Duration(5 * time.Second),
+ Icon: "fas fa-mobile-alt",
Form: []notifier.NotificationForm{{
Type: "text",
Title: "Device Identifiers",
diff --git a/source/source.go b/source/source.go
index 82a8bbc1..7d63f5ca 100644
--- a/source/source.go
+++ b/source/source.go
@@ -158,6 +158,7 @@ func CreateAllAssets(folder string) error {
MakePublicFolder(folder + "/assets/css")
MakePublicFolder(folder + "/assets/scss")
MakePublicFolder(folder + "/assets/font")
+ MakePublicFolder(folder + "/assets/files")
utils.Log(1, "Inserting scss, css, and javascript files into assets folder")
CopyAllToPublic(FontBox, "font")
CopyAllToPublic(ScssBox, "scss")
@@ -167,6 +168,9 @@ func CreateAllAssets(folder string) error {
CopyToPublic(TmplBox, folder+"/assets", "robots.txt")
CopyToPublic(TmplBox, folder+"/assets", "statup.png")
CopyToPublic(TmplBox, folder+"/assets", "favicon.ico")
+ CopyToPublic(TmplBox, folder+"/assets/files", "swagger.json")
+ CopyToPublic(TmplBox, folder+"/assets/files", "postman.json")
+ CopyToPublic(TmplBox, folder+"/assets/files", "grafana.json")
utils.Log(1, "Compiling CSS from SCSS style...")
err := CompileSASS(utils.Directory)
utils.Log(1, "Statup assets have been inserted")
diff --git a/source/tmpl/form_service.html b/source/tmpl/form_service.html
index 84549909..6d2e1708 100644
--- a/source/tmpl/form_service.html
+++ b/source/tmpl/form_service.html
@@ -14,7 +14,7 @@
diff --git a/source/tmpl/grafana.json b/source/tmpl/grafana.json
new file mode 100644
index 00000000..bf9c8fb0
--- /dev/null
+++ b/source/tmpl/grafana.json
@@ -0,0 +1,583 @@
+{
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "id": 16,
+ "iteration": 1542323708843,
+ "links": [],
+ "panels": [
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": true,
+ "colors": [
+ "#890f02",
+ "rgba(237, 129, 40, 0.89)",
+ "rgb(72, 198, 35)"
+ ],
+ "datasource": null,
+ "format": "locale",
+ "gauge": {
+ "maxValue": 1,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 2,
+ "w": 5,
+ "x": 0,
+ "y": 0
+ },
+ "id": 6,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "statup_service_online{name=\"${service}\"}",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "0,1",
+ "title": "",
+ "transparent": true,
+ "type": "singlestat",
+ "valueFontSize": "120%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "ONLINE",
+ "value": "1"
+ },
+ {
+ "op": "=",
+ "text": "OFFLINE",
+ "value": "0"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fill": 1,
+ "gridPos": {
+ "h": 8,
+ "w": 19,
+ "x": 5,
+ "y": 0
+ },
+ "id": 2,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "statup_service_latency{name=\"${service}\"}",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{name}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "${service} Latency",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "ms",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#890f02"
+ ],
+ "datasource": null,
+ "decimals": 0,
+ "format": "ms",
+ "gauge": {
+ "maxValue": 500,
+ "minValue": 1,
+ "show": true,
+ "thresholdLabels": true,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 5,
+ "x": 0,
+ "y": 2
+ },
+ "id": 7,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "statup_service_latency{name=\"${service}\"}",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "250,400",
+ "title": "",
+ "transparent": true,
+ "type": "singlestat",
+ "valueFontSize": "50%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": null,
+ "fill": 1,
+ "gridPos": {
+ "h": 8,
+ "w": 19,
+ "x": 5,
+ "y": 8
+ },
+ "id": 8,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "statup_service_response_length{name=\"${service}\"}",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{name}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "${service} Response Size",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": null,
+ "format": "locale",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 5,
+ "x": 0,
+ "y": 9
+ },
+ "id": 5,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "statup_service_status_code{name=\"${service}\"}",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Response Status Code",
+ "type": "singlestat",
+ "valueFontSize": "120%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": null,
+ "format": "bytes",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 5,
+ "x": 0,
+ "y": 12
+ },
+ "id": 4,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "statup_service_response_length{name=\"${service}\"}",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Response Size",
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ }
+ ],
+ "schemaVersion": 16,
+ "style": "dark",
+ "tags": [],
+ "templating": {
+ "list": [
+ {
+ "allValue": null,
+ "current": {
+ "text": "SQLite Statup",
+ "value": "SQLite Statup"
+ },
+ "datasource": "prometheus",
+ "hide": 0,
+ "includeAll": false,
+ "label": "service",
+ "multi": false,
+ "name": "service",
+ "options": [],
+ "query": "label_values(statup_service_latency, name)",
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-6h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "",
+ "title": "Statup",
+ "uid": "6BzRjddmz",
+ "version": 25
+}
\ No newline at end of file
diff --git a/source/tmpl/help.md b/source/tmpl/help.md
index 5e09043b..dd115d9a 100644
--- a/source/tmpl/help.md
+++ b/source/tmpl/help.md
@@ -7,17 +7,38 @@ Statup is an easy to use Status Page monitor for your websites and applications.
-# Services
+# Core Elements
+Statup is continuing being updated and has many awesome features to help you catch issues if your servers go down.
+
+## Services
For each website and application you want to add a new Service. Each Service will require a URL endpoint to test your applications status.
You can also add expected HTTP responses (regex allow), expected HTTP response codes, and other fields to make sure your service is online or offline.
-# Statup Settings
-You can change multiple settings in your Statup instance.
+## Settings
+Changing variables for your Statup instance is fairly simple and quick. You can change the footer HTML/text, domain of server, and many other aspects.
+The guide below will explain each setting feature.
-# Users
-Users can access the Statup Dashboard to add, remove, and view services.
+#### Export Assets
+The single Statup binary file includes all assets used for the web page. Go the the Theme Editor in Settings and click Enable Assets.
+This will create a 'assets' folder in the working directory, it will create all the assets used into their own folders.
-# Plugins
+#### Custom Design
+After you've exported the assets you can edit the CSS directly or use the Theme Editor to customize the SASS design.
+Statup uses sass to generate CSS files from SASS. You can install sass with a command below.
+
+- node: `npm install sass -g`
+- ruby: `gem install sass`
+
+#### CDN Assets
+If you want to host the Statup assets from our CDN rather than from your local instance, enable "Use CDN" toggle switch on the Settings page.
+
+## Notifications
+Statup includes a few notification methods to receive alerts when a service is online/offline. Each notifier is different, users can create your own notifier and send a Push Request to github.
+
+## Users
+Administrators can add, update, and remove all elements on your Statup instance. Other users can only view the status page and
+
+## Plugins
Creating a plugin for Statup is not that difficult, if you know a little bit of Go Language you can create any type of application to be embedded into the Status framework.
Checkout the example plugin that includes all the interfaces, information, and custom HTTP routing at https://github.com/hunterlong/statup_plugin.
Anytime there is an action on your status page, all of your plugins will be notified of the change with the values that were changed or created.
@@ -25,260 +46,30 @@ Anytime there is an action on your status page, all of your plugins will be noti
Using the statup/plugin Golang package you can quickly implement the event listeners. Statup uses upper.io/db.v3 for the database connection.
You can use the database inside of your plugin to create, update, and destroy tables/data. Please only use respectable plugins!
-# Custom Stlying
-On Statup Status Page server can you create your own custom stylesheet to be rendered on the index view of your status page. Go to Settings and click on Custom Styling.
-
-# API Endpoints
+# API Usage
Statup includes a RESTFUL API so you can view, update, and edit your services with easy to use routes. You can currently view, update and delete services, view, create, update users, and get detailed information about the Statup instance. To make life easy, try out a Postman or Swagger JSON file and use it on your Statup Server.
-Postman JSON Export | Swagger Export
+Postman Export | Swagger Export | Swagger Hub
-## Authentication
+### API Authentication
Authentication uses the Statup API Secret to accept remote requests. You can find the API Secret in the Settings page of your Statup server. To send requests to your Statup API, include a Authorization Header when you send the request. The API will accept any one of the headers below.
- HTTP Header: `Authorization: API SECRET HERE`
- HTTP Header: `Authorization: Bearer API SECRET HERE`
-## Main Route `/api`
-The main API route will show you all services and failures along with them.
-
-## Services
-The services API endpoint will show you detailed information about services and will allow you to edit/delete services with POST/DELETE http methods.
-
-### Viewing All Services
-- Endpoint: `/api/services`
-- Method: `GET`
-- Response: Array of [Services](https://github.com/hunterlong/statup/wiki/API#service-response)
-- Response Type: `application/json`
-- Request Type: `application/json`
-
-### Viewing Service
-- Endpoint: `/api/services/{id}`
-- Method: `GET`
-- Response: [Service](https://github.com/hunterlong/statup/wiki/API#service-response)
-- Response Type: `application/json`
-- Request Type: `application/json`
-
-### Updating Service
-- Endpoint: `/api/services/{id}`
-- Method: `POST`
-- Response: [Service](https://github.com/hunterlong/statup/wiki/API#service-response)
-- Response Type: `application/json`
-- Request Type: `application/json`
-
-POST Data:
-``` json
-{
- "name": "Updated Service",
- "domain": "https://google.com",
- "expected": "",
- "expected_status": 200,
- "check_interval": 15,
- "type": "http",
- "method": "GET",
- "post_data": "",
- "port": 0,
- "timeout": 10,
- "order_id": 0
-}
-```
-
-### Deleting Service
-- Endpoint: `/api/services/{id}`
-- Method: `DELETE`
-- Response: [Object Response](https://github.com/hunterlong/statup/wiki/API#object-response)
-- Response Type: `application/json`
-- Request Type: `application/json`
-
-Response:
-``` json
-{
- "status": "success",
- "id": 4,
- "type": "service",
- "method": "delete"
-}
-```
-
-## Users
-The users API endpoint will show you users that are registered inside your Statup instance.
-
-### View All Users
-- Endpoint: `/api/users`
-- Method: `GET`
-- Response: Array of [Users](https://github.com/hunterlong/statup/wiki/API#user-response)
-- Response Type: `application/json`
-- Request Type: `application/json`
-
-### Viewing User
-- Endpoint: `/api/users/{id}`
-- Method: `GET`
-- Response: [User](https://github.com/hunterlong/statup/wiki/API#user-response)
-- Response Type: `application/json`
-- Request Type: `application/json`
-
-### Creating New User
-- Endpoint: `/api/users`
-- Method: `POST`
-- Response: [User](https://github.com/hunterlong/statup/wiki/API#user-response)
-- Response Type: `application/json`
-- Request Type: `application/json`
-
-POST Data:
-``` json
-{
- "username": "newadmin",
- "email": "info@email.com",
- "password": "password123",
- "admin": true
-}
-```
-
-### Updating User
-- Endpoint: `/api/users/{id}`
-- Method: `POST`
-- Response: [User](https://github.com/hunterlong/statup/wiki/API#user-response)
-- Response Type: `application/json`
-- Request Type: `application/json`
-
-POST Data:
-``` json
-{
- "username": "updatedadmin",
- "email": "info@email.com",
- "password": "password123",
- "admin": true
-}
-```
-
-### Deleting User
-- Endpoint: `/api/services/{id}`
-- Method: `DELETE`
-- Response: [Object Response](https://github.com/hunterlong/statup/wiki/API#object-response)
-- Response Type: `application/json`
-- Request Type: `application/json`
-
-Response:
-``` json
-{
- "status": "success",
- "id": 3,
- "type": "user",
- "method": "delete"
-}
-```
-
-# Service Response
-``` json
-{
- "id": 8,
- "name": "Test Service 0",
- "domain": "https://status.coinapp.io",
- "expected": "",
- "expected_status": 200,
- "check_interval": 1,
- "type": "http",
- "method": "GET",
- "post_data": "",
- "port": 0,
- "timeout": 30,
- "order_id": 0,
- "created_at": "2018-09-12T09:07:03.045832088-07:00",
- "updated_at": "2018-09-12T09:07:03.046114305-07:00",
- "online": false,
- "latency": 0.031411064,
- "24_hours_online": 0,
- "avg_response": "",
- "status_code": 502,
- "last_online": "0001-01-01T00:00:00Z",
- "dns_lookup_time": 0.001727175,
- "failures": [
- {
- "id": 5187,
- "issue": "HTTP Status Code 502 did not match 200",
- "created_at": "2018-09-12T10:41:46.292277471-07:00"
- },
- {
- "id": 5188,
- "issue": "HTTP Status Code 502 did not match 200",
- "created_at": "2018-09-12T10:41:47.337659862-07:00"
- }
- ]
-}
-```
-
-# User Response
-``` json
-{
- "id": 1,
- "username": "admin",
- "api_key": "02f324450a631980121e8fd6ea7dfe4a7c685a2f",
- "admin": true,
- "created_at": "2018-09-12T09:06:53.906398511-07:00",
- "updated_at": "2018-09-12T09:06:54.972440207-07:00"
-}
-```
-
-# Object Response
-``` json
-{
- "type": "service",
- "id": 19,
- "method": "delete",
- "status": "success"
-}
-```
-
-# Main API Response
-``` json
-{
- "name": "Awesome Status",
- "description": "An awesome status page by Statup",
- "footer": "This is my custom footer",
- "domain": "https://demo.statup.io",
- "version": "v0.56",
- "migration_id": 1536768413,
- "created_at": "2018-09-12T09:06:53.905374829-07:00",
- "updated_at": "2018-09-12T09:07:01.654201225-07:00",
- "database": "sqlite",
- "started_on": "2018-09-12T10:43:07.760729349-07:00",
- "services": [
- {
- "id": 1,
- "name": "Google",
- "domain": "https://google.com",
- "expected": "",
- "expected_status": 200,
- "check_interval": 10,
- "type": "http",
- "method": "GET",
- "post_data": "",
- "port": 0,
- "timeout": 10,
- "order_id": 0,
- "created_at": "2018-09-12T09:06:54.97549122-07:00",
- "updated_at": "2018-09-12T09:06:54.975624103-07:00",
- "online": true,
- "latency": 0.09080986,
- "24_hours_online": 0,
- "avg_response": "",
- "status_code": 200,
- "last_online": "2018-09-12T10:44:07.931990439-07:00",
- "dns_lookup_time": 0.005543935
- }
- ]
-}
-```
-
# Prometheus Exporter
Statup includes a prometheus exporter so you can have even more monitoring power with your services. The prometheus exporter can be seen on `/metrics`, simply create another exporter in your prometheus config. Use your Statup API Secret for the Authorization Bearer header, the `/metrics` URL is dedicated for Prometheus and requires the correct API Secret has `Authorization` header.
# Grafana Dashboard
-Statup has a [Grafana Dashboard](https://grafana.com/dashboards/6950) that you can quickly implement if you've added your Statup service to Prometheus. Import Dashboard ID: `6950` into your Grafana dashboard and watch the metrics come in!
+Statup has a Grafana Dashboard that you can quickly implement if you've added your Statup service to Prometheus. Import Dashboard ID: `6950` into your Grafana dashboard and watch the metrics come in!
-
+
+Grafana Dashboard | Grafana JSON Export
+
+
+
## Basic Prometheus Exporter
If you have Statup and the Prometheus server in the same Docker network, you can use the yaml config below.
@@ -341,7 +132,7 @@ It may be useful to load your environment using a `.env` file in the root direct
If you have the `DB_CONN` environment variable set Statup will bypass all values in config.yml and will require you to have the other DB_* variables in place. You can pass in these environment variables without requiring a .env file.
-## `.env` File
+### `.env` File
```bash
DB_CONN=postgres
DB_HOST=0.0.0.0
@@ -397,7 +188,7 @@ make cypress-install
make cypress-test
```
-## Testing
+# Testing
* If you want to test your updates with the current golang testing units, you can follow the guide below to run a full test process. Each test for Statup will run in MySQL, Postgres, and SQlite to make sure all database types work correctly.
## Create Docker Databases
diff --git a/dev/postman.json b/source/tmpl/postman.json
similarity index 100%
rename from dev/postman.json
rename to source/tmpl/postman.json
diff --git a/dev/swagger.json b/source/tmpl/swagger.json
similarity index 100%
rename from dev/swagger.json
rename to source/tmpl/swagger.json
diff --git a/types/user.go b/types/user.go
index 9ce39e37..065d721e 100644
--- a/types/user.go
+++ b/types/user.go
@@ -23,10 +23,10 @@ import (
type User struct {
Id int64 `gorm:"primary_key;column:id" json:"id"`
Username string `gorm:"type:varchar(100);unique;column:username;" json:"username,omitempty"`
- Password string `gorm:"column:password" json:"password,omitempty"`
+ Password string `gorm:"column:password" json:"-"`
Email string `gorm:"type:varchar(100);unique;column:email" json:"email,omitempty"`
ApiKey string `gorm:"column:api_key" json:"api_key,omitempty"`
- ApiSecret string `gorm:"column:api_secret" json:"-"`
+ ApiSecret string `gorm:"column:api_secret" json:"api_secret,omitempty"`
Admin NullBool `gorm:"column:administrator" json:"admin,omitempty"`
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`