mirror of https://github.com/statping/statping
frontend change, oauth fixes
parent
edeac80ee7
commit
4fec05c43e
|
@ -1,4 +1,4 @@
|
||||||
# 0.90.68 (09-15-2020)
|
# 0.90.68 (09-17-2020)
|
||||||
- Added DB_DSN env for mysql, postgres or sqlite DSN database connection string
|
- 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 READ_ONLY env for a read only connection to the database
|
||||||
- Added Custom OAuth OpenID toggle switch in settings (appends 'openid' in scope)
|
- Added Custom OAuth OpenID toggle switch in settings (appends 'openid' in scope)
|
||||||
|
|
18
cmd/cli.go
18
cmd/cli.go
|
@ -18,6 +18,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
importAll *bool
|
||||||
|
)
|
||||||
|
|
||||||
func assetsCli() error {
|
func assetsCli() error {
|
||||||
dir := utils.Directory
|
dir := utils.Directory
|
||||||
if err := utils.InitLogs(); err != nil {
|
if err := utils.InitLogs(); err != nil {
|
||||||
|
@ -254,6 +258,9 @@ func importCli(args []string) error {
|
||||||
if len(exportData.Messages) > 0 {
|
if len(exportData.Messages) > 0 {
|
||||||
log.Printf("Messages: %d\n", len(exportData.Messages))
|
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 {
|
if len(exportData.Users) > 0 {
|
||||||
log.Printf("Users: %d\n", len(exportData.Users))
|
log.Printf("Users: %d\n", len(exportData.Users))
|
||||||
}
|
}
|
||||||
|
@ -285,14 +292,14 @@ func importCli(args []string) error {
|
||||||
if ask("Import Core settings?") {
|
if ask("Import Core settings?") {
|
||||||
c := exportData.Core
|
c := exportData.Core
|
||||||
if err := c.Update(); err != nil {
|
if err := c.Update(); err != nil {
|
||||||
return err
|
log.Errorln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, s := range exportData.Groups {
|
for _, s := range exportData.Groups {
|
||||||
if ask(fmt.Sprintf("Import Group '%s'?", s.Name)) {
|
if ask(fmt.Sprintf("Import Group '%s'?", s.Name)) {
|
||||||
s.Id = 0
|
s.Id = 0
|
||||||
if err := s.Create(); err != nil {
|
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)) {
|
if ask(fmt.Sprintf("Import Service '%s'?", s.Name)) {
|
||||||
s.Id = 0
|
s.Id = 0
|
||||||
if err := s.Create(); err != nil {
|
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)) {
|
if ask(fmt.Sprintf("Import Checkin '%s'?", s.Name)) {
|
||||||
s.Id = 0
|
s.Id = 0
|
||||||
if err := s.Create(); err != nil {
|
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)) {
|
if ask(fmt.Sprintf("Import Message '%s'?", s.Title)) {
|
||||||
s.Id = 0
|
s.Id = 0
|
||||||
if err := s.Create(); err != nil {
|
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 {
|
func ask(format string) bool {
|
||||||
|
|
||||||
fmt.Printf(fmt.Sprintf(format + " [y/N]: "))
|
fmt.Printf(fmt.Sprintf(format + " [y/N]: "))
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
text, _ := reader.ReadString('\n')
|
text, _ := reader.ReadString('\n')
|
||||||
|
|
|
@ -265,6 +265,10 @@ class Api {
|
||||||
return axios.get('api/settings/configs').then(response => (response.data)) || []
|
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() {
|
token() {
|
||||||
return $cookies.get(tokenKey);
|
return $cookies.get(tokenKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
<codemirror v-show="loaded" v-model="configs" ref="configs" :options="cmOptions" class="mt-4 codemirrorInput"/>
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ name: "Configs",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loaded: false,
|
loaded: false,
|
||||||
configs: "okkoko: okokoko",
|
configs: null,
|
||||||
cmOptions: {
|
cmOptions: {
|
||||||
height: 700,
|
height: 700,
|
||||||
tabSize: 4,
|
tabSize: 4,
|
||||||
|
@ -35,14 +36,27 @@ name: "Configs",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.loaded = false
|
||||||
this.update()
|
this.update()
|
||||||
|
this.loaded = true
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
"configs" () {
|
||||||
|
this.$refs.configs.codemirror.refresh()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async update() {
|
async update() {
|
||||||
this.loaded = false
|
|
||||||
this.configs = await Api.configs()
|
this.configs = await Api.configs()
|
||||||
this.loaded = true
|
this.$refs.configs.codemirror.value = this.configs
|
||||||
this.$refs.configs.codemirror.refresh()
|
this.$refs.configs.codemirror.refresh()
|
||||||
|
},
|
||||||
|
async save() {
|
||||||
|
try {
|
||||||
|
await Api.configs_save(this.configs)
|
||||||
|
} catch(e) {
|
||||||
|
window.console.error(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ const chinese = {
|
||||||
logout: "注销",
|
logout: "注销",
|
||||||
online: "在线",
|
online: "在线",
|
||||||
offline: "离线",
|
offline: "离线",
|
||||||
|
configs: "配置",
|
||||||
username: "用户名",
|
username: "用户名",
|
||||||
password: "密码",
|
password: "密码",
|
||||||
email: "电子邮件",
|
email: "电子邮件",
|
||||||
|
|
|
@ -9,6 +9,7 @@ const english = {
|
||||||
logout: "Logout",
|
logout: "Logout",
|
||||||
online: "Online",
|
online: "Online",
|
||||||
offline: "Offline",
|
offline: "Offline",
|
||||||
|
configs: "Configuration",
|
||||||
username: "Username",
|
username: "Username",
|
||||||
password: "Password",
|
password: "Password",
|
||||||
email: "Email",
|
email: "Email",
|
||||||
|
|
|
@ -9,6 +9,7 @@ const french = {
|
||||||
logout: "Déconnexion",
|
logout: "Déconnexion",
|
||||||
online: "En ligne",
|
online: "En ligne",
|
||||||
offline: "Offline",
|
offline: "Offline",
|
||||||
|
configs: "Configuration",
|
||||||
username: "Nom d'utilisateur",
|
username: "Nom d'utilisateur",
|
||||||
password: "mot de passe",
|
password: "mot de passe",
|
||||||
email: "Email",
|
email: "Email",
|
||||||
|
|
|
@ -9,6 +9,7 @@ const german = {
|
||||||
logout: "Abmelden",
|
logout: "Abmelden",
|
||||||
online: "Online",
|
online: "Online",
|
||||||
offline: "Offline",
|
offline: "Offline",
|
||||||
|
configs: "Konfiguration",
|
||||||
username: "Benutzername",
|
username: "Benutzername",
|
||||||
password: "Kennwort",
|
password: "Kennwort",
|
||||||
email: "Mail",
|
email: "Mail",
|
||||||
|
|
|
@ -9,6 +9,7 @@ const italian = {
|
||||||
logout: "Disconnetti",
|
logout: "Disconnetti",
|
||||||
online: "Online",
|
online: "Online",
|
||||||
offline: "Offline",
|
offline: "Offline",
|
||||||
|
configs: "Configurazione",
|
||||||
username: "Nome utente",
|
username: "Nome utente",
|
||||||
password: "Password",
|
password: "Password",
|
||||||
email: "E-mail",
|
email: "E-mail",
|
||||||
|
|
|
@ -9,6 +9,7 @@ const japanese = {
|
||||||
logout: "ログアウト",
|
logout: "ログアウト",
|
||||||
online: "オンライン",
|
online: "オンライン",
|
||||||
offline: "オフライン",
|
offline: "オフライン",
|
||||||
|
configs: "構成",
|
||||||
username: "ユーザ名",
|
username: "ユーザ名",
|
||||||
password: "パスワード",
|
password: "パスワード",
|
||||||
email: "Eメール",
|
email: "Eメール",
|
||||||
|
|
|
@ -9,6 +9,7 @@ const korean = {
|
||||||
logout: "로그아웃",
|
logout: "로그아웃",
|
||||||
online: "온라인",
|
online: "온라인",
|
||||||
offline: "오프라인",
|
offline: "오프라인",
|
||||||
|
configs: "구성",
|
||||||
username: "사용자 이름",
|
username: "사용자 이름",
|
||||||
password: "비밀번호",
|
password: "비밀번호",
|
||||||
email: "이메일",
|
email: "이메일",
|
||||||
|
|
|
@ -9,6 +9,7 @@ const russian = {
|
||||||
logout: "Выход из системы",
|
logout: "Выход из системы",
|
||||||
online: "Онлайн",
|
online: "Онлайн",
|
||||||
offline: "Оффлайн",
|
offline: "Оффлайн",
|
||||||
|
configs: "Конфигурация",
|
||||||
username: "Имя пользователя",
|
username: "Имя пользователя",
|
||||||
password: "Пароль",
|
password: "Пароль",
|
||||||
email: "Электронная почта",
|
email: "Электронная почта",
|
||||||
|
|
|
@ -9,6 +9,7 @@ const spanish = {
|
||||||
logout: "Cerrar sesión",
|
logout: "Cerrar sesión",
|
||||||
online: "En línea",
|
online: "En línea",
|
||||||
offline: "Offline",
|
offline: "Offline",
|
||||||
|
configs: "Configuración",
|
||||||
username: "Nombre de usuario",
|
username: "Nombre de usuario",
|
||||||
password: "Contraseña",
|
password: "Contraseña",
|
||||||
email: "Correo",
|
email: "Correo",
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
<font-awesome-icon icon="cloud-download-alt" class="mr-2"/> {{ $t('import') }}
|
<font-awesome-icon icon="cloud-download-alt" class="mr-2"/> {{ $t('import') }}
|
||||||
</a>
|
</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">
|
<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="cloud-download-alt" class="mr-2"/> {{ $t('configs') }}
|
<font-awesome-icon icon="cogs" class="mr-2"/> {{ $t('configs') }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<h6 class="mt-4 text-muted">{{$t('notifiers')}}</h6>
|
<h6 class="mt-4 text-muted">{{$t('notifiers')}}</h6>
|
||||||
|
|
|
@ -10,11 +10,13 @@ import (
|
||||||
"github.com/statping/statping/types/core"
|
"github.com/statping/statping/types/core"
|
||||||
"github.com/statping/statping/types/errors"
|
"github.com/statping/statping/types/errors"
|
||||||
"github.com/statping/statping/types/groups"
|
"github.com/statping/statping/types/groups"
|
||||||
|
"github.com/statping/statping/types/incidents"
|
||||||
"github.com/statping/statping/types/messages"
|
"github.com/statping/statping/types/messages"
|
||||||
"github.com/statping/statping/types/notifications"
|
"github.com/statping/statping/types/notifications"
|
||||||
"github.com/statping/statping/types/services"
|
"github.com/statping/statping/types/services"
|
||||||
"github.com/statping/statping/types/users"
|
"github.com/statping/statping/types/users"
|
||||||
"github.com/statping/statping/utils"
|
"github.com/statping/statping/utils"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -162,14 +164,16 @@ func apiThemeRemoveHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExportData struct {
|
type ExportData struct {
|
||||||
Config *configs.DbConfig `json:"config,omitempty"`
|
Config *configs.DbConfig `json:"config,omitempty"`
|
||||||
Core *core.Core `json:"core"`
|
Core *core.Core `json:"core"`
|
||||||
Services []services.Service `json:"services"`
|
Services []services.Service `json:"services"`
|
||||||
Messages []*messages.Message `json:"messages"`
|
Messages []*messages.Message `json:"messages"`
|
||||||
Checkins []*checkins.Checkin `json:"checkins"`
|
Incidents []*incidents.Incident `json:"incidents"`
|
||||||
Users []*users.User `json:"users"`
|
IncidentUpdates []*incidents.IncidentUpdate `json:"incident_updates"`
|
||||||
Groups []*groups.Group `json:"groups"`
|
Checkins []*checkins.Checkin `json:"checkins"`
|
||||||
Notifiers []notifications.Notification `json:"notifiers"`
|
Users []*users.User `json:"users"`
|
||||||
|
Groups []*groups.Group `json:"groups"`
|
||||||
|
Notifiers []notifications.Notification `json:"notifiers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ExportData) JSON() []byte {
|
func (e *ExportData) JSON() []byte {
|
||||||
|
@ -262,7 +266,32 @@ func settingsImportHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func configsSaveHandler(w http.ResponseWriter, r *http.Request) {
|
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) {
|
func configsViewHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -271,7 +300,7 @@ func configsViewHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(err, w, r)
|
sendErrorJson(err, w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Write(db.ToYAML())
|
w.Write(db.Clean().ToYAML())
|
||||||
}
|
}
|
||||||
|
|
||||||
func settingsExportHandler(w http.ResponseWriter, r *http.Request) {
|
func settingsExportHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -18,6 +18,28 @@ func (d *DbConfig) Save(directory string) error {
|
||||||
return nil
|
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 {
|
func (d *DbConfig) ToYAML() []byte {
|
||||||
c, err := yaml.Marshal(d)
|
c, err := yaml.Marshal(d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -6,15 +6,15 @@ const SqliteFilename = "statping.db"
|
||||||
|
|
||||||
// DbConfig struct is used for the Db connection and creates the 'config.yml' file
|
// DbConfig struct is used for the Db connection and creates the 'config.yml' file
|
||||||
type DbConfig struct {
|
type DbConfig struct {
|
||||||
DbConn string `yaml:"connection" json:"connection"`
|
DbConn string `yaml:"connection,omitempty" json:"connection"`
|
||||||
DbHost string `yaml:"host,omitempty" json:"-"`
|
DbHost string `yaml:"host,omitempty" json:"-"`
|
||||||
DbUser string `yaml:"user,omitempty" json:"-"`
|
DbUser string `yaml:"user,omitempty" json:"-"`
|
||||||
DbPass string `yaml:"password,omitempty" json:"-"`
|
DbPass string `yaml:"password,omitempty" json:"-"`
|
||||||
DbData string `yaml:"database,omitempty" json:"-"`
|
DbData string `yaml:"database,omitempty" json:"-"`
|
||||||
DbPort int `yaml:"port,omitempty" json:"-"`
|
DbPort int `yaml:"port,omitempty" json:"-"`
|
||||||
ApiSecret string `yaml:"api_secret" json:"-"`
|
ApiSecret string `yaml:"api_secret,omitempty" json:"-"`
|
||||||
Language string `yaml:"language" json:"language"`
|
Language string `yaml:"language,omitempty" json:"language"`
|
||||||
AllowReports bool `yaml:"allow_reports" json:"allow_reports"`
|
AllowReports bool `yaml:"allow_reports,omitempty" json:"allow_reports"`
|
||||||
Project string `yaml:"-" json:"-"`
|
Project string `yaml:"-" json:"-"`
|
||||||
Description string `yaml:"-" json:"-"`
|
Description string `yaml:"-" json:"-"`
|
||||||
Domain string `yaml:"-" json:"-"`
|
Domain string `yaml:"-" json:"-"`
|
||||||
|
@ -22,7 +22,7 @@ type DbConfig struct {
|
||||||
Password string `yaml:"-" json:"-"`
|
Password string `yaml:"-" json:"-"`
|
||||||
Email string `yaml:"-" json:"-"`
|
Email string `yaml:"-" json:"-"`
|
||||||
Error error `yaml:"-" json:"-"`
|
Error error `yaml:"-" json:"-"`
|
||||||
Location string `yaml:"location" json:"-"`
|
Location string `yaml:"location,omitempty" json:"-"`
|
||||||
SqlFile string `yaml:"sqlfile,omitempty" json:"-"`
|
SqlFile string `yaml:"sqlfile,omitempty" json:"-"`
|
||||||
LetsEncryptHost string `yaml:"letsencrypt_host,omitempty" json:"letsencrypt_host"`
|
LetsEncryptHost string `yaml:"letsencrypt_host,omitempty" json:"letsencrypt_host"`
|
||||||
LetsEncryptEmail string `yaml:"letsencrypt_email,omitempty" json:"letsencrypt_email"`
|
LetsEncryptEmail string `yaml:"letsencrypt_email,omitempty" json:"letsencrypt_email"`
|
||||||
|
|
Loading…
Reference in New Issue