pull/429/head
hunterlong 2020-01-14 20:58:22 -08:00
parent 23b230f61f
commit 134bd073ff
15 changed files with 316 additions and 23 deletions

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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,

View File

@ -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
}
]
})

View File

@ -4,7 +4,7 @@ module.exports = {
proxy: {
'/api': {
logLevel: 'debug',
target: 'http://0.0.0.0:8585'
target: 'http://0.0.0.0:8282'
}
}
}

View File

@ -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 {

View File

@ -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")

View File

@ -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)
}

6
types/safe.go Normal file
View File

@ -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"}
)

View File

@ -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"`