Add admin login API and remove hardcoded secrets

- 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>
This commit is contained in:
Shayan Azadi
2026-07-16 17:29:47 +03:30
parent 7e71d922d3
commit 50c9cf613f
13 changed files with 791 additions and 141 deletions

View File

@@ -2,10 +2,106 @@
"info": {
"_postman_id": "zoneco-org-api-collection",
"name": "Zoneco ORG API",
"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 استفاده کنید.",
"description": "مجموعه کامل APIهای بک‌اند Zoneco ORG.\n\n1) متغیرهای collection را تنظیم کنید: base_url, admin_username, admin_password\n2) Admin Auth > POST Admin Login را بزنید\n3) توکن در admin_token ذخیره می‌شود\n4) درخواست‌های ادمین با Authorization: Token {{admin_token}} ارسال می‌شوند\n\nCredentials را در متغیرها بگذارید — در کد هاردکد نکنید.",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Admin Auth",
"description": "ورود ادمین با username/password و دریافت توکن",
"item": [
{
"name": "POST Admin Login",
"event": [
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
"if (pm.response.code === 200) {",
" var json = pm.response.json();",
" if (json.token) {",
" pm.collectionVariables.set('admin_token', json.token);",
" }",
"}"
]
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"username\": \"{{admin_username}}\",\n \"password\": \"{{admin_password}}\"\n}"
},
"url": "{{base_url}}/api/admin/login/",
"description": "Login with admin credentials. Saves token to admin_token automatically."
}
},
{
"name": "GET Admin Me",
"request": {
"auth": {
"type": "apikey",
"apikey": [
{
"key": "key",
"value": "Authorization",
"type": "string"
},
{
"key": "value",
"value": "Token {{admin_token}}",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "GET",
"header": [],
"url": "{{base_url}}/api/admin/me/"
}
},
{
"name": "POST Admin Logout",
"request": {
"auth": {
"type": "apikey",
"apikey": [
{
"key": "key",
"value": "Authorization",
"type": "string"
},
{
"key": "value",
"value": "Token {{admin_token}}",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "POST",
"header": [],
"url": "{{base_url}}/api/admin/logout/"
}
}
]
},
{
"name": "Contact Us",
"description": "APIهای فرم تماس با ما",
@@ -50,8 +146,15 @@
"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",
@@ -66,15 +169,31 @@
"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"}
"type": "apikey",
"apikey": [
{
"key": "key",
"value": "Authorization",
"type": "string"
},
{
"key": "value",
"value": "Token {{admin_token}}",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "PATCH",
"header": [
{"key": "Content-Type", "value": "application/json"}
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
@@ -87,10 +206,23 @@
"name": "DELETE Contact Us (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
"type": "apikey",
"apikey": [
{
"key": "key",
"value": "Authorization",
"type": "string"
},
{
"key": "value",
"value": "Token {{admin_token}}",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "DELETE",
@@ -120,15 +252,22 @@
"url": "{{base_url}}/api/compositions/{{composition_id}}/"
}
},
{
{
"name": "GET Compositions by Created At",
"request": {
"method": "GET",
"header": [],
"url": {
"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", ""],
"host": [
"{{base_url}}"
],
"path": [
"api",
"compositions",
"by-created-at",
""
],
"query": [
{
"key": "from",
@@ -145,11 +284,14 @@
}
},
{
"name": "POST Create Composition (JSON)",
"name": "POST Create Composition (JSON)",
"request": {
"method": "POST",
"header": [
{"key": "Content-Type", "value": "application/json"}
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
@@ -166,11 +308,32 @@
"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)"}
{
"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)"
}
]
},
"url": "{{base_url}}/api/compositions/"
@@ -180,10 +343,23 @@
"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"}
"type": "apikey",
"apikey": [
{
"key": "key",
"value": "Authorization",
"type": "string"
},
{
"key": "value",
"value": "Token {{admin_token}}",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "POST",
@@ -191,8 +367,16 @@
"body": {
"mode": "formdata",
"formdata": [
{"key": "uploaded_images", "type": "file", "src": []},
{"key": "main_image_index", "value": "0", "type": "text"}
{
"key": "uploaded_images",
"type": "file",
"src": []
},
{
"key": "main_image_index",
"value": "0",
"type": "text"
}
]
},
"url": "{{base_url}}/api/compositions/{{composition_id}}/add-images/"
@@ -202,15 +386,31 @@
"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"}
"type": "apikey",
"apikey": [
{
"key": "key",
"value": "Authorization",
"type": "string"
},
{
"key": "value",
"value": "Token {{admin_token}}",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "POST",
"header": [
{"key": "Content-Type", "value": "application/json"}
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
@@ -223,10 +423,23 @@
"name": "DELETE Composition Image (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
"type": "apikey",
"apikey": [
{
"key": "key",
"value": "Authorization",
"type": "string"
},
{
"key": "value",
"value": "Token {{admin_token}}",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "DELETE",
@@ -238,15 +451,31 @@
"name": "PATCH Update Composition (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
"type": "apikey",
"apikey": [
{
"key": "key",
"value": "Authorization",
"type": "string"
},
{
"key": "value",
"value": "Token {{admin_token}}",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "PATCH",
"header": [
{"key": "Content-Type", "value": "application/json"}
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
@@ -259,10 +488,23 @@
"name": "DELETE Composition (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
"type": "apikey",
"apikey": [
{
"key": "key",
"value": "Authorization",
"type": "string"
},
{
"key": "value",
"value": "Token {{admin_token}}",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "DELETE",
@@ -297,7 +539,10 @@
"request": {
"method": "POST",
"header": [
{"key": "Content-Type", "value": "application/json"}
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
@@ -314,11 +559,31 @@
"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": []}
{
"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/"
@@ -352,15 +617,31 @@
"name": "PATCH Update Campaign (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
"type": "apikey",
"apikey": [
{
"key": "key",
"value": "Authorization",
"type": "string"
},
{
"key": "value",
"value": "Token {{admin_token}}",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "PATCH",
"header": [
{"key": "Content-Type", "value": "application/json"}
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
@@ -373,10 +654,23 @@
"name": "DELETE Campaign (Admin)",
"request": {
"auth": {
"type": "basic",
"basic": [
{"key": "username", "value": "{{admin_username}}", "type": "string"},
{"key": "password", "value": "{{admin_password}}", "type": "string"}
"type": "apikey",
"apikey": [
{
"key": "key",
"value": "Authorization",
"type": "string"
},
{
"key": "value",
"value": "Token {{admin_token}}",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "DELETE",
@@ -390,7 +684,7 @@
"variable": [
{
"key": "base_url",
"value": "http://localhost:8000",
"value": "http://127.0.0.1:8000",
"type": "string"
},
{
@@ -405,13 +699,18 @@
},
{
"key": "admin_username",
"value": "Zoneco_@1405",
"value": "",
"type": "string"
},
{
"key": "admin_password",
"value": "Fun_@_zone2026",
"value": "",
"type": "string"
},
{
"key": "admin_token",
"value": "",
"type": "string"
}
]
}
}