- 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>
262 lines
6.7 KiB
Markdown
262 lines
6.7 KiB
Markdown
# Zoneco ORG Backend API
|
|
|
|
A Django REST Framework backend for Zoneco ORG with PostgreSQL database.
|
|
|
|
---
|
|
|
|
## Test Status
|
|
|
|
```
|
|
Ran 24 tests in ~12s — OK (0 failures)
|
|
```
|
|
|
|
| Group | Tests | Status |
|
|
|-------|-------|--------|
|
|
| Contact Us | 6 | ✅ All pass |
|
|
| Compositions | 11 | ✅ All pass |
|
|
| Campaigns | 7 | ✅ All pass |
|
|
|
|
Run tests at any time:
|
|
```bash
|
|
cd backend
|
|
python manage.py test api -v 2
|
|
```
|
|
|
|
---
|
|
|
|
## Features
|
|
|
|
- **Contact Us API** — Contact form submissions with category filter
|
|
- **Composition API** — Multi-image upload, main image flag, date-range filter
|
|
- **Campaign API** — Campaigns with active / upcoming / ended filters
|
|
- **Admin Panel** — Full Django admin at `/admin/`
|
|
- **Image Upload** — JPEG, PNG, WebP, GIF, max 5 MB, stored in `media/`
|
|
- **CORS Enabled** — Configured for frontend integration
|
|
- **Pagination** — 20 items per page
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### 1. Install dependencies
|
|
|
|
```bash
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
### 2. Create PostgreSQL database
|
|
|
|
```sql
|
|
CREATE DATABASE "Zoneco_ORG";
|
|
```
|
|
|
|
### 3. Apply migrations
|
|
|
|
```bash
|
|
python manage.py migrate
|
|
```
|
|
|
|
### 4. Run development server
|
|
|
|
```bash
|
|
python manage.py runserver
|
|
```
|
|
|
|
API available at `{{base_url}}/api/`
|
|
|
|
---
|
|
|
|
## Admin Credentials
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| URL | `{{base_url}}/admin/` |
|
|
| Username | `Zoneco_@1405` |
|
|
| Password | `Fun_@_zone2026` |
|
|
|
|
---
|
|
|
|
## API Endpoints
|
|
|
|
### Authentication
|
|
|
|
| Action | Access |
|
|
|--------|--------|
|
|
| GET (list, retrieve, custom filters) | Public — no login required |
|
|
| POST (create) | Public — no login required |
|
|
| PUT / PATCH / DELETE | Admin only — Basic Auth required |
|
|
|
|
---
|
|
|
|
### Contact Us — `/api/contact-us/`
|
|
|
|
| Method | Endpoint | Access | Description |
|
|
|--------|----------|--------|-------------|
|
|
| GET | `/api/contact-us/` | Public | List all submissions |
|
|
| POST | `/api/contact-us/` | Public | Submit a contact form |
|
|
| GET | `/api/contact-us/{id}/` | Public | Get one submission |
|
|
| GET | `/api/contact-us/by_category/?category=...` | Public | Filter by category |
|
|
| PATCH | `/api/contact-us/{id}/` | Admin | Partial update |
|
|
| PUT | `/api/contact-us/{id}/` | Admin | Full update |
|
|
| DELETE | `/api/contact-us/{id}/` | Admin | Delete |
|
|
|
|
**Category choices:** `همکاری` · `فروش` · `پشتیبانی` · `درخواست مشاور` · `سایر`
|
|
|
|
**Fields:**
|
|
|
|
| Field | Type | Required |
|
|
|-------|------|----------|
|
|
| `name` | string | Yes |
|
|
| `email_or_phone` | string | Yes |
|
|
| `description` | string | Yes |
|
|
| `category` | string | Yes |
|
|
|
|
---
|
|
|
|
### Compositions — `/api/compositions/`
|
|
|
|
Each composition can have **multiple images**. One image can be flagged as the **main image** (`is_main: true`).
|
|
|
|
| Method | Endpoint | Access | Description |
|
|
|--------|----------|--------|-------------|
|
|
| GET | `/api/compositions/` | Public | List all compositions |
|
|
| POST | `/api/compositions/` | Public | Create composition (with optional images) |
|
|
| GET | `/api/compositions/{id}/` | Public | Get one composition |
|
|
| GET | `/api/compositions/by-created-at/?from=...&to=...` | Public | Filter by creation date range |
|
|
| POST | `/api/compositions/{id}/add-images/` | Admin | Add images to existing composition |
|
|
| POST | `/api/compositions/{id}/set-main-image/` | Admin | Set main image |
|
|
| DELETE | `/api/compositions/{id}/images/{image_id}/` | Admin | Delete a single image |
|
|
| PATCH | `/api/compositions/{id}/` | Admin | Partial update |
|
|
| PUT | `/api/compositions/{id}/` | Admin | Full update |
|
|
| DELETE | `/api/compositions/{id}/` | Admin | Delete composition |
|
|
|
|
**Fields:**
|
|
|
|
| Field | Type | Required | Notes |
|
|
|-------|------|----------|-------|
|
|
| `name` | string | Yes | |
|
|
| `description` | string | Yes | |
|
|
| `uploaded_images` | file[] | No | One or more image files (multipart) |
|
|
| `main_image_index` | integer | No | 0-based index of main image in `uploaded_images`. Defaults to 0. |
|
|
|
|
**Image constraints:** JPEG, PNG, WebP, GIF — max **5 MB** each — stored at `media/compositions/`
|
|
|
|
**`by-created-at` query params:**
|
|
|
|
| Param | Required | Format |
|
|
|-------|----------|--------|
|
|
| `from` | At least one | ISO 8601 e.g. `2026-06-01T00:00:00Z` |
|
|
| `to` | At least one | ISO 8601 e.g. `2026-06-30T23:59:59Z` |
|
|
|
|
---
|
|
|
|
### Campaigns — `/api/campaigns/`
|
|
|
|
| Method | Endpoint | Access | Description |
|
|
|--------|----------|--------|-------------|
|
|
| GET | `/api/campaigns/` | Public | List all campaigns |
|
|
| POST | `/api/campaigns/` | Public | Create campaign |
|
|
| GET | `/api/campaigns/{id}/` | Public | Get one campaign |
|
|
| GET | `/api/campaigns/active/` | Public | Currently active campaigns |
|
|
| GET | `/api/campaigns/upcoming/` | Public | Not started yet |
|
|
| GET | `/api/campaigns/ended/` | Public | Already finished |
|
|
| PATCH | `/api/campaigns/{id}/` | Admin | Partial update |
|
|
| PUT | `/api/campaigns/{id}/` | Admin | Full update |
|
|
| DELETE | `/api/campaigns/{id}/` | Admin | Delete |
|
|
|
|
**Fields:**
|
|
|
|
| Field | Type | Required | Notes |
|
|
|-------|------|----------|-------|
|
|
| `name` | string | Yes | |
|
|
| `description` | string | Yes | |
|
|
| `start_time` | datetime | Yes | ISO 8601 |
|
|
| `end_time` | datetime | Yes | Must be after `start_time` |
|
|
| `image` | file | No | Campaign image (multipart) |
|
|
|
|
**Read-only computed fields:** `is_active`, `is_upcoming`, `is_ended`
|
|
|
|
---
|
|
|
|
## Models
|
|
|
|
### ContactUs
|
|
|
|
| Field | Type |
|
|
|-------|------|
|
|
| `name` | CharField |
|
|
| `email_or_phone` | CharField |
|
|
| `description` | TextField |
|
|
| `category` | CharField (choices) |
|
|
| `created_at` | DateTimeField (auto) |
|
|
| `updated_at` | DateTimeField (auto) |
|
|
|
|
### Composition
|
|
|
|
| Field | Type |
|
|
|-------|------|
|
|
| `name` | CharField |
|
|
| `description` | TextField |
|
|
| `image` | ImageField (legacy) |
|
|
| `created_at` | DateTimeField (auto) |
|
|
| `updated_at` | DateTimeField (auto) |
|
|
|
|
### CompositionImage
|
|
|
|
| Field | Type |
|
|
|-------|------|
|
|
| `composition` | ForeignKey → Composition |
|
|
| `image` | ImageField |
|
|
| `is_main` | BooleanField |
|
|
| `created_at` | DateTimeField (auto) |
|
|
|
|
DB constraint: only one `is_main=True` per composition.
|
|
|
|
### Campaign
|
|
|
|
| Field | Type |
|
|
|-------|------|
|
|
| `name` | CharField |
|
|
| `description` | TextField |
|
|
| `start_time` | DateTimeField |
|
|
| `end_time` | DateTimeField |
|
|
| `image` | ImageField |
|
|
| `created_at` | DateTimeField (auto) |
|
|
| `updated_at` | DateTimeField (auto) |
|
|
|
|
---
|
|
|
|
## Media Files
|
|
|
|
| Content | Path |
|
|
|---------|------|
|
|
| Composition images | `media/compositions/` |
|
|
| Campaign images | `media/campaigns/` |
|
|
|
|
---
|
|
|
|
## Postman Collection
|
|
|
|
Import `backend/Zoneco_ORG_API.postman_collection.json` into Postman.
|
|
|
|
Set the `base_url` collection variable to your server address.
|
|
|
|
---
|
|
|
|
## Persian Documentation
|
|
|
|
Full Persian API documentation: `backend/API_DOCS_FA.md`
|
|
|
|
---
|
|
|
|
## HTTP Status Codes
|
|
|
|
| Code | Meaning |
|
|
|------|---------|
|
|
| 200 | OK |
|
|
| 201 | Created |
|
|
| 204 | Deleted (no body) |
|
|
| 400 | Invalid data |
|
|
| 403 | Forbidden (login required) |
|
|
| 404 | Not found |
|