Add multi-image compositions, docker setup, tests, and docs

- Add CompositionImage model with multi-image upload and main image flag
- Add composition endpoints: add-images, set-main-image, delete image, by-created-at filter
- Make contact-us by_category public
- Add 24 API tests covering all endpoints
- Add Dockerfile, docker-compose, entrypoint and docker docs
- Add Persian API docs and update README and Postman collection

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Shayan Azadi
2026-06-24 13:43:34 +03:30
parent cc2e082d53
commit 7e71d922d3
18 changed files with 2332 additions and 398 deletions

View File

@@ -2,197 +2,29 @@
"info": {
"_postman_id": "zoneco-org-api-collection",
"name": "Zoneco ORG API",
"description": "Complete API collection for Zoneco ORG backend - Campaign, Contact Us, and Composition endpoints",
"description": "مجموعه کامل APIهای بک‌اند Zoneco ORG — شامل Contact Us، Compositions (با آپلود چند تصویر) و Campaigns.\n\nمتغیرها:\n- base_url: آدرس سرور (پیش‌فرض http://localhost:8000)\n- composition_id: شناسه ترکیب برای تست\n- image_id: شناسه تصویر ترکیب\n\nبرای درخواست‌های ادمین از Basic Auth استفاده کنید.",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Campaigns",
"item": [
{
"name": "GET All Campaigns",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/campaigns/",
"host": [
"{{base_url}}"
],
"path": [
"api",
"campaigns",
""
]
},
"description": "Get all campaigns"
},
"response": []
},
{
"name": "GET Campaign by ID",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/campaigns/1/",
"host": [
"{{base_url}}"
],
"path": [
"api",
"campaigns",
"1",
""
]
},
"description": "Get a specific campaign by ID"
},
"response": []
},
{
"name": "POST Create Campaign",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"کمپین تست\",\n \"description\": \"این یک کمپین تستی است\",\n \"start_time\": \"2024-01-01T00:00:00Z\",\n \"end_time\": \"2024-12-31T23:59:59Z\"\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{base_url}}/api/campaigns/",
"host": [
"{{base_url}}"
],
"path": [
"api",
"campaigns",
""
]
},
"description": "Create a new campaign"
},
"response": []
},
{
"name": "GET Active Campaigns",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/campaigns/active/",
"host": [
"{{base_url}}"
],
"path": [
"api",
"campaigns",
"active",
""
]
},
"description": "Get all currently active campaigns"
},
"response": []
},
{
"name": "GET Upcoming Campaigns",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/campaigns/upcoming/",
"host": [
"{{base_url}}"
],
"path": [
"api",
"campaigns",
"upcoming",
""
]
},
"description": "Get all upcoming campaigns"
},
"response": []
},
{
"name": "GET Ended Campaigns",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/campaigns/ended/",
"host": [
"{{base_url}}"
],
"path": [
"api",
"campaigns",
"ended",
""
]
},
"description": "Get all ended campaigns"
},
"response": []
}
],
"description": "Campaign management endpoints"
},
{
"name": "Contact Us",
"description": "APIهای فرم تماس با ما",
"item": [
{
"name": "GET All Contact Us",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/contact-us/",
"host": [
"{{base_url}}"
],
"path": [
"api",
"contact-us",
""
]
},
"description": "Get all contact form submissions"
},
"response": []
"url": "{{base_url}}/api/contact-us/"
}
},
{
"name": "GET Contact Us by ID",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/contact-us/1/",
"host": [
"{{base_url}}"
],
"path": [
"api",
"contact-us",
"1",
""
]
},
"description": "Get a specific contact submission by ID"
},
"response": []
"url": "{{base_url}}/api/contact-us/1/"
}
},
{
"name": "POST Create Contact Us",
@@ -206,27 +38,10 @@
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"احمد محمدی\",\n \"email_or_phone\": \"ahmad@example.com\",\n \"description\": \"سلام، می‌خواستم در مورد خدمات شما اطلاعات بیشتری دریافت کنم.\",\n \"category\": \"پشتیبانی\"\n}",
"options": {
"raw": {
"language": "json"
}
}
"raw": "{\n \"name\": \"احمد محمدی\",\n \"email_or_phone\": \"ahmad@example.com\",\n \"description\": \"سلام، می‌خواستم در مورد خدمات شما اطلاعات بیشتری دریافت کنم.\",\n \"category\": \"پشتیبانی\"\n}"
},
"url": {
"raw": "{{base_url}}/api/contact-us/",
"host": [
"{{base_url}}"
],
"path": [
"api",
"contact-us",
""
]
},
"description": "Submit a new contact form"
},
"response": []
"url": "{{base_url}}/api/contact-us/"
}
},
{
"name": "GET Contact Us by Category",
@@ -235,110 +50,341 @@
"header": [],
"url": {
"raw": "{{base_url}}/api/contact-us/by_category/?category=پشتیبانی",
"host": [
"{{base_url}}"
],
"path": [
"api",
"contact-us",
"by_category",
""
],
"host": ["{{base_url}}"],
"path": ["api", "contact-us", "by_category", ""],
"query": [
{
"key": "category",
"value": "پشتیبانی",
"description": "Category: همکاری, فروش, پشتیبانی, درخواست مشاور, سایر"
"description": "همکاری | فروش | پشتیبانی | درخواست مشاور | سایر"
}
]
}
}
},
{
"name": "PATCH Update Contact Us (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
]
},
"description": "Get contacts filtered by category"
},
"response": []
"method": "PATCH",
"header": [
{"key": "Content-Type", "value": "application/json"}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"نام بروزرسانی شده\"\n}"
},
"url": "{{base_url}}/api/contact-us/1/"
}
},
{
"name": "DELETE Contact Us (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
]
},
"method": "DELETE",
"header": [],
"url": "{{base_url}}/api/contact-us/1/"
}
}
],
"description": "Contact form submission endpoints"
]
},
{
"name": "Compositions",
"description": "APIهای ترکیبات — پشتیبانی از آپلود چند تصویر با تصویر اصلی",
"item": [
{
"name": "GET All Compositions",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/compositions/",
"host": [
"{{base_url}}"
],
"path": [
"api",
"compositions",
""
]
},
"description": "Get all compositions"
},
"response": []
"url": "{{base_url}}/api/compositions/"
}
},
{
"name": "GET Composition by ID",
"request": {
"method": "GET",
"header": [],
"url": "{{base_url}}/api/compositions/{{composition_id}}/"
}
},
{
"name": "GET Compositions by Created At",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/compositions/1/",
"host": [
"{{base_url}}"
],
"path": [
"api",
"compositions",
"1",
""
"raw": "{{base_url}}/api/compositions/by-created-at/?from=2026-01-01T00:00:00Z&to=2026-12-31T23:59:59Z",
"host": ["{{base_url}}"],
"path": ["api", "compositions", "by-created-at", ""],
"query": [
{
"key": "from",
"value": "2026-01-01T00:00:00Z",
"description": "Start datetime — ISO 8601 (UTC). At least one of from/to required."
},
{
"key": "to",
"value": "2026-12-31T23:59:59Z",
"description": "End datetime — ISO 8601 (UTC). At least one of from/to required."
}
]
},
"description": "Get a specific composition by ID"
},
"response": []
}
}
},
{
"name": "POST Create Composition",
"name": "POST Create Composition (JSON)",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
{"key": "Content-Type", "value": "application/json"}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"ترکیب تست\",\n \"description\": \"این یک ترکیب تستی است\"\n}",
"options": {
"raw": {
"language": "json"
}
}
"raw": "{\n \"name\": \"ترکیب تست\",\n \"description\": \"این یک ترکیب تستی است\"\n}"
},
"url": {
"raw": "{{base_url}}/api/compositions/",
"host": [
"{{base_url}}"
],
"path": [
"api",
"compositions",
""
"url": "{{base_url}}/api/compositions/"
}
},
{
"name": "POST Create Composition with Images",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "formdata",
"formdata": [
{"key": "name", "value": "ترکیب با تصویر", "type": "text"},
{"key": "description", "value": "ترکیب با چند تصویر", "type": "text"},
{"key": "uploaded_images", "type": "file", "src": []},
{"key": "uploaded_images", "type": "file", "src": []},
{"key": "main_image_index", "value": "0", "type": "text", "description": "ایندکس تصویر اصلی (از 0)"}
]
},
"description": "Create a new composition"
},
"response": []
"url": "{{base_url}}/api/compositions/"
}
},
{
"name": "POST Add Images to Composition (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
]
},
"method": "POST",
"header": [],
"body": {
"mode": "formdata",
"formdata": [
{"key": "uploaded_images", "type": "file", "src": []},
{"key": "main_image_index", "value": "0", "type": "text"}
]
},
"url": "{{base_url}}/api/compositions/{{composition_id}}/add-images/"
}
},
{
"name": "POST Set Main Image (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
]
},
"method": "POST",
"header": [
{"key": "Content-Type", "value": "application/json"}
],
"body": {
"mode": "raw",
"raw": "{\n \"image_id\": {{image_id}}\n}"
},
"url": "{{base_url}}/api/compositions/{{composition_id}}/set-main-image/"
}
},
{
"name": "DELETE Composition Image (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
]
},
"method": "DELETE",
"header": [],
"url": "{{base_url}}/api/compositions/{{composition_id}}/images/{{image_id}}/"
}
},
{
"name": "PATCH Update Composition (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
]
},
"method": "PATCH",
"header": [
{"key": "Content-Type", "value": "application/json"}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"نام بروزرسانی شده\"\n}"
},
"url": "{{base_url}}/api/compositions/{{composition_id}}/"
}
},
{
"name": "DELETE Composition (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
]
},
"method": "DELETE",
"header": [],
"url": "{{base_url}}/api/compositions/{{composition_id}}/"
}
}
],
"description": "Composition management endpoints"
]
},
{
"name": "Campaigns",
"description": "APIهای کمپین‌ها",
"item": [
{
"name": "GET All Campaigns",
"request": {
"method": "GET",
"header": [],
"url": "{{base_url}}/api/campaigns/"
}
},
{
"name": "GET Campaign by ID",
"request": {
"method": "GET",
"header": [],
"url": "{{base_url}}/api/campaigns/1/"
}
},
{
"name": "POST Create Campaign",
"request": {
"method": "POST",
"header": [
{"key": "Content-Type", "value": "application/json"}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"کمپین تست\",\n \"description\": \"این یک کمپین تستی است\",\n \"start_time\": \"2026-06-01T00:00:00Z\",\n \"end_time\": \"2026-12-31T23:59:59Z\"\n}"
},
"url": "{{base_url}}/api/campaigns/"
}
},
{
"name": "POST Create Campaign with Image",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "formdata",
"formdata": [
{"key": "name", "value": "کمپین با تصویر", "type": "text"},
{"key": "description", "value": "توضیحات کمپین", "type": "text"},
{"key": "start_time", "value": "2026-06-01T00:00:00Z", "type": "text"},
{"key": "end_time", "value": "2026-12-31T23:59:59Z", "type": "text"},
{"key": "image", "type": "file", "src": []}
]
},
"url": "{{base_url}}/api/campaigns/"
}
},
{
"name": "GET Active Campaigns",
"request": {
"method": "GET",
"header": [],
"url": "{{base_url}}/api/campaigns/active/"
}
},
{
"name": "GET Upcoming Campaigns",
"request": {
"method": "GET",
"header": [],
"url": "{{base_url}}/api/campaigns/upcoming/"
}
},
{
"name": "GET Ended Campaigns",
"request": {
"method": "GET",
"header": [],
"url": "{{base_url}}/api/campaigns/ended/"
}
},
{
"name": "PATCH Update Campaign (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
]
},
"method": "PATCH",
"header": [
{"key": "Content-Type", "value": "application/json"}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"نام بروزرسانی شده\"\n}"
},
"url": "{{base_url}}/api/campaigns/1/"
}
},
{
"name": "DELETE Campaign (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
]
},
"method": "DELETE",
"header": [],
"url": "{{base_url}}/api/campaigns/1/"
}
}
]
}
],
"variable": [
@@ -346,7 +392,26 @@
"key": "base_url",
"value": "http://localhost:8000",
"type": "string"
},
{
"key": "composition_id",
"value": "1",
"type": "string"
},
{
"key": "image_id",
"value": "1",
"type": "string"
},
{
"key": "admin_username",
"value": "Zoneco_@1405",
"type": "string"
},
{
"key": "admin_password",
"value": "Fun_@_zone2026",
"type": "string"
}
]
}