Úprava hlavní AppFactory konfigurace {html.escape(ENV_PATH)}.
Zdroj pravdy zůstává tento soubor. Při uložení se vytvoří časově označený backup.
Dostupné pouze administrátorům.
{notice}
Proměnné
Jak se změny projeví
Proměnné používané shell skripty: stačí znovu spustit příslušný skript.
Portal / Worker / Webhook / Monitor: je potřeba restart kontejnerů (tlačítka níže).
Domény, HTTPS a Caddy hodnoty: spusťte generate-caddyfile.sh (Regenerate Caddy).
UID/GID proměnné: je potřeba opatrný restart/redeploy celého stacku.
Navazující akce
Akce nevolají docker přímo — vytvoří úlohu do fronty (zpracuje worker). Historii najdete v
Úlohách.
{action_buttons}
""",
user=user,
)
@router.get("/admin/environment", response_class=HTMLResponse)
def environment_page(request: Request, message: str = "", error: str = "", user=Depends(require_user)):
require_admin(user)
return _render_page(user, read_entries(), message=message, error=error)
@router.post("/admin/environment", response_class=HTMLResponse)
def environment_save(
request: Request,
key: list[str] = Form(default=[]),
value: list[str] = Form(default=[]),
user=Depends(require_user),
):
require_admin(user)
# Sestav uspořádaný seznam dvojic; prázdné řádky (bez klíče i hodnoty) ignoruj.
pairs: list[tuple[str, str]] = []
for raw_key, raw_value in zip(key, value):
k = (raw_key or "").strip()
v = (raw_value or "").replace("\r", "").replace("\n", " ")
if not k and not v:
continue
pairs.append((k, v))
# Validace: klíč podle regexu, žádné duplicity.
invalid_keys = sorted({k for k, _ in pairs if not KEY_RE.match(k)})
seen: set[str] = set()
duplicate_keys = sorted({k for k, _ in pairs if k in seen or seen.add(k)})
if invalid_keys or duplicate_keys:
problems = []
if invalid_keys:
problems.append("neplatné klíče: " + ", ".join(invalid_keys))
if duplicate_keys:
problems.append("duplicitní klíče: " + ", ".join(duplicate_keys))
error = "Změny nebyly uloženy — " + "; ".join(problems) + "."
# Re-render z odeslaných dat, ať admin nepřijde o rozdělanou editaci.
return _render_page(user, pairs, error=error)
# Spočítej změněné klíče (pro audit – bez hodnot).
original = dict(read_entries())
new_map = dict(pairs)
added = set(new_map) - set(original)
removed = set(original) - set(new_map)
modified = {k for k in set(new_map) & set(original) if new_map[k] != original[k]}
changed_keys = sorted(added | removed | modified)
if not changed_keys:
return RedirectResponse(
url="/portal/admin/environment?message=" + quote("Žádné změny k uložení."),
status_code=303,
)
try:
backup_path = save_entries(pairs)
except OSError as exc:
return _render_page(user, pairs, error=f"Soubor se nepodařilo uložit: {exc.strerror or exc}")
log_audit_event(
user,
action="environment.updated",
target_type="environment",
target_id=os.path.basename(ENV_PATH),
metadata={"changed_keys": changed_keys, "backup": os.path.basename(backup_path) if backup_path else None},
)
backup_note = f" Backup: {os.path.basename(backup_path)}." if backup_path else ""
message = (
f"Uloženo {len(changed_keys)} změněných klíčů.{backup_note} "
"Změny se projeví podle typu proměnné různě – viz doporučené akce níže."
)
return RedirectResponse(
url="/portal/admin/environment?message=" + quote(message),
status_code=303,
)