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
Some checks failed
Deploy Tracker / deploy (push) Failing after 5s
This commit is contained in:
parent
dc6556074e
commit
b67587b647
@ -19,11 +19,11 @@ UPLOAD_DIR = os.environ.get("UPLOAD_DIR", "/data/uploads")
|
|||||||
MAX_FILE_SIZE = 50 * 1024 * 1024 # 50MB
|
MAX_FILE_SIZE = 50 * 1024 * 1024 # 50MB
|
||||||
|
|
||||||
|
|
||||||
def _get_member(request: Request) -> Member:
|
def _get_member_id(request: Request) -> str:
|
||||||
member = getattr(request.state, "member", None)
|
member_id = getattr(request.state, "member_id", None)
|
||||||
if not member:
|
if not member_id:
|
||||||
raise HTTPException(401, "Not authenticated")
|
raise HTTPException(401, "Not authenticated")
|
||||||
return member
|
return member_id
|
||||||
|
|
||||||
|
|
||||||
@router.post("/upload")
|
@router.post("/upload")
|
||||||
@ -33,7 +33,7 @@ async def upload_file(
|
|||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_db),
|
||||||
):
|
):
|
||||||
"""Upload a file and return attachment metadata (not yet linked to a message)."""
|
"""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
|
# Read file
|
||||||
content = await file.read()
|
content = await file.read()
|
||||||
|
|||||||
@ -53,10 +53,15 @@ def project_file_out(f: ProjectFile) -> ProjectFileOut:
|
|||||||
updated_at=f.updated_at.isoformat() if f.updated_at else "",
|
updated_at=f.updated_at.isoformat() if f.updated_at else "",
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_member(request: Request) -> Member:
|
async def _get_member(request: Request, db: AsyncSession) -> Member:
|
||||||
member = getattr(request.state, "member", None)
|
"""Get member from request state, re-fetched from DB to avoid detached objects."""
|
||||||
if not member:
|
member_id = getattr(request.state, "member_id", None)
|
||||||
|
if not member_id:
|
||||||
raise HTTPException(401, "Not authenticated")
|
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
|
return member
|
||||||
|
|
||||||
|
|
||||||
@ -97,7 +102,7 @@ async def upload_project_file(
|
|||||||
description: Optional[str] = Form(None),
|
description: Optional[str] = Form(None),
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_db),
|
||||||
):
|
):
|
||||||
member = _get_member(request)
|
member = await _get_member(request, db)
|
||||||
project = await _get_project(slug, db)
|
project = await _get_project(slug, db)
|
||||||
|
|
||||||
content = await file.read()
|
content = await file.read()
|
||||||
@ -227,7 +232,7 @@ async def update_project_file(
|
|||||||
data: ProjectFileUpdate,
|
data: ProjectFileUpdate,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_db),
|
||||||
):
|
):
|
||||||
member = _get_member(request)
|
member = await _get_member(request, db)
|
||||||
project = await _get_project(slug, db)
|
project = await _get_project(slug, db)
|
||||||
|
|
||||||
result = await db.execute(
|
result = await db.execute(
|
||||||
@ -257,7 +262,7 @@ async def delete_project_file(
|
|||||||
file_id: str,
|
file_id: str,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_db),
|
||||||
):
|
):
|
||||||
member = _get_member(request)
|
member = await _get_member(request, db)
|
||||||
project = await _get_project(slug, db)
|
project = await _get_project(slug, db)
|
||||||
|
|
||||||
result = await db.execute(
|
result = await db.execute(
|
||||||
|
|||||||
@ -132,6 +132,7 @@ async def auth_middleware(request: Request, call_next):
|
|||||||
return JSONResponse(status_code=401, content={"error": "Invalid or expired token"})
|
return JSONResponse(status_code=401, content={"error": "Invalid or expired token"})
|
||||||
|
|
||||||
request.state.member = member
|
request.state.member = member
|
||||||
|
request.state.member_id = str(member.id)
|
||||||
return await call_next(request)
|
return await call_next(request)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user