Fix #3: Avoid detached SQLAlchemy objects in middleware — store member_id, re-fetch in endpoints
Some checks failed
Deploy Tracker / deploy (push) Failing after 5s

This commit is contained in:
markov 2026-02-26 15:12:36 +01:00
parent dc6556074e
commit b67587b647
3 changed files with 17 additions and 11 deletions

View File

@ -19,11 +19,11 @@ UPLOAD_DIR = os.environ.get("UPLOAD_DIR", "/data/uploads")
MAX_FILE_SIZE = 50 * 1024 * 1024 # 50MB
def _get_member(request: Request) -> Member:
member = getattr(request.state, "member", None)
if not member:
def _get_member_id(request: Request) -> str:
member_id = getattr(request.state, "member_id", None)
if not member_id:
raise HTTPException(401, "Not authenticated")
return member
return member_id
@router.post("/upload")
@ -33,7 +33,7 @@ async def upload_file(
db: AsyncSession = Depends(get_db),
):
"""Upload a file and return attachment metadata (not yet linked to a message)."""
member = _get_member(request)
member_id = _get_member_id(request)
# Read file
content = await file.read()

View File

@ -53,10 +53,15 @@ def project_file_out(f: ProjectFile) -> ProjectFileOut:
updated_at=f.updated_at.isoformat() if f.updated_at else "",
)
def _get_member(request: Request) -> Member:
member = getattr(request.state, "member", None)
if not member:
async def _get_member(request: Request, db: AsyncSession) -> Member:
"""Get member from request state, re-fetched from DB to avoid detached objects."""
member_id = getattr(request.state, "member_id", None)
if not member_id:
raise HTTPException(401, "Not authenticated")
result = await db.execute(select(Member).where(Member.id == uuid.UUID(member_id)))
member = result.scalar_one_or_none()
if not member:
raise HTTPException(401, "Member not found")
return member
@ -97,7 +102,7 @@ async def upload_project_file(
description: Optional[str] = Form(None),
db: AsyncSession = Depends(get_db),
):
member = _get_member(request)
member = await _get_member(request, db)
project = await _get_project(slug, db)
content = await file.read()
@ -227,7 +232,7 @@ async def update_project_file(
data: ProjectFileUpdate,
db: AsyncSession = Depends(get_db),
):
member = _get_member(request)
member = await _get_member(request, db)
project = await _get_project(slug, db)
result = await db.execute(
@ -257,7 +262,7 @@ async def delete_project_file(
file_id: str,
db: AsyncSession = Depends(get_db),
):
member = _get_member(request)
member = await _get_member(request, db)
project = await _get_project(slug, db)
result = await db.execute(

View File

@ -132,6 +132,7 @@ async def auth_middleware(request: Request, call_next):
return JSONResponse(status_code=401, content={"error": "Invalid or expired token"})
request.state.member = member
request.state.member_id = str(member.id)
return await call_next(request)