- Added DB_DSN env for mysql, postgres or sqlite DSN database connection string
- Added READ_ONLY env for a read only connection to the database
- Added Custom OAuth OpenID toggle switch in settings (appends 'openid' in scope)
- Fixed Custom OAuth response_type issue
- Added Configs tab in Settings to edit the config.yml from frontend
master
Hunter Long 4 years ago committed by GitHub
parent a216187055
commit 93d9dc9915
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,3 +1,10 @@
# 0.90.68 (09-17-2020)
- Added DB_DSN env for mysql, postgres or sqlite DSN database connection string
- Added READ_ONLY env for a read only connection to the database
- Added Custom OAuth OpenID toggle switch in settings (appends 'openid' in scope)
- Fixed Custom OAuth response_type issue
- Added Configs tab in Settings to edit the config.yml from frontend
# 0.90.67 (09-14-2020)
- Modified core settings to update config.yml on save
- Modified Theme Editor to restart the HTTP router on create/delete (fixing 404's)

@ -18,6 +18,10 @@ import (
"time"
)
var (
importAll *bool
)
func assetsCli() error {
dir := utils.Directory
if err := utils.InitLogs(); err != nil {
@ -254,6 +258,9 @@ func importCli(args []string) error {
if len(exportData.Messages) > 0 {
log.Printf("Messages: %d\n", len(exportData.Messages))
}
if len(exportData.Incidents) > 0 {
log.Printf("Incidents: %d\n", len(exportData.Incidents))
}
if len(exportData.Users) > 0 {
log.Printf("Users: %d\n", len(exportData.Users))
}
@ -285,14 +292,14 @@ func importCli(args []string) error {
if ask("Import Core settings?") {
c := exportData.Core
if err := c.Update(); err != nil {
return err
log.Errorln(err)
}
}
for _, s := range exportData.Groups {
if ask(fmt.Sprintf("Import Group '%s'?", s.Name)) {
s.Id = 0
if err := s.Create(); err != nil {
return err
log.Errorln(err)
}
}
}
@ -300,7 +307,7 @@ func importCli(args []string) error {
if ask(fmt.Sprintf("Import Service '%s'?", s.Name)) {
s.Id = 0
if err := s.Create(); err != nil {
return err
log.Errorln(err)
}
}
}
@ -308,7 +315,7 @@ func importCli(args []string) error {
if ask(fmt.Sprintf("Import Checkin '%s'?", s.Name)) {
s.Id = 0
if err := s.Create(); err != nil {
return err
log.Errorln(err)
}
}
}
@ -316,7 +323,7 @@ func importCli(args []string) error {
if ask(fmt.Sprintf("Import Message '%s'?", s.Title)) {
s.Id = 0
if err := s.Create(); err != nil {
return err
log.Errorln(err)
}
}
}
@ -333,6 +340,7 @@ func importCli(args []string) error {
}
func ask(format string) bool {
fmt.Printf(fmt.Sprintf(format + " [y/N]: "))
reader := bufio.NewReader(os.Stdin)
text, _ := reader.ReadString('\n')

@ -169,10 +169,6 @@ func Available(db Database) bool {
return true
}
func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
return db.Where("service = ?", 1000)
}
func (it *Db) MultipleSelects(args ...string) Database {
joined := strings.Join(args, ", ")
return it.Select(joined)
@ -181,6 +177,7 @@ func (it *Db) MultipleSelects(args ...string) Database {
type Db struct {
Database *gorm.DB
Type string
ReadOnly bool
}
// Openw is a drop-in replacement for Open()
@ -223,6 +220,9 @@ func OpenTester() (Database, error) {
default:
dbString = fmt.Sprintf("file:%s?mode=memory&cache=shared", utils.RandomString(12))
}
if utils.Params.IsSet("DB_DSN") {
dbString = utils.Params.GetString("DB_DSN")
}
newDb, err := Openw(testDB, dbString)
if err != nil {
return nil, err
@ -239,6 +239,7 @@ func Wrap(db *gorm.DB) Database {
return &Db{
Database: db,
Type: db.Dialect().GetName(),
ReadOnly: utils.Params.GetBool("READ_ONLY"),
}
}
@ -379,14 +380,26 @@ func (it *Db) Related(value interface{}, foreignKeys ...string) Database {
}
func (it *Db) FirstOrInit(out interface{}, where ...interface{}) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.FirstOrInit(out, where...))
}
func (it *Db) FirstOrCreate(out interface{}, where ...interface{}) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.FirstOrCreate(out, where...))
}
func (it *Db) Update(attrs ...interface{}) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.Update(attrs...))
}
@ -395,22 +408,42 @@ func (it *Db) Updates(values interface{}, ignoreProtectedAttrs ...bool) Database
}
func (it *Db) UpdateColumn(attrs ...interface{}) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.UpdateColumn(attrs...))
}
func (it *Db) UpdateColumns(values interface{}) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.UpdateColumns(values))
}
func (it *Db) Save(value interface{}) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.Save(value))
}
func (it *Db) Create(value interface{}) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.Create(value))
}
func (it *Db) Delete(value interface{}, where ...interface{}) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.Delete(value, where...))
}
@ -435,14 +468,26 @@ func (it *Db) Debug() Database {
}
func (it *Db) Begin() Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.Begin())
}
func (it *Db) Commit() Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.Commit())
}
func (it *Db) Rollback() Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.Rollback())
}
@ -455,14 +500,26 @@ func (it *Db) RecordNotFound() bool {
}
func (it *Db) CreateTable(values ...interface{}) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.CreateTable(values...))
}
func (it *Db) DropTable(values ...interface{}) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.DropTable(values...))
}
func (it *Db) DropTableIfExists(values ...interface{}) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.DropTableIfExists(values...))
}
@ -471,26 +528,50 @@ func (it *Db) HasTable(value interface{}) bool {
}
func (it *Db) AutoMigrate(values ...interface{}) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.AutoMigrate(values...))
}
func (it *Db) ModifyColumn(column string, typ string) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.ModifyColumn(column, typ))
}
func (it *Db) DropColumn(column string) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.DropColumn(column))
}
func (it *Db) AddIndex(indexName string, columns ...string) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.AddIndex(indexName, columns...))
}
func (it *Db) AddUniqueIndex(indexName string, columns ...string) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.AddUniqueIndex(indexName, columns...))
}
func (it *Db) RemoveIndex(indexName string) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.RemoveIndex(indexName))
}
@ -519,6 +600,10 @@ func (it *Db) SetJoinTableHandler(source interface{}, column string, handler gor
}
func (it *Db) AddForeignKey(field string, dest string, onDelete string, onUpdate string) Database {
if it.ReadOnly {
it.Database.Error = nil
return Wrap(it.Database)
}
return Wrap(it.Database.AddForeignKey(field, dest, onDelete, onUpdate))
}

@ -16,6 +16,8 @@ var (
// Maintenance will automatically delete old records from 'failures' and 'hits'
// this function is currently set to delete records 7+ days old every 60 minutes
// env: REMOVE_AFTER - golang duration parsed time for deleting records older than REMOVE_AFTER duration from now
// env: CLEANUP_INTERVAL - golang duration parsed time for checking old records routine
func Maintenance() {
dur := utils.Params.GetDuration("REMOVE_AFTER")
interval := utils.Params.GetDuration("CLEANUP_INTERVAL")

42
dev/kubernetes.yml vendored

@ -0,0 +1,42 @@
apiVersion: v1
kind: Service
metadata:
name: statping
spec:
ports:
- port: 8080
selector:
app: statping
clusterIP: None
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: statping
spec:
selector:
matchLabels:
app: statping
strategy:
type: Recreate
template:
metadata:
labels:
app: statping
spec:
containers:
- image: statping/statping
name: statping
env:
- name: ALLOW_REPORTS
value: "true"
ports:
- containerPort: 8080
name: statping
volumeMounts:
- name: statping-storage
mountPath: /app
volumes:
- name: statping-storage
persistentVolumeClaim:
claimName: statping-claim

@ -7,8 +7,8 @@ const tokenKey = "statping_auth";
class Api {
constructor() {
this.version = "0.90.66";
this.commit = "a3ce4124f654b13c7f2af88b8410f998bd57fcef";
this.version = "0.90.67";
this.commit = "7e121335791d2143a2eefd404dbcce83b8f46f61";
}
async oauth() {
@ -261,6 +261,14 @@ class Api {
})
}
async configs() {
return axios.get('api/settings/configs').then(response => (response.data)) || []
}
async configs_save(data) {
return axios.post('api/settings/configs', data).then(response => (response.data)) || []
}
token() {
return $cookies.get(tokenKey);
}

@ -10,10 +10,6 @@ A {
color: $text-color;
}
A:HOVER {
color: lighten($text-color, 12%) !important;
}
.modal-backdrop {
position: absolute;
top: 0;

@ -0,0 +1,67 @@
<template>
<div>
<h3>Configuration</h3>
For security reasons, all database credentials cannot be editted from this page.
<codemirror v-show="loaded" v-model="configs" ref="configs" :options="cmOptions" class="mt-4 codemirrorInput"/>
<button @click.prevent="save" class="btn col-12 btn-primary mt-3">Save</button>
</div>
</template>
<script>
import Api from "../../API";
import {codemirror} from 'vue-codemirror'
import('codemirror/lib/codemirror.css')
import('codemirror/mode/yaml/yaml.js')
export default {
name: "Configs",
components: {
codemirror
},
data() {
return {
loaded: false,
configs: null,
cmOptions: {
height: 700,
tabSize: 4,
lineNumbers: true,
matchBrackets: true,
mode: "text/x-yaml",
line: true
}
}
},
mounted() {
this.loaded = false
this.update()
this.loaded = true
},
watch: {
"configs" () {
this.$refs.configs.codemirror.refresh()
}
},
methods: {
async update() {
this.configs = await Api.configs()
this.$refs.configs.codemirror.value = this.configs
this.$refs.configs.codemirror.refresh()
},
async save() {
try {
await Api.configs_save(this.configs)
} catch(e) {
window.console.error(e)
}
}
}
}
</script>
<style scoped>
</style>

@ -6,14 +6,16 @@
</p>
<div v-if="!loaded" class="mt-4 row">
<div class="col-6 custom-file">
<input @change="onFileChange" type="file" class="custom-file-input" id="customFile" accept=".json,application/json">
<div class="col-8 custom-file">
<input @change="onFileChange" type="file" class="custom-file-input pointer" id="customFile" accept=".json,application/json">
<label class="custom-file-label" for="customFile">Choose exported Statping JSON file</label>
</div>
<a class="ml-2 col-2 btn btn-light btn-outline-secondary" href="/api/settings/export">Export</a>
<div class="col-4">
<a class="btn btn-block btn-light btn-outline-secondary" href="/api/settings/export">Export</a>
</div>
</div>
<div v-if="loaded" class="col-12 mb-3">
<div v-if="loaded" class="col-12 mb-4">
<h3>Core Settings
<span @click="file.core.enabled = !!file.core.enabled" class="switch switch-sm float-right">
<input @change="update" v-model="file.core.enabled" type="checkbox" class="switch" :id="`switch-core`">
@ -21,13 +23,13 @@
</span>
</h3>
<div class="row"><span class="col-4">Name</span><span class="col-8 text-right font-weight-bold">{{file.core.name}}</span></div>
<div class="row"><span class="col-4">Description</span><span class="col-8 text-right font-weight-bold">{{file.core.description}}</span></div>
<div class="row"><span class="col-4">Domain</span><span class="col-8 text-right font-weight-bold">{{file.core.domain}}</span></div>
<div class="row mb-2"><span class="col-4">Name</span><span class="col-8 text-right font-weight-bold">{{file.core.name}}</span></div>
<div class="row mb-2"><span class="col-4">Description</span><span class="col-8 text-right font-weight-bold">{{file.core.description}}</span></div>
<div class="row mb-2"><span class="col-4">Domain</span><span class="col-8 text-right font-weight-bold">{{file.core.domain}}</span></div>
</div>
<div v-if="loaded" class="col-12 mb-3">
<div v-if="loaded" class="col-12 mb-4">
<h3>Users
<button @click.prevent="toggle_all(file.users)" class="btn btn-sm btn-outline-dark float-right mt-1">Select All</button>
</h3>
@ -51,7 +53,7 @@
</div>
<div v-if="loaded" class="col-12 mb-3">
<div v-if="loaded" class="col-12 mb-4">
<h3>Checkins
<button @click.prevent="toggle_all(file.checkins)" class="btn btn-sm btn-outline-dark float-right mt-1">Select All</button>
</h3>
@ -60,10 +62,10 @@
</div>
<div v-for="checkin in file.checkins" v-bind:key="checkin.id" class="row">
<div class="col-4 font-weight-bold">
{{checkin.id}}
{{checkin.name}}
</div>
<div class="col-6">
{{checkin.service_id}}
Service #{{checkin.service_id}}
</div>
<div class="col-2 text-right">
<span @click="checkin.enabled = !!checkin.enabled" class="switch switch-sm">
@ -74,7 +76,7 @@
</div>
</div>
<div v-if="loaded" class="col-12 mb-3">
<div v-if="loaded" class="col-12 mb-4">
<h3>Services
<button @click.prevent="toggle_all(file.services)" class="btn btn-sm btn-outline-dark float-right mt-1">Select All</button>
</h3>
@ -97,7 +99,7 @@
</div>
</div>
<div v-if="loaded" class="col-12 mb-3">
<div v-if="loaded" class="col-12 mb-4">
<h3>Groups
<button @click.prevent="toggle_all(file.groups)" class="btn btn-sm btn-outline-dark float-right mt-1">Select All</button>
</h3>
@ -117,6 +119,26 @@
</div>
</div>
<div v-if="loaded" class="col-12 mb-4">
<h3>Incidents
<button @click.prevent="toggle_all(file.incidents)" class="btn btn-sm btn-outline-dark float-right mt-1">Select All</button>
</h3>
<div v-if="!file.incidents" class="alert alert-link">
No Incidents in file
</div>
<div v-for="incident in file.incidents" v-bind:key="incident.id" class="row">
<div class="col-4 font-weight-bold">
{{incident.name}}
</div>
<div class="col-8 text-right">
<span @click="incident.enabled = !!incident.enabled" class="switch switch-sm">
<input @change="update" v-model="incident.enabled" type="checkbox" class="switch" :id="`switch-incident-${incident.id}`">
<label :for="`switch-incident-${incident.id}`"></label>
</span>
</div>
</div>
</div>
<div v-if="loaded" class="col-12 mb-3">
<h3>Notifiers
<button @click.prevent="toggle_all(file.notifiers)" class="btn btn-sm btn-outline-dark float-right mt-1">Select All</button>
@ -141,7 +163,9 @@
{{error}}
</div>
<button v-if="loaded" @click.prevent="import_all" class="btn btn-success">Import</button>
<div class="col-12">
<button v-if="loaded" @click.prevent="import_all" class="btn btn-block btn-success">Import</button>
</div>
</div>
</template>

@ -95,17 +95,31 @@
}
this.loading = false
},
encode(val) {
return encodeURI(val)
},
custom_scopes() {
let scopes = []
if (this.oauth.custom_open_id) {
scopes.push("openid")
}
scopes.push(this.oauth.custom_scopes.split(","))
if (scopes.length !== 0) {
return "&scopes="+scopes.join(",")
}
return ""
},
GHlogin() {
window.location = `https://github.com/login/oauth/authorize?client_id=${this.oauth.gh_client_id}&redirect_uri=${this.core.domain}/oauth/github&scope=user,repo`
window.location = `https://github.com/login/oauth/authorize?client_id=${this.oauth.gh_client_id}&redirect_uri=${this.encode(this.core.domain+"/oauth/github")}&scope=user,repo`
},
Slacklogin() {
window.location = `https://slack.com/oauth/authorize?client_id=${this.oauth.slack_client_id}&redirect_uri=${this.core.domain}/oauth/slack&scope=identity.basic`
window.location = `https://slack.com/oauth/authorize?client_id=${this.oauth.slack_client_id}&redirect_uri=${this.encode(this.core.domain+"/oauth/slack")}&scope=identity.basic`
},
Googlelogin() {
window.location = `https://accounts.google.com/signin/oauth?client_id=${this.oauth.google_client_id}&redirect_uri=${this.core.domain}/oauth/google&response_type=code&scope=https://www.googleapis.com/auth/userinfo.profile+https://www.googleapis.com/auth/userinfo.email`
window.location = `https://accounts.google.com/signin/oauth?client_id=${this.oauth.google_client_id}&redirect_uri=${this.encode(this.core.domain+"/oauth/google")}&response_type=code&scope=https://www.googleapis.com/auth/userinfo.profile+https://www.googleapis.com/auth/userinfo.email`
},
Customlogin() {
window.location = `${this.oauth.custom_endpoint_auth}?client_id=${this.oauth.custom_client_id}&redirect_uri=${this.core.domain}/oauth/custom${this.oauth.custom_scopes !== "" ? "&scope="+this.oauth.custom_scopes : "" }`
window.location = `${this.oauth.custom_endpoint_auth}?client_id=${this.oauth.custom_client_id}&redirect_uri=${this.encode(this.core.domain+"/oauth/custom")}&response_type=code${this.custom_scopes()}`
}
}
}

@ -168,8 +168,8 @@
<label for="switch-custom-oauth" class="mb-0"> </label>
</span>
</div>
<div class="card-body" :class="{'d-none': !expanded.custom}">
<div class="form-group row mt-3">
<div class="card-body" :class="{'d-none': !expanded.custom || !custom_enabled}">
<div class="form-group row">
<label for="custom_name" class="col-sm-4 col-form-label">Custom Name</label>
<div class="col-sm-8">
<input v-model="oauth.custom_name" type="text" class="form-control" id="custom_name" required>
@ -199,13 +199,24 @@
<input v-model="oauth.custom_endpoint_token" type="text" class="form-control" id="custom_endpoint_token" required>
</div>
</div>
<div class="form-group row">
<label for="custom_scopes" class="col-sm-4 col-form-label">Scopes</label>
<div class="col-sm-8">
<input v-model="oauth.custom_scopes" type="text" class="form-control" id="custom_scopes">
<small>Optional comma delimited list of oauth scopes</small>
</div>
<div class="form-group row">
<label for="custom_scopes" class="col-sm-4 col-form-label">Scopes</label>
<div class="col-sm-8">
<input v-model="oauth.custom_scopes" type="text" class="form-control" id="custom_scopes">
<small>Optional comma delimited list of oauth scopes</small>
</div>
</div>
<div class="form-group row">
<label for="custom_scopes" class="col-sm-4 col-form-label">Open ID</label>
<div class="col-sm-8">
<span @click="oauth.custom_open_id = !!oauth.custom_open_id" class="switch switch-rd-gr float-right">
<input v-model="oauth.custom_open_id" type="checkbox" id="switch-custom-openid" :checked="oauth.custom_open_id">
<label for="switch-custom-openid" class="mb-0"> </label>
</span>
<small>Enable if provider is OpenID</small>
</div>
</div>
<div class="form-group row">
<label for="slack_callback" class="col-sm-4 col-form-label">Callback URL</label>
<div class="col-sm-8">
@ -271,6 +282,7 @@
custom_endpoint_auth: "",
custom_endpoint_token: "",
custom_scopes: "",
custom_open_id: false,
}
}
},

@ -9,6 +9,7 @@ const chinese = {
logout: "注销",
online: "在线",
offline: "离线",
configs: "配置",
username: "用户名",
password: "密码",
email: "电子邮件",

@ -9,6 +9,7 @@ login,Login
logout,Logout
online,Online
offline,Offline
configs,Configuration
username,Username
password,Password
email,Email

1 key en
9 logout Logout
10 online Online
11 offline Offline
12 configs Configuration
13 username Username
14 password Password
15 email Email

@ -9,6 +9,7 @@ const english = {
logout: "Logout",
online: "Online",
offline: "Offline",
configs: "Configuration",
username: "Username",
password: "Password",
email: "Email",

@ -9,6 +9,7 @@ const french = {
logout: "Déconnexion",
online: "En ligne",
offline: "Offline",
configs: "Configuration",
username: "Nom d'utilisateur",
password: "mot de passe",
email: "Email",

@ -9,6 +9,7 @@ const german = {
logout: "Abmelden",
online: "Online",
offline: "Offline",
configs: "Konfiguration",
username: "Benutzername",
password: "Kennwort",
email: "Mail",

@ -9,6 +9,7 @@ const italian = {
logout: "Disconnetti",
online: "Online",
offline: "Offline",
configs: "Configurazione",
username: "Nome utente",
password: "Password",
email: "E-mail",

@ -9,6 +9,7 @@ const japanese = {
logout: "ログアウト",
online: "オンライン",
offline: "オフライン",
configs: "構成",
username: "ユーザ名",
password: "パスワード",
email: "Eメール",

@ -9,6 +9,7 @@ const korean = {
logout: "로그아웃",
online: "온라인",
offline: "오프라인",
configs: "구성",
username: "사용자 이름",
password: "비밀번호",
email: "이메일",

@ -9,6 +9,7 @@ const russian = {
logout: "Выход из системы",
online: "Онлайн",
offline: "Оффлайн",
configs: "Конфигурация",
username: "Имя пользователя",
password: "Пароль",
email: "Электронная почта",

@ -9,6 +9,7 @@ const spanish = {
logout: "Cerrar sesión",
online: "En línea",
offline: "Offline",
configs: "Configuración",
username: "Nombre de usuario",
password: "Contraseña",
email: "Correo",

@ -1545,8 +1545,8 @@ systemctl start statping
<p>You can even run Statping on your Raspberry Pi by installing the precompiled binary from <a href="https://github.com/statping/statping/releases/latest" target="_blank">Latest Releases</a>. For the Raspberry Pi 3 you&rsquo;ll want to download the <code>statping-linux-arm7.tar.gz</code> file. Be sure to change <code>VERSION</code> to the latest version in Releases, and include the &lsquo;v&rsquo;.</p>
<pre><code>VERSION=$(curl -sL &quot;https://github.com/statping/statping/releases/latest&quot; | grep -o 'tag/[v.0-9]*' | awk -F/ '{print $2}' | head -n1)
wget https://github.com/statping/statping/releases/download/$VERSION/statping-linux-arm7.tar.gz
tar -xvzf statping-linux-arm7.tar.gz
wget https://github.com/statping/statping/releases/download/$VERSION/statping-linux-arm-7.tar.gz
tar -xvzf statping-linux-arm-7.tar.gz
chmod +x statping
mv statping /usr/local/bin/statping
@ -2275,7 +2275,7 @@ OluFxewsEO0QNDrfFb+0gnjYlnGqOFcZjUMXbDdY5oLSPtXohynuTK1qyQ==
</div>
<div class="text-center small text-dim" v-pre>
Automatically generated from Statping's Wiki on 2020-09-09 01:24:21.649582 &#43;0000 UTC
Automatically generated from Statping's Wiki on 2020-09-15 19:09:14.703237 &#43;0000 UTC
</div>
</div>

@ -4,10 +4,16 @@
<div class="col-md-3 col-sm-12 mb-4 mb-md-0">
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
<div v-if="version_below" class="alert small text-center mt-0 pt-0 pb-0">
<div v-if="version_below" class="col-12 small text-center mt-0 pt-0 pb-0 mb-3">
Update {{github.tag_name}} Available
<a href="https://github.com/statping/statping/releases/latest" class="btn btn-sm text-success mt-2">Download</a>
<a href="https://github.com/statping/statping/blob/master/CHANGELOG.md" class="btn btn-sm text-dim mt-2">Changelog</a>
<div class="row">
<div class="col-6">
<a href="https://github.com/statping/statping/releases/latest" class="btn btn-sm text-success mt-2">Download</a>
</div>
<div class="col-6">
<a href="https://github.com/statping/statping/blob/master/CHANGELOG.md" class="btn btn-sm text-dim mt-2">Changelog</a>
</div>
</div>
</div>
<h6 class="text-muted">{{ $t('main_settings') }}</h6>
@ -27,6 +33,9 @@
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-import-tab')}" id="v-pills-import-tab" data-toggle="pill" href="#v-pills-import" role="tab" aria-controls="v-pills-import" aria-selected="false">
<font-awesome-icon icon="cloud-download-alt" class="mr-2"/> {{ $t('import') }}
</a>
<a @click.prevent="changeTab" class="nav-link" v-bind:class="{active: liClass('v-pills-configs-tab')}" id="v-pills-configs-tab" data-toggle="pill" href="#v-pills-configs" role="tab" aria-controls="v-pills-configs" aria-selected="false">
<font-awesome-icon icon="cogs" class="mr-2"/> {{ $t('configs') }}
</a>
<h6 class="mt-4 text-muted">{{$t('notifiers')}}</h6>
@ -105,9 +114,13 @@
<Cache/>
</div>
<div class="tab-pane fade" v-bind:class="{active: liClass('v-pills-oauth-tab'), show: liClass('v-pills-oauth-tab')}" id="v-pills-oauth" role="tabpanel" aria-labelledby="v-pills-oauth-tab">
<OAuth/>
</div>
<div class="tab-pane fade" v-bind:class="{active: liClass('v-pills-oauth-tab'), show: liClass('v-pills-oauth-tab')}" id="v-pills-oauth" role="tabpanel" aria-labelledby="v-pills-oauth-tab">
<OAuth/>
</div>
<div class="tab-pane fade" v-bind:class="{active: liClass('v-pills-configs-tab'), show: liClass('v-pills-configs-tab')}" id="v-pills-configs" role="tabpanel" aria-labelledby="v-pills-configs-tab">
<Configs/>
</div>
<div class="tab-pane fade" v-bind:class="{active: liClass('v-pills-import-tab'), show: liClass('v-pills-import-tab')}" id="v-pills-import" role="tabpanel" aria-labelledby="v-pills-import-tab">
<Importer/>
@ -140,10 +153,12 @@
const Cache = () => import(/* webpackChunkName: "dashboard" */ '@/components/Dashboard/Cache')
const Importer = () => import(/* webpackChunkName: "dashboard" */ '@/components/Dashboard/Importer')
const Variables = () => import(/* webpackChunkName: "dashboard" */ '@/components/Dashboard/Variables')
const Configs = () => import(/* webpackChunkName: "dashboard" */ '@/components/Dashboard/Configs')
export default {
name: 'Settings',
components: {
Configs,
Importer,
Variables,
OAuth,

@ -6,6 +6,7 @@ go 1.14
require (
github.com/GeertJohan/go.rice v1.0.0
github.com/aws/aws-sdk-go v1.30.20
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/fatih/structs v1.1.0
github.com/foomo/simplecert v1.7.5
@ -17,12 +18,13 @@ require (
github.com/jinzhu/gorm v1.9.12
github.com/mattn/go-sqlite3 v2.0.3+incompatible
github.com/pkg/errors v0.9.1
github.com/pquerna/cachecontrol v0.0.0-20200819021114-67c6ae64274f // indirect
github.com/prometheus/client_golang v1.1.0
github.com/sirupsen/logrus v1.5.0
github.com/spf13/cobra v1.0.0
github.com/spf13/viper v1.6.3
github.com/statping/emails v1.0.0
github.com/stretchr/testify v1.5.1
github.com/stretchr/testify v1.6.1
github.com/t-tiger/gorm-bulk-insert/v2 v2.0.1
github.com/tensorflow/tensorflow v2.3.0+incompatible // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9

@ -131,6 +131,8 @@ github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk=
github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@ -552,6 +554,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/cachecontrol v0.0.0-20200819021114-67c6ae64274f h1:JDEmUDtyiLMyMlFwiaDOv2hxUp35497fkwePcLeV7j4=
github.com/pquerna/cachecontrol v0.0.0-20200819021114-67c6ae64274f/go.mod h1:hoLfEwdY11HjRfKFH6KqnPsfxlo3BP6bJehpDv8t6sQ=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
@ -652,6 +656,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/t-tiger/gorm-bulk-insert/v2 v2.0.1 h1:HGVkRrwDCbmSP6h1CoBDj6l/mhnvsP5JbYaQ4ss0R6o=
@ -1047,6 +1052,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.0.1 h1:omJoilUzyrAp0xNoio88lGJCroGdIOen9hq2A/+3ifw=
gorm.io/driver/mysql v1.0.1/go.mod h1:KtqSthtg55lFp3S5kUXqlGaelnWpKitn4k1xZTnoiPw=
gorm.io/driver/postgres v1.0.0 h1:Yh4jyFQ0a7F+JPU0Gtiam/eKmpT/XFc1FKxotGqc6FM=

@ -10,11 +10,13 @@ import (
"github.com/statping/statping/types/core"
"github.com/statping/statping/types/errors"
"github.com/statping/statping/types/groups"
"github.com/statping/statping/types/incidents"
"github.com/statping/statping/types/messages"
"github.com/statping/statping/types/notifications"
"github.com/statping/statping/types/services"
"github.com/statping/statping/types/users"
"github.com/statping/statping/utils"
"gopkg.in/yaml.v2"
"io"
"io/ioutil"
"net/http"
@ -162,14 +164,16 @@ func apiThemeRemoveHandler(w http.ResponseWriter, r *http.Request) {
}
type ExportData struct {
Config *configs.DbConfig `json:"config,omitempty"`
Core *core.Core `json:"core"`
Services []services.Service `json:"services"`
Messages []*messages.Message `json:"messages"`
Checkins []*checkins.Checkin `json:"checkins"`
Users []*users.User `json:"users"`
Groups []*groups.Group `json:"groups"`
Notifiers []notifications.Notification `json:"notifiers"`
Config *configs.DbConfig `json:"config,omitempty"`
Core *core.Core `json:"core"`
Services []services.Service `json:"services"`
Messages []*messages.Message `json:"messages"`
Incidents []*incidents.Incident `json:"incidents"`
IncidentUpdates []*incidents.IncidentUpdate `json:"incident_updates"`
Checkins []*checkins.Checkin `json:"checkins"`
Users []*users.User `json:"users"`
Groups []*groups.Group `json:"groups"`
Notifiers []notifications.Notification `json:"notifiers"`
}
func (e *ExportData) JSON() []byte {
@ -261,6 +265,44 @@ func settingsImportHandler(w http.ResponseWriter, r *http.Request) {
sendJsonAction(exportData, "import", w, r)
}
func configsSaveHandler(w http.ResponseWriter, r *http.Request) {
data, err := ioutil.ReadAll(r.Body)
if err != nil {
sendErrorJson(err, w, r)
return
}
defer r.Body.Close()
var cfg *configs.DbConfig
if err := yaml.Unmarshal(data, &cfg); err != nil {
sendErrorJson(err, w, r)
return
}
oldCfg, err := configs.LoadConfigs(utils.Directory + "/configs.yml")
if err != nil {
sendErrorJson(err, w, r)
return
}
newCfg := cfg.Merge(oldCfg)
if err := newCfg.Save(utils.Directory); err != nil {
sendErrorJson(err, w, r)
return
}
sendJsonAction(newCfg.Clean(), "updated", w, r)
}
func configsViewHandler(w http.ResponseWriter, r *http.Request) {
db, err := configs.LoadConfigs(utils.Directory + "/configs.yml")
if err != nil {
sendErrorJson(err, w, r)
return
}
w.Write(db.Clean().ToYAML())
}
func settingsExportHandler(w http.ResponseWriter, r *http.Request) {
exported, err := ExportSettings()
if err != nil {

@ -11,9 +11,7 @@ import (
func customOAuth(r *http.Request) (*oAuth, error) {
auth := core.App.OAuth
code := r.URL.Query().Get("code")
scopes := strings.Split(auth.CustomScopes, ",")
config := &oauth2.Config{
ClientID: auth.CustomClientID,
ClientSecret: auth.CustomClientSecret,

@ -103,6 +103,8 @@ func Router() *mux.Router {
api.Handle("/api/logs/last", authenticated(logsLineHandler, false)).Methods("GET")
api.Handle("/api/settings/import", authenticated(settingsImportHandler, false)).Methods("POST")
api.Handle("/api/settings/export", authenticated(settingsExportHandler, false)).Methods("GET")
api.Handle("/api/settings/configs", authenticated(configsViewHandler, false)).Methods("GET")
api.Handle("/api/settings/configs", authenticated(configsSaveHandler, false)).Methods("POST")
// API OAUTH Routes
api.Handle("/api/oauth", scoped(apiOAuthHandler)).Methods("GET")

@ -59,7 +59,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
return
}
if err := configs.CreateAdminUser(confgs); err != nil {
if err := configs.CreateAdminUser(); err != nil {
sendErrorJson(err, w, r)
return
}

@ -22,7 +22,7 @@ type discord struct {
var Discorder = &discord{&notifications.Notification{
Method: "discord",
Title: "discord",
Title: "Discord",
Description: "Send notifications to your discord channel using discord webhooks. Insert your discord channel Webhook URL to receive notifications. Based on the <a href=\"https://discordapp.com/developers/docs/resources/Webhook\">discord webhooker API</a>.",
Author: "Hunter Long",
AuthorUrl: "https://github.com/hunterlong",

@ -29,7 +29,7 @@ func (s *slack) Select() *notifications.Notification {
var slacker = &slack{&notifications.Notification{
Method: slackMethod,
Title: "slack",
Title: "Slack",
Description: "Send notifications to your slack channel when a service is offline. Insert your Incoming webhook URL for your channel to receive notifications. Based on the <a href=\"https://api.slack.com/incoming-webhooks\">Slack API</a>.",
Author: "Hunter Long",
AuthorUrl: "https://github.com/hunterlong",

@ -20,6 +20,7 @@ import (
"time"
)
// initModels sets the database for each Statping type packages
func initModels(db database.Database) {
core.SetDB(db)
services.SetDB(db)
@ -67,6 +68,10 @@ func Connect(configs *DbConfig, retry bool) error {
log.Infoln(fmt.Sprintf("Database %s connection was successful.", configs.DbConn))
}
if utils.Params.GetBool("READ_ONLY") {
log.Warnln("Running in READ ONLY MODE")
}
configs.Db = dbSession
initModels(configs.Db)
@ -74,7 +79,9 @@ func Connect(configs *DbConfig, retry bool) error {
return err
}
func CreateAdminUser(c *DbConfig) error {
// CreateAdminUser will create the default admin user "admin", "admin", or use the
// environment variables ADMIN_USER, ADMIN_PASSWORD, and ADMIN_EMAIL if set.
func CreateAdminUser() error {
adminUser := utils.Params.GetString("ADMIN_USER")
adminPass := utils.Params.GetString("ADMIN_PASSWORD")
adminEmail := utils.Params.GetString("ADMIN_EMAIL")

@ -8,8 +8,9 @@ import (
"strings"
)
var log = utils.Log
var log = utils.Log.WithField("type", "configs")
// ConnectConfigs will connect to the database and save the config.yml file
func ConnectConfigs(configs *DbConfig, retry bool) error {
err := Connect(configs, retry)
if err != nil {
@ -21,6 +22,8 @@ func ConnectConfigs(configs *DbConfig, retry bool) error {
return nil
}
// findDbFile will attempt to find the "statping.db" database file in the current
// working directory, or from STATPING_DIR env.
func findDbFile(configs *DbConfig) (string, error) {
location := utils.Directory + "/" + SqliteFilename
if configs == nil {
@ -37,6 +40,7 @@ func findDbFile(configs *DbConfig) (string, error) {
return location, nil
}
// findSQLin walks the current walking directory for statping.db
func findSQLin(path string) (string, error) {
filename := SqliteFilename
var found []string

@ -18,6 +18,37 @@ func (d *DbConfig) Save(directory string) error {
return nil
}
// Merge will merge the database connection info into the input
func (d *DbConfig) Merge(newCfg *DbConfig) *DbConfig {
d.DbConn = newCfg.DbConn
d.DbHost = newCfg.DbHost
d.DbPort = newCfg.DbPort
d.DbData = newCfg.DbData
d.DbUser = newCfg.DbUser
d.DbPass = newCfg.DbPass
return d
}
// Clean hides all sensitive database information for API requests
func (d *DbConfig) Clean() *DbConfig {
d.DbConn = ""
d.DbHost = ""
d.DbPort = 0
d.DbData = ""
d.DbUser = ""
d.DbPass = ""
return d
}
func (d *DbConfig) ToYAML() []byte {
c, err := yaml.Marshal(d)
if err != nil {
log.Errorln(err)
return nil
}
return c
}
func (d *DbConfig) ConnectionString() string {
var conn string
postgresSSL := utils.Params.GetString("POSTGRES_SSLMODE")

@ -38,7 +38,7 @@ func (d *DbConfig) ResetCore() error {
if err := d.CreateDatabase(); err != nil {
return errors.Wrap(err, "error creating database")
}
if err := CreateAdminUser(d); err != nil {
if err := CreateAdminUser(); err != nil {
return errors.Wrap(err, "error creating default admin user")
}
if utils.Params.GetBool("SAMPLE_DATA") {

@ -6,15 +6,15 @@ const SqliteFilename = "statping.db"
// DbConfig struct is used for the Db connection and creates the 'config.yml' file
type DbConfig struct {
DbConn string `yaml:"connection" json:"connection"`
DbHost string `yaml:"host" json:"-"`
DbUser string `yaml:"user" json:"-"`
DbPass string `yaml:"password" json:"-"`
DbData string `yaml:"database" json:"-"`
DbPort int `yaml:"port" json:"-"`
ApiSecret string `yaml:"api_secret" json:"-"`
Language string `yaml:"language" json:"language"`
AllowReports bool `yaml:"allow_reports" json:"allow_reports"`
DbConn string `yaml:"connection,omitempty" json:"connection"`
DbHost string `yaml:"host,omitempty" json:"-"`
DbUser string `yaml:"user,omitempty" json:"-"`
DbPass string `yaml:"password,omitempty" json:"-"`
DbData string `yaml:"database,omitempty" json:"-"`
DbPort int `yaml:"port,omitempty" json:"-"`
ApiSecret string `yaml:"api_secret,omitempty" json:"-"`
Language string `yaml:"language,omitempty" json:"language"`
AllowReports bool `yaml:"allow_reports,omitempty" json:"allow_reports"`
Project string `yaml:"-" json:"-"`
Description string `yaml:"-" json:"-"`
Domain string `yaml:"-" json:"-"`
@ -22,7 +22,7 @@ type DbConfig struct {
Password string `yaml:"-" json:"-"`
Email string `yaml:"-" json:"-"`
Error error `yaml:"-" json:"-"`
Location string `yaml:"location" json:"-"`
Location string `yaml:"location,omitempty" json:"-"`
SqlFile string `yaml:"sqlfile,omitempty" json:"-"`
LetsEncryptHost string `yaml:"letsencrypt_host,omitempty" json:"letsencrypt_host"`
LetsEncryptEmail string `yaml:"letsencrypt_email,omitempty" json:"letsencrypt_email"`
@ -33,21 +33,21 @@ type DbConfig struct {
DemoMode bool `yaml:"demo_mode" json:"demo_mode"`
DisableLogs bool `yaml:"disable_logs" json:"disable_logs"`
UseAssets bool `yaml:"use_assets" json:"use_assets"`
BasePath string `yaml:"base_path" json:"base_path"`
BasePath string `yaml:"base_path,omitempty" json:"base_path"`
AdminUser string `yaml:"admin_user" json:"admin_user"`
AdminPassword string `yaml:"admin_password" json:"admin_password"`
AdminEmail string `yaml:"admin_email" json:"admin_email"`
AdminUser string `yaml:"admin_user,omitempty" json:"admin_user"`
AdminPassword string `yaml:"admin_password,omitempty" json:"admin_password"`
AdminEmail string `yaml:"admin_email,omitempty" json:"admin_email"`
MaxOpenConnections int `yaml:"db_open_connections" json:"db_open_connections"`
MaxIdleConnections int `yaml:"db_idle_connections" json:"db_idle_connections"`
MaxLifeConnections int `yaml:"db_max_life_connections" json:"db_max_life_connections"`
MaxOpenConnections int `yaml:"db_open_connections,omitempty" json:"db_open_connections"`
MaxIdleConnections int `yaml:"db_idle_connections,omitempty" json:"db_idle_connections"`
MaxLifeConnections int `yaml:"db_max_life_connections,omitempty" json:"db_max_life_connections"`
SampleData bool `yaml:"sample_data" json:"sample_data"`
UseCDN bool `yaml:"use_cdn" json:"use_cdn"`
DisableColors bool `yaml:"disable_colors" json:"disable_colors"`
PostgresSSLMode string `yaml:"postgres_ssl" json:"postgres_ssl"`
PostgresSSLMode string `yaml:"postgres_ssl,omitempty" json:"postgres_ssl"`
Db database.Database `yaml:"-" json:"-"`
}

@ -45,24 +45,25 @@ type Core struct {
}
type OAuth struct {
Providers string `gorm:"column:oauth_providers;" json:"oauth_providers"`
GithubClientID string `gorm:"column:gh_client_id" json:"gh_client_id"`
GithubClientSecret string `gorm:"column:gh_client_secret" json:"gh_client_secret" scope:"admin"`
GithubUsers string `gorm:"column:gh_users" json:"gh_users" scope:"admin"`
GithubOrgs string `gorm:"column:gh_orgs" json:"gh_orgs" scope:"admin"`
GoogleClientID string `gorm:"column:google_client_id" json:"google_client_id"`
GoogleClientSecret string `gorm:"column:google_client_secret" json:"google_client_secret" scope:"admin"`
GoogleUsers string `gorm:"column:google_users" json:"google_users" scope:"admin"`
SlackClientID string `gorm:"column:slack_client_id" json:"slack_client_id"`
SlackClientSecret string `gorm:"column:slack_client_secret" json:"slack_client_secret" scope:"admin"`
SlackTeam string `gorm:"column:slack_team" json:"slack_team" scope:"admin"`
SlackUsers string `gorm:"column:slack_users" json:"slack_users" scope:"admin"`
CustomName string `gorm:"column:custom_name" json:"custom_name"`
CustomClientID string `gorm:"column:custom_client_id" json:"custom_client_id"`
CustomClientSecret string `gorm:"column:custom_client_secret" json:"custom_client_secret" scope:"admin"`
CustomEndpointAuth string `gorm:"column:custom_endpoint_auth" json:"custom_endpoint_auth"`
CustomEndpointToken string `gorm:"column:custom_endpoint_token" json:"custom_endpoint_token" scope:"admin"`
CustomScopes string `gorm:"column:custom_scopes" json:"custom_scopes"`
Providers string `gorm:"column:oauth_providers;" json:"oauth_providers"`
GithubClientID string `gorm:"column:gh_client_id" json:"gh_client_id"`
GithubClientSecret string `gorm:"column:gh_client_secret" json:"gh_client_secret" scope:"admin"`
GithubUsers string `gorm:"column:gh_users" json:"gh_users" scope:"admin"`
GithubOrgs string `gorm:"column:gh_orgs" json:"gh_orgs" scope:"admin"`
GoogleClientID string `gorm:"column:google_client_id" json:"google_client_id"`
GoogleClientSecret string `gorm:"column:google_client_secret" json:"google_client_secret" scope:"admin"`
GoogleUsers string `gorm:"column:google_users" json:"google_users" scope:"admin"`
SlackClientID string `gorm:"column:slack_client_id" json:"slack_client_id"`
SlackClientSecret string `gorm:"column:slack_client_secret" json:"slack_client_secret" scope:"admin"`
SlackTeam string `gorm:"column:slack_team" json:"slack_team" scope:"admin"`
SlackUsers string `gorm:"column:slack_users" json:"slack_users" scope:"admin"`
CustomName string `gorm:"column:custom_name" json:"custom_name"`
CustomClientID string `gorm:"column:custom_client_id" json:"custom_client_id"`
CustomClientSecret string `gorm:"column:custom_client_secret" json:"custom_client_secret" scope:"admin"`
CustomEndpointAuth string `gorm:"column:custom_endpoint_auth" json:"custom_endpoint_auth"`
CustomEndpointToken string `gorm:"column:custom_endpoint_token" json:"custom_endpoint_token" scope:"admin"`
CustomScopes string `gorm:"column:custom_scopes" json:"custom_scopes"`
CustomIsOpenID null.NullBool `gorm:"column:custom_open_id" json:"custom_open_id"`
}
// AllNotifiers contains all the Notifiers loaded

@ -30,6 +30,7 @@ func InitEnvs() {
Params.SetDefault("DEBUG", false)
Params.SetDefault("DEMO_MODE", false)
Params.SetDefault("DB_CONN", "")
Params.SetDefault("DB_DSN", "")
Params.SetDefault("DISABLE_LOGS", false)
Params.SetDefault("USE_ASSETS", false)
Params.SetDefault("BASE_PATH", "")
@ -53,6 +54,7 @@ func InitEnvs() {
Params.SetDefault("LETSENCRYPT_EMAIL", "")
Params.SetDefault("LETSENCRYPT_LOCAL", false)
Params.SetDefault("LETSENCRYPT_ENABLE", false)
Params.SetDefault("READ_ONLY", false)
Params.SetDefault("LOGS_MAX_COUNT", 5)
Params.SetDefault("LOGS_MAX_AGE", 28)
Params.SetDefault("LOGS_MAX_SIZE", 16)

@ -1 +1 @@
0.90.67
0.90.68
Loading…
Cancel
Save