mirror of https://github.com/statping/statping
				
				
				
			vue
							parent
							
								
									23b230f61f
								
							
						
					
					
						commit
						134bd073ff
					
				
							
								
								
									
										5
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										5
									
								
								Makefile
								
								
								
								
							| 
						 | 
				
			
			@ -17,6 +17,9 @@ release: dev-deps
 | 
			
		|||
	gpg --import statping.gpg
 | 
			
		||||
	make build-all
 | 
			
		||||
 | 
			
		||||
frontend:
 | 
			
		||||
	cd frontend && yarn serve
 | 
			
		||||
 | 
			
		||||
# build and push the images to docker hub
 | 
			
		||||
docker: docker-build-all docker-publish-all
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -371,5 +374,5 @@ heroku:
 | 
			
		|||
checkall:
 | 
			
		||||
	golangci-lint run ./...
 | 
			
		||||
 | 
			
		||||
.PHONY: all build build-all build-alpine test-all test test-api docker
 | 
			
		||||
.PHONY: all build build-all build-alpine test-all test test-api docker frontend
 | 
			
		||||
.SILENT: travis_s3_creds
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
import axios from 'axios'
 | 
			
		||||
 | 
			
		||||
class Api {
 | 
			
		||||
  constructor() {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async root () {
 | 
			
		||||
    return axios.get('/api').then(response => (response.data))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async services () {
 | 
			
		||||
    return axios.get('/api/services').then(response => (response.data))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async groups () {
 | 
			
		||||
    return axios.get('/api/groups').then(response => (response.data))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
const api = new Api()
 | 
			
		||||
export default api
 | 
			
		||||
| 
						 | 
				
			
			@ -1,24 +1,13 @@
 | 
			
		|||
import Vue from 'vue'
 | 
			
		||||
import App from './App.vue'
 | 
			
		||||
import VueRouter from 'vue-router'
 | 
			
		||||
import Index from "./components/Pages/Index";
 | 
			
		||||
const router = require("routes")
 | 
			
		||||
 | 
			
		||||
require("./assets/css/bootstrap.min.css")
 | 
			
		||||
require("./assets/css/base.css")
 | 
			
		||||
 | 
			
		||||
Vue.use(VueRouter)
 | 
			
		||||
 | 
			
		||||
const router = new VueRouter({
 | 
			
		||||
  routes: [
 | 
			
		||||
    {
 | 
			
		||||
      path: '/',
 | 
			
		||||
      name: 'Index',
 | 
			
		||||
      component: Index
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Vue.config.productionTip = false
 | 
			
		||||
new Vue({
 | 
			
		||||
  router,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,75 @@
 | 
			
		|||
<template>
 | 
			
		||||
    <div class="container col-md-7 col-sm-12 mt-2 sm-container">
 | 
			
		||||
 | 
			
		||||
        <Header :core="core"/>
 | 
			
		||||
 | 
			
		||||
        <Group/>
 | 
			
		||||
        <Group/>
 | 
			
		||||
        <Group/>
 | 
			
		||||
        <div v-for="(group, index) in groups" v-bind:key="index">
 | 
			
		||||
            <Group :group=group />
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <MessageBlock/>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="col-12 full-col-12">
 | 
			
		||||
 | 
			
		||||
            <div v-for="(service, index) in services" v-bind:key="index">
 | 
			
		||||
                <ServiceBlock :service=service />
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import ServiceBlock from '../components/Service/ServiceBlock.vue'
 | 
			
		||||
import MessageBlock from "../components/Index/MessageBlock";
 | 
			
		||||
import Group from "../components/Index/Group";
 | 
			
		||||
import Header from "../components/Index/Header";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'Dashboard',
 | 
			
		||||
  components: {
 | 
			
		||||
    Header,
 | 
			
		||||
    Group,
 | 
			
		||||
    MessageBlock,
 | 
			
		||||
    ServiceBlock,
 | 
			
		||||
  },
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      services: null,
 | 
			
		||||
      groups: null,
 | 
			
		||||
      core: null,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  beforeMount() {
 | 
			
		||||
    this.getAPI()
 | 
			
		||||
    this.getGroups()
 | 
			
		||||
    this.getServices()
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getAPI: function() {
 | 
			
		||||
      axios
 | 
			
		||||
        .get('/api')
 | 
			
		||||
        .then(response => (this.core = response.data))
 | 
			
		||||
    },
 | 
			
		||||
    getServices: function() {
 | 
			
		||||
      axios
 | 
			
		||||
        .get('/api/services')
 | 
			
		||||
        .then(response => (this.services = response.data))
 | 
			
		||||
    },
 | 
			
		||||
    getGroups: function() {
 | 
			
		||||
      axios
 | 
			
		||||
        .get('/api/groups')
 | 
			
		||||
        .then(response => (this.groups = response.data))
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
 | 
			
		||||
<style scoped>
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
<template>
 | 
			
		||||
    <div v-show="core" class="container col-md-7 col-sm-12 mt-2 sm-container">
 | 
			
		||||
 | 
			
		||||
        <Header :core="core"/>
 | 
			
		||||
 | 
			
		||||
        <div v-for="(group, index) in groups" v-bind:key="index">
 | 
			
		||||
            <Group :group=group />
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <MessageBlock/>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="col-12 full-col-12">
 | 
			
		||||
 | 
			
		||||
            <div v-for="(service, index) in services" v-bind:key="index">
 | 
			
		||||
                <ServiceBlock :service=service />
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import ServiceBlock from '../components/Service/ServiceBlock.vue'
 | 
			
		||||
import MessageBlock from "../components/Index/MessageBlock";
 | 
			
		||||
import Group from "../components/Index/Group";
 | 
			
		||||
import Header from "../components/Index/Header";
 | 
			
		||||
import Api from "../components/API"
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'Index',
 | 
			
		||||
  components: {
 | 
			
		||||
    Header,
 | 
			
		||||
    Group,
 | 
			
		||||
    MessageBlock,
 | 
			
		||||
    ServiceBlock,
 | 
			
		||||
  },
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      services: null,
 | 
			
		||||
      groups: null,
 | 
			
		||||
      core: null,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  beforeMount() {
 | 
			
		||||
    this.loadAll()
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    async loadAll () {
 | 
			
		||||
      this.core = await Api.root()
 | 
			
		||||
      this.groups = await Api.groups()
 | 
			
		||||
      this.services = await Api.services()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
 | 
			
		||||
<style scoped>
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
<template>
 | 
			
		||||
    <div class="container col-md-7 col-sm-12 mt-2 sm-container">
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'Service',
 | 
			
		||||
  components: {
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      service: null,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  beforeMount() {
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
 | 
			
		||||
<style scoped>
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
<template>
 | 
			
		||||
    <div class="container col-md-7 col-sm-12 mt-2 sm-container">
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'Services',
 | 
			
		||||
  components: {
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      services: null,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  beforeMount() {
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
 | 
			
		||||
<style scoped>
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -25,15 +25,14 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import ServiceBlock from '../Service/ServiceBlock.vue'
 | 
			
		||||
import MessageBlock from "../Index/MessageBlock";
 | 
			
		||||
import Group from "../Index/Group";
 | 
			
		||||
import Header from "../Index/Header";
 | 
			
		||||
const axios = require('axios');
 | 
			
		||||
import ServiceBlock from '../components/Service/ServiceBlock.vue'
 | 
			
		||||
import MessageBlock from "../components/Index/MessageBlock";
 | 
			
		||||
import Group from "../components/Index/Group";
 | 
			
		||||
import Header from "../components/Index/Header";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'Index',
 | 
			
		||||
  name: 'Settings',
 | 
			
		||||
  components: {
 | 
			
		||||
    Header,
 | 
			
		||||
    Group,
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,7 @@
 | 
			
		|||
import Index from "./components/Pages/Index";
 | 
			
		||||
import Index from "./pages/Index";
 | 
			
		||||
import VueRouter from 'vue-router'
 | 
			
		||||
import Dashboard from "./pages/Dashboard";
 | 
			
		||||
import Settings from "./pages/Settings";
 | 
			
		||||
 | 
			
		||||
const router = new VueRouter({
 | 
			
		||||
  routes: [
 | 
			
		||||
| 
						 | 
				
			
			@ -7,6 +9,16 @@ const router = new VueRouter({
 | 
			
		|||
      path: '/',
 | 
			
		||||
      name: 'Index',
 | 
			
		||||
      component: Index
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: '/dashboard',
 | 
			
		||||
      name: 'Dashboard',
 | 
			
		||||
      component: Dashboard
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: '/settings',
 | 
			
		||||
      name: 'Settings',
 | 
			
		||||
      component: Settings
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ module.exports = {
 | 
			
		|||
    proxy: {
 | 
			
		||||
      '/api': {
 | 
			
		||||
        logLevel: 'debug',
 | 
			
		||||
        target: 'http://0.0.0.0:8585'
 | 
			
		||||
        target: 'http://0.0.0.0:8282'
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ import (
 | 
			
		|||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -272,6 +273,66 @@ func returnJson(d interface{}, w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	json.NewEncoder(w).Encode(d)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func safeTypes(obj interface{}) []string {
 | 
			
		||||
	if reflect.ValueOf(obj).Kind() == reflect.Ptr {
 | 
			
		||||
		obj = &obj
 | 
			
		||||
	}
 | 
			
		||||
	switch v := obj.(type) {
 | 
			
		||||
	case types.Service:
 | 
			
		||||
		return types.SafeService
 | 
			
		||||
	default:
 | 
			
		||||
		fmt.Printf("%T\n", v)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func expandServices(s []types.ServiceInterface) []*types.Service {
 | 
			
		||||
	var services []*types.Service
 | 
			
		||||
	for _, v := range s {
 | 
			
		||||
		services = append(services, v.Select())
 | 
			
		||||
	}
 | 
			
		||||
	return services
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func returnSafeJson(w http.ResponseWriter, r *http.Request, input interface{}) {
 | 
			
		||||
	allData := make([]map[string]*json.RawMessage, 0, 1)
 | 
			
		||||
	s := reflect.ValueOf(input)
 | 
			
		||||
	for i := 0; i < s.Len(); i++ {
 | 
			
		||||
		obj := s.Index(i)
 | 
			
		||||
		allData = append(allData, safeJsonKeys(obj))
 | 
			
		||||
	}
 | 
			
		||||
	returnJson(allData, w, r)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func safeJsonKeys(in reflect.Value) map[string]*json.RawMessage {
 | 
			
		||||
 | 
			
		||||
	thisObj := in.Elem().Interface()
 | 
			
		||||
	nn := make(map[string]*json.RawMessage)
 | 
			
		||||
 | 
			
		||||
	v := reflect.ValueOf(thisObj)
 | 
			
		||||
	typeOfS := v.Type()
 | 
			
		||||
	fmt.Println("fields: ", v.NumField())
 | 
			
		||||
	for i := 0; i < v.NumField(); i++ {
 | 
			
		||||
		inter := v.Field(i).Interface()
 | 
			
		||||
		fmt.Println(v.Field(i).CanSet())
 | 
			
		||||
		if typeOfS.Field(i).Type.String() == "types.NullString" {
 | 
			
		||||
			ggg := inter.(types.NullString)
 | 
			
		||||
			fmt.Println("OKKOKOK: ", ggg)
 | 
			
		||||
			v.Field(i).SetString(ggg.String)
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Printf("Field: %s\tValue: %v\n", typeOfS.Field(i).Type.String(), v.Field(i).Interface())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data, _ := json.Marshal(thisObj)
 | 
			
		||||
 | 
			
		||||
	json.Unmarshal(data, &nn)
 | 
			
		||||
	removeKeys := safeTypes(thisObj)
 | 
			
		||||
	for _, k := range removeKeys {
 | 
			
		||||
		delete(nn, k)
 | 
			
		||||
	}
 | 
			
		||||
	return nn
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// error404Handler is a HTTP handler for 404 error pages
 | 
			
		||||
func error404Handler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if usingSSL {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -131,7 +131,7 @@ func Router() *mux.Router {
 | 
			
		|||
	r.Handle("/api/reorder/groups", authenticated(apiGroupReorderHandler, false)).Methods("POST")
 | 
			
		||||
 | 
			
		||||
	// API SERVICE Routes
 | 
			
		||||
	r.Handle("/api/services", readOnly(apiAllServicesHandler, false)).Methods("GET")
 | 
			
		||||
	r.Handle("/api/services", http.HandlerFunc(apiAllServicesHandler)).Methods("GET")
 | 
			
		||||
	r.Handle("/api/services", authenticated(apiCreateServiceHandler, false)).Methods("POST")
 | 
			
		||||
	r.Handle("/api/services/{id}", readOnly(apiServiceHandler, false)).Methods("GET")
 | 
			
		||||
	r.Handle("/api/reorder/services", authenticated(reorderServiceHandler, false)).Methods("POST")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -294,7 +294,12 @@ func apiServiceDeleteHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func apiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	admin := IsAdmin(r)
 | 
			
		||||
	services := core.Services()
 | 
			
		||||
	if !admin {
 | 
			
		||||
		returnSafeJson(w, r, expandServices(services))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	returnJson(services, w, r)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
package types
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	SafeService = []string{"domain", "expected_status", "expected", "allow_notifications", "headers", "method",
 | 
			
		||||
		"port", "timeout", "status_code", "verify_ssl", "post_data", "type", "check_interval", "failures"}
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ import (
 | 
			
		|||
type Service struct {
 | 
			
		||||
	Id                 int64              `gorm:"primary_key;column:id" json:"id"`
 | 
			
		||||
	Name               string             `gorm:"column:name" json:"name"`
 | 
			
		||||
	Domain             string             `gorm:"column:domain" json:"domain"`
 | 
			
		||||
	Domain             string             `gorm:"column:domain" json:"domain" private:"true"`
 | 
			
		||||
	Expected           NullString         `gorm:"column:expected" json:"expected"`
 | 
			
		||||
	ExpectedStatus     int                `gorm:"default:200;column:expected_status" json:"expected_status"`
 | 
			
		||||
	Interval           int                `gorm:"default:30;column:check_interval" json:"check_interval"`
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue