Implemented admin pane + user permission

This commit is contained in:
Martino Ferrari
2026-06-22 17:49:14 +02:00
parent 73fcbe7b28
commit ac24011487
67 changed files with 5925 additions and 411 deletions
+30 -11
View File
@@ -152,18 +152,32 @@ func main() {
}
brk.Register(srvVars)
// Build the global access policy from config: every user is trusted with
// full write access unless downgraded by the blacklist; groups are named
// sets of users referenced by per-panel sharing.
blacklist := make(map[string]string, len(cfg.Server.Blacklist))
for _, e := range cfg.Server.Blacklist {
blacklist[e.User] = e.Level
}
groups := make(map[string][]string, len(cfg.Groups))
// Build the role-based access policy from config: each [[groups]] entry lists
// members by role (viewer/operator/logiceditor/auditor/admin) and an optional
// parent for nesting. Every user is an implicit viewer of the built-in public
// group; a config with no roles at all is fully open (everyone admin).
specs := make([]access.GroupSpec, 0, len(cfg.Groups))
for _, g := range cfg.Groups {
groups[g.Name] = g.Members
members := make(map[string]access.Role)
assign := func(users []string, role access.Role) {
for _, u := range users {
members[u] = role
}
}
assign(g.Viewers, access.RoleViewer)
assign(g.Operators, access.RoleOperator)
assign(g.LogicEditors, access.RoleLogic)
assign(g.Auditors, access.RoleAuditor)
assign(g.Admins, access.RoleAdmin)
specs = append(specs, access.GroupSpec{Name: g.Name, Parent: g.Parent, Members: members})
}
policy := access.New(cfg.Server.DefaultUser, specs)
// Once enabled, runtime admin-pane changes persist to {storage_dir}/access.json,
// which (when present on a later startup) supersedes the TOML access config.
if err := policy.EnablePersistence(cfg.Server.StorageDir); err != nil {
log.Error("failed to load access store", "err", err)
os.Exit(1)
}
policy := access.New(cfg.Server.DefaultUser, blacklist, groups, cfg.Server.LogicEditors, cfg.Audit.Readers)
// Audit log: when enabled, every system-affecting action (user/automated
// signal writes, interface and control-logic mutations) is recorded to SQLite.
@@ -199,9 +213,14 @@ func main() {
// to server variables. Installed before Reload so running graphs can emit.
dialogs := server.NewDialogHub(brk, policy, recorder, log)
ctrlEngine.SetNotifier(dialogs)
// Debug hub: control-logic editors observe live graphs or dry-run unsaved
// edits; the engine pushes per-node execution events through it.
debugHub := server.NewDebugHub(ctrlEngine, log)
ctrlEngine.SetDebugObserver(debugHub)
ctrlEngine.Reload()
srv := server.New(cfg.Server.Listen, webFS, brk, synthDS, store, cfgStore, policy, aclStore, ctrlStore, ctrlEngine, dialogs, recorder, cfg.Datasource.EPICS.ChannelFinderURL, cfg.Datasource.EPICS.ArchiveURL, cfg.Server.TrustedUserHeader, log)
srv := server.New(cfg.Server.Listen, webFS, brk, synthDS, store, cfgStore, policy, aclStore, ctrlStore, ctrlEngine, dialogs, debugHub, recorder, cfg.Datasource.EPICS.ChannelFinderURL, cfg.Datasource.EPICS.ArchiveURL, cfg.Server.TrustedUserHeader, log)
if err := srv.Start(ctx); err != nil {
fmt.Fprintf(os.Stderr, "server error: %v\n", err)