Handle settings

This commit is contained in:
nemunaire 2022-10-05 20:16:53 +02:00
parent 8f64a349ec
commit 25a4d7be2c
7 changed files with 210 additions and 58 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@ actions
gongs
reveil
routines
settings.json
tracks
vendor
ui/build

View File

@ -1,16 +1,38 @@
package api
import (
"net/http"
"github.com/gin-gonic/gin"
"git.nemunai.re/nemunaire/reveil/config"
"git.nemunai.re/nemunaire/reveil/model"
)
func declareSettingsRoutes(cfg *config.Config, router *gin.RouterGroup) {
router.GET("/settings", func(c *gin.Context) {
settings, err := reveil.ReadSettings(cfg.SettingsFile)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
c.JSON(http.StatusOK, settings)
})
router.PUT("/settings", func(c *gin.Context) {
var config reveil.Settings
err := c.ShouldBindJSON(&config)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
err = reveil.SaveSettings(cfg.SettingsFile, config)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
c.JSON(http.StatusOK, config)
})
}

View File

@ -10,6 +10,7 @@ func (c *Config) declareFlags() {
flag.StringVar(&c.BaseURL, "baseurl", c.BaseURL, "URL prepended to each URL")
flag.StringVar(&c.Bind, "bind", c.Bind, "Bind port/socket")
flag.StringVar(&c.DevProxy, "dev", c.DevProxy, "Use ui directory instead of embedded assets")
flag.StringVar(&c.SettingsFile, "settings-file", c.SettingsFile, "Path to the file containing the settings")
flag.StringVar(&c.TracksDir, "tracks-dir", c.TracksDir, "Path to the directory containing the tracks")
flag.StringVar(&c.GongsDir, "gongs-dir", c.GongsDir, "Path to the directory containing the gongs")
flag.StringVar(&c.ActionsDir, "actions-dir", c.ActionsDir, "Path to the directory containing the actions")
@ -22,6 +23,7 @@ func Consolidated() (cfg *Config, err error) {
// Define defaults options
cfg = &Config{
Bind: "127.0.0.1:8080",
SettingsFile: "./settings.json",
TracksDir: "./tracks/",
GongsDir: "./gongs/",
ActionsDir: "./actions/",

View File

@ -10,6 +10,7 @@ type Config struct {
Bind string
ExternalURL URL
BaseURL string
SettingsFile string
TracksDir string
GongsDir string
ActionsDir string

54
model/settings.go Normal file
View File

@ -0,0 +1,54 @@
package reveil
import (
"encoding/json"
"os"
"time"
)
// Settings represents the settings panel.
type Settings struct {
Language string `json:"language"`
GongInterval time.Duration `json:"gong_interval"`
WeatherDelay time.Duration `json:"weather_delay"`
WeatherAction string `json:"weather_action"`
}
// ExistsSettings checks if the settings file can by found at the given path.
func ExistsSettings(settingsPath string) bool {
_, err := os.Stat(settingsPath)
return !os.IsNotExist(err)
}
// ReadSettings parses the file at the given location.
func ReadSettings(path string) (*Settings, error) {
var s Settings
if fd, err := os.Open(path); err != nil {
return nil, err
} else {
defer fd.Close()
jdec := json.NewDecoder(fd)
if err := jdec.Decode(&s); err != nil {
return &s, err
}
return &s, nil
}
}
// SaveSettings saves settings at the given location.
func SaveSettings(path string, s interface{}) error {
if fd, err := os.Create(path); err != nil {
return err
} else {
defer fd.Close()
jenc := json.NewEncoder(fd)
if err := jenc.Encode(s); err != nil {
return err
}
return nil
}
}

38
ui/src/lib/settings.js Normal file
View File

@ -0,0 +1,38 @@
export class Settings {
constructor(res) {
if (res) {
this.update(res);
}
}
update({ language, gong_interval, weather_delay, weather_action }) {
this.language = language;
this.gong_interval = gong_interval;
this.weather_delay = weather_delay;
this.weather_action = weather_action;
}
async save() {
const res = await fetch(`api/settings`, {
method: 'PUT',
headers: {'Accept': 'application/json'},
body: JSON.stringify(this),
});
if (res.status == 200) {
const data = await res.json();
this.update(data);
return data;
} else {
throw new Error((await res.json()).errmsg);
}
}
}
export async function getSettings() {
const res = await fetch(`api/settings`, {headers: {'Accept': 'application/json'}})
if (res.status == 200) {
return new Settings(await res.json());
} else {
throw new Error((await res.json()).errmsg);
}
}

View File

@ -8,7 +8,17 @@
InputGroup,
InputGroupText,
Label,
Spinner,
} from 'sveltestrap';
import { actions } from '../../stores/actions';
import { getSettings } from '../../lib/settings';
let settingsP = getSettings();
$: settingsP.then((s) => settings = s);
let settings;
</script>
<Container class="flex-fill d-flex flex-column py-2">
@ -16,6 +26,11 @@
Paramètres
</h2>
<Form>
{#await settingsP}
<div class="d-flex justify-content-center align-items-center gap-2">
<Spinner color="primary" /> Chargement en cours&hellip;
</div>
{:then}
<FormGroup>
<Label for="gongIntervals">Intervalle entre les gongs</Label>
<InputGroup>
@ -23,6 +38,8 @@
type="number"
id="gongIntervals"
placeholder="20"
bind:value={settings.gong_interval}
on:change={() => settings.save()}
/>
<InputGroupText>min</InputGroupText>
</InputGroup>
@ -35,6 +52,8 @@
type="number"
id="weatherDelay"
placeholder="5"
bind:value={settings.weather_delay}
on:change={() => settings.save()}
/>
<InputGroupText>min</InputGroupText>
</InputGroup>
@ -42,12 +61,24 @@
<FormGroup>
<Label for="weatherRituel">Rituel pour l'annonce météo</Label>
{#if $actions.list}
<Input
type="select"
id="weatherRituel"
bind:value={settings.weather_action}
on:change={() => settings.save()}
>
<option value="1">test</option>
{#each $actions.list as action (action.id)}
<option value="{action.path}">{action.name}</option>
{/each}
</Input>
{:else}
{#await actions.refresh()}
<div class="d-flex justify-content-center align-items-center gap-2">
<Spinner color="primary" /> Chargement en cours&hellip;
</div>
{/await}
{/if}
</FormGroup>
<FormGroup>
@ -55,6 +86,8 @@
<Input
type="select"
id="greetingLanguage"
bind:value={settings.lang}
on:change={() => settings.save()}
>
<option value="fr_FR">Français</option>
<option value="en_US">Anglais</option>
@ -62,5 +95,6 @@
<option value="de_DE">Allemand</option>
</Input>
</FormGroup>
{/await}
</Form>
</Container>