From 30038d51031b8313bf5023a49218d5988d3272af Mon Sep 17 00:00:00 2001 From: aramesh-site deploy Date: Wed, 30 Sep 2026 10:37:30 +0000 Subject: [PATCH] =?UTF-8?q?fix(media):=20=D8=B3=D9=82=D9=81=20=D8=A2=D9=BE?= =?UTF-8?q?=D9=84=D9=88=D8=AF=20=DB=B1=DB=B0=E2=86=92=DB=B2=DB=B5=20=D9=85?= =?UTF-8?q?=DA=AF=D8=A7=D8=A8=D8=A7=DB=8C=D8=AA=20(=D9=84=D8=A8=D9=87=20?= =?UTF-8?q?=DB=B3=DB=B0MB)=20+=20=D9=BE=DB=8C=D8=A7=D9=85=20=D9=85=D8=B4?= =?UTF-8?q?=D8=AE=D8=B5=20=DB=B4=DB=B1=DB=B3=20=D9=88=20=D9=BE=DB=8C=D8=B4?= =?UTF-8?q?=E2=80=8C=DA=86=DA=A9=20=D8=AD=D8=AC=D9=85=20=D8=B3=D9=85=D8=AA?= =?UTF-8?q?=20=DA=A9=D8=A7=D8=B1=D8=A8=D8=B1=20=E2=80=94=20=D9=81=D8=A7?= =?UTF-8?q?=DB=8C=D9=84=E2=80=8C=D9=87=D8=A7=DB=8C=20=D8=A8=D8=B2=D8=B1?= =?UTF-8?q?=DA=AF=20=D8=AA=DB=8C=D9=85=20=D9=85=D8=AD=D8=AA=D9=88=D8=A7=20?= =?UTF-8?q?=D8=AF=D8=B1=20=D9=84=D8=A8=D9=87=20=D8=B1=D8=AF=20=D9=85=DB=8C?= =?UTF-8?q?=E2=80=8C=D8=B4=D8=AF=D9=86=D8=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/config.py | 3 ++- frontend/src/admin/adminClient.ts | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/backend/app/config.py b/backend/app/config.py index 2edf067..c963867 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -26,7 +26,8 @@ class Settings(BaseSettings): s3_bucket: str = "aramesh-media" # پیشوند عمومی مسیر تصاویر — Traefik آن را به باکت پروکسی می‌کند media_public_base: str = "/media" - media_max_upload_mb: int = 10 + # رندرهای معماری حجیم‌اند — لبه (Traefik api-bodylimit) باید همیشه بزرگ‌تر از این باشد + media_max_upload_mb: int = 25 # نشانی کامل سایت (مثل https://aramesh.example) — برای sitemap و آدرس مطلق OG site_url: str = "" diff --git a/frontend/src/admin/adminClient.ts b/frontend/src/admin/adminClient.ts index c3600a4..2a0a5bc 100644 --- a/frontend/src/admin/adminClient.ts +++ b/frontend/src/admin/adminClient.ts @@ -3,6 +3,9 @@ import { API_URL } from '../config' const TOKEN_KEY = 'aramesh_admin_token' +/** سقف آپلود — هم‌اندازهٔ media_max_upload_mb بک‌اند (تنظیمات) */ +const MAX_UPLOAD_BYTES = 25 * 1024 * 1024 + /** رویداد تغییر وضعیت ورود — لایه‌های دیگر (مثل نوار ادمین) با آن همگام می‌مانند */ export const AUTH_CHANGE_EVENT = 'aramesh:auth-change' @@ -43,9 +46,11 @@ async function authFetch(path: string, options: RequestInit = {}): Promise const detail = typeof data?.detail === 'string' ? data.detail - : res.status === 409 - ? 'رکوردی با این مقدار تکراری وجود دارد' - : 'خطا در ذخیره‌سازی — دوباره تلاش کنید' + : res.status === 413 + ? 'حجم فایل بیش از حد مجاز است (حداکثر ۲۵ مگابایت)' + : res.status === 409 + ? 'رکوردی با این مقدار تکراری وجود دارد' + : 'خطا در ذخیره‌سازی — دوباره تلاش کنید' throw new HttpError(res.status, detail) } return res.status === 204 ? (null as T) : ((await res.json()) as T) @@ -88,6 +93,10 @@ export const adminApi = { authFetch(`/api/admin/${resource}/reorder`, { method: 'POST', body: JSON.stringify({ ids }) }), upload: async (file: File, name?: string): Promise<{ url: string; key: string }> => { + // پیش‌چک سمت کاربر — خطای ۴۱۳ لبه/CDN به‌صورت صفحه HTML می‌رسد و پیام خاص از دست می‌رود + if (file.size > MAX_UPLOAD_BYTES) { + throw new HttpError(413, 'حجم فایل بیش از ۲۵ مگابایت است — فایل را کوچک‌تر کنید') + } const fd = new FormData() fd.append('file', file) if (name && name.trim()) fd.append('name', name.trim())