v0.252.0 — the sentences the program builds follow the language (R-557 slice 2 release A)
gates / gates (push) Successful in 23s
gates / gates (push) Successful in 23s
Slice 1 translated the dashboard's markup. The sentences the program BUILDS were still Hungarian literals in Go, so an English household clicked an English button and was answered in Hungarian. 226 of them move into the bundle here. A flash was the hard part: it travels inside the redirect URL and is rendered by a DIFFERENT request, so it now carries a bundle key plus its parameters. A link minted by an older controller carries prose and is shown verbatim — never a raw key, never dropped. Also converted: page data and view-model text, the internal/api JSON answers, the alert banners (Alert.MessageKey, rendered on the way out of GetAlerts), 237 country names at display, and the four page titles built around an app name (R-566 closed). Hungarian is byte-identical, and that is measured rather than read: scripts/i18n_go_parity.py freezes every Go literal at the base commit (7 467) and refuses a key whose Hungarian is not that text, byte for byte. Three decoys, each seen to convict. Its own first version filtered the capture through an ASCII-Hungarian word list and missed seven real literals — the R-565 class. The filter is gone. Nothing on the wire moved, and wire goldens now hold it there: the report's health warnings and every notify event message stay Hungarian, because the hub MAILS the controller's sentence when it has no entry of its own. Slice 3 (R-558) owns those. MinAgent: 0.131.0 (unchanged). No hub release needed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -23,11 +23,17 @@ import (
|
||||
// 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 offboxRedirect(w http.ResponseWriter, r *http.Request, key string, isErr bool, args ...string) {
|
||||
offboxRedirectTo(w, r, "/backups/remote", key, isErr, args...)
|
||||
}
|
||||
|
||||
func offboxRedirectTo(w http.ResponseWriter, r *http.Request, page, msg string, isErr bool) {
|
||||
// offboxRedirectTo sends the customer to `page` with a flash.
|
||||
//
|
||||
// `key` names a bundle message, not a sentence (v0.252.0, R-557) — the page that RENDERS the flash is
|
||||
// reached by a second request, and only that request knows the household's language. `args` fill the
|
||||
// message's printf verbs and ride as repeated `fa` parameters. A value the bundle does not know is
|
||||
// shown verbatim, so a link minted by an older controller still reads correctly.
|
||||
func offboxRedirectTo(w http.ResponseWriter, r *http.Request, page, key string, isErr bool, args ...string) {
|
||||
q := "flash"
|
||||
if isErr {
|
||||
q = "flash_error"
|
||||
@@ -39,13 +45,13 @@ func offboxRedirectTo(w http.ResponseWriter, r *http.Request, page, msg string,
|
||||
if strings.Contains(page, "?") {
|
||||
sep = "&"
|
||||
}
|
||||
http.Redirect(w, r, page+sep+q+"="+url.QueryEscape(msg), http.StatusFound)
|
||||
http.Redirect(w, r, page+sep+flashQuery(q, key, args...), http.StatusFound)
|
||||
}
|
||||
|
||||
// offboxConfigHandler saves the off-box target + (out-of-band) SSH key + known_hosts.
|
||||
func (s *Server) offboxConfigHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if s.backupMgr == nil {
|
||||
offboxRedirect(w, r, "A mentéskezelő nem elérhető.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.mgr_unavailable", true)
|
||||
return
|
||||
}
|
||||
_ = r.ParseForm()
|
||||
@@ -60,30 +66,30 @@ func (s *Server) offboxConfigHandler(w http.ResponseWriter, r *http.Request) {
|
||||
knownHosts := r.FormValue("known_hosts")
|
||||
|
||||
if host == "" || user == "" || repoPath == "" {
|
||||
offboxRedirect(w, r, "A cél címe, a felhasználó és a tárhely útvonala kötelező.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.fields_required", true)
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(repoPath, "/") {
|
||||
offboxRedirect(w, r, "A tárhely útvonalának abszolútnak kell lennie (/-rel kezdődjön).", true)
|
||||
offboxRedirect(w, r, "flash.offbox.path_absolute", true)
|
||||
return
|
||||
}
|
||||
// Validate BEFORE persisting — host/user/repo flow into the ssh command restic runs; reject anything
|
||||
// that could inject an ssh option (leading '-') or a metacharacter (the security boundary).
|
||||
if err := backup.ValidateOffboxTarget(&settings.OffboxTarget{Host: host, User: user, RepoPath: repoPath, Port: port}); err != nil {
|
||||
offboxRedirect(w, r, "Érvénytelen beállítás: "+err.Error(), true)
|
||||
offboxRedirect(w, r, "flash.offbox.config_invalid", true, err.Error())
|
||||
return
|
||||
}
|
||||
// First-time config requires the SSH key + a pinned known-host line (no blind TOFU).
|
||||
existing := s.backupMgr.OffboxConfigured()
|
||||
if !existing && (strings.TrimSpace(sshKey) == "" || strings.TrimSpace(knownHosts) == "") {
|
||||
offboxRedirect(w, r, "Az első beállításhoz az SSH privát kulcs és a célgép ismert-host sora is kötelező.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.first_setup_needs_key", true)
|
||||
return
|
||||
}
|
||||
|
||||
// Write secrets out-of-band (0600 key/pw, 0644 known_hosts); never logged.
|
||||
if err := s.backupMgr.WriteOffboxSecrets(sshKey, knownHosts); err != nil {
|
||||
s.logger.Printf("[ERROR] [web] offbox secrets: %v", err)
|
||||
offboxRedirect(w, r, "A hitelesítő adatok mentése sikertelen.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.creds_save_failed", true)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -110,26 +116,30 @@ func (s *Server) offboxConfigHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// it PENDING — no offsite RUN proceeds until escrow is confirmed (atomicity). Re-editing an already
|
||||
// escrowed target keeps it escrowed (WriteOffboxSecrets leaves the password unchanged). A stage-push
|
||||
// failure does NOT mark escrowed; it is surfaced (the run gate still protects data).
|
||||
stageErr := ""
|
||||
stageKey := ""
|
||||
if tgt.Enabled {
|
||||
if tgt.EscrowState != "escrowed" {
|
||||
tgt.EscrowState = "pending"
|
||||
}
|
||||
if client, cerr := s.agentClient(); cerr != nil {
|
||||
stageErr = " — a kulcs letéti előkészítése nem sikerült (az ügynök nem elérhető); próbáld újra."
|
||||
stageKey = "flash.offbox.target_saved_escrow_agent_down"
|
||||
s.logger.Printf("[WARN] [web] offbox escrow stage: agent client: %v", cerr)
|
||||
} else if err := s.backupMgr.PushOffboxPasswordForEscrow(r.Context(), client.StageEscrowSecret); err != nil {
|
||||
stageErr = " — a kulcs letéti előkészítése nem sikerült; próbáld újra."
|
||||
stageKey = "flash.offbox.target_saved_escrow_failed"
|
||||
s.logger.Printf("[WARN] [web] offbox escrow stage: %v", err) // err carries no secret
|
||||
}
|
||||
}
|
||||
if err := s.settings.SetOffboxTarget(tgt); err != nil {
|
||||
offboxRedirect(w, r, "A beállítás mentése sikertelen.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.save_failed", true)
|
||||
return
|
||||
}
|
||||
s.logger.Printf("[INFO] [web] off-box target configured: %s@%s:%s (port %d, enabled=%v, escrow=%s)", user, host, repoPath, port, tgt.Enabled, tgt.EscrowState)
|
||||
s.reportTriggerNow() // v0.139.0: offsite enable/disable reaches the hub in seconds
|
||||
offboxRedirect(w, r, "A távoli mentési cél elmentve."+stageErr, stageErr != "")
|
||||
savedKey := "flash.offbox.target_saved"
|
||||
if stageKey != "" {
|
||||
savedKey = stageKey
|
||||
}
|
||||
offboxRedirect(w, r, savedKey, stageKey != "")
|
||||
}
|
||||
|
||||
// offboxConfirmEscrowHandler marks the offsite repo password as escrowed under R (fork-4).
|
||||
@@ -139,14 +149,14 @@ func (s *Server) offboxConfigHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// no restic_pw_sha256 and can never auto-confirm; the operator vouches by hand after a verified ceremony.
|
||||
func (s *Server) offboxConfirmEscrowHandler(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)
|
||||
offboxRedirect(w, r, "flash.offbox.target_not_set", true)
|
||||
return
|
||||
}
|
||||
if err := s.settings.UpdateOffboxStatus(func(o *settings.OffboxTarget) {
|
||||
o.EscrowState = "escrowed"
|
||||
o.CeremonyCompletedAt = "" // v0.138.0: clear the awaiting-card stamp on confirm
|
||||
}); err != nil {
|
||||
offboxRedirect(w, r, "A beállítás mentése sikertelen.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.save_failed", true)
|
||||
return
|
||||
}
|
||||
s.logger.Printf("[INFO] [web] off-box escrow confirmed — offsite runs enabled")
|
||||
@@ -156,7 +166,7 @@ func (s *Server) offboxConfirmEscrowHandler(w http.ResponseWriter, r *http.Reque
|
||||
if err := s.wipeStagedEscrow(r.Context()); err != nil {
|
||||
s.logger.Printf("[ERROR] [web] escrow confirmed but the agent-staged secret was NOT wiped (re-confirm to retry): %v", err)
|
||||
}
|
||||
offboxRedirect(w, r, "A kulcs letétbe helyezése megerősítve — a távoli mentés mostantól futhat.", false)
|
||||
offboxRedirect(w, r, "flash.offbox.escrow_confirmed", false)
|
||||
}
|
||||
|
||||
// wipeStagedEscrow calls the injected seam (tests), else the agent's DELETE /escrow/stage-secret over the
|
||||
@@ -179,22 +189,22 @@ func (s *Server) wipeStagedEscrow(ctx context.Context) error {
|
||||
// is never logged. Body: {password, force?}.
|
||||
func (s *Server) offboxInjectPasswordHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if s.backupMgr == nil {
|
||||
offboxRedirect(w, r, "A mentéskezelő nem elérhető.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.mgr_unavailable", true)
|
||||
return
|
||||
}
|
||||
_ = r.ParseForm()
|
||||
pw := r.FormValue("password")
|
||||
force := r.FormValue("force") == "on" || r.FormValue("force") == "true"
|
||||
if strings.TrimSpace(pw) == "" {
|
||||
offboxRedirect(w, r, "A repo jelszó kötelező.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.repo_pw_required", true)
|
||||
return
|
||||
}
|
||||
if err := s.backupMgr.InjectOffboxPassword(pw, force); err != nil {
|
||||
offboxRedirect(w, r, "A jelszó beállítása sikertelen: "+err.Error(), true)
|
||||
offboxRedirect(w, r, "flash.offbox.repo_pw_failed", true, err.Error())
|
||||
return
|
||||
}
|
||||
s.logger.Printf("[INFO] [web] off-box repo password injected (DR pre-place, force=%v)", force)
|
||||
offboxRedirect(w, r, "A helyreállított repo jelszó beállítva.", false)
|
||||
offboxRedirect(w, r, "flash.offbox.repo_pw_set", false)
|
||||
}
|
||||
|
||||
// offboxToggleHandler flips an app's off-box inclusion.
|
||||
@@ -203,32 +213,32 @@ func (s *Server) offboxToggleHandler(w http.ResponseWriter, r *http.Request) {
|
||||
app := strings.TrimSpace(r.FormValue("app"))
|
||||
on := r.FormValue("enabled") == "on" || r.FormValue("enabled") == "true"
|
||||
if app == "" {
|
||||
offboxRedirect(w, r, "Hiányzó alkalmazás.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.app_missing", true)
|
||||
return
|
||||
}
|
||||
if err := s.settings.SetAppOffbox(app, on); err != nil {
|
||||
offboxRedirect(w, r, "A beállítás mentése sikertelen.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.save_failed", true)
|
||||
return
|
||||
}
|
||||
s.reportTriggerNow() // v0.139.0: per-app offsite toggle reaches the hub in seconds
|
||||
offboxRedirect(w, r, "A távoli mentés beállítása frissítve.", false)
|
||||
offboxRedirect(w, r, "flash.offbox.app_setting_updated", false)
|
||||
}
|
||||
|
||||
// offboxRunHandler triggers an off-box backup now (async — it can run for minutes).
|
||||
func (s *Server) offboxRunHandler(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)
|
||||
offboxRedirect(w, r, "flash.offbox.target_not_set", true)
|
||||
return
|
||||
}
|
||||
// fork-4 atomicity: refuse the run until the repo password is escrowed under R.
|
||||
if !s.backupMgr.OffboxRunnable() {
|
||||
offboxRedirect(w, r, "A távoli mentés a kulcs letétbe helyezésére vár.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.waiting_for_escrow", true)
|
||||
return
|
||||
}
|
||||
// Offsite-repo continuity (v0.142.0): an ORPHANED repo can't be written — route the customer to the
|
||||
// orphan card's explanation/reset instead of attempting a doomed write.
|
||||
if s.backupMgr.OffboxOrphaned() {
|
||||
offboxRedirect(w, r, "A távoli tároló elárvult — előbb indíts új távoli mentést a kártyán látható módon.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.repo_orphaned", true)
|
||||
return
|
||||
}
|
||||
// R-234: the single-flight decision is taken SYNCHRONOUSLY, before the goroutine, so the customer
|
||||
@@ -239,7 +249,7 @@ func (s *Server) offboxRunHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// question is about. (The documented "use RestoreStatus for display" trap is a different question.)
|
||||
if s.backupMgr.IsRunning() {
|
||||
s.logger.Printf("[INFO] [web] manual off-box backup NOT started for this request: a run is already in flight")
|
||||
offboxRedirect(w, r, "Már fut egy távoli mentés — ez a kérés nem indított újat. A most látható eredmény még a korábbi futásé; várd meg, míg ez befejeződik.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.run_already_going", true)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
@@ -256,7 +266,7 @@ func (s *Server) offboxRunHandler(w http.ResponseWriter, r *http.Request) {
|
||||
s.logger.Printf("[WARN] [web] manual off-box backup failed: %v", err)
|
||||
}
|
||||
}()
|
||||
offboxRedirect(w, r, "A távoli mentés elindult — az állapot itt frissül.", false)
|
||||
offboxRedirect(w, r, "flash.offbox.run_started", false)
|
||||
}
|
||||
|
||||
// offboxResetHandler is the CLAIMED confirmed orphaned-repo reset (Scenario C): move the old (recovery-
|
||||
@@ -264,15 +274,15 @@ func (s *Server) offboxRunHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// explicitly confirmed (confirm=1, set by the reveal-then-confirm block on the orphan card).
|
||||
func (s *Server) offboxResetHandler(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)
|
||||
offboxRedirect(w, r, "flash.offbox.target_not_set", true)
|
||||
return
|
||||
}
|
||||
if !s.backupMgr.OffboxOrphaned() {
|
||||
offboxRedirect(w, r, "Az offsite tároló nincs elárvult állapotban.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.not_orphaned", true)
|
||||
return
|
||||
}
|
||||
if r.FormValue("confirm") != "1" {
|
||||
offboxRedirect(w, r, "A visszaállításhoz megerősítés szükséges.", true)
|
||||
offboxRedirect(w, r, "flash.offbox.needs_confirmation", true)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
@@ -282,7 +292,7 @@ func (s *Server) offboxResetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
s.logger.Printf("[WARN] [web] offbox orphaned-repo reset failed: %v", err)
|
||||
}
|
||||
}()
|
||||
offboxRedirect(w, r, "Új távoli mentés indítása folyamatban — a régi előzmény félretéve (nem törölve).", false)
|
||||
offboxRedirect(w, r, "flash.offbox.restart_started", false)
|
||||
}
|
||||
|
||||
// offboxStatusHandler (Part C) is the poll source for the remote-backup run status — the page polls it
|
||||
@@ -314,13 +324,13 @@ func (s *Server) offboxStatusHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// with a reveal cue; the revealed confirm POSTs mode=full&confirm=1, re-checked at execution).
|
||||
func (s *Server) offboxRestoreHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if s.backupMgr == nil || !s.backupMgr.OffboxConfigured() {
|
||||
offboxRedirectTo(w, r, "/backups/restore", "A távoli mentési cél nincs beállítva.", true)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.target_not_set", true)
|
||||
return
|
||||
}
|
||||
_ = r.ParseForm()
|
||||
app := strings.TrimSpace(r.FormValue("app"))
|
||||
if app == "" {
|
||||
offboxRedirectTo(w, r, "/backups/restore", "Hiányzó alkalmazás.", true)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.app_missing", true)
|
||||
return
|
||||
}
|
||||
mode := strings.TrimSpace(r.FormValue("mode"))
|
||||
@@ -377,7 +387,7 @@ func (s *Server) offboxRestoreHandler(w http.ResponseWriter, r *http.Request) {
|
||||
where := s.backupMgr.OffsiteRestoreScratchPath(app)
|
||||
s.backupMgr.EndRestoreOp(true, restoreScratchOutcomeMsg(app, where, full))
|
||||
}()
|
||||
offboxRedirectTo(w, r, restoreWizardPath(app), "A távoli visszaállítás elindult — az állapot itt frissül.", false)
|
||||
offboxRedirectTo(w, r, restoreWizardPath(app), "flash.offbox.restore_started", false)
|
||||
}
|
||||
|
||||
// restoreScratchOutcomeMsg builds the OUTCOME flash for a completed scratch restore. Pure, so the
|
||||
@@ -420,18 +430,18 @@ func restoreScratchOutcomeMsg(app, where string, full bool) string {
|
||||
// because that is the only part the customer can check against what they see in the app.
|
||||
func (s *Server) offboxReconstituteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if s.backupMgr == nil || !s.backupMgr.OffboxConfigured() {
|
||||
offboxRedirectTo(w, r, "/backups/restore", "A távoli mentési cél nincs beállítva.", true)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.target_not_set", true)
|
||||
return
|
||||
}
|
||||
_ = r.ParseForm()
|
||||
app := strings.TrimSpace(r.FormValue("app"))
|
||||
if app == "" {
|
||||
offboxRedirectTo(w, r, "/backups/restore", "Hiányzó alkalmazás.", true)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.app_missing", true)
|
||||
return
|
||||
}
|
||||
// This one overwrites live files and replays a database — it must never happen on a stray click.
|
||||
if r.FormValue("confirm") != "1" {
|
||||
offboxRedirectTo(w, r, restoreWizardPath(app), "A teljes visszaállítás megerősítés nélkül nem hajtható végre.", true)
|
||||
offboxRedirectTo(w, r, restoreWizardPath(app), "flash.offbox.full_needs_confirmation", true)
|
||||
return
|
||||
}
|
||||
if msg, blocked := s.restoreOpBlocked(); blocked {
|
||||
@@ -465,7 +475,7 @@ func (s *Server) offboxReconstituteHandler(w http.ResponseWriter, r *http.Reques
|
||||
app, res.FilesPlaced, res.DBsReplayed, res.SnapshotID)
|
||||
s.backupMgr.EndRestoreOp(true, reconstituteOutcomeMsg(app, res))
|
||||
}()
|
||||
offboxRedirectTo(w, r, restoreWizardPath(app), "A teljes visszaállítás elindult — az állapot itt frissül.", false)
|
||||
offboxRedirectTo(w, r, restoreWizardPath(app), "flash.offbox.full_restore_started", false)
|
||||
}
|
||||
|
||||
// offsiteScratchIncompleteMsg (R-358) is the server-side refusal shown when a place or reconstitute is
|
||||
@@ -535,17 +545,17 @@ func reconstituteOutcomeMsg(app string, res backup.OffsiteReconstituteResult) st
|
||||
// It now refuses while ANY backup or restore op is running.
|
||||
func (s *Server) offboxVerifyCopyDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if s.backupMgr == nil {
|
||||
offboxRedirectTo(w, r, "/backups/restore", "A mentéskezelő nem érhető el.", true)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.mgr_unreachable", true)
|
||||
return
|
||||
}
|
||||
_ = r.ParseForm()
|
||||
stack := strings.TrimSpace(r.FormValue("stack"))
|
||||
if stack == "" {
|
||||
offboxRedirectTo(w, r, "/backups/restore", "Hiányzó ellenőrző másolat.", true)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.scratch_missing", true)
|
||||
return
|
||||
}
|
||||
if r.FormValue("confirm") != "1" {
|
||||
offboxRedirectTo(w, r, "/backups/restore", "A törlés megerősítés nélkül nem hajtható végre.", true)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.delete_needs_confirmation", true)
|
||||
return
|
||||
}
|
||||
// R-360: `restoreOpBlocked()` and not `IsRunning()`. No app-name comparison is added deliberately:
|
||||
@@ -559,24 +569,24 @@ func (s *Server) offboxVerifyCopyDeleteHandler(w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
if err := s.backupMgr.DeleteOffsiteRestoreCopy(stack); err != nil {
|
||||
s.logger.Printf("[WARN] [web] verification-copy delete %s: %v", stack, err)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "A másolat törlése nem sikerült: "+err.Error(), true)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.delete_failed", true, err.Error())
|
||||
return
|
||||
}
|
||||
s.logger.Printf("[INFO] [web] verification copy deleted: %s", stack)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "Az ellenőrző másolat törölve. A tényleges adataid változatlanok.", false)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.scratch_deleted", false)
|
||||
}
|
||||
|
||||
// offboxPlaceHandler places a COMPLETED full-restore scratch into the app's live locations via a
|
||||
// missing-only merge (§7.3). Never overwrites existing files. Async on a background context.
|
||||
func (s *Server) offboxPlaceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if s.backupMgr == nil || !s.backupMgr.OffboxConfigured() {
|
||||
offboxRedirectTo(w, r, "/backups/restore", "A távoli mentési cél nincs beállítva.", true)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.target_not_set", true)
|
||||
return
|
||||
}
|
||||
_ = r.ParseForm()
|
||||
app := strings.TrimSpace(r.FormValue("app"))
|
||||
if app == "" {
|
||||
offboxRedirectTo(w, r, "/backups/restore", "Hiányzó alkalmazás.", true)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.app_missing", true)
|
||||
return
|
||||
}
|
||||
if msg, blocked := s.restoreOpBlocked(); blocked {
|
||||
@@ -603,7 +613,7 @@ func (s *Server) offboxPlaceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
s.logger.Printf("[INFO] [web] off-box place %s completed (async)", app)
|
||||
s.backupMgr.EndRestoreOp(true, "A(z) "+app+" hiányzó fájljai helyreállítva az élő adatok közé.")
|
||||
}()
|
||||
offboxRedirectTo(w, r, restoreWizardPath(app), "A helyreállítás elindult — az állapot itt frissül.", false)
|
||||
offboxRedirectTo(w, r, restoreWizardPath(app), "flash.offbox.recover_started", false)
|
||||
}
|
||||
|
||||
// --- R-7b: „Megosztások" restore ------------------------------------------------------------------
|
||||
@@ -617,7 +627,7 @@ func (s *Server) offboxPlaceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// (POST /backup/shares/restore). Non-destructive: nothing live is touched until the place action.
|
||||
func (s *Server) sharesRestoreHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if s.backupMgr == nil || !s.backupMgr.OffboxConfigured() {
|
||||
offboxRedirectTo(w, r, "/backups/restore", "A távoli mentési cél nincs beállítva.", true)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.target_not_set", true)
|
||||
return
|
||||
}
|
||||
if msg, blocked := s.restoreOpBlocked(); blocked {
|
||||
@@ -636,14 +646,14 @@ func (s *Server) sharesRestoreHandler(w http.ResponseWriter, r *http.Request) {
|
||||
s.logger.Printf("[INFO] [web] shares restore completed (async)")
|
||||
s.backupMgr.EndRestoreOp(true, "A megosztások visszaállítása elkészült — most helyreállíthatod az élő adatok közé.")
|
||||
}()
|
||||
offboxRedirectTo(w, r, "/backups/restore", "A megosztások visszaállítása elindult — az állapot itt frissül.", false)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.shares_restore_started", false)
|
||||
}
|
||||
|
||||
// sharesPlaceHandler merges a completed shares scratch into the live share folders, re-adds the
|
||||
// missing definitions and restores the household credential (POST /backup/shares/place).
|
||||
func (s *Server) sharesPlaceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if s.backupMgr == nil || !s.backupMgr.OffboxConfigured() {
|
||||
offboxRedirectTo(w, r, "/backups/restore", "A távoli mentési cél nincs beállítva.", true)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.target_not_set", true)
|
||||
return
|
||||
}
|
||||
if msg, blocked := s.restoreOpBlocked(); blocked {
|
||||
@@ -664,5 +674,5 @@ func (s *Server) sharesPlaceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
res.FilesRestored, len(res.DefinitionsAdded))
|
||||
s.backupMgr.EndRestoreOp(true, res.FlashMessage())
|
||||
}()
|
||||
offboxRedirectTo(w, r, "/backups/restore", "A megosztások helyreállítása elindult — az állapot itt frissül.", false)
|
||||
offboxRedirectTo(w, r, "/backups/restore", "flash.offbox.shares_recover_started", false)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user