Add sanity checks for configuration and UI to display errors.

This commit is contained in:
Justin Hawkins 2021-10-10 12:47:37 +10:30
parent 1809033049
commit 3e6cf49394
5 changed files with 59 additions and 11 deletions

View File

@ -70,7 +70,7 @@ func DefaultConfig() *ConfigV2 {
c.WatchInterval = 10 c.WatchInterval = 10
c.Port = 9090 c.Port = 9090
w := Watcher{ w := Watcher{
WebHookURL: "abcedf", WebHookURL: "https://webhook.url.here",
Path: "/your/screenshot/dir/here", Path: "/your/screenshot/dir/here",
Username: "", Username: "",
NoWatermark: false, NoWatermark: false,
@ -127,6 +127,28 @@ func (c *ConfigService) Load() error {
func (c *ConfigService) Save() error { func (c *ConfigService) Save() error {
daulog.SendLog("saving configuration", daulog.LogTypeInfo) daulog.SendLog("saving configuration", daulog.LogTypeInfo)
// sanity checks
for _, watcher := range c.Config.Watchers {
// give the sample one a pass? this is kinda gross...
if watcher.Path == "/your/screenshot/dir/here" {
continue
}
info, err := os.Stat(watcher.Path)
if os.IsNotExist(err) {
return fmt.Errorf("path '%s' does not exist", watcher.Path)
}
if !info.IsDir() {
return fmt.Errorf("path '%s' is not a directory", watcher.Path)
}
}
for _, watcher := range c.Config.Watchers {
if strings.Index(watcher.WebHookURL, "https://") != 0 {
return fmt.Errorf("webhook URL '%s' does not look valid", watcher.WebHookURL)
}
}
jsonString, _ := json.Marshal(c.Config) jsonString, _ := json.Marshal(c.Config)
err := ioutil.WriteFile(c.ConfigFilename, jsonString, os.ModePerm) err := ioutil.WriteFile(c.ConfigFilename, jsonString, os.ModePerm)
if err != nil { if err != nil {

View File

@ -3,9 +3,12 @@
<main role="main" class="inner DAU" x-data="configuration()" x-init="get_config()"> <main role="main" class="inner DAU" x-data="configuration()" x-init="get_config()">
<h1 class="DAU-heading">Config</h1> <h1 class="DAU-heading">Config</h1>
</a> <div x-cloak x-show="error" class="alert alert-danger" role="alert" x-text="error">
</div>
<div x-cloak x-show="success" class="alert alert-success" role="alert" x-text="success">
</div>
<form class=""> <form x-cloak class="">
<p>Configuration changes are not made until the Save button is pressed <p>Configuration changes are not made until the Save button is pressed
at the bottom of this page. at the bottom of this page.
@ -138,7 +141,7 @@
<div class="my-5"> <div class="my-5">
<button type="button" class="btn btn-secondary" href="#" <button type="button" class="btn btn-secondary" href="#"
@click.prevent="config.Watchers.push({Username: '', WebHookURL: '', Path: '', NoWatermark: false, Exclude: []});"> @click.prevent="config.Watchers.push({Username: '', WebHookURL: 'https://webhook.url.here/', Path: '/directory/path/here', NoWatermark: false, Exclude: []});">
Add a new watcher</button> Add a new watcher</button>
</div> </div>
@ -161,7 +164,7 @@
<script> <script>
function configuration() { function configuration() {
return { return {
config: {}, config: {}, error: '', success: '',
get_config() { get_config() {
fetch('/rest/config') fetch('/rest/config')
.then(response => response.json()) // convert to json .then(response => response.json()) // convert to json
@ -171,11 +174,18 @@
}) })
}, },
save_config() { save_config() {
this.error = '';
this.success = '';
fetch('/rest/config', { method: 'POST', body: JSON.stringify(this.config) }) fetch('/rest/config', { method: 'POST', body: JSON.stringify(this.config) })
.then(response => response.json()) // convert to json .then(response => response.json()) // convert to json
.then(json => { .then(json => {
this.config = json; if (json.error) {
console.log(json); this.error = json.error
} else {
this.success = 'Configuration saved';
this.config = json;
}
window.scrollTo(0,0);
}) })
} }

View File

@ -108,3 +108,6 @@ pre {
.mastfoot { .mastfoot {
color: rgba(255, 255, 255, .5); color: rgba(255, 255, 255, .5);
} }
/* for alpine.js */
[x-cloak] { display: none !important; }

View File

@ -108,23 +108,36 @@ func (ws *WebService) getLogs(w http.ResponseWriter, r *http.Request) {
func (ws *WebService) handleConfig(w http.ResponseWriter, r *http.Request) { func (ws *WebService) handleConfig(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" { if r.Method == "POST" {
type ErrorResponse struct {
Error string `json:"error"`
}
newConfig := config.ConfigV2{} newConfig := config.ConfigV2{}
defer r.Body.Close() defer r.Body.Close()
b, err := ioutil.ReadAll(r.Body) b, err := ioutil.ReadAll(r.Body)
if err != nil { if err != nil {
w.WriteHeader(400)
w.Write([]byte("bad body")) w.Write([]byte("bad body"))
return return
} }
err = json.Unmarshal(b, &newConfig) err = json.Unmarshal(b, &newConfig)
if err != nil { if err != nil {
w.Write([]byte("bad data")) w.WriteHeader(400)
log.Printf("%s", err) j, _ := json.Marshal(ErrorResponse{Error: "badly formed JSON"})
w.Write(j)
return return
} }
ws.Config.Config = newConfig ws.Config.Config = newConfig
ws.Config.Save() err = ws.Config.Save()
if err != nil {
w.WriteHeader(400)
j, _ := json.Marshal(ErrorResponse{Error: err.Error()})
w.Write(j)
return
}
} }
b, _ := json.Marshal(ws.Config.Config) b, _ := json.Marshal(ws.Config.Config)

View File

@ -78,7 +78,7 @@ func TestGetConfig(t *testing.T) {
t.Errorf("expected error to be nil got %v", err) t.Errorf("expected error to be nil got %v", err)
} }
if string(b) != `{"WatchInterval":10,"Version":2,"Port":9090,"Watchers":[{"WebHookURL":"abcedf","Path":"/your/screenshot/dir/here","Username":"","NoWatermark":false,"Exclude":[]}]}` { if string(b) != `{"WatchInterval":10,"Version":2,"Port":9090,"Watchers":[{"WebHookURL":"https://webhook.url.here","Path":"/your/screenshot/dir/here","Username":"","NoWatermark":false,"Exclude":[]}]}` {
t.Errorf("Got unexpected response %v", string(b)) t.Errorf("Got unexpected response %v", string(b))
} }
} }