mirror of https://github.com/statping/statping
vue js public api with scopes within struct tags. neato.
parent
134bd073ff
commit
30e64f688c
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<router-view></router-view>
|
<router-view/>
|
||||||
<Footer/>
|
<Footer/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -9,7 +9,9 @@
|
||||||
import Footer from "./components/Footer";
|
import Footer from "./components/Footer";
|
||||||
export default {
|
export default {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
components: {Footer},
|
components: {
|
||||||
|
Footer
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,18 @@ class Api {
|
||||||
return axios.get('/api/services').then(response => (response.data))
|
return axios.get('/api/services').then(response => (response.data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async service (id) {
|
||||||
|
return axios.get('/api/services/'+id).then(response => (response.data))
|
||||||
|
}
|
||||||
|
|
||||||
async groups () {
|
async groups () {
|
||||||
return axios.get('/api/groups').then(response => (response.data))
|
return axios.get('/api/groups').then(response => (response.data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async group (id) {
|
||||||
|
return axios.get('/api/groups/'+id).then(response => (response.data))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
const api = new Api()
|
const api = new Api()
|
||||||
export default api
|
export default api
|
||||||
|
|
|
@ -1,12 +1,50 @@
|
||||||
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'
|
||||||
const router = require("routes")
|
import Index from "./pages/Index";
|
||||||
|
import Dashboard from "./pages/Dashboard";
|
||||||
|
import Settings from "./pages/Settings";
|
||||||
|
import Service from "./pages/Service";
|
||||||
|
import Services from "./pages/Services";
|
||||||
|
|
||||||
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)
|
const routes = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'Index',
|
||||||
|
component: Index
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/dashboard',
|
||||||
|
name: 'Dashboard',
|
||||||
|
component: Dashboard
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/settings',
|
||||||
|
name: 'Settings',
|
||||||
|
component: Settings
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/services',
|
||||||
|
name: 'Services',
|
||||||
|
component: Services
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/service/:id',
|
||||||
|
name: 'Service',
|
||||||
|
component: Service
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const router = new VueRouter
|
||||||
|
({
|
||||||
|
mode: 'history',
|
||||||
|
routes
|
||||||
|
})
|
||||||
|
|
||||||
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
new Vue({
|
new Vue({
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="container col-md-7 col-sm-12 mt-2 sm-container">
|
<div v-show="core" class="container col-md-7 col-sm-12 mt-2 sm-container">
|
||||||
|
|
||||||
<Header :core="core"/>
|
<Header :core="core"/>
|
||||||
|
|
||||||
<Group/>
|
|
||||||
<Group/>
|
|
||||||
<Group/>
|
|
||||||
<div v-for="(group, index) in groups" v-bind:key="index">
|
<div v-for="(group, index) in groups" v-bind:key="index">
|
||||||
<Group :group=group />
|
<Group :group=group />
|
||||||
</div>
|
</div>
|
||||||
|
@ -29,6 +26,7 @@ import ServiceBlock from '../components/Service/ServiceBlock.vue'
|
||||||
import MessageBlock from "../components/Index/MessageBlock";
|
import MessageBlock from "../components/Index/MessageBlock";
|
||||||
import Group from "../components/Index/Group";
|
import Group from "../components/Index/Group";
|
||||||
import Header from "../components/Index/Header";
|
import Header from "../components/Index/Header";
|
||||||
|
import Api from "../components/API"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Dashboard',
|
name: 'Dashboard',
|
||||||
|
@ -46,25 +44,13 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
this.getAPI()
|
this.loadAll()
|
||||||
this.getGroups()
|
|
||||||
this.getServices()
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getAPI: function() {
|
async loadAll () {
|
||||||
axios
|
this.core = await Api.root()
|
||||||
.get('/api')
|
this.groups = await Api.groups()
|
||||||
.then(response => (this.core = response.data))
|
this.services = await Api.services()
|
||||||
},
|
|
||||||
getServices: function() {
|
|
||||||
axios
|
|
||||||
.get('/api/services')
|
|
||||||
.then(response => (this.services = response.data))
|
|
||||||
},
|
|
||||||
getGroups: function() {
|
|
||||||
axios
|
|
||||||
.get('/api/groups')
|
|
||||||
.then(response => (this.groups = response.data))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="container col-md-7 col-sm-12 mt-2 sm-container">
|
<div class="container col-md-7 col-sm-12 mt-2 sm-container">
|
||||||
|
{{service}}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Api from "../components/API"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Service',
|
name: 'Service',
|
||||||
|
@ -13,14 +14,18 @@ export default {
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
id: null,
|
||||||
service: null,
|
service: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
|
this.id = this.$route.params.id
|
||||||
|
this.getService()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
async getService() {
|
||||||
|
this.service = await Api.services()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
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: [
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
name: 'Index',
|
|
||||||
component: Index
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/dashboard',
|
|
||||||
name: 'Dashboard',
|
|
||||||
component: Dashboard
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/settings',
|
|
||||||
name: 'Settings',
|
|
||||||
component: Settings
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
export default router
|
|
|
@ -4,7 +4,7 @@ module.exports = {
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
logLevel: 'debug',
|
logLevel: 'debug',
|
||||||
target: 'http://0.0.0.0:8282'
|
target: 'http://0.0.0.0:8585'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -294,43 +294,94 @@ func expandServices(s []types.ServiceInterface) []*types.Service {
|
||||||
return services
|
return services
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toSafeJson(input interface{}) map[string]interface{} {
|
||||||
|
thisData := make(map[string]interface{})
|
||||||
|
t := reflect.TypeOf(input)
|
||||||
|
elem := reflect.ValueOf(input)
|
||||||
|
|
||||||
|
d, _ := json.Marshal(input)
|
||||||
|
|
||||||
|
var raw map[string]*json.RawMessage
|
||||||
|
json.Unmarshal(d, &raw)
|
||||||
|
|
||||||
|
if t.Kind() == reflect.Ptr {
|
||||||
|
input = &input
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Type:", t.Name())
|
||||||
|
fmt.Println("Kind:", t.Kind())
|
||||||
|
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
field := t.Field(i)
|
||||||
|
|
||||||
|
// Get the field tag value
|
||||||
|
tag := field.Tag.Get("scope")
|
||||||
|
jsonTag := field.Tag.Get("json")
|
||||||
|
|
||||||
|
tags := strings.Split(tag, ",")
|
||||||
|
|
||||||
|
if jsonTag == "" || jsonTag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
trueValue := elem.Field(i).Interface()
|
||||||
|
trueValue = fixValue(field, trueValue)
|
||||||
|
|
||||||
|
if tag == "" {
|
||||||
|
thisData[jsonTag] = trueValue
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if isPublic(tags) {
|
||||||
|
thisData[jsonTag] = trueValue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%d. %v (%v), tags: '%v'\n", i, field.Name, field.Type.Name(), tags)
|
||||||
|
}
|
||||||
|
return thisData
|
||||||
|
}
|
||||||
|
|
||||||
func returnSafeJson(w http.ResponseWriter, r *http.Request, input interface{}) {
|
func returnSafeJson(w http.ResponseWriter, r *http.Request, input interface{}) {
|
||||||
allData := make([]map[string]*json.RawMessage, 0, 1)
|
if reflect.ValueOf(input).Kind() == reflect.Slice {
|
||||||
|
alldata := make([]map[string]interface{}, 0, 1)
|
||||||
s := reflect.ValueOf(input)
|
s := reflect.ValueOf(input)
|
||||||
for i := 0; i < s.Len(); i++ {
|
for i := 0; i < s.Len(); i++ {
|
||||||
obj := s.Index(i)
|
alldata = append(alldata, toSafeJson(s.Index(i).Interface()))
|
||||||
allData = append(allData, safeJsonKeys(obj))
|
|
||||||
}
|
}
|
||||||
returnJson(allData, w, r)
|
returnJson(alldata, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
returnJson(input, w, r)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func safeJsonKeys(in reflect.Value) map[string]*json.RawMessage {
|
func fixValue(field reflect.StructField, val interface{}) interface{} {
|
||||||
|
typeName := field.Type.Name()
|
||||||
thisObj := in.Elem().Interface()
|
switch typeName {
|
||||||
nn := make(map[string]*json.RawMessage)
|
case "NullString":
|
||||||
|
nullItem := val.(types.NullString)
|
||||||
v := reflect.ValueOf(thisObj)
|
return nullItem.String
|
||||||
typeOfS := v.Type()
|
case "NullBool":
|
||||||
fmt.Println("fields: ", v.NumField())
|
nullItem := val.(types.NullBool)
|
||||||
for i := 0; i < v.NumField(); i++ {
|
return nullItem.Bool
|
||||||
inter := v.Field(i).Interface()
|
case "NullFloat64":
|
||||||
fmt.Println(v.Field(i).CanSet())
|
nullItem := val.(types.NullFloat64)
|
||||||
if typeOfS.Field(i).Type.String() == "types.NullString" {
|
return nullItem.Float64
|
||||||
ggg := inter.(types.NullString)
|
case "NullInt64":
|
||||||
fmt.Println("OKKOKOK: ", ggg)
|
nullItem := val.(types.NullInt64)
|
||||||
v.Field(i).SetString(ggg.String)
|
return nullItem.Int64
|
||||||
|
default:
|
||||||
|
return val
|
||||||
}
|
}
|
||||||
fmt.Printf("Field: %s\tValue: %v\n", typeOfS.Field(i).Type.String(), v.Field(i).Interface())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data, _ := json.Marshal(thisObj)
|
func isPublic(tags []string) bool {
|
||||||
|
for _, v := range tags {
|
||||||
json.Unmarshal(data, &nn)
|
if v == "public" {
|
||||||
removeKeys := safeTypes(thisObj)
|
return true
|
||||||
for _, k := range removeKeys {
|
|
||||||
delete(nn, k)
|
|
||||||
}
|
}
|
||||||
return nn
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// error404Handler is a HTTP handler for 404 error pages
|
// error404Handler is a HTTP handler for 404 error pages
|
||||||
|
|
|
@ -15,6 +15,12 @@ var (
|
||||||
authPass string
|
authPass string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func scopedRoute(handler func(w http.ResponseWriter, r *http.Request)) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
handler(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// basicAuthHandler is a middleware to implement HTTP basic authentication using
|
// basicAuthHandler is a middleware to implement HTTP basic authentication using
|
||||||
// AUTH_USERNAME and AUTH_PASSWORD environment variables
|
// AUTH_USERNAME and AUTH_PASSWORD environment variables
|
||||||
func basicAuthHandler(next http.Handler) http.Handler {
|
func basicAuthHandler(next http.Handler) http.Handler {
|
||||||
|
|
|
@ -114,7 +114,7 @@ func Router() *mux.Router {
|
||||||
r.Handle("/group/{id}", http.HandlerFunc(groupViewHandler)).Methods("GET")
|
r.Handle("/group/{id}", http.HandlerFunc(groupViewHandler)).Methods("GET")
|
||||||
|
|
||||||
// API Routes
|
// API Routes
|
||||||
r.Handle("/api", authenticated(apiIndexHandler, false))
|
r.Handle("/api", scopedRoute(apiIndexHandler))
|
||||||
r.Handle("/api/renew", authenticated(apiRenewHandler, false))
|
r.Handle("/api/renew", authenticated(apiRenewHandler, false))
|
||||||
r.Handle("/api/clear_cache", authenticated(apiClearCacheHandler, false))
|
r.Handle("/api/clear_cache", authenticated(apiClearCacheHandler, false))
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ func Router() *mux.Router {
|
||||||
r.Handle("/api/integrations/{name}", authenticated(apiIntegrationHandler, false)).Methods("POST")
|
r.Handle("/api/integrations/{name}", authenticated(apiIntegrationHandler, false)).Methods("POST")
|
||||||
|
|
||||||
// API GROUPS Routes
|
// API GROUPS Routes
|
||||||
r.Handle("/api/groups", readOnly(apiAllGroupHandler, false)).Methods("GET")
|
r.Handle("/api/groups", scopedRoute(apiAllGroupHandler)).Methods("GET")
|
||||||
r.Handle("/api/groups", authenticated(apiCreateGroupHandler, false)).Methods("POST")
|
r.Handle("/api/groups", authenticated(apiCreateGroupHandler, false)).Methods("POST")
|
||||||
r.Handle("/api/groups/{id}", readOnly(apiGroupHandler, false)).Methods("GET")
|
r.Handle("/api/groups/{id}", readOnly(apiGroupHandler, false)).Methods("GET")
|
||||||
r.Handle("/api/groups/{id}", authenticated(apiGroupUpdateHandler, false)).Methods("POST")
|
r.Handle("/api/groups/{id}", authenticated(apiGroupUpdateHandler, false)).Methods("POST")
|
||||||
|
@ -131,9 +131,9 @@ 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", http.HandlerFunc(apiAllServicesHandler)).Methods("GET")
|
r.Handle("/api/services", scopedRoute(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}", scopedRoute(apiServiceHandler)).Methods("GET")
|
||||||
r.Handle("/api/reorder/services", authenticated(reorderServiceHandler, false)).Methods("POST")
|
r.Handle("/api/reorder/services", authenticated(reorderServiceHandler, false)).Methods("POST")
|
||||||
r.Handle("/api/services/{id}/running", authenticated(apiServiceRunningHandler, false)).Methods("POST")
|
r.Handle("/api/services/{id}/running", authenticated(apiServiceRunningHandler, false)).Methods("POST")
|
||||||
r.Handle("/api/services/{id}/data", cached("30s", "application/json", apiServiceDataHandler)).Methods("GET")
|
r.Handle("/api/services/{id}/data", cached("30s", "application/json", apiServiceDataHandler)).Methods("GET")
|
||||||
|
|
|
@ -294,15 +294,23 @@ 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)
|
isAdmin := IsAdmin(r)
|
||||||
services := core.Services()
|
services := core.Services()
|
||||||
if !admin {
|
if !isAdmin {
|
||||||
returnSafeJson(w, r, expandServices(services))
|
returnSafeJson(w, r, joinServices(services))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
returnJson(services, w, r)
|
returnJson(services, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func joinServices(srvs []types.ServiceInterface) []types.Service {
|
||||||
|
var services []types.Service
|
||||||
|
for _, v := range srvs {
|
||||||
|
services = append(services, *v.Select())
|
||||||
|
}
|
||||||
|
return services
|
||||||
|
}
|
||||||
|
|
||||||
func servicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
|
func servicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
service := core.SelectService(utils.ToInt(vars["id"]))
|
service := core.SelectService(utils.ToInt(vars["id"]))
|
||||||
|
|
|
@ -23,21 +23,21 @@ 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" private:"true"`
|
Domain string `gorm:"column:domain" json:"domain" private:"true" scope:"user,admin"`
|
||||||
Expected NullString `gorm:"column:expected" json:"expected"`
|
Expected NullString `gorm:"column:expected" json:"expected" scope:"user,admin"`
|
||||||
ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status"`
|
ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status" scope:"user,admin"`
|
||||||
Interval int `gorm:"default:30;column:check_interval" json:"check_interval"`
|
Interval int `gorm:"default:30;column:check_interval" json:"check_interval" scope:"user,admin"`
|
||||||
Type string `gorm:"column:check_type" json:"type"`
|
Type string `gorm:"column:check_type" json:"type" scope:"user,admin"`
|
||||||
Method string `gorm:"column:method" json:"method"`
|
Method string `gorm:"column:method" json:"method" scope:"user,admin"`
|
||||||
PostData NullString `gorm:"column:post_data" json:"post_data"`
|
PostData NullString `gorm:"column:post_data" json:"post_data" scope:"user,admin"`
|
||||||
Port int `gorm:"not null;column:port" json:"port"`
|
Port int `gorm:"not null;column:port" json:"port" scope:"user,admin"`
|
||||||
Timeout int `gorm:"default:30;column:timeout" json:"timeout"`
|
Timeout int `gorm:"default:30;column:timeout" json:"timeout" scope:"user,admin"`
|
||||||
Order int `gorm:"default:0;column:order_id" json:"order_id"`
|
Order int `gorm:"default:0;column:order_id" json:"order_id"`
|
||||||
AllowNotifications NullBool `gorm:"default:true;column:allow_notifications" json:"allow_notifications"`
|
AllowNotifications NullBool `gorm:"default:true;column:allow_notifications" json:"allow_notifications" scope:"user,admin"`
|
||||||
VerifySSL NullBool `gorm:"default:false;column:verify_ssl" json:"verify_ssl"`
|
VerifySSL NullBool `gorm:"default:false;column:verify_ssl" json:"verify_ssl" scope:"user,admin"`
|
||||||
Public NullBool `gorm:"default:true;column:public" json:"public"`
|
Public NullBool `gorm:"default:true;column:public" json:"public"`
|
||||||
GroupId int `gorm:"default:0;column:group_id" json:"group_id"`
|
GroupId int `gorm:"default:0;column:group_id" json:"group_id"`
|
||||||
Headers NullString `gorm:"column:headers" json:"headers"`
|
Headers NullString `gorm:"column:headers" json:"headers" scope:"user,admin"`
|
||||||
Permalink NullString `gorm:"column:permalink" json:"permalink"`
|
Permalink NullString `gorm:"column:permalink" json:"permalink"`
|
||||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||||
|
@ -56,8 +56,8 @@ type Service struct {
|
||||||
SuccessNotified bool `gorm:"-" json:"-"` // Is 'true' if the user has already be informed that the Services now again available
|
SuccessNotified bool `gorm:"-" json:"-"` // Is 'true' if the user has already be informed that the Services now again available
|
||||||
LastStatusCode int `gorm:"-" json:"status_code"`
|
LastStatusCode int `gorm:"-" json:"status_code"`
|
||||||
LastOnline time.Time `gorm:"-" json:"last_success"`
|
LastOnline time.Time `gorm:"-" json:"last_success"`
|
||||||
Failures []FailureInterface `gorm:"-" json:"failures,omitempty"`
|
Failures []FailureInterface `gorm:"-" json:"failures,omitempty" scope:"user,admin"`
|
||||||
Checkins []CheckinInterface `gorm:"-" json:"checkins,omitempty"`
|
Checkins []CheckinInterface `gorm:"-" json:"checkins,omitempty" scope:"user,admin"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeforeCreate for Service will set CreatedAt to UTC
|
// BeforeCreate for Service will set CreatedAt to UTC
|
||||||
|
|
Loading…
Reference in New Issue