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 gpg --import statping.gpg
make build-all make build-all
frontend:
cd frontend && yarn serve
# build and push the images to docker hub # build and push the images to docker hub
docker: docker-build-all docker-publish-all docker: docker-build-all docker-publish-all
@ -371,5 +374,5 @@ heroku:
checkall: checkall:
golangci-lint run ./... 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 .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 Vue from 'vue'
import App from './App.vue' import App from './App.vue'
import VueRouter from 'vue-router' import VueRouter from 'vue-router'
import Index from "./components/Pages/Index"; const router = require("routes")
require("./assets/css/bootstrap.min.css") require("./assets/css/bootstrap.min.css")
require("./assets/css/base.css") require("./assets/css/base.css")
Vue.use(VueRouter) Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{
path: '/',
name: 'Index',
component: Index
}
]
})
Vue.config.productionTip = false Vue.config.productionTip = false
new Vue({ new Vue({
router, 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> </template>
<script> <script>
import ServiceBlock from '../Service/ServiceBlock.vue' import ServiceBlock from '../components/Service/ServiceBlock.vue'
import MessageBlock from "../Index/MessageBlock"; import MessageBlock from "../components/Index/MessageBlock";
import Group from "../Index/Group"; import Group from "../components/Index/Group";
import Header from "../Index/Header"; import Header from "../components/Index/Header";
const axios = require('axios');
export default { export default {
name: 'Index', name: 'Settings',
components: { components: {
Header, Header,
Group, Group,

View File

@ -1,5 +1,7 @@
import Index from "./components/Pages/Index"; import Index from "./pages/Index";
import VueRouter from 'vue-router' import VueRouter from 'vue-router'
import Dashboard from "./pages/Dashboard";
import Settings from "./pages/Settings";
const router = new VueRouter({ const router = new VueRouter({
routes: [ routes: [
@ -7,6 +9,16 @@ const router = new VueRouter({
path: '/', path: '/',
name: 'Index', name: 'Index',
component: Index component: Index
},
{
path: '/dashboard',
name: 'Dashboard',
component: Dashboard
},
{
path: '/settings',
name: 'Settings',
component: Settings
} }
] ]
}) })

View File

@ -4,7 +4,7 @@ module.exports = {
proxy: { proxy: {
'/api': { '/api': {
logLevel: 'debug', 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" "net/http"
"os" "os"
"path" "path"
"reflect"
"strings" "strings"
"time" "time"
@ -272,6 +273,66 @@ func returnJson(d interface{}, w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(d) 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 // error404Handler is a HTTP handler for 404 error pages
func error404Handler(w http.ResponseWriter, r *http.Request) { func error404Handler(w http.ResponseWriter, r *http.Request) {
if usingSSL { if usingSSL {

View File

@ -131,7 +131,7 @@ func Router() *mux.Router {
r.Handle("/api/reorder/groups", authenticated(apiGroupReorderHandler, false)).Methods("POST") r.Handle("/api/reorder/groups", authenticated(apiGroupReorderHandler, false)).Methods("POST")
// API SERVICE Routes // 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", authenticated(apiCreateServiceHandler, false)).Methods("POST")
r.Handle("/api/services/{id}", readOnly(apiServiceHandler, false)).Methods("GET") r.Handle("/api/services/{id}", readOnly(apiServiceHandler, false)).Methods("GET")
r.Handle("/api/reorder/services", authenticated(reorderServiceHandler, false)).Methods("POST") 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) { func apiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
admin := IsAdmin(r)
services := core.Services() services := core.Services()
if !admin {
returnSafeJson(w, r, expandServices(services))
return
}
returnJson(services, w, r) 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 { type Service struct {
Id int64 `gorm:"primary_key;column:id" json:"id"` Id int64 `gorm:"primary_key;column:id" json:"id"`
Name string `gorm:"column:name" json:"name"` 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"` Expected NullString `gorm:"column:expected" json:"expected"`
ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status"` ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status"`
Interval int `gorm:"default:30;column:check_interval" json:"check_interval"` Interval int `gorm:"default:30;column:check_interval" json:"check_interval"`