adding more functions to media managament system

This commit is contained in:
onysd 2026-09-03 00:54:09 +03:00
parent 95e62c2d77
commit 70c0ba44f0
30 changed files with 1494 additions and 104 deletions

View file

@ -133,3 +133,56 @@ func TestWriteEnvValuesRoundTrip(t *testing.T) {
t.Error(".env lost .env.example's comment lines on write")
}
}
// TestWriteEnvValuesPreservesUnrelatedCustomValues guards against a real
// regression: a save that only touches one section's keys used to reset
// every OTHER already-customized key (e.g. TELESRV_ADMIN_UI_PASSWORD) back
// to .env.example's bare template default, because the old implementation
// fell back to the template line instead of the current .env value for any
// key missing from that save's payload.
func TestWriteEnvValuesPreservesUnrelatedCustomValues(t *testing.T) {
root := findRepoRoot(t)
tmpl, err := os.ReadFile(filepath.Join(root, ".env.example"))
if err != nil {
t.Fatal(err)
}
dir := t.TempDir()
if err := os.WriteFile(filepath.Join(dir, ".env.example"), tmpl, 0o644); err != nil {
t.Fatal(err)
}
m := NewManager(dir)
// First save sets the admin password, as a one-time setup step would.
if err := m.WriteEnvValues(map[string]string{
"TELESRV_ADMIN_UI_PASSWORD": "s3cret",
}); err != nil {
t.Fatal(err)
}
// A later, unrelated save (e.g. the Storage page) that never mentions
// the password must not disturb it.
if err := m.WriteEnvValues(map[string]string{
"TELESRV_STORAGE_MAX_TOTAL_BYTES": "209715200",
}); err != nil {
t.Fatal(err)
}
groups, err := m.ReadEnvGroups()
if err != nil {
t.Fatal(err)
}
values := map[string]string{}
for _, g := range groups {
for _, f := range g.Fields {
values[f.Key] = f.Value
}
}
if values["TELESRV_ADMIN_UI_PASSWORD"] != "s3cret" {
t.Errorf("TELESRV_ADMIN_UI_PASSWORD = %q, want it preserved as \"s3cret\" after an unrelated save", values["TELESRV_ADMIN_UI_PASSWORD"])
}
if values["TELESRV_STORAGE_MAX_TOTAL_BYTES"] != "209715200" {
t.Errorf("TELESRV_STORAGE_MAX_TOTAL_BYTES = %q, want 209715200", values["TELESRV_STORAGE_MAX_TOTAL_BYTES"])
}
}

View file

@ -637,15 +637,25 @@ func (m *Manager) readEnvFile() (map[string]string, error) {
// WriteEnvValues rewrites .env from .env.example's exact text, substituting
// each known key's value in place -- see save_env()'s docstring in
// server-panel.py for why this (not a fresh key=value dump) is what
// preserves comments/layout. Only keys present in values are touched; a
// template-commented optional field is uncommented when given a non-empty
// value and left as-is when given an empty one.
// preserves comments/layout. Only keys present in values are set to a new
// value; every other key keeps whatever is already in the current .env
// (falling back to the template's own default only for a key .env never
// set) -- previously this fell straight back to the template default for
// any key not in this particular save's payload, silently wiping out every
// other customized setting (e.g. TELESRV_ADMIN_UI_PASSWORD) on every save
// that only touches one section's keys. A template-commented optional field
// is uncommented when given a non-empty value and left as-is when given an
// empty one.
func (m *Manager) WriteEnvValues(values map[string]string) error {
tmplPath := filepath.Join(m.Root, ".env.example")
tmplData, err := os.ReadFile(tmplPath)
if err != nil {
return fmt.Errorf("read .env.example: %w", err)
}
existing, err := m.readEnvFile()
if err != nil {
return err
}
lines := strings.Split(string(tmplData), "\n")
// Split() on a trailing "\n" leaves one empty trailing element; drop it
// so the join below doesn't add a spurious blank line before the final
@ -657,15 +667,20 @@ func (m *Manager) WriteEnvValues(values map[string]string) error {
seen := map[string]bool{}
for _, raw := range lines {
line := strings.TrimSpace(raw)
if a := activeFieldRe.FindStringSubmatch(line); a != nil {
if v, ok := values[a[1]]; ok && !seen[a[1]] {
if a := activeFieldRe.FindStringSubmatch(line); a != nil && !seen[a[1]] {
if v, ok := values[a[1]]; ok {
seen[a[1]] = true
out = append(out, a[1]+"="+v)
continue
}
if v, ok := existing[a[1]]; ok {
seen[a[1]] = true
out = append(out, a[1]+"="+v)
continue
}
}
if c := commentedFieldRe.FindStringSubmatch(line); c != nil {
if v, ok := values[c[1]]; ok && !seen[c[1]] {
if c := commentedFieldRe.FindStringSubmatch(line); c != nil && !seen[c[1]] {
if v, ok := values[c[1]]; ok {
seen[c[1]] = true
if v != "" {
out = append(out, c[1]+"="+v)
@ -674,6 +689,14 @@ func (m *Manager) WriteEnvValues(values map[string]string) error {
}
continue
}
// A previously-enabled optional field shows up in the current
// .env as an active line even though the template still has it
// commented out -- keep it enabled with its existing value.
if v, ok := existing[c[1]]; ok {
seen[c[1]] = true
out = append(out, c[1]+"="+v)
continue
}
}
out = append(out, raw)
}