fix: backup storage relative to vault parent + global capture click handler for close button
CI / lint (push) Failing after 4s
CI / test (push) Has been skipped
CI / build (push) Has been skipped
CI / security (push) Failing after 5s

- _backup_file: resolve relative backup path against vault parent (survives CWD changes)
- _get_backup_root: same resolution logic for listing
- backups.js: global document-level capture-phase click handler for .backup-close-btn
  (works regardless of innerHTML replacements, text node targets, or event bubbling)
This commit is contained in:
2026-06-04 15:22:02 -04:00
parent af05604e99
commit bc8083fd6b
2 changed files with 46 additions and 31 deletions
+30 -5
View File
@@ -715,22 +715,29 @@ def _resolve_safe_path(vault_root: Path, relative_path: str) -> Path:
def _backup_file(file_path: Path, vault_name: str, relative_path: str):
"""Create a timestamped backup of a file before modification.
Backups are stored in .obsigate-backup/{vault}/{relative_path}.{timestamp}.bak
Backups are stored in {backup_root}/{vault}/{relative_path}.{timestamp}.bak
Silently skips if the file doesn't exist or can't be read.
"""
try:
if not file_path.exists() or not file_path.is_file():
logger.debug(f"Backup skipped: file not found {file_path}")
return
backup_root = Path(os.environ.get("OBSIGATE_BACKUP_DIR", ".obsigate-backup"))
# Resolve relative to vault root for consistency
if not backup_root.is_absolute():
vault_data = get_vault_data(vault_name)
if vault_data:
vault_root_path = Path(vault_data["path"])
backup_root = vault_root_path.parent / backup_root
backup_dir = backup_root / vault_name / Path(relative_path).parent
backup_dir.mkdir(parents=True, exist_ok=True)
timestamp = int(time.time())
backup_name = f"{file_path.name}.{timestamp}.bak"
backup_path = backup_dir / backup_name
shutil.copy2(file_path, backup_path)
logger.debug(f"Backed up {relative_path} to {backup_path}")
logger.info(f"Backup created: {relative_path} -> {backup_path}")
except Exception as e:
logger.warning(f"Failed to backup {relative_path}: {e}")
logger.warning(f"Failed to backup {relative_path} (vault={vault_name}): {e}", exc_info=True)
def _check_vault_writable(vault_root: Path) -> bool:
@@ -1928,8 +1935,26 @@ async def api_file_move(
# ---------------------------------------------------------------------------
def _get_backup_root() -> Path:
"""Return the backup root directory as configured."""
return Path(os.environ.get("OBSIGATE_BACKUP_DIR", ".obsigate-backup"))
"""Return the backup root directory as configured.
If the configured path is relative, it is resolved relative to the
first vault's parent directory for consistency with _backup_file.
"""
root = Path(os.environ.get("OBSIGATE_BACKUP_DIR", ".obsigate-backup"))
if not root.is_absolute():
# Resolve relative to the first vault's parent so backups survive CWD changes
try:
from backend.indexer import get_vault_data as _get_vd
vaults = index # use the module-level index
if vaults:
first_name = next(iter(vaults.keys()))
vd = _get_vd(first_name)
if vd:
vault_parent = Path(vd["path"]).parent
root = vault_parent / root
except Exception:
pass # fall back to relative
return root
def _get_backup_dir(vault_name: str, relative_path: str) -> Path: