mirror of https://github.com/statping/statping
parent
1aef1948d4
commit
c20cde567e
|
@ -18,7 +18,7 @@ services:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- VERSION=0.28.3
|
- VERSION=0.28.4
|
||||||
- DB_HOST=localhost
|
- DB_HOST=localhost
|
||||||
- DB_USER=travis
|
- DB_USER=travis
|
||||||
- DB_PASS=
|
- DB_PASS=
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
ENV VERSION=v0.28.3
|
ENV VERSION=v0.28.4
|
||||||
|
|
||||||
RUN apk --no-cache add libstdc++ ca-certificates
|
RUN apk --no-cache add libstdc++ ca-certificates
|
||||||
RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \
|
RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \
|
||||||
|
@ -20,9 +20,6 @@ RUN printf "#!/usr/bin/env sh\n\$1\n" > $CMD_FILE && \
|
||||||
chmod +x $CMD_FILE
|
chmod +x $CMD_FILE
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
#COPY build/statup-linux-alpine /usr/local/bin/statup
|
|
||||||
|
|
||||||
VOLUME /app
|
VOLUME /app
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
ENTRYPOINT statup
|
ENTRYPOINT statup
|
3
cli.go
3
cli.go
|
@ -16,6 +16,8 @@ func CatchCLI(args []string) {
|
||||||
core.CreateAllAssets()
|
core.CreateAllAssets()
|
||||||
case "sass":
|
case "sass":
|
||||||
core.CompileSASS()
|
core.CompileSASS()
|
||||||
|
case "api":
|
||||||
|
HelpEcho()
|
||||||
case "export":
|
case "export":
|
||||||
var err error
|
var err error
|
||||||
fmt.Printf("Statup v%v Exporting Static 'index.html' page...\n", VERSION)
|
fmt.Printf("Statup v%v Exporting Static 'index.html' page...\n", VERSION)
|
||||||
|
@ -84,6 +86,7 @@ func HelpEcho() {
|
||||||
fmt.Println(" statup - Main command to run Statup server")
|
fmt.Println(" statup - Main command to run Statup server")
|
||||||
fmt.Println(" statup version - Returns the current version of Statup")
|
fmt.Println(" statup version - Returns the current version of Statup")
|
||||||
fmt.Println(" statup run - Check all service 1 time and then quit")
|
fmt.Println(" statup run - Check all service 1 time and then quit")
|
||||||
|
fmt.Println(" statup assets - Export all assets used locally to be edited.")
|
||||||
fmt.Println(" statup env - Show all environment variables being used for Statup")
|
fmt.Println(" statup env - Show all environment variables being used for Statup")
|
||||||
fmt.Println(" statup export - Exports the index page as a static HTML for pushing")
|
fmt.Println(" statup export - Exports the index page as a static HTML for pushing")
|
||||||
fmt.Println(" to Github Pages or your own FTP server. Export will")
|
fmt.Println(" to Github Pages or your own FTP server. Export will")
|
||||||
|
|
|
@ -96,6 +96,10 @@ func CreateAllAssets() {
|
||||||
CopyToPublic(JsBox, "js", "jquery-3.3.1.slim.min.js")
|
CopyToPublic(JsBox, "js", "jquery-3.3.1.slim.min.js")
|
||||||
CopyToPublic(JsBox, "js", "main.js")
|
CopyToPublic(JsBox, "js", "main.js")
|
||||||
CopyToPublic(JsBox, "js", "setup.js")
|
CopyToPublic(JsBox, "js", "setup.js")
|
||||||
|
CopyToPublic(JsBox, "js", "setup.js")
|
||||||
|
CopyToPublic(TmplBox, "", "robots.txt")
|
||||||
|
CopyToPublic(TmplBox, "", "favicon.ico")
|
||||||
|
|
||||||
utils.Log(1, "Compiling CSS from SCSS style...")
|
utils.Log(1, "Compiling CSS from SCSS style...")
|
||||||
err := CompileSASS()
|
err := CompileSASS()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -5,7 +5,9 @@ import (
|
||||||
"github.com/hunterlong/statup/types"
|
"github.com/hunterlong/statup/types"
|
||||||
"github.com/hunterlong/statup/utils"
|
"github.com/hunterlong/statup/utils"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -33,7 +35,28 @@ func (s *Service) CheckQueue() {
|
||||||
time.Sleep(time.Duration(s.Interval) * time.Second)
|
time.Sleep(time.Duration(s.Interval) * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) DNSCheck() (float64, error) {
|
||||||
|
t1 := time.Now()
|
||||||
|
url, err := url.Parse(s.Domain)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
_, err = net.LookupIP(url.Host)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
t2 := time.Now()
|
||||||
|
subTime := t2.Sub(t1).Seconds()
|
||||||
|
return subTime, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) Check() *Service {
|
func (s *Service) Check() *Service {
|
||||||
|
dnsLookup, err := s.DNSCheck()
|
||||||
|
if err != nil {
|
||||||
|
s.Failure(fmt.Sprintf("Could not get IP address for domain %v, %v", s.Domain, err))
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
s.dnsLookup = dnsLookup
|
||||||
t1 := time.Now()
|
t1 := time.Now()
|
||||||
client := http.Client{
|
client := http.Client{
|
||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
|
|
20
core/core.go
20
core/core.go
|
@ -10,16 +10,16 @@ type PluginJSON types.PluginJSON
|
||||||
type PluginRepos types.PluginRepos
|
type PluginRepos types.PluginRepos
|
||||||
|
|
||||||
type Core struct {
|
type Core struct {
|
||||||
Name string `db:"name"`
|
Name string `db:"name" json:"name"`
|
||||||
Description string `db:"description"`
|
Description string `db:"description" json:"name"`
|
||||||
Config string `db:"config"`
|
Config string `db:"config" json:"-"`
|
||||||
ApiKey string `db:"api_key"`
|
ApiKey string `db:"api_key" json:"-"`
|
||||||
ApiSecret string `db:"api_secret"`
|
ApiSecret string `db:"api_secret" json:"-"`
|
||||||
Style string `db:"style"`
|
Style string `db:"style" json:"-"`
|
||||||
Footer string `db:"footer"`
|
Footer string `db:"footer" json:"-"`
|
||||||
Domain string `db:"domain"`
|
Domain string `db:"domain" json:"domain,omitempty"`
|
||||||
Version string `db:"version"`
|
Version string `db:"version" json:"version,omitempty"`
|
||||||
Services []*Service
|
Services []*Service `json:"services,omitempty"`
|
||||||
Plugins []plugin.Info
|
Plugins []plugin.Info
|
||||||
Repos []PluginJSON
|
Repos []PluginJSON
|
||||||
//PluginFields []PluginSelect
|
//PluginFields []PluginSelect
|
||||||
|
|
|
@ -94,6 +94,10 @@ func (f *Failure) ParseError() string {
|
||||||
if err {
|
if err {
|
||||||
return fmt.Sprintf("SSL Certificate invalid")
|
return fmt.Sprintf("SSL Certificate invalid")
|
||||||
}
|
}
|
||||||
|
err = strings.Contains(f.Issue, "Client.Timeout exceeded while awaiting headers")
|
||||||
|
if err {
|
||||||
|
return fmt.Sprintf("Connection Timed Out")
|
||||||
|
}
|
||||||
err = strings.Contains(f.Issue, "no such host")
|
err = strings.Contains(f.Issue, "no such host")
|
||||||
if err {
|
if err {
|
||||||
return fmt.Sprintf("Domain is offline or not found")
|
return fmt.Sprintf("Domain is offline or not found")
|
||||||
|
@ -106,5 +110,13 @@ func (f *Failure) ParseError() string {
|
||||||
if err {
|
if err {
|
||||||
return fmt.Sprintf("Connection Failed")
|
return fmt.Sprintf("Connection Failed")
|
||||||
}
|
}
|
||||||
|
err = strings.Contains(f.Issue, "can't assign requested address")
|
||||||
|
if err {
|
||||||
|
return fmt.Sprintf("Unable to Request Address")
|
||||||
|
}
|
||||||
|
err = strings.Contains(f.Issue, "no route to host")
|
||||||
|
if err {
|
||||||
|
return fmt.Sprintf("Domain is offline or not found")
|
||||||
|
}
|
||||||
return f.Issue
|
return f.Issue
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ type Service struct {
|
||||||
LastResponse string
|
LastResponse string
|
||||||
LastStatusCode int
|
LastStatusCode int
|
||||||
LastOnline time.Time
|
LastOnline time.Time
|
||||||
|
dnsLookup float64 `json:"dns_lookup_time"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func serviceCol() db.Collection {
|
func serviceCol() db.Collection {
|
||||||
|
@ -194,7 +195,12 @@ func (u *Service) Delete() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Service) Update() {
|
func (u *Service) Update(s *Service) {
|
||||||
|
res := serviceCol().Find("id", u.Id)
|
||||||
|
err := res.Update(s)
|
||||||
|
if err != nil {
|
||||||
|
utils.Log(3, fmt.Sprintf("Failed to update service %v. %v", u.Name, err))
|
||||||
|
}
|
||||||
OnUpdateService(u)
|
OnUpdateService(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,18 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func ApiIndexHandler(w http.ResponseWriter, r *http.Request) {
|
func ApiIndexHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !isAPIAuthorized(r) {
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
json.NewEncoder(w).Encode(core.CoreApp)
|
json.NewEncoder(w).Encode(core.CoreApp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApiCheckinHandler(w http.ResponseWriter, r *http.Request) {
|
func ApiCheckinHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !isAPIAuthorized(r) {
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
checkin := core.FindCheckin(vars["api"])
|
checkin := core.FindCheckin(vars["api"])
|
||||||
checkin.Receivehit()
|
checkin.Receivehit()
|
||||||
|
@ -21,32 +29,63 @@ func ApiCheckinHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApiServiceHandler(w http.ResponseWriter, r *http.Request) {
|
func ApiServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !isAPIAuthorized(r) {
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
service := core.SelectService(utils.StringInt(vars["id"]))
|
service := core.SelectService(utils.StringInt(vars["id"]))
|
||||||
json.NewEncoder(w).Encode(service)
|
json.NewEncoder(w).Encode(service)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
func ApiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !isAPIAuthorized(r) {
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
service := core.SelectService(utils.StringInt(vars["id"]))
|
service := core.SelectService(utils.StringInt(vars["id"]))
|
||||||
var s core.Service
|
var s core.Service
|
||||||
decoder := json.NewDecoder(r.Body)
|
decoder := json.NewDecoder(r.Body)
|
||||||
decoder.Decode(&s)
|
decoder.Decode(&s)
|
||||||
json.NewEncoder(w).Encode(service)
|
service.Update(&s)
|
||||||
|
json.NewEncoder(w).Encode(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
|
func ApiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !isAPIAuthorized(r) {
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
services, _ := core.SelectAllServices()
|
services, _ := core.SelectAllServices()
|
||||||
json.NewEncoder(w).Encode(services)
|
json.NewEncoder(w).Encode(services)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApiUserHandler(w http.ResponseWriter, r *http.Request) {
|
func ApiUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !isAPIAuthorized(r) {
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
user, _ := core.SelectUser(utils.StringInt(vars["id"]))
|
user, _ := core.SelectUser(utils.StringInt(vars["id"]))
|
||||||
json.NewEncoder(w).Encode(user)
|
json.NewEncoder(w).Encode(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApiAllUsersHandler(w http.ResponseWriter, r *http.Request) {
|
func ApiAllUsersHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !isAPIAuthorized(r) {
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
users, _ := core.SelectAllUsers()
|
users, _ := core.SelectAllUsers()
|
||||||
json.NewEncoder(w).Encode(users)
|
json.NewEncoder(w).Encode(users)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isAPIAuthorized(r *http.Request) bool {
|
||||||
|
if IsAuthenticated(r) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if isAuthorized(r) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -14,8 +14,7 @@ type dashboard struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func DashboardHandler(w http.ResponseWriter, r *http.Request) {
|
func DashboardHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
auth := IsAuthenticated(r)
|
if !IsAuthenticated(r) {
|
||||||
if !auth {
|
|
||||||
err := core.ErrorResponse{}
|
err := core.ErrorResponse{}
|
||||||
ExecuteResponse(w, r, "login.html", err)
|
ExecuteResponse(w, r, "login.html", err)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,28 +1,10 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hunterlong/statup/core"
|
|
||||||
"github.com/hunterlong/statup/utils"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RobotsTxtHandler(w http.ResponseWriter, r *http.Request) {
|
func Error404Handler(w http.ResponseWriter, r *http.Request) {
|
||||||
robots := []byte(`User-agent: *
|
w.WriteHeader(http.StatusNotFound)
|
||||||
Disallow: /login
|
ExecuteResponse(w, r, "error_404.html", nil)
|
||||||
Disallow: /dashboard
|
|
||||||
|
|
||||||
Host: ` + core.CoreApp.Domain)
|
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
w.Write([]byte(robots))
|
|
||||||
}
|
|
||||||
|
|
||||||
func FavIconHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
data, err := core.TmplBox.String("favicon.ico")
|
|
||||||
if err != nil {
|
|
||||||
utils.Log(2, err)
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "image/x-icon")
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
w.Write([]byte(data))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,24 +8,26 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Use your Statup Secret API Key for Authentication
|
||||||
|
//
|
||||||
|
// scrape_configs:
|
||||||
|
// - job_name: 'statup'
|
||||||
|
// bearer_token: MY API SECRET HERE
|
||||||
|
// static_configs:
|
||||||
|
// - targets: ['statup:8080']
|
||||||
|
//
|
||||||
|
|
||||||
func PrometheusHandler(w http.ResponseWriter, r *http.Request) {
|
func PrometheusHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
utils.Log(1, fmt.Sprintf("Prometheus /metrics Request From IP: %v\n", r.RemoteAddr))
|
utils.Log(1, fmt.Sprintf("Prometheus /metrics Request From IP: %v\n", r.RemoteAddr))
|
||||||
var token string
|
if !isAuthorized(r) {
|
||||||
tokens, ok := r.Header["Authorization"]
|
|
||||||
if ok && len(tokens) >= 1 {
|
|
||||||
token = tokens[0]
|
|
||||||
token = strings.TrimPrefix(token, "Bearer ")
|
|
||||||
}
|
|
||||||
if token != core.CoreApp.ApiSecret {
|
|
||||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics := []string{}
|
metrics := []string{}
|
||||||
system := fmt.Sprintf("statup_total_failures %v\n", core.CountFailures())
|
system := fmt.Sprintf("statup_total_failures %v\n", core.CountFailures())
|
||||||
system += fmt.Sprintf("statup_total_services %v", len(core.CoreApp.Services))
|
system += fmt.Sprintf("statup_total_services %v", len(core.CoreApp.Services))
|
||||||
metrics = append(metrics, system)
|
metrics = append(metrics, system)
|
||||||
|
|
||||||
for _, v := range core.CoreApp.Services {
|
for _, v := range core.CoreApp.Services {
|
||||||
online := 1
|
online := 1
|
||||||
if !v.Online {
|
if !v.Online {
|
||||||
|
@ -42,3 +44,16 @@ func PrometheusHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte(output))
|
w.Write([]byte(output))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isAuthorized(r *http.Request) bool {
|
||||||
|
var token string
|
||||||
|
tokens, ok := r.Header["Authorization"]
|
||||||
|
if ok && len(tokens) >= 1 {
|
||||||
|
token = tokens[0]
|
||||||
|
token = strings.TrimPrefix(token, "Bearer ")
|
||||||
|
}
|
||||||
|
if token == core.CoreApp.ApiSecret {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -10,17 +10,7 @@ import (
|
||||||
func Router() *mux.Router {
|
func Router() *mux.Router {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.Handle("/", http.HandlerFunc(IndexHandler))
|
r.Handle("/", http.HandlerFunc(IndexHandler))
|
||||||
if core.UsingAssets {
|
LocalizedAssets(r)
|
||||||
cssHandler := http.FileServer(http.Dir("./assets/css"))
|
|
||||||
jsHandler := http.FileServer(http.Dir("./assets/js"))
|
|
||||||
r.PathPrefix("/css/").Handler(http.StripPrefix("/css/", cssHandler))
|
|
||||||
r.PathPrefix("/js/").Handler(http.StripPrefix("/js/", jsHandler))
|
|
||||||
} else {
|
|
||||||
r.PathPrefix("/css/").Handler(http.StripPrefix("/css/", http.FileServer(core.CssBox.HTTPBox())))
|
|
||||||
r.PathPrefix("/js/").Handler(http.StripPrefix("/js/", http.FileServer(core.JsBox.HTTPBox())))
|
|
||||||
}
|
|
||||||
r.Handle("/robots.txt", http.HandlerFunc(RobotsTxtHandler)).Methods("GET")
|
|
||||||
r.Handle("/favicon.ico", http.HandlerFunc(FavIconHandler)).Methods("GET")
|
|
||||||
r.Handle("/setup", http.HandlerFunc(SetupHandler)).Methods("GET")
|
r.Handle("/setup", http.HandlerFunc(SetupHandler)).Methods("GET")
|
||||||
r.Handle("/setup", http.HandlerFunc(ProcessSetupHandler)).Methods("POST")
|
r.Handle("/setup", http.HandlerFunc(ProcessSetupHandler)).Methods("POST")
|
||||||
r.Handle("/dashboard", http.HandlerFunc(DashboardHandler)).Methods("GET")
|
r.Handle("/dashboard", http.HandlerFunc(DashboardHandler)).Methods("GET")
|
||||||
|
@ -54,6 +44,25 @@ func Router() *mux.Router {
|
||||||
r.Handle("/api/users", http.HandlerFunc(ApiAllUsersHandler))
|
r.Handle("/api/users", http.HandlerFunc(ApiAllUsersHandler))
|
||||||
r.Handle("/api/users/{id}", http.HandlerFunc(ApiUserHandler))
|
r.Handle("/api/users/{id}", http.HandlerFunc(ApiUserHandler))
|
||||||
r.Handle("/metrics", http.HandlerFunc(PrometheusHandler))
|
r.Handle("/metrics", http.HandlerFunc(PrometheusHandler))
|
||||||
|
r.NotFoundHandler = http.HandlerFunc(Error404Handler)
|
||||||
Store = sessions.NewCookieStore([]byte("secretinfo"))
|
Store = sessions.NewCookieStore([]byte("secretinfo"))
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LocalizedAssets(r *mux.Router) *mux.Router {
|
||||||
|
if core.UsingAssets {
|
||||||
|
cssHandler := http.FileServer(http.Dir("./assets/css"))
|
||||||
|
jsHandler := http.FileServer(http.Dir("./assets/js"))
|
||||||
|
indexHandler := http.FileServer(http.Dir("./assets/"))
|
||||||
|
r.PathPrefix("/css/").Handler(http.StripPrefix("/css/", cssHandler))
|
||||||
|
r.PathPrefix("/js/").Handler(http.StripPrefix("/js/", jsHandler))
|
||||||
|
r.PathPrefix("/robots.txt").Handler(indexHandler)
|
||||||
|
r.PathPrefix("/favicon.ico").Handler(indexHandler)
|
||||||
|
} else {
|
||||||
|
r.PathPrefix("/css/").Handler(http.StripPrefix("/css/", http.FileServer(core.CssBox.HTTPBox())))
|
||||||
|
r.PathPrefix("/js/").Handler(http.StripPrefix("/js/", http.FileServer(core.JsBox.HTTPBox())))
|
||||||
|
r.PathPrefix("/robots.txt").Handler(http.FileServer(core.TmplBox.HTTPBox()))
|
||||||
|
r.PathPrefix("/favicon.ico").Handler(http.FileServer(core.TmplBox.HTTPBox()))
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ func ServicesUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
interval, _ := strconv.Atoi(r.PostForm.Get("interval"))
|
interval, _ := strconv.Atoi(r.PostForm.Get("interval"))
|
||||||
port, _ := strconv.Atoi(r.PostForm.Get("port"))
|
port, _ := strconv.Atoi(r.PostForm.Get("port"))
|
||||||
checkType := r.PostForm.Get("check_type")
|
checkType := r.PostForm.Get("check_type")
|
||||||
service = &core.Service{
|
serviceUpdate := &core.Service{
|
||||||
Name: name,
|
Name: name,
|
||||||
Domain: domain,
|
Domain: domain,
|
||||||
Method: method,
|
Method: method,
|
||||||
|
@ -115,7 +115,7 @@ func ServicesUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
Type: checkType,
|
Type: checkType,
|
||||||
Port: port,
|
Port: port,
|
||||||
}
|
}
|
||||||
service.Update()
|
service.Update(serviceUpdate)
|
||||||
ExecuteResponse(w, r, "service.html", service)
|
ExecuteResponse(w, r, "service.html", service)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ HTML, BODY {
|
||||||
font-size: 2.3rem;
|
font-size: 2.3rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
display: block;
|
display: block;
|
||||||
color: #47d337; }
|
color: #4f4f4f; }
|
||||||
|
|
||||||
.stats_area {
|
.stats_area {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -8,7 +8,7 @@ $description-color: #939393;
|
||||||
$service-background: #ffffff;
|
$service-background: #ffffff;
|
||||||
$service-border: 1px solid rgba(0,0,0,.125);
|
$service-border: 1px solid rgba(0,0,0,.125);
|
||||||
$service-title: #444444;
|
$service-title: #444444;
|
||||||
$service-stats-color: #47d337;
|
$service-stats-color: #4f4f4f;
|
||||||
$service-description-color: #fff;
|
$service-description-color: #fff;
|
||||||
$service-stats-size: 2.3rem;
|
$service-stats-size: 2.3rem;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1.0, user-scalable=0">
|
||||||
|
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="/css/base.css">
|
||||||
|
|
||||||
|
<title>Statup | Page Not Found</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="container col-md-7 col-sm-12 mt-md-5 bg-light">
|
||||||
|
|
||||||
|
<div class="col-12 mt-3">
|
||||||
|
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
Sorry, this page doesn't seem to exist.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "footer"}}
|
||||||
|
|
||||||
|
<script src="/js/jquery-3.3.1.slim.min.js"></script>
|
||||||
|
<script src="/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -3,6 +3,6 @@
|
||||||
{{ if .Core.Footer }}
|
{{ if .Core.Footer }}
|
||||||
{{ safe .Core.Footer }}
|
{{ safe .Core.Footer }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<a href="https://statup.io" target="_blank">Statup {{ VERSION }} made with ❤️</a> | <a href="/dashboard">Dashboard</a>
|
<a href="https://github.com/hunterlong/statup" target="_blank">Statup {{ VERSION }} made with ❤️</a> | <a href="/dashboard">Dashboard</a>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
|
@ -1,35 +0,0 @@
|
||||||
{{define "slack"}}
|
|
||||||
|
|
||||||
<form action="/plugins/save_slack" method="POST">
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="custom-control custom-checkbox">
|
|
||||||
<input type="checkbox" class="custom-control-input" id="customCheck1">
|
|
||||||
<label class="custom-control-label" for="customCheck1">Slack Integration Enabled</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label for="inputPassword3" class="col-sm-4 col-form-label">API Key</label>
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<input type="text" name="domain" class="form-control" id="inputPassword3">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label for="inputPassword3" class="col-sm-4 col-form-label">API Secret</label>
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<input type="text" name="expected" class="form-control" id="inputPassword3">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label for="inputPassword3" class="col-sm-4 col-form-label">Channel</label>
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<input type="number" name="expected_status" class="form-control" id="inputPassword3">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<button type="submit" class="btn btn-success">Save</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{{end}}
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
User-agent: *
|
||||||
|
Disallow: /login
|
||||||
|
Disallow: /dashboard
|
|
@ -23,11 +23,11 @@ type Hit struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Failure struct {
|
type Failure struct {
|
||||||
Id int `db:"id,omitempty"`
|
Id int `db:"id,omitempty" json:"id"`
|
||||||
Issue string `db:"issue"`
|
Issue string `db:"issue" json:"issue"`
|
||||||
Method string `db:"method"`
|
Method string `db:"method" json:"method,omitempty"`
|
||||||
Service int64 `db:"service"`
|
Service int64 `db:"service" json:"service_id"`
|
||||||
CreatedAt time.Time `db:"created_at"`
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Checkin struct {
|
type Checkin struct {
|
||||||
|
@ -43,17 +43,17 @@ type Checkin struct {
|
||||||
type Communication struct {
|
type Communication struct {
|
||||||
Id int64 `db:"id,omitempty" json:"id"`
|
Id int64 `db:"id,omitempty" json:"id"`
|
||||||
Method string `db:"method" json:"method"`
|
Method string `db:"method" json:"method"`
|
||||||
Host string `db:"host" json:"host"`
|
Host string `db:"host" json:"-"`
|
||||||
Port int `db:"port" json:"port"`
|
Port int `db:"port" json:"-"`
|
||||||
Username string `db:"username" json:"user"`
|
Username string `db:"username" json:"-"`
|
||||||
Password string `db:"password" json:"-"`
|
Password string `db:"password" json:"-"`
|
||||||
Var1 string `db:"var1" json:"var1"`
|
Var1 string `db:"var1" json:"-"`
|
||||||
Var2 string `db:"var2" json:"var2"`
|
Var2 string `db:"var2" json:"-"`
|
||||||
ApiKey string `db:"api_key" json:"api_key"`
|
ApiKey string `db:"api_key" json:"-"`
|
||||||
ApiSecret string `db:"api_secret" json:"api_secret"`
|
ApiSecret string `db:"api_secret" json:"-"`
|
||||||
Enabled bool `db:"enabled" json:"enabled"`
|
Enabled bool `db:"enabled" json:"enabled"`
|
||||||
Limits int64 `db:"limits" json:"limits"`
|
Limits int64 `db:"limits" json:"-"`
|
||||||
Removable bool `db:"removable" json:"removable"`
|
Removable bool `db:"removable" json:"-"`
|
||||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue