open-notebook/api
Luis Novo d9f6a86c1a
Some checks are pending
Development Build / summary (push) Blocked by required conditions
Development Build / build-single (push) Blocked by required conditions
Development Build / extract-version (push) Waiting to run
Development Build / build-regular (push) Blocked by required conditions
Tests / Backend Tests (push) Waiting to run
Tests / Backend Lint (push) Waiting to run
Tests / Backend Typecheck (push) Waiting to run
Tests / Frontend Tests (push) Waiting to run
Tests / Frontend Lint (push) Waiting to run
Tests / Frontend Build (push) Waiting to run
refactor(podcasts): store audio paths relative to PODCASTS_FOLDER (#1111)
* refactor(podcasts): store audio paths relative to PODCASTS_FOLDER

audio_file previously stored the absolute path returned by
podcast-creator (sometimes as a file:// URI), which kept path traversal
representable in the DB and broke playback when DATA_FOLDER moved.

- New single choke point open_notebook/podcasts/audio_paths.py:
  to_relative_audio_path() validates at write time (the DB can never
  hold an absolute or root-escaping value) and
  resolve_contained_audio_path() joins + resolves + contains at read
  time, replacing the per-router guards from #1018. Absolute/file://
  legacy values are treated as invalid (same 403/404 as before).
- Generation command stores the relative form; in-band "ERROR: ..."
  values from podcast-creator now fail the job with the real error.
- build_episode_output_dir() builds from PODCASTS_FOLDER so the write
  root and the validation root cannot drift.
- Migration 21 converts legacy rows under the known roots (plain
  file:/// URIs, /app/data/podcasts/, /data/podcasts/,
  ./data/podcasts/, data/podcasts/) via a single-strip IF/ELSE chain;
  rows under other roots stay untouched by design.

Closes #1030

* test: use the tolerant migration-count assertion pattern

Per review: assert >= 21 with up/down parity and a distinctive-SQL check on
index 20, matching the convention from the migration-19/20 tests, so the next
migration doesn't trip an unrelated test file.
2026-07-12 14:00:34 -03:00
..
routers refactor(podcasts): store audio paths relative to PODCASTS_FOLDER (#1111) 2026-07-12 14:00:34 -03:00
__init__.py Api podcast migration (#93) 2025-07-17 08:36:11 -03:00
AGENTS.md docs: restructure documentation around AGENTS.md, VISION.md and decision records (#1032) 2026-07-10 15:33:19 -03:00
auth.py chore: remove dead auth helper and fix stale default-password docs (#1026) 2026-07-10 15:47:40 -03:00
CLAUDE.md docs: restructure documentation around AGENTS.md, VISION.md and decision records (#1032) 2026-07-10 15:33:19 -03:00
command_service.py refactor(api): remove dead Streamlit-era service layer and demo commands (#1054) 2026-07-11 18:17:44 -03:00
credentials_service.py ci: gate PRs on mypy, start ignore_errors burn-down (#1076) 2026-07-11 19:25:29 -03:00
main.py refactor(api): single context-building implementation (#1079) 2026-07-11 19:55:46 -03:00
middleware.py fix: reject oversized request bodies before auth/routing (#1014) 2026-07-10 11:15:18 -03:00
models.py refactor(frontend): consume GET /api/providers instead of the manual provider table (#1108) 2026-07-12 12:46:38 -03:00
podcast_service.py fix(podcasts): reference speaker profiles by record ID instead of name (#1110) 2026-07-12 13:05:04 -03:00