feat: GET /transcripts/{filename} — serve transcript content
This commit is contained in:
+11
-1
@@ -6,7 +6,7 @@ from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Depends, HTTPExce
|
||||
|
||||
from api.state import state, Status
|
||||
from config import load as load_config
|
||||
from output import list_transcripts
|
||||
from output import list_transcripts, read_transcript
|
||||
|
||||
router = APIRouter()
|
||||
_ws_clients: list[WebSocket] = []
|
||||
@@ -124,6 +124,16 @@ async def get_transcripts(user: dict = Depends(current_user)):
|
||||
return list_transcripts(user_dir)
|
||||
|
||||
|
||||
@router.get("/transcripts/{filename}")
|
||||
async def get_transcript(filename: str, user: dict = Depends(current_user)):
|
||||
from fastapi.responses import PlainTextResponse
|
||||
user_dir = os.path.join(user["output_dir"], user["username"])
|
||||
content = read_transcript(user_dir, filename)
|
||||
if content is None:
|
||||
raise HTTPException(status_code=404, detail="Nicht gefunden")
|
||||
return PlainTextResponse(content)
|
||||
|
||||
|
||||
@router.get("/config")
|
||||
async def get_config(user: dict = Depends(current_user)):
|
||||
return load_config()
|
||||
|
||||
@@ -35,6 +35,17 @@ def save_transcript(
|
||||
return path
|
||||
|
||||
|
||||
def read_transcript(output_dir: str, filename: str) -> str | None:
|
||||
"""Return file content if filename is a plain .md file inside output_dir."""
|
||||
if os.path.basename(filename) != filename or not filename.endswith(".md"):
|
||||
return None
|
||||
path = os.path.join(output_dir, filename)
|
||||
if not os.path.exists(path):
|
||||
return None
|
||||
with open(path, encoding="utf-8") as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def list_transcripts(output_dir: str, limit: int = 20) -> list[dict]:
|
||||
if not os.path.exists(output_dir):
|
||||
return []
|
||||
|
||||
@@ -45,6 +45,30 @@ def test_status_requires_auth():
|
||||
assert r.status_code == 401
|
||||
|
||||
|
||||
def make_app_for_dir(output_dir: str):
|
||||
from fastapi import FastAPI
|
||||
from api.router import router, current_user
|
||||
app = FastAPI()
|
||||
app.dependency_overrides[current_user] = lambda: {"username": "", "output_dir": output_dir, "is_admin": False}
|
||||
app.include_router(router)
|
||||
return app
|
||||
|
||||
|
||||
def test_get_transcript_returns_content(tmp_path):
|
||||
f = tmp_path / "2026-01-01-0900-test.md"
|
||||
f.write_text("# Hello\n\ncontent here\n")
|
||||
client = TestClient(make_app_for_dir(str(tmp_path)))
|
||||
r = client.get("/transcripts/2026-01-01-0900-test.md")
|
||||
assert r.status_code == 200
|
||||
assert "Hello" in r.text
|
||||
|
||||
|
||||
def test_get_transcript_rejects_path_traversal(tmp_path):
|
||||
client = TestClient(make_app_for_dir(str(tmp_path)))
|
||||
r = client.get("/transcripts/..%2Fsecret.md")
|
||||
assert r.status_code == 404
|
||||
|
||||
|
||||
def test_login_rejects_wrong_credentials():
|
||||
import tempfile, os
|
||||
from unittest.mock import patch
|
||||
|
||||
Reference in New Issue
Block a user