Files
ITWorx Pulse release export bd774932d5
Public source validation / validate (push) Failing after 3m8s
Publish ITWorx Pulse source
2026-09-03 02:09:19 +02:00

87 lines
2.3 KiB
Go

package dashboard
import (
"encoding/json"
"errors"
"fmt"
"regexp"
)
const CurrentSchemaVersion = 2
var slugPattern = regexp.MustCompile("^[a-z0-9]+(?:-[a-z0-9]+)*$")
type Document map[string]any
func Validate(document Document) error {
if document == nil {
return errors.New("dashboard document is required")
}
if version, ok := number(document["schemaVersion"]); !ok || version < 1 || version > CurrentSchemaVersion {
return errors.New("unsupported dashboard schema version")
}
for _, field := range []string{"id", "slug", "name", "scope", "variables", "widgets", "settings"} {
if _, ok := document[field]; !ok {
return fmt.Errorf("dashboard field %q is required", field)
}
}
slug, ok := document["slug"].(string)
if !ok || !slugPattern.MatchString(slug) || len(slug) > 80 {
return errors.New("invalid dashboard slug")
}
name, ok := document["name"].(string)
if !ok || name == "" || len(name) > 120 {
return errors.New("invalid dashboard name")
}
scope, ok := document["scope"].(string)
if !ok || scope != "personal" && scope != "shared" && scope != "system" {
return errors.New("invalid dashboard scope")
}
if _, ok := document["widgets"].([]any); !ok {
return errors.New("dashboard widgets must be an array")
}
if _, ok := document["variables"].([]any); !ok {
return errors.New("dashboard variables must be an array")
}
if _, ok := document["settings"].(map[string]any); !ok {
return errors.New("dashboard settings must be an object")
}
return nil
}
func Migrate(document Document) (Document, error) {
if err := Validate(document); err != nil {
return nil, err
}
version, _ := number(document["schemaVersion"])
if version == CurrentSchemaVersion {
return clone(document), nil
}
migrated := clone(document)
migrated["schemaVersion"] = CurrentSchemaVersion
settings := migrated["settings"].(map[string]any)
if _, ok := settings["live"]; !ok {
settings["live"] = false
}
if _, ok := settings["refreshSeconds"]; !ok {
settings["refreshSeconds"] = 30
}
return migrated, nil
}
func clone(document Document) Document {
encoded, _ := json.Marshal(document)
var result Document
_ = json.Unmarshal(encoded, &result)
return result
}
func number(value any) (int, bool) {
switch v := value.(type) {
case int:
return v, true
case float64:
return int(v), v == float64(int(v))
default:
return 0, false
}
}