Initial commit
Test / test (push) Successful in 7m5s
Release / gates (push) Successful in 7m28s
Release / build (amd64, freebsd) (push) Successful in 2m52s
Release / build (amd64, linux) (push) Successful in 2m46s
Release / build (arm64, freebsd) (push) Successful in 2m22s
Release / build (arm64, linux) (push) Successful in 2m38s
Release / build (loong64, linux) (push) Successful in 2m7s
Release / build (riscv64, linux) (push) Successful in 2m17s
Release / release (push) Successful in 1m0s

Assisted-by: GLM 5.3
This commit is contained in:
2026-09-29 10:03:32 +02:00
commit f8ed33df83
206 changed files with 44165 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
package webhooks
import (
"fmt"
"os"
"sourcedock.dev/petrbalvin/interpres/v2"
"sourcedock.dev/petrbalvin/volumen/internal/tomlfile"
)
// File is the admin-managed hook store: webhooks.toml beside the users
// file. The admin edits it through the settings forms, so a change
// applies without a restart; the file is written atomically with
// owner-only permissions, like the other state files.
type File struct {
Path string
}
// LoadFile reads the hook store. A missing file means no hooks, not an
// error; a malformed one is, because silently dropping the operator's
// endpoints would hide a real fault.
func LoadFile(path string) ([]Webhook, error) {
raw, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("read %s: %w", path, err)
}
data, err := interpres.ParseMap(raw)
if err != nil {
return nil, fmt.Errorf("parse %s: %w", path, err)
}
var out []Webhook
for _, entry := range tomlfile.Tables(data["webhooks"]) {
url := tomlfile.String(entry["url"])
if url == "" {
continue
}
out = append(out, Webhook{
URL: url,
Secret: tomlfile.String(entry["secret"]),
Events: stringList(entry["events"]),
Enabled: tomlfile.Bool(entry["enabled"], true),
})
}
return out, nil
}
// SaveFile replaces the hook store with the given hooks.
func SaveFile(path string, hooks []Webhook) error {
rows := make([]map[string]any, 0, len(hooks))
for _, hook := range hooks {
rows = append(rows, map[string]any{
"url": hook.URL,
"secret": hook.Secret,
"events": hook.Events,
"enabled": hook.Enabled,
})
}
if err := tomlfile.Write(path, "webhooks", rows); err != nil {
return fmt.Errorf("write %s: %w", path, err)
}
return nil
}
// stringList reads a string array that may arrive as either the []any
// the parser produces or a typed slice.
func stringList(value any) []string {
switch list := value.(type) {
case []string:
return list
case []any:
out := make([]string, 0, len(list))
for _, item := range list {
if s, ok := item.(string); ok && s != "" {
out = append(out, s)
}
}
return out
}
return nil
}