- Add token-based admin login/logout/me endpoints - Bootstrap admin from ADMIN_USERNAME/ADMIN_PASSWORD in Docker entrypoint - Read ALLOWED_HOSTS and CORS from env only (no hardcoded server IPs) - Keep docs/Postman/tests free of real credentials - Cover login and auth flows with 31 local API tests Co-authored-by: Cursor <cursoragent@cursor.com>
585 lines
13 KiB
Markdown
585 lines
13 KiB
Markdown
<div dir="rtl" lang="fa">
|
||
|
||
# مستندات API (Zoneco ORG)
|
||
|
||
این سند نحوهٔ کارکرد APIهای بکاند پروژه Zoneco ORG را به زبان فارسی توضیح میدهد.
|
||
|
||
---
|
||
|
||
## وضعیت تستها
|
||
|
||
```
|
||
Ran 31 tests — OK (0 failures)
|
||
```
|
||
|
||
| تعداد تست | گروه |
|
||
|-----------|------|
|
||
| ۷ تست | Admin Login |
|
||
| ۶ تست | Contact Us |
|
||
| ۱۱ تست | Compositions |
|
||
| ۷ تست | Campaigns |
|
||
|
||
اجرای تستها:
|
||
|
||
```bash
|
||
cd backend
|
||
python manage.py test api -v 2
|
||
```
|
||
|
||
---
|
||
|
||
## اطلاعات پایه
|
||
|
||
| مقدار | مورد |
|
||
|--------|------|
|
||
| `{{base_url}}` | آدرس پایه |
|
||
| `/api/` | پیشوند API |
|
||
| JSON | فرمت پاسخ |
|
||
| ۲۰ آیتم در هر صفحه | صفحهبندی |
|
||
| `/admin/` | پنل ادمین |
|
||
|
||
### متغیر Postman
|
||
|
||
در فایل Postman از متغیر `{{base_url}}` استفاده شده است.
|
||
مقدار آن را مطابق محیط اجرا (لوکال، سرور تست یا پروداکشن) تنظیم کنید.
|
||
|
||
**نمونهٔ آدرس کامل یک endpoint:**
|
||
|
||
```
|
||
{{base_url}}/api/contact-us/
|
||
```
|
||
|
||
---
|
||
|
||
## سطح دسترسی
|
||
|
||
| دسترسی | عملیات |
|
||
|--------|--------|
|
||
| عمومی — بدون نیاز به ورود | لیست و جزئیات (متد `GET`) |
|
||
| عمومی — بدون نیاز به ورود | ایجاد (متد `POST`) |
|
||
| فقط ادمین — نیاز به توکن | ویرایش و حذف (متدهای `PUT`، `PATCH`، `DELETE`) |
|
||
|
||
---
|
||
|
||
## ۰. ورود ادمین (Admin Login)
|
||
|
||
| مقدار | مورد |
|
||
|--------|------|
|
||
| `{{admin_username}}` از env (`ADMIN_USERNAME`) | نام کاربری |
|
||
| `{{admin_password}}` از env (`ADMIN_PASSWORD`) | رمز عبور |
|
||
| `{{base_url}}/admin/` | پنل جنگو ادمین |
|
||
| `POST {{base_url}}/api/admin/login/` | ورود از طریق API |
|
||
|
||
> نام کاربری و رمز در کد هاردکد نمیشوند. روی سرور در فایل `.env` تنظیم کنید.
|
||
|
||
### ورود و دریافت توکن
|
||
|
||
```
|
||
POST {{base_url}}/api/admin/login/
|
||
Content-Type: application/json
|
||
```
|
||
|
||
```json
|
||
{
|
||
"username": "{{admin_username}}",
|
||
"password": "{{admin_password}}"
|
||
}
|
||
```
|
||
|
||
**پاسخ نمونه:**
|
||
|
||
```json
|
||
{
|
||
"token": "<token>",
|
||
"user": {
|
||
"id": 1,
|
||
"username": "<admin_username>",
|
||
"is_staff": true,
|
||
"is_superuser": true
|
||
}
|
||
}
|
||
```
|
||
|
||
در درخواستهای محافظتشده این هدر را بفرستید:
|
||
|
||
```
|
||
Authorization: Token <token>
|
||
```
|
||
|
||
### اطلاعات ادمین فعلی
|
||
|
||
```
|
||
GET {{base_url}}/api/admin/me/
|
||
Authorization: Token <token>
|
||
```
|
||
|
||
### خروج (حذف توکن)
|
||
|
||
```
|
||
POST {{base_url}}/api/admin/logout/
|
||
Authorization: Token <token>
|
||
```
|
||
|
||
برای درخواستهای ادمین در Postman، ابتدا login کنید، سپس توکن را در متغیر `admin_token` بگذارید.
|
||
|
||
---
|
||
|
||
## ۱. تماس با ما (Contact Us)
|
||
|
||
**مسیر پایه:**
|
||
|
||
```
|
||
/api/contact-us/
|
||
```
|
||
|
||
### فیلدها
|
||
|
||
| توضیح | الزامی | نوع | فیلد |
|
||
|-------|--------|-----|------|
|
||
| نام و نام خانوادگی | بله | string | `name` |
|
||
| ایمیل یا شماره تماس | بله | string | `email_or_phone` |
|
||
| متن پیام | بله | string | `description` |
|
||
| دستهبندی | بله | string | `category` |
|
||
|
||
**مقادیر مجاز برای `category`:**
|
||
|
||
- همکاری
|
||
- فروش
|
||
- پشتیبانی
|
||
- درخواست مشاور
|
||
- سایر
|
||
|
||
---
|
||
|
||
### دریافت لیست تماسها
|
||
|
||
```
|
||
GET {{base_url}}/api/contact-us/
|
||
```
|
||
|
||
**پاسخ نمونه:**
|
||
|
||
```json
|
||
{
|
||
"count": 1,
|
||
"next": null,
|
||
"previous": null,
|
||
"results": [
|
||
{
|
||
"id": 1,
|
||
"name": "احمد محمدی",
|
||
"email_or_phone": "ahmad@example.com",
|
||
"description": "سلام، سوالی دارم.",
|
||
"category": "پشتیبانی",
|
||
"created_at": "2025-12-17T12:00:00Z",
|
||
"updated_at": "2025-12-17T12:00:00Z"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### دریافت یک تماس
|
||
|
||
```
|
||
GET {{base_url}}/api/contact-us/{id}/
|
||
```
|
||
|
||
---
|
||
|
||
### ثبت تماس جدید
|
||
|
||
```
|
||
POST {{base_url}}/api/contact-us/
|
||
Content-Type: application/json
|
||
```
|
||
|
||
**بدنه درخواست:**
|
||
|
||
```json
|
||
{
|
||
"name": "احمد محمدی",
|
||
"email_or_phone": "09121234567",
|
||
"description": "میخواهم در مورد محصولات اطلاعات بگیرم.",
|
||
"category": "فروش"
|
||
}
|
||
```
|
||
|
||
**کد پاسخ:** `201 Created`
|
||
|
||
---
|
||
|
||
### فیلتر بر اساس دستهبندی
|
||
|
||
```
|
||
GET {{base_url}}/api/contact-us/by_category/?category=پشتیبانی
|
||
```
|
||
|
||
| توضیح | الزامی | پارامتر |
|
||
|-------|--------|---------|
|
||
| یکی از دستههای مجاز | بله | `category` |
|
||
|
||
اگر پارامتر `category` ارسال نشود، خطای `400` برمیگردد.
|
||
|
||
---
|
||
|
||
### ویرایش و حذف (ادمین)
|
||
|
||
```
|
||
PUT {{base_url}}/api/contact-us/{id}/
|
||
PATCH {{base_url}}/api/contact-us/{id}/
|
||
DELETE {{base_url}}/api/contact-us/{id}/
|
||
```
|
||
|
||
نیاز به احراز هویت ادمین دارد.
|
||
|
||
---
|
||
|
||
## ۲. ترکیبات (Compositions)
|
||
|
||
**مسیر پایه:**
|
||
|
||
```
|
||
/api/compositions/
|
||
```
|
||
|
||
هر ترکیب میتواند **چند تصویر** داشته باشد.
|
||
یکی از تصاویر با فیلد `is_main: true` بهعنوان **تصویر اصلی** مشخص میشود.
|
||
|
||
### فیلدها
|
||
|
||
| توضیح | الزامی | نوع | فیلد |
|
||
|-------|--------|-----|------|
|
||
| نام ترکیب | بله | string | `name` |
|
||
| توضیحات | بله | string | `description` |
|
||
| یک یا چند فایل تصویر (فقط در ایجاد/ویرایش) | خیر | file[] | `uploaded_images` |
|
||
| ایندکس تصویر اصلی (شمارش از ۰) | خیر | integer | `main_image_index` |
|
||
|
||
### محدودیت تصاویر
|
||
|
||
- فرمتهای مجاز: JPEG، PNG، WebP، GIF
|
||
- حداکثر حجم هر فایل: **۵ مگابایت**
|
||
- مسیر ذخیره: `media/compositions/`
|
||
|
||
---
|
||
|
||
### دریافت لیست ترکیبات
|
||
|
||
```
|
||
GET {{base_url}}/api/compositions/
|
||
```
|
||
|
||
---
|
||
|
||
### دریافت یک ترکیب
|
||
|
||
```
|
||
GET {{base_url}}/api/compositions/{id}/
|
||
```
|
||
|
||
**پاسخ نمونه:**
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"name": "ترکیب A",
|
||
"description": "توضیحات ترکیب",
|
||
"image": null,
|
||
"image_url": null,
|
||
"images": [
|
||
{
|
||
"id": 2,
|
||
"image": "/media/compositions/img2.jpg",
|
||
"image_url": "{{base_url}}/media/compositions/img2.jpg",
|
||
"is_main": true,
|
||
"created_at": "2025-12-17T12:00:00Z"
|
||
},
|
||
{
|
||
"id": 1,
|
||
"image": "/media/compositions/img1.jpg",
|
||
"image_url": "{{base_url}}/media/compositions/img1.jpg",
|
||
"is_main": false,
|
||
"created_at": "2025-12-17T11:00:00Z"
|
||
}
|
||
],
|
||
"main_image": {
|
||
"id": 2,
|
||
"image_url": "{{base_url}}/media/compositions/img2.jpg",
|
||
"is_main": true,
|
||
"created_at": "2025-12-17T12:00:00Z"
|
||
},
|
||
"created_at": "2025-12-17T10:00:00Z",
|
||
"updated_at": "2025-12-17T12:00:00Z"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### فیلتر بر اساس تاریخ ایجاد
|
||
|
||
```
|
||
GET {{base_url}}/api/compositions/by-created-at/?from=2026-06-01T00:00:00Z&to=2026-06-30T23:59:59Z
|
||
```
|
||
|
||
| توضیح | الزامی | پارامتر |
|
||
|-------|--------|---------|
|
||
| برگشت ترکیبهایی که `created_at >= from` | حداقل یکی | `from` |
|
||
| برگشت ترکیبهایی که `created_at <= to` | حداقل یکی | `to` |
|
||
|
||
فرمت تاریخ: ISO 8601 — مثال: `2026-06-01T00:00:00Z`
|
||
|
||
اگر هیچ پارامتری ارسال نشود، خطای `400` برمیگردد.
|
||
|
||
---
|
||
|
||
### ایجاد ترکیب (بدون تصویر)
|
||
|
||
```
|
||
POST {{base_url}}/api/compositions/
|
||
Content-Type: application/json
|
||
```
|
||
|
||
```json
|
||
{
|
||
"name": "ترکیب تست",
|
||
"description": "توضیحات ترکیب"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### ایجاد ترکیب با چند تصویر
|
||
|
||
```
|
||
POST {{base_url}}/api/compositions/
|
||
Content-Type: multipart/form-data
|
||
```
|
||
|
||
| مقدار نمونه | نوع | فیلد |
|
||
|-------------|-----|------|
|
||
| ترکیب A | text | `name` |
|
||
| توضیحات | text | `description` |
|
||
| image1.jpg | file | `uploaded_images` |
|
||
| image2.jpg | file | `uploaded_images` |
|
||
| 1 | text | `main_image_index` |
|
||
|
||
**نکته:** فیلد `uploaded_images` را برای هر تصویر یکبار تکرار کنید.
|
||
|
||
**نکته:** اگر `main_image_index` ارسال نشود، **اولین تصویر** بهعنوان تصویر اصلی انتخاب میشود.
|
||
|
||
---
|
||
|
||
### افزودن تصویر به ترکیب موجود (ادمین)
|
||
|
||
```
|
||
POST {{base_url}}/api/compositions/{id}/add-images/
|
||
Content-Type: multipart/form-data
|
||
```
|
||
|
||
| نوع | فیلد |
|
||
|-----|------|
|
||
| file (یک یا چند فایل) | `uploaded_images` |
|
||
| text (اختیاری) | `main_image_index` |
|
||
|
||
---
|
||
|
||
### تنظیم تصویر اصلی (ادمین)
|
||
|
||
```
|
||
POST {{base_url}}/api/compositions/{id}/set-main-image/
|
||
Content-Type: application/json
|
||
```
|
||
|
||
```json
|
||
{
|
||
"image_id": 3
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### حذف یک تصویر (ادمین)
|
||
|
||
```
|
||
DELETE {{base_url}}/api/compositions/{id}/images/{image_id}/
|
||
```
|
||
|
||
**کد پاسخ:** `204 No Content`
|
||
|
||
---
|
||
|
||
### ویرایش و حذف ترکیب (ادمین)
|
||
|
||
```
|
||
PUT {{base_url}}/api/compositions/{id}/
|
||
PATCH {{base_url}}/api/compositions/{id}/
|
||
DELETE {{base_url}}/api/compositions/{id}/
|
||
```
|
||
|
||
---
|
||
|
||
## ۳. کمپینها (Campaigns)
|
||
|
||
**مسیر پایه:**
|
||
|
||
```
|
||
/api/campaigns/
|
||
```
|
||
|
||
### فیلدها
|
||
|
||
| توضیح | الزامی | نوع | فیلد |
|
||
|-------|--------|-----|------|
|
||
| نام کمپین | بله | string | `name` |
|
||
| توضیحات | بله | string | `description` |
|
||
| زمان شروع (ISO 8601) | بله | datetime | `start_time` |
|
||
| زمان پایان (باید بعد از `start_time` باشد) | بله | datetime | `end_time` |
|
||
| تصویر کمپین | خیر | file | `image` |
|
||
|
||
### فیلدهای محاسباتی (فقط خواندنی)
|
||
|
||
| توضیح | فیلد |
|
||
|-------|------|
|
||
| آیا کمپین الان فعال است | `is_active` |
|
||
| آیا کمپین هنوز شروع نشده | `is_upcoming` |
|
||
| آیا کمپین تمام شده | `is_ended` |
|
||
|
||
---
|
||
|
||
### دریافت لیست کمپینها
|
||
|
||
```
|
||
GET {{base_url}}/api/campaigns/
|
||
```
|
||
|
||
---
|
||
|
||
### دریافت یک کمپین
|
||
|
||
```
|
||
GET {{base_url}}/api/campaigns/{id}/
|
||
```
|
||
|
||
---
|
||
|
||
### ایجاد کمپین
|
||
|
||
```
|
||
POST {{base_url}}/api/campaigns/
|
||
Content-Type: application/json
|
||
```
|
||
|
||
```json
|
||
{
|
||
"name": "کمپین نوروز",
|
||
"description": "تخفیف ویژه نوروز",
|
||
"start_time": "2026-03-01T00:00:00Z",
|
||
"end_time": "2026-03-31T23:59:59Z"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### کمپینهای فعال
|
||
|
||
```
|
||
GET {{base_url}}/api/campaigns/active/
|
||
```
|
||
|
||
کمپینهایی که زمان فعلی بین `start_time` و `end_time` قرار دارد.
|
||
|
||
---
|
||
|
||
### کمپینهای آینده
|
||
|
||
```
|
||
GET {{base_url}}/api/campaigns/upcoming/
|
||
```
|
||
|
||
کمپینهایی که هنوز شروع نشدهاند.
|
||
|
||
---
|
||
|
||
### کمپینهای پایانیافته
|
||
|
||
```
|
||
GET {{base_url}}/api/campaigns/ended/
|
||
```
|
||
|
||
---
|
||
|
||
### ویرایش و حذف (ادمین)
|
||
|
||
```
|
||
PUT {{base_url}}/api/campaigns/{id}/
|
||
PATCH {{base_url}}/api/campaigns/{id}/
|
||
DELETE {{base_url}}/api/campaigns/{id}/
|
||
```
|
||
|
||
---
|
||
|
||
## کدهای وضعیت HTTP
|
||
|
||
| معنی | کد |
|
||
|------|-----|
|
||
| موفق | `200` |
|
||
| ایجاد شد | `201` |
|
||
| حذف شد (بدون بدنه) | `204` |
|
||
| داده نامعتبر | `400` |
|
||
| دسترسی ندارید | `403` |
|
||
| یافت نشد | `404` |
|
||
|
||
---
|
||
|
||
## فایل Postman
|
||
|
||
مجموعه Postman در مسیر زیر قرار دارد:
|
||
|
||
```
|
||
backend/Zoneco_ORG_API.postman_collection.json
|
||
```
|
||
|
||
### نحوه import
|
||
|
||
1. Postman را باز کنید
|
||
2. گزینه **Import** را بزنید
|
||
3. فایل `Zoneco_ORG_API.postman_collection.json` را انتخاب کنید
|
||
4. متغیر `{{base_url}}` را مطابق محیط خود تنظیم کنید
|
||
5. برای درخواستهای ادمین، در تب **Authorization** گزینه **Basic Auth** را فعال کنید
|
||
|
||
---
|
||
|
||
## خلاصه endpointها
|
||
|
||
| دسترسی | Endpoint | Method | # |
|
||
|--------|----------|--------|---|
|
||
| عمومی | `/api/admin/login/` | POST | 1 |
|
||
| ادمین | `/api/admin/logout/` | POST | 2 |
|
||
| ادمین | `/api/admin/me/` | GET | 3 |
|
||
| عمومی | `/api/contact-us/` | GET | 4 |
|
||
| عمومی | `/api/contact-us/` | POST | 5 |
|
||
| عمومی | `/api/contact-us/{id}/` | GET | 6 |
|
||
| عمومی | `/api/contact-us/by_category/?category=...` | GET | 7 |
|
||
| ادمین | `/api/contact-us/{id}/` | PUT/PATCH/DELETE | 8 |
|
||
| عمومی | `/api/compositions/` | GET | 9 |
|
||
| عمومی | `/api/compositions/` | POST | 10 |
|
||
| عمومی | `/api/compositions/{id}/` | GET | 11 |
|
||
| عمومی | `/api/compositions/by-created-at/?from=...&to=...` | GET | 12 |
|
||
| ادمین | `/api/compositions/{id}/add-images/` | POST | 13 |
|
||
| ادمین | `/api/compositions/{id}/set-main-image/` | POST | 14 |
|
||
| ادمین | `/api/compositions/{id}/images/{image_id}/` | DELETE | 15 |
|
||
| ادمین | `/api/compositions/{id}/` | PUT/PATCH/DELETE | 16 |
|
||
| عمومی | `/api/campaigns/` | GET | 17 |
|
||
| عمومی | `/api/campaigns/` | POST | 18 |
|
||
| عمومی | `/api/campaigns/{id}/` | GET | 19 |
|
||
| عمومی | `/api/campaigns/active/` | GET | 20 |
|
||
| عمومی | `/api/campaigns/upcoming/` | GET | 21 |
|
||
| عمومی | `/api/campaigns/ended/` | GET | 22 |
|
||
| ادمین | `/api/campaigns/{id}/` | PUT/PATCH/DELETE | 23 |
|
||
|
||
> **توجه:** در Postman قبل از هر مسیر، مقدار `{{base_url}}` را قرار دهید.
|
||
> مثال: `{{base_url}}/api/campaigns/active/`
|
||
|
||
</div>
|