Files
ds-chat/backend/app/services/upload_settings_service.py
T
ksmithandClaude Sonnet 5 62e4760c8a Add admin-configurable upload size limits
The 8MB image/file/avatar cap is now a site setting (UploadSettings,
single-row table like SmtpSettings) editable from the Admin Settings tab,
instead of a hardcoded constant. All three upload endpoints read the live
value and interpolate it into their 413 messages. A new GET
/api/uploads/limit endpoint (open to any authenticated user, unlike the
admin-only settings endpoints) lets the composer reject an oversized file
client-side before it ever hits the network, though the server still
enforces the same cap independently.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 20:44:05 -06:00

34 lines
1.3 KiB
Python

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.models import UploadSettings
from app.storage import DEFAULT_MAX_UPLOAD_BYTES
async def get_upload_settings(db: AsyncSession) -> UploadSettings:
"""Unlike SmtpSettings (where "no row yet" means "unconfigured, skip"),
an upload cap must always resolve to a usable value -- so this creates
the row with the default on first read instead of returning None."""
result = await db.execute(select(UploadSettings).limit(1))
settings_row = result.scalar_one_or_none()
if settings_row is None:
settings_row = UploadSettings(max_upload_bytes=DEFAULT_MAX_UPLOAD_BYTES)
db.add(settings_row)
await db.commit()
await db.refresh(settings_row)
return settings_row
async def update_upload_settings(db: AsyncSession, *, max_upload_bytes: int) -> UploadSettings:
settings_row = await get_upload_settings(db)
settings_row.max_upload_bytes = max_upload_bytes
await db.commit()
await db.refresh(settings_row)
return settings_row
def format_mb(num_bytes: int) -> str:
"""Used in 413 error messages, which need to reflect the live
admin-configured cap rather than a hardcoded "8 MB"."""
return f"{num_bytes / (1024 * 1024):g} MB"