controller: backups IA split — four sub-pages (Áttekintés /backups, Távoli mentés /backups/remote, Alkalmazások /backups/apps, Visszaállítás /backups/restore); sections MOVED verbatim (backups_split_move_check.py enforces vs df7ad37); shared data builder extracted; offbox restore-to-verify relocated to the restore page; flash redirects + tier-3 anchors + tier2 back-link retargeted

Claude-Session: https://claude.ai/code/session_01GzammAMzsJTgpQHqxwM2bC
This commit is contained in:
2026-07-13 09:35:01 +02:00
parent df7ad378f4
commit 0ece2ba85c
13 changed files with 1093 additions and 733 deletions
+12 -6
View File
@@ -17,13 +17,19 @@ import (
// The SSH private key + known-host line are provided out-of-band by the operator (textareas) and written
// to 0600/0644 files by the backup Manager; they are NEVER echoed back, logged, or stored in settings.
// offboxRedirect sends the operator back to the backups page with a flash (success or error) message.
// offboxRedirect sends the customer back to the Távoli mentés page with a flash (success or
// error) message (v0.124.0 IA split: the offbox controls live on /backups/remote; the
// restore-to-verify flow redirects to /backups/restore via offboxRedirectTo).
func offboxRedirect(w http.ResponseWriter, r *http.Request, msg string, isErr bool) {
offboxRedirectTo(w, r, "/backups/remote", msg, isErr)
}
func offboxRedirectTo(w http.ResponseWriter, r *http.Request, page, msg string, isErr bool) {
q := "flash"
if isErr {
q = "flash_error"
}
http.Redirect(w, r, "/backups?"+q+"="+url.QueryEscape(msg), http.StatusFound)
http.Redirect(w, r, page+"?"+q+"="+url.QueryEscape(msg), http.StatusFound)
}
// offboxConfigHandler saves the off-box target + (out-of-band) SSH key + known_hosts.
@@ -211,20 +217,20 @@ func (s *Server) offboxRunHandler(w http.ResponseWriter, r *http.Request) {
// overwrite live data; the operator inspects the restored files).
func (s *Server) offboxRestoreHandler(w http.ResponseWriter, r *http.Request) {
if s.backupMgr == nil || !s.backupMgr.OffboxConfigured() {
offboxRedirect(w, r, "A távoli mentési cél nincs beállítva.", true)
offboxRedirectTo(w, r, "/backups/restore", "A távoli mentési cél nincs beállítva.", true)
return
}
_ = r.ParseForm()
app := strings.TrimSpace(r.FormValue("app"))
if app == "" {
offboxRedirect(w, r, "Hiányzó alkalmazás.", true)
offboxRedirectTo(w, r, "/backups/restore", "Hiányzó alkalmazás.", true)
return
}
// Part B: fast-path refuse a concurrent op, then run async on a BACKGROUND context. The old code
// bounded on r.Context()+30m — a proxy read-timeout then CANCELED the SFTP restore mid-flight
// (worse than F4: not just an error page, an aborted restore). Background ctx fixes that.
if s.backupMgr.IsRunning() {
offboxRedirect(w, r, "Egy mentési/visszaállítási művelet már fut.", true)
offboxRedirectTo(w, r, "/backups/restore", "Egy mentési/visszaállítási művelet már fut.", true)
return
}
dest := filepath.Join(s.cfg.Paths.DataDir, "offbox-restore", app)
@@ -240,5 +246,5 @@ func (s *Server) offboxRestoreHandler(w http.ResponseWriter, r *http.Request) {
s.logger.Printf("[INFO] [web] off-box restore %s completed (async) → %s", app, dest)
s.backupMgr.EndRestoreOp(true, "A(z) "+app+" visszaállítva ide (ellenőrzésre): "+dest)
}()
offboxRedirect(w, r, "A távoli visszaállítás elindult — az állapot itt frissül.", false)
offboxRedirectTo(w, r, "/backups/restore", "A távoli visszaállítás elindult — az állapot itt frissül.", false)
}