diff --git a/handlers/routes.go b/handlers/routes.go index 514b7894..119b3c79 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -112,6 +112,7 @@ func Router() *mux.Router { r.Handle("/api/services", authenticated(apiCreateServiceHandler, false)).Methods("POST") r.Handle("/api/services/{id}", readOnly(apiServiceHandler, false)).Methods("GET") r.Handle("/api/services/reorder", authenticated(reorderServiceHandler, false)).Methods("POST") + r.Handle("/api/services/{id}/running", authenticated(apiServiceRunningHandler, false)).Methods("POST") r.Handle("/api/services/{id}/data", cached("30s", "application/json", http.HandlerFunc(apiServiceDataHandler))).Methods("GET") r.Handle("/api/services/{id}/ping", cached("30s", "application/json", http.HandlerFunc(apiServicePingDataHandler))).Methods("GET") r.Handle("/api/services/{id}/heatmap", cached("30s", "application/json", http.HandlerFunc(apiServiceHeatmapHandler))).Methods("GET") diff --git a/handlers/services.go b/handlers/services.go index ce18b2ee..8873926b 100644 --- a/handlers/services.go +++ b/handlers/services.go @@ -166,6 +166,21 @@ func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) { sendJsonAction(service, "update", w, r) } +func apiServiceRunningHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + service := core.SelectService(utils.ToInt(vars["id"])) + if service == nil { + sendErrorJson(errors.New("service not found"), w, r) + return + } + if service.IsRunning() { + service.Close() + } else { + service.Start() + } + sendJsonAction(service, "running", w, r) +} + func apiServiceDataHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) service := core.SelectService(utils.ToInt(vars["id"])) diff --git a/notifiers/webhook.go b/notifiers/webhook.go index 5f7d97bf..ec63d8a1 100644 --- a/notifiers/webhook.go +++ b/notifiers/webhook.go @@ -100,14 +100,8 @@ func (w *webhooker) Select() *notifier.Notification { } func replaceBodyText(body string, s *types.Service, f *types.Failure) string { - if s != nil { - body = strings.Replace(body, "%service.Name", s.Name, -1) - body = strings.Replace(body, "%service.Id", utils.ToString(s.Id), -1) - body = strings.Replace(body, "%service.Online", utils.ToString(s.Online), -1) - } - if strings.Contains(body, "%failure.Issue") && f != nil { - body = strings.Replace(body, "%failure.Issue", f.Issue, -1) - } + body = utils.ConvertInterface(body, s) + body = utils.ConvertInterface(body, f) return body } diff --git a/source/css/base.css b/source/css/base.css index 5dfd6df0..e2100410 100644 --- a/source/css/base.css +++ b/source/css/base.css @@ -7,66 +7,54 @@ /* Mobile Service Container */ HTML, BODY { background-color: #fcfcfc; - padding-bottom: 10px; -} + padding-bottom: 10px; } .container { padding-top: 20px; padding-bottom: 25px; max-width: 860px; - box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; -} + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; } .header-title { - color: #464646; -} + color: #464646; } .header-desc { - color: #939393; -} + color: #939393; } .btn { - border-radius: 0.2rem; -} + border-radius: 0.2rem; } .online_list .badge { - margin-top: 0.2rem; -} + margin-top: 0.2rem; } .navbar { - margin-bottom: 30px; -} + margin-bottom: 30px; } .btn-sm { line-height: 1.3; - font-size: 0.75rem; -} + font-size: 0.75rem; } .view_service_btn { position: absolute; bottom: -40px; - right: 40px; -} + right: 40px; } .service_lower_info { position: absolute; bottom: -40px; left: 40px; color: #d1ffca; - font-size: 0.85rem; -} + font-size: 0.85rem; } .lg_number { font-size: 2.3rem; font-weight: bold; display: block; - color: #4f4f4f; -} + color: #4f4f4f; } .stats_area { text-align: center; - color: #a5a5a5; -} + color: #a5a5a5; } .lower_canvas { height: 3.4rem; @@ -74,101 +62,82 @@ HTML, BODY { background-color: #48d338; padding: 15px 10px; margin-left: 0px !important; - margin-right: 0px !important; -} + margin-right: 0px !important; } .lower_canvas SPAN { font-size: 1rem; - color: #fff; -} + color: #fff; } .footer { text-decoration: none; - margin-top: 20px; -} + margin-top: 20px; } .footer A { color: #8d8d8d; - text-decoration: none; -} + text-decoration: none; } .footer A:HOVER { - color: #6d6d6d; -} + color: #6d6d6d; } .badge { color: white; - border-radius: 0.2rem; -} + border-radius: 0.2rem; } .btn-group { - height: 25px; -} -.btn-group A { - padding: 0.1rem 0.75rem; - font-size: 0.8rem; -} + height: 25px; } + .btn-group A { + padding: 0.1rem .75rem; + font-size: 0.8rem; } .card-body .badge { - color: #fff; -} + color: #fff; } .nav-pills .nav-link { - border-radius: 0.2rem; -} + border-radius: 0.2rem; } .form-control { - border-radius: 0.2rem; -} + border-radius: 0.2rem; } .card { background-color: #ffffff; - border: 1px solid rgba(0, 0, 0, 0.125); -} + border: 1px solid rgba(0, 0, 0, 0.125); } .card-body { - overflow: hidden; -} + overflow: hidden; } .card-body H4 A { color: #444444; - text-decoration: none; -} + text-decoration: none; } .chart-container { position: relative; height: 170px; width: 100%; - overflow: hidden; -} + overflow: hidden; } .service-chart-container { position: relative; height: 400px; - width: 100%; -} + width: 100%; } .service-chart-heatmap { position: relative; height: 300px; - width: 100%; -} + width: 100%; } .inputTags-field { border: 0; background-color: transparent; - padding-top: 0.13rem; -} + padding-top: .13rem; } input.inputTags-field:focus { - outline-width: 0; -} + outline-width: 0; } .inputTags-list { display: block; width: 100%; min-height: calc(2.25rem + 2px); - padding: 0.2rem 0.35rem; + padding: .2rem .35rem; font-size: 1rem; font-weight: 400; line-height: 1.5; @@ -176,9 +145,8 @@ input.inputTags-field:focus { background-color: #fff; background-clip: padding-box; border: 1px solid #ced4da; - border-radius: 0.25rem; - transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; -} + border-radius: .25rem; + transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out; } .inputTags-item { background-color: #3aba39; @@ -186,81 +154,63 @@ input.inputTags-field:focus { padding: 5px 8px; font-size: 10pt; color: white; - border-radius: 4px; -} + border-radius: 4px; } .inputTags-item .close-item { margin-left: 6px; font-size: 13pt; font-weight: bold; - cursor: pointer; -} + cursor: pointer; } .btn-primary { background-color: #3e9bff; border-color: #006fe6; - color: white; -} -.btn-primary.dyn-dark { - background-color: #32a825 !important; - border-color: #2c9320 !important; -} -.btn-primary.dyn-light { - background-color: #75de69 !important; - border-color: #88e37e !important; -} + color: white; } + .btn-primary.dyn-dark { + background-color: #32a825 !important; + border-color: #2c9320 !important; } + .btn-primary.dyn-light { + background-color: #75de69 !important; + border-color: #88e37e !important; } .btn-success { - background-color: #47d337; -} -.btn-success.dyn-dark { - background-color: #32a825 !important; - border-color: #2c9320 !important; -} -.btn-success.dyn-light { - background-color: #75de69 !important; - border-color: #88e37e !important; -} + background-color: #47d337; } + .btn-success.dyn-dark { + background-color: #32a825 !important; + border-color: #2c9320 !important; } + .btn-success.dyn-light { + background-color: #75de69 !important; + border-color: #88e37e !important; } .btn-danger { - background-color: #dd3545; -} -.btn-danger.dyn-dark { - background-color: #b61f2d !important; - border-color: #a01b28 !important; -} -.btn-danger.dyn-light { - background-color: #e66975 !important; - border-color: #e97f89 !important; -} + background-color: #dd3545; } + .btn-danger.dyn-dark { + background-color: #b61f2d !important; + border-color: #a01b28 !important; } + .btn-danger.dyn-light { + background-color: #e66975 !important; + border-color: #e97f89 !important; } .bg-success { - background-color: #47d337 !important; -} + background-color: #47d337 !important; } .bg-danger { - background-color: #dd3545 !important; -} + background-color: #dd3545 !important; } .bg-success .dyn-dark { - background-color: #35b027 !important; -} + background-color: #35b027 !important; } .bg-danger .dyn-dark { - background-color: #bf202f !important; -} + background-color: #bf202f !important; } .nav-pills .nav-link.active, .nav-pills .show > .nav-link { - background-color: #13a00d; -} + background-color: #13a00d; } .nav-pills A { - color: #424242; -} + color: #424242; } .nav-pills I { - margin-right: 10px; -} + margin-right: 10px; } .CodeMirror { /* Bootstrap Settings */ @@ -280,26 +230,23 @@ input.inputTags-field:focus { border: 1px solid #ccc; border-radius: 4px; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; /* Code Mirror Settings */ font-family: monospace; position: relative; overflow: hidden; - height: 80vh; -} + height: 80vh; } .CodeMirror-focused { /* Bootstrap Settings */ border-color: #66afe9; outline: 0; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); - transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; -} + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; } .switch { font-size: 1rem; - position: relative; -} + position: relative; } .switch input { position: absolute; @@ -310,8 +257,7 @@ input.inputTags-field:focus { clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; - padding: 0; -} + padding: 0; } .switch input + label { position: relative; @@ -324,26 +270,23 @@ input.inputTags-field:focus { outline: none; user-select: none; vertical-align: middle; - text-indent: calc(calc(calc(2.375rem * .8) * 2) + .5rem); -} + text-indent: calc(calc(calc(2.375rem * .8) * 2) + .5rem); } .switch input + label::before, .switch input + label::after { - content: ""; + content: ''; position: absolute; top: 0; left: 0; width: calc(calc(2.375rem * .8) * 2); bottom: 0; - display: block; -} + display: block; } .switch input + label::before { right: 0; background-color: #dee2e6; border-radius: calc(2.375rem * .8); - transition: 0.2s all; -} + transition: 0.2s all; } .switch input + label::after { top: 2px; @@ -352,154 +295,120 @@ input.inputTags-field:focus { height: calc(calc(2.375rem * .8) - calc(2px * 2)); border-radius: 50%; background-color: white; - transition: 0.2s all; -} + transition: 0.2s all; } .switch input:checked + label::before { - background-color: #08d; -} + background-color: #08d; } .switch input:checked + label::after { - margin-left: calc(2.375rem * .8); -} + margin-left: calc(2.375rem * .8); } .switch input:focus + label::before { outline: none; - box-shadow: 0 0 0 0.2rem rgba(0, 136, 221, 0.25); -} + box-shadow: 0 0 0 0.2rem rgba(0, 136, 221, 0.25); } .switch input:disabled + label { color: #868e96; - cursor: not-allowed; -} + cursor: not-allowed; } .switch input:disabled + label::before { - background-color: #e9ecef; -} + background-color: #e9ecef; } .switch.switch-sm { - font-size: 0.875rem; -} + font-size: 0.875rem; } .switch.switch-sm input + label { min-width: calc(calc(1.9375rem * .8) * 2); height: calc(1.9375rem * .8); line-height: calc(1.9375rem * .8); - text-indent: calc(calc(calc(1.9375rem * .8) * 2) + .5rem); -} + text-indent: calc(calc(calc(1.9375rem * .8) * 2) + .5rem); } .switch.switch-sm input + label::before { - width: calc(calc(1.9375rem * .8) * 2); -} + width: calc(calc(1.9375rem * .8) * 2); } .switch.switch-sm input + label::after { width: calc(calc(1.9375rem * .8) - calc(2px * 2)); - height: calc(calc(1.9375rem * .8) - calc(2px * 2)); -} + height: calc(calc(1.9375rem * .8) - calc(2px * 2)); } .switch.switch-sm input:checked + label::after { - margin-left: calc(1.9375rem * .8); -} + margin-left: calc(1.9375rem * .8); } .switch.switch-lg { - font-size: 1.25rem; -} + font-size: 1.25rem; } .switch.switch-lg input + label { min-width: calc(calc(3rem * .8) * 2); height: calc(3rem * .8); line-height: calc(3rem * .8); - text-indent: calc(calc(calc(3rem * .8) * 2) + .5rem); -} + text-indent: calc(calc(calc(3rem * .8) * 2) + .5rem); } .switch.switch-lg input + label::before { - width: calc(calc(3rem * .8) * 2); -} + width: calc(calc(3rem * .8) * 2); } .switch.switch-lg input + label::after { width: calc(calc(3rem * .8) - calc(2px * 2)); - height: calc(calc(3rem * .8) - calc(2px * 2)); -} + height: calc(calc(3rem * .8) - calc(2px * 2)); } .switch.switch-lg input:checked + label::after { - margin-left: calc(3rem * .8); -} + margin-left: calc(3rem * .8); } .switch + .switch { - margin-left: 1rem; -} + margin-left: 1rem; } @keyframes pulse_animation { 0% { - transform: scale(1); - } + transform: scale(1); } 30% { - transform: scale(1); - } + transform: scale(1); } 40% { - transform: scale(1.02); - } + transform: scale(1.02); } 50% { - transform: scale(1); - } + transform: scale(1); } 60% { - transform: scale(1); - } + transform: scale(1); } 70% { - transform: scale(1.05); - } + transform: scale(1.05); } 80% { - transform: scale(1); - } + transform: scale(1); } 100% { - transform: scale(1); - } -} + transform: scale(1); } } .pulse { animation-name: pulse_animation; animation-duration: 1500ms; transform-origin: 70% 70%; animation-iteration-count: infinite; - animation-timing-function: linear; -} + animation-timing-function: linear; } @keyframes glow-grow { 0% { opacity: 0; - transform: scale(1); - } + transform: scale(1); } 80% { - opacity: 1; - } + opacity: 1; } 100% { transform: scale(2); - opacity: 0; - } -} + opacity: 0; } } .pulse-glow { animation-name: glow-grown; animation-duration: 100ms; transform-origin: 70% 30%; animation-iteration-count: infinite; - animation-timing-function: linear; -} + animation-timing-function: linear; } .pulse-glow:before, .pulse-glow:after { position: absolute; - content: ""; + content: ''; height: 0.5rem; width: 1.75rem; top: 1.2rem; right: 2.15rem; border-radius: 0; box-shadow: 0 0 7px #47d337; - animation: glow-grow 2s ease-out infinite; -} + animation: glow-grow 2s ease-out infinite; } .sortable_drag { - background-color: #0000000f; -} + background-color: #0000000f; } .drag_icon { cursor: move; @@ -513,132 +422,112 @@ input.inputTags-field:focus { margin-right: 5px; margin-left: -10px; text-align: center; - color: #b1b1b1; -} + color: #b1b1b1; } /* (Optional) Apply a "closed-hand" cursor during drag operation. */ .drag_icon:active { cursor: grabbing; cursor: -moz-grabbing; - cursor: -webkit-grabbing; -} + cursor: -webkit-grabbing; } .switch_btn { float: right; margin: -1px 0px 0px 0px; - display: block; -} + display: block; } #start_container { position: absolute; z-index: 99999; - margin-top: 20px; -} + margin-top: 20px; } #end_container { position: absolute; z-index: 99999; margin-top: 20px; - right: 0; -} + right: 0; } .pointer { - cursor: pointer; -} + cursor: pointer; } .jumbotron { - background-color: white; -} + background-color: white; } + +.toggle-service { + font-size: 18pt; + float: left; + margin: 2px 3px 0 0; + cursor: pointer; } @media (max-width: 767px) { HTML, BODY { - background-color: #fcfcfc; - } + background-color: #fcfcfc; } .sm-container { margin-top: 0px !important; - padding: 0 !important; - } + padding: 0 !important; } .list-group-item H5 { - font-size: 0.9rem; - } + font-size: 0.9rem; } .container { padding: 0px !important; - padding-top: 15px !important; - } + padding-top: 15px !important; } .group_header { - margin-left: 15px; - } + margin-left: 15px; } .navbar { margin-left: 0px; margin-top: 0px; width: 100%; - margin-bottom: 0; - } + margin-bottom: 0; } .btn-sm { line-height: 0.9rem; - font-size: 0.65rem; - } + font-size: 0.65rem; } .full-col-12 { padding-left: 0px; - padding-right: 0px; - } + padding-right: 0px; } .card { border: 0; border-radius: 0rem; padding: 0; - background-color: #ffffff; - } + background-color: #ffffff; } .card-body { font-size: 10pt; - padding: 0px 10px; - } + padding: 0px 10px; } .lg_number { - font-size: 7.8vw; - } + font-size: 7.8vw; } .stats_area { margin-top: 1.5rem !important; - margin-bottom: 1.5rem !important; - } + margin-bottom: 1.5rem !important; } .stats_area .col-4 { padding-left: 0; padding-right: 0; - font-size: 0.6rem; - } + font-size: 0.6rem; } .list-group-item { border-top: 1px solid #e4e4e4; - border: 0px; - } + border: 0px; } .list-group-item:first-child { border-top-left-radius: 0; - border-top-right-radius: 0; - } + border-top-right-radius: 0; } .list-group-item:last-child { border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - } + border-bottom-left-radius: 0; } .list-group-item P { - font-size: 0.7rem; - } + font-size: 0.7rem; } .service-chart-container { - height: 200px; - } -} + height: 200px; } } /*# sourceMappingURL=base.css.map */ diff --git a/source/js/main.js b/source/js/main.js index da44cb53..c16bde3c 100644 --- a/source/js/main.js +++ b/source/js/main.js @@ -86,6 +86,29 @@ $('.scrollclick').on('click',function(e) { e.preventDefault(); }); +$('.toggle-service').on('click',function(e) { + let obj = $(this); + let serviceId = obj.attr("data-id"); + let online = obj.attr("data-online"); + let d = confirm("Do you want to stop this service?"); + if (d) { + $.ajax({ + url: "/api/services/" + serviceId + "/running", + type: 'POST', + success: function (data) { + if (online === "true") { + obj.removeClass("fa-toggle-on text-success"); + obj.addClass("fa-toggle-off text-black-50"); + } else { + obj.removeClass("fa-toggle-off text-black-50"); + obj.addClass("fa-toggle-on text-success"); + } + obj.attr("data-online", online !== "true"); + } + }); + } +}); + $('select#service_type').on('change', function() { var selected = $('#service_type option:selected').val(); var typeLabel = $('#service_type_label'); diff --git a/source/scss/base.scss b/source/scss/base.scss index 16ec2b3a..37cac487 100644 --- a/source/scss/base.scss +++ b/source/scss/base.scss @@ -522,4 +522,11 @@ input.inputTags-field:focus { background-color: white; } +.toggle-service { + font-size: 18pt; + float: left; + margin: 2px 3px 0 0; + cursor: pointer; +} + @import 'mobile'; diff --git a/source/tmpl/services.gohtml b/source/tmpl/services.gohtml index 54bac80f..498078fd 100644 --- a/source/tmpl/services.gohtml +++ b/source/tmpl/services.gohtml @@ -20,7 +20,9 @@ {{range .Services}} {{.Name}} - {{if .Online}}ONLINE{{else}}OFFLINE{{end}} + {{if .Online}}ONLINE{{else}}OFFLINE{{end}} + + {{if .Public.Bool}}PUBLIC{{else}}PRIVATE{{end}} {{if ne .GroupId 0}}{{(Group .GroupId).Name}}{{end}} diff --git a/source/wiki.go b/source/wiki.go index bc6a9af5..be065e5d 100644 --- a/source/wiki.go +++ b/source/wiki.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2019-04-29 13:44:31.662592 -0700 PDT m=+0.521272428 +// 2019-04-30 13:54:41.673055 -0700 PDT m=+0.482478008 // // This contains the most recently Markdown source for the Statping Wiki. package source diff --git a/utils/utils.go b/utils/utils.go index 0be8b83c..41624484 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -27,6 +27,7 @@ import ( "net/http" "os" "os/exec" + "reflect" "regexp" "strconv" "strings" @@ -80,6 +81,22 @@ func ToInt(s interface{}) int64 { } } +// ConvertInterface will take all the keys/values from an interface and replace all %type.Key from a string +// Input: {"name": "%service.Name", "domain": "%service.Domain"} +// Output: {"name": "Google DNS", "domain": "8.8.8.8"} +func ConvertInterface(in string, obj interface{}) string { + s := reflect.ValueOf(obj).Elem() + typeOfT := s.Type() + for i := 0; i < s.NumField(); i++ { + f := s.Field(i) + find := strings.Split(fmt.Sprintf("%s.%v", typeOfT, typeOfT.Field(i).Name), ".") + find[1] = strings.ToLower(find[1]) + key := strings.Join(find[1:], ".") + in = strings.ReplaceAll(in, fmt.Sprintf("%%%v", key), fmt.Sprintf("%v", f.Interface())) + } + return in +} + // ToString converts a int to a string func ToString(s interface{}) string { switch v := s.(type) { diff --git a/utils/utils_test.go b/utils/utils_test.go index fabd090b..bd6c7775 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -24,6 +24,17 @@ import ( "time" ) +func TestConvertInterface(t *testing.T) { + type Service struct { + Name string + Domain string + } + sample := `{"name": "%service.Name", "domain": "%service.Domain"}` + input := &Service{"Test Name", "statping.com"} + out := ConvertInterface(sample, input) + assert.Equal(t, `{"name": "Test Name", "domain": "statping.com"}`, out) +} + func TestCreateLog(t *testing.T) { err := createLog(Directory) assert.Nil(t, err) diff --git a/version.txt b/version.txt index dadefde0..cf26a53e 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.80.56 +0.80.57