mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 06:51:08 -05:00
Refactor API structure and add comprehensive user management features
- Restructure API v1 with improved serializers organization - Add user deletion requests and moderation queue system - Implement bulk moderation operations and permissions - Add user profile enhancements with display names and avatars - Expand ride and park API endpoints with better filtering - Add manufacturer API with detailed ride relationships - Improve authentication flows and error handling - Update frontend documentation and API specifications
This commit is contained in:
748
docs/frontend.md
748
docs/frontend.md
@@ -1,420 +1,372 @@
|
||||
# ThrillWiki Frontend API Documentation
|
||||
|
||||
This document provides comprehensive documentation for frontend developers on how to integrate with the ThrillWiki API endpoints.
|
||||
Last updated: 2025-08-29
|
||||
|
||||
## Base URL
|
||||
```
|
||||
http://localhost:8000/api/v1/
|
||||
```
|
||||
This document provides comprehensive documentation for all ThrillWiki API endpoints that the NextJS frontend should use.
|
||||
|
||||
## Authentication
|
||||
Most endpoints are publicly accessible. Admin endpoints require authentication.
|
||||
|
||||
## Content Discovery Endpoints
|
||||
All API requests require authentication via JWT tokens. Include the token in the Authorization header:
|
||||
|
||||
```typescript
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
```
|
||||
|
||||
## Base URL
|
||||
|
||||
All API endpoints are prefixed with `/api/v1/`
|
||||
|
||||
## Moderation System API
|
||||
|
||||
The moderation system provides comprehensive content moderation, user management, and administrative tools. All moderation endpoints require moderator-level permissions or above.
|
||||
|
||||
### Moderation Reports
|
||||
|
||||
#### List Reports
|
||||
- **GET** `/api/v1/moderation/reports/`
|
||||
- **Permissions**: Moderators and above can view all reports, regular users can only view their own reports
|
||||
- **Query Parameters**:
|
||||
- `status`: Filter by report status (PENDING, UNDER_REVIEW, RESOLVED, DISMISSED)
|
||||
- `priority`: Filter by priority (LOW, MEDIUM, HIGH, URGENT)
|
||||
- `report_type`: Filter by report type (SPAM, HARASSMENT, INAPPROPRIATE_CONTENT, etc.)
|
||||
- `reported_by`: Filter by user ID who made the report
|
||||
- `assigned_moderator`: Filter by assigned moderator ID
|
||||
- `created_after`: Filter reports created after date (ISO format)
|
||||
- `created_before`: Filter reports created before date (ISO format)
|
||||
- `unassigned`: Boolean filter for unassigned reports
|
||||
- `overdue`: Boolean filter for overdue reports based on SLA
|
||||
- `search`: Search in reason and description fields
|
||||
- `ordering`: Order by fields (created_at, updated_at, priority, status)
|
||||
|
||||
#### Create Report
|
||||
- **POST** `/api/v1/moderation/reports/`
|
||||
- **Permissions**: Any authenticated user
|
||||
- **Body**: CreateModerationReportData
|
||||
|
||||
#### Get Report Details
|
||||
- **GET** `/api/v1/moderation/reports/{id}/`
|
||||
- **Permissions**: Moderators and above, or report creator
|
||||
|
||||
#### Update Report
|
||||
- **PATCH** `/api/v1/moderation/reports/{id}/`
|
||||
- **Permissions**: Moderators and above
|
||||
- **Body**: Partial UpdateModerationReportData
|
||||
|
||||
#### Assign Report
|
||||
- **POST** `/api/v1/moderation/reports/{id}/assign/`
|
||||
- **Permissions**: Moderators and above
|
||||
- **Body**: `{ "moderator_id": number }`
|
||||
|
||||
#### Resolve Report
|
||||
- **POST** `/api/v1/moderation/reports/{id}/resolve/`
|
||||
- **Permissions**: Moderators and above
|
||||
- **Body**: `{ "resolution_action": string, "resolution_notes": string }`
|
||||
|
||||
#### Report Statistics
|
||||
- **GET** `/api/v1/moderation/reports/stats/`
|
||||
- **Permissions**: Moderators and above
|
||||
- **Returns**: ModerationStatsData
|
||||
|
||||
### Moderation Queue
|
||||
|
||||
#### List Queue Items
|
||||
- **GET** `/api/v1/moderation/queue/`
|
||||
- **Permissions**: Moderators and above
|
||||
- **Query Parameters**:
|
||||
- `status`: Filter by status (PENDING, IN_PROGRESS, COMPLETED, CANCELLED)
|
||||
- `priority`: Filter by priority (LOW, MEDIUM, HIGH, URGENT)
|
||||
- `item_type`: Filter by item type (CONTENT_REVIEW, USER_REVIEW, BULK_ACTION, etc.)
|
||||
- `assigned_to`: Filter by assigned moderator ID
|
||||
- `unassigned`: Boolean filter for unassigned items
|
||||
- `has_related_report`: Boolean filter for items with related reports
|
||||
- `search`: Search in title and description fields
|
||||
|
||||
#### Get My Queue
|
||||
- **GET** `/api/v1/moderation/queue/my_queue/`
|
||||
- **Permissions**: Moderators and above
|
||||
- **Returns**: Queue items assigned to current user
|
||||
|
||||
#### Assign Queue Item
|
||||
- **POST** `/api/v1/moderation/queue/{id}/assign/`
|
||||
- **Permissions**: Moderators and above
|
||||
- **Body**: `{ "moderator_id": number }`
|
||||
|
||||
#### Unassign Queue Item
|
||||
- **POST** `/api/v1/moderation/queue/{id}/unassign/`
|
||||
- **Permissions**: Moderators and above
|
||||
|
||||
#### Complete Queue Item
|
||||
- **POST** `/api/v1/moderation/queue/{id}/complete/`
|
||||
- **Permissions**: Moderators and above
|
||||
- **Body**: CompleteQueueItemData
|
||||
|
||||
### Moderation Actions
|
||||
|
||||
#### List Actions
|
||||
- **GET** `/api/v1/moderation/actions/`
|
||||
- **Permissions**: Moderators and above
|
||||
- **Query Parameters**:
|
||||
- `action_type`: Filter by action type (WARNING, USER_SUSPENSION, USER_BAN, etc.)
|
||||
- `moderator`: Filter by moderator ID
|
||||
- `target_user`: Filter by target user ID
|
||||
- `is_active`: Boolean filter for active actions
|
||||
- `expired`: Boolean filter for expired actions
|
||||
- `expiring_soon`: Boolean filter for actions expiring within 24 hours
|
||||
- `has_related_report`: Boolean filter for actions with related reports
|
||||
|
||||
#### Create Action
|
||||
- **POST** `/api/v1/moderation/actions/`
|
||||
- **Permissions**: Moderators and above (with role-based restrictions)
|
||||
- **Body**: CreateModerationActionData
|
||||
|
||||
#### Get Active Actions
|
||||
- **GET** `/api/v1/moderation/actions/active/`
|
||||
- **Permissions**: Moderators and above
|
||||
|
||||
#### Get Expired Actions
|
||||
- **GET** `/api/v1/moderation/actions/expired/`
|
||||
- **Permissions**: Moderators and above
|
||||
|
||||
#### Deactivate Action
|
||||
- **POST** `/api/v1/moderation/actions/{id}/deactivate/`
|
||||
- **Permissions**: Moderators and above
|
||||
|
||||
### Bulk Operations
|
||||
|
||||
#### List Bulk Operations
|
||||
- **GET** `/api/v1/moderation/bulk-operations/`
|
||||
- **Permissions**: Admins and superusers only
|
||||
- **Query Parameters**:
|
||||
- `status`: Filter by status (PENDING, RUNNING, COMPLETED, FAILED, CANCELLED)
|
||||
- `operation_type`: Filter by operation type
|
||||
- `priority`: Filter by priority
|
||||
- `created_by`: Filter by creator ID
|
||||
- `can_cancel`: Boolean filter for cancellable operations
|
||||
- `has_failures`: Boolean filter for operations with failures
|
||||
- `in_progress`: Boolean filter for operations in progress
|
||||
|
||||
#### Create Bulk Operation
|
||||
- **POST** `/api/v1/moderation/bulk-operations/`
|
||||
- **Permissions**: Admins and superusers only
|
||||
- **Body**: CreateBulkOperationData
|
||||
|
||||
#### Get Running Operations
|
||||
- **GET** `/api/v1/moderation/bulk-operations/running/`
|
||||
- **Permissions**: Admins and superusers only
|
||||
|
||||
#### Cancel Operation
|
||||
- **POST** `/api/v1/moderation/bulk-operations/{id}/cancel/`
|
||||
- **Permissions**: Admins and superusers only
|
||||
|
||||
#### Retry Operation
|
||||
- **POST** `/api/v1/moderation/bulk-operations/{id}/retry/`
|
||||
- **Permissions**: Admins and superusers only
|
||||
|
||||
#### Get Operation Logs
|
||||
- **GET** `/api/v1/moderation/bulk-operations/{id}/logs/`
|
||||
- **Permissions**: Admins and superusers only
|
||||
|
||||
### User Moderation
|
||||
|
||||
#### Get User Moderation Profile
|
||||
- **GET** `/api/v1/moderation/users/{id}/`
|
||||
- **Permissions**: Moderators and above
|
||||
- **Returns**: UserModerationProfileData
|
||||
|
||||
#### Take Action Against User
|
||||
- **POST** `/api/v1/moderation/users/{id}/moderate/`
|
||||
- **Permissions**: Moderators and above
|
||||
- **Body**: CreateModerationActionData
|
||||
|
||||
#### Search Users
|
||||
- **GET** `/api/v1/moderation/users/search/`
|
||||
- **Permissions**: Moderators and above
|
||||
- **Query Parameters**:
|
||||
- `query`: Search in username and email
|
||||
- `role`: Filter by user role
|
||||
- `has_restrictions`: Boolean filter for users with active restrictions
|
||||
|
||||
#### User Moderation Statistics
|
||||
- **GET** `/api/v1/moderation/users/stats/`
|
||||
- **Permissions**: Moderators and above
|
||||
|
||||
## Parks API
|
||||
|
||||
### Parks Listing
|
||||
- **GET** `/api/v1/parks/`
|
||||
- **Query Parameters**:
|
||||
- `search`: Search in park names and descriptions
|
||||
- `country`: Filter by country code
|
||||
- `state`: Filter by state/province
|
||||
- `city`: Filter by city
|
||||
- `status`: Filter by operational status
|
||||
- `park_type`: Filter by park type
|
||||
- `has_rides`: Boolean filter for parks with rides
|
||||
- `ordering`: Order by fields (name, opened_date, ride_count, etc.)
|
||||
- `page`: Page number for pagination
|
||||
- `page_size`: Number of results per page
|
||||
|
||||
### Park Details
|
||||
- **GET** `/api/v1/parks/{slug}/`
|
||||
- **Returns**: Complete park information including rides, photos, and statistics
|
||||
|
||||
### Park Rides
|
||||
- **GET** `/api/v1/parks/{park_slug}/rides/`
|
||||
- **Query Parameters**: Similar filtering options as global rides endpoint
|
||||
|
||||
### Park Photos
|
||||
- **GET** `/api/v1/parks/{park_slug}/photos/`
|
||||
- **Query Parameters**:
|
||||
- `photo_type`: Filter by photo type (banner, card, gallery)
|
||||
- `ordering`: Order by upload date, likes, etc.
|
||||
|
||||
## Rides API
|
||||
|
||||
### Rides Listing
|
||||
- **GET** `/api/v1/rides/`
|
||||
- **Query Parameters**:
|
||||
- `search`: Search in ride names and descriptions
|
||||
- `park`: Filter by park slug
|
||||
- `manufacturer`: Filter by manufacturer slug
|
||||
- `ride_type`: Filter by ride type
|
||||
- `status`: Filter by operational status
|
||||
- `opened_after`: Filter rides opened after date
|
||||
- `opened_before`: Filter rides opened before date
|
||||
- `height_min`: Minimum height requirement
|
||||
- `height_max`: Maximum height requirement
|
||||
- `has_photos`: Boolean filter for rides with photos
|
||||
- `ordering`: Order by fields (name, opened_date, height, etc.)
|
||||
|
||||
### Ride Details
|
||||
- **GET** `/api/v1/rides/{park_slug}/{ride_slug}/`
|
||||
- **Returns**: Complete ride information including specifications, photos, and reviews
|
||||
|
||||
### Ride Photos
|
||||
- **GET** `/api/v1/rides/{park_slug}/{ride_slug}/photos/`
|
||||
|
||||
### Ride Reviews
|
||||
- **GET** `/api/v1/rides/{park_slug}/{ride_slug}/reviews/`
|
||||
- **POST** `/api/v1/rides/{park_slug}/{ride_slug}/reviews/`
|
||||
|
||||
## Manufacturers API
|
||||
|
||||
### Manufacturers Listing
|
||||
- **GET** `/api/v1/rides/manufacturers/`
|
||||
- **Query Parameters**:
|
||||
- `search`: Search in manufacturer names
|
||||
- `country`: Filter by country
|
||||
- `has_rides`: Boolean filter for manufacturers with rides
|
||||
- `ordering`: Order by name, ride_count, etc.
|
||||
|
||||
### Manufacturer Details
|
||||
- **GET** `/api/v1/rides/manufacturers/{slug}/`
|
||||
|
||||
### Manufacturer Rides
|
||||
- **GET** `/api/v1/rides/manufacturers/{slug}/rides/`
|
||||
|
||||
## Authentication API
|
||||
|
||||
### Login
|
||||
- **POST** `/api/v1/auth/login/`
|
||||
- **Body**: `{ "username": string, "password": string }`
|
||||
- **Returns**: JWT tokens and user data
|
||||
|
||||
### Signup
|
||||
- **POST** `/api/v1/auth/signup/`
|
||||
- **Body**: User registration data
|
||||
|
||||
### Logout
|
||||
- **POST** `/api/v1/auth/logout/`
|
||||
|
||||
### Current User
|
||||
- **GET** `/api/v1/auth/user/`
|
||||
- **Returns**: Current user profile data
|
||||
|
||||
### Password Reset
|
||||
- **POST** `/api/v1/auth/password/reset/`
|
||||
- **Body**: `{ "email": string }`
|
||||
|
||||
### Password Change
|
||||
- **POST** `/api/v1/auth/password/change/`
|
||||
- **Body**: `{ "old_password": string, "new_password": string }`
|
||||
|
||||
## Statistics API
|
||||
|
||||
### Global Statistics
|
||||
- **GET** `/api/v1/stats/`
|
||||
- **Returns**: Global platform statistics
|
||||
|
||||
### Trending Content
|
||||
Get trending parks and rides based on view counts, ratings, and recency.
|
||||
|
||||
**Endpoint:** `GET /trending/content/`
|
||||
|
||||
**Parameters:**
|
||||
- `limit` (optional): Number of trending items to return (default: 20, max: 100)
|
||||
- `timeframe` (optional): Timeframe for trending calculation - "day", "week", "month" (default: "week")
|
||||
|
||||
**Response Format:**
|
||||
```json
|
||||
{
|
||||
"trending_rides": [
|
||||
{
|
||||
"id": 137,
|
||||
"name": "Steel Vengeance",
|
||||
"park": "Cedar Point",
|
||||
"category": "ride",
|
||||
"rating": 4.8,
|
||||
"rank": 1,
|
||||
"views": 15234,
|
||||
"views_change": "+25%",
|
||||
"slug": "steel-vengeance",
|
||||
"date_opened": "2018-05-05",
|
||||
"url": "https://thrillwiki.com/parks/cedar-point/rides/steel-vengeance/",
|
||||
"park_url": "https://thrillwiki.com/parks/cedar-point/",
|
||||
"card_image": "https://media.thrillwiki.com/rides/steel-vengeance-card.jpg"
|
||||
}
|
||||
],
|
||||
"trending_parks": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Cedar Point",
|
||||
"park": "Cedar Point",
|
||||
"category": "park",
|
||||
"rating": 4.6,
|
||||
"rank": 1,
|
||||
"views": 45678,
|
||||
"views_change": "+12%",
|
||||
"slug": "cedar-point",
|
||||
"date_opened": "1870-01-01",
|
||||
"url": "https://thrillwiki.com/parks/cedar-point/",
|
||||
"card_image": "https://media.thrillwiki.com/parks/cedar-point-card.jpg",
|
||||
"city": "Sandusky",
|
||||
"state": "Ohio",
|
||||
"country": "USA",
|
||||
"primary_company": "Cedar Fair"
|
||||
}
|
||||
],
|
||||
"latest_reviews": []
|
||||
}
|
||||
```
|
||||
|
||||
### New Content
|
||||
Get recently added parks and rides.
|
||||
|
||||
**Endpoint:** `GET /trending/new/`
|
||||
|
||||
**Parameters:**
|
||||
- `limit` (optional): Number of new items to return (default: 20, max: 100)
|
||||
- `days` (optional): Number of days to look back for new content (default: 30, max: 365)
|
||||
|
||||
**Response Format:**
|
||||
```json
|
||||
{
|
||||
"recently_added": [
|
||||
{
|
||||
"id": 137,
|
||||
"name": "Steel Vengeance",
|
||||
"park": "Cedar Point",
|
||||
"category": "ride",
|
||||
"date_added": "2018-05-05",
|
||||
"date_opened": "2018-05-05",
|
||||
"slug": "steel-vengeance",
|
||||
"url": "https://thrillwiki.com/parks/cedar-point/rides/steel-vengeance/",
|
||||
"park_url": "https://thrillwiki.com/parks/cedar-point/",
|
||||
"card_image": "https://media.thrillwiki.com/rides/steel-vengeance-card.jpg"
|
||||
},
|
||||
{
|
||||
"id": 42,
|
||||
"name": "Dollywood",
|
||||
"park": "Dollywood",
|
||||
"category": "park",
|
||||
"date_added": "2018-05-01",
|
||||
"date_opened": "1986-05-03",
|
||||
"slug": "dollywood",
|
||||
"url": "https://thrillwiki.com/parks/dollywood/",
|
||||
"card_image": "https://media.thrillwiki.com/parks/dollywood-card.jpg",
|
||||
"city": "Pigeon Forge",
|
||||
"state": "Tennessee",
|
||||
"country": "USA",
|
||||
"primary_company": "Dollywood Company"
|
||||
}
|
||||
],
|
||||
"newly_opened": [
|
||||
{
|
||||
"id": 136,
|
||||
"name": "Time Traveler",
|
||||
"park": "Silver Dollar City",
|
||||
"category": "ride",
|
||||
"date_added": "2018-04-28",
|
||||
"date_opened": "2018-04-28",
|
||||
"slug": "time-traveler",
|
||||
"url": "https://thrillwiki.com/parks/silver-dollar-city/rides/time-traveler/",
|
||||
"park_url": "https://thrillwiki.com/parks/silver-dollar-city/",
|
||||
"card_image": "https://media.thrillwiki.com/rides/time-traveler-card.jpg"
|
||||
}
|
||||
],
|
||||
"upcoming": []
|
||||
}
|
||||
```
|
||||
|
||||
**Key Changes:**
|
||||
- **REMOVED:** `location` field from all trending and new content responses
|
||||
- **ADDED:** `park` field - shows the park name for both parks and rides
|
||||
- **ADDED:** `date_opened` field - shows when the park/ride originally opened
|
||||
|
||||
### Trigger Content Calculation (Admin Only)
|
||||
Manually trigger the calculation of trending and new content.
|
||||
|
||||
**Endpoint:** `POST /trending/calculate/`
|
||||
|
||||
**Authentication:** Admin access required
|
||||
|
||||
**Response Format:**
|
||||
```json
|
||||
{
|
||||
"message": "Trending content calculation completed",
|
||||
"trending_completed": true,
|
||||
"new_content_completed": true,
|
||||
"completion_time": "2025-08-28 16:41:42",
|
||||
"trending_output": "Successfully calculated 50 trending items for all",
|
||||
"new_content_output": "Successfully calculated 50 new items for all"
|
||||
}
|
||||
```
|
||||
|
||||
## Data Field Descriptions
|
||||
|
||||
### Common Fields
|
||||
- `id`: Unique identifier for the item
|
||||
- `name`: Display name of the park or ride
|
||||
- `park`: Name of the park (for rides, this is the parent park; for parks, this is the park itself)
|
||||
- `category`: Type of content ("park" or "ride")
|
||||
- `slug`: URL-friendly identifier
|
||||
- `date_opened`: ISO date string of when the park/ride originally opened (YYYY-MM-DD format)
|
||||
- `url`: Frontend URL for direct navigation to the item's detail page
|
||||
- `card_image`: URL to the card image for display in lists and grids (available for both parks and rides)
|
||||
|
||||
### Park-Specific Fields
|
||||
- `city`: City where the park is located (shortened format)
|
||||
- `state`: State/province where the park is located (shortened format)
|
||||
- `country`: Country where the park is located (shortened format)
|
||||
- `primary_company`: Name of the primary operating company for the park
|
||||
|
||||
### Ride-Specific Fields
|
||||
- `park_url`: Frontend URL for the ride's parent park
|
||||
|
||||
### Trending-Specific Fields
|
||||
- `rating`: Average user rating (0.0 to 10.0)
|
||||
- `rank`: Position in trending list (1-based)
|
||||
- `views`: Current view count
|
||||
- `views_change`: Percentage change in views (e.g., "+25%")
|
||||
|
||||
### New Content-Specific Fields
|
||||
- `date_added`: ISO date string of when the item was added to the database (YYYY-MM-DD format)
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### Content Categorization
|
||||
The API automatically categorizes new content based on dates:
|
||||
- **Recently Added**: Items added to the database in the last 30 days
|
||||
- **Newly Opened**: Items that opened in the last year
|
||||
- **Upcoming**: Future openings (currently empty, reserved for future use)
|
||||
|
||||
### Caching
|
||||
- Trending content is cached for 24 hours
|
||||
- New content is cached for 30 minutes
|
||||
- Use the admin trigger endpoint to force cache refresh
|
||||
|
||||
### Error Handling
|
||||
All endpoints return standard HTTP status codes:
|
||||
- `200`: Success
|
||||
- `400`: Bad request (invalid parameters)
|
||||
- `403`: Forbidden (admin endpoints only)
|
||||
- `500`: Internal server error
|
||||
|
||||
### Rate Limiting
|
||||
No rate limiting is currently implemented, but it may be added in the future.
|
||||
|
||||
## Migration from Previous API Format
|
||||
|
||||
If you were previously using the API with `location` fields, update your frontend code:
|
||||
|
||||
**Before:**
|
||||
```javascript
|
||||
const ride = {
|
||||
name: "Steel Vengeance",
|
||||
location: "Cedar Point", // OLD FIELD
|
||||
category: "ride"
|
||||
};
|
||||
```
|
||||
|
||||
**After:**
|
||||
```javascript
|
||||
const ride = {
|
||||
name: "Steel Vengeance",
|
||||
park: "Cedar Point", // NEW FIELD
|
||||
category: "ride",
|
||||
date_opened: "2018-05-05" // NEW FIELD
|
||||
};
|
||||
```
|
||||
|
||||
## Backend Architecture Changes
|
||||
|
||||
The trending system has been migrated from Celery-based async processing to Django management commands for better reliability and simpler deployment:
|
||||
|
||||
### Management Commands
|
||||
- `python manage.py calculate_trending` - Calculate trending content
|
||||
- `python manage.py calculate_new_content` - Calculate new content
|
||||
|
||||
### Direct Calculation
|
||||
The API now uses direct calculation instead of async tasks, providing immediate results while maintaining performance through caching.
|
||||
|
||||
## URL Fields for Frontend Navigation
|
||||
|
||||
All API responses now include dynamically generated `url` fields that provide direct links to the frontend pages for each entity. These URLs are generated based on the configured `FRONTEND_DOMAIN` setting.
|
||||
|
||||
### URL Patterns
|
||||
- **Parks**: `https://domain.com/parks/{park-slug}/`
|
||||
- **Rides**: `https://domain.com/parks/{park-slug}/rides/{ride-slug}/`
|
||||
- **Ride Models**: `https://domain.com/rides/manufacturers/{manufacturer-slug}/{model-slug}/`
|
||||
- **Companies (Operators)**: `https://domain.com/parks/operators/{operator-slug}/`
|
||||
- **Companies (Property Owners)**: `https://domain.com/parks/owners/{owner-slug}/`
|
||||
- **Companies (Manufacturers)**: `https://domain.com/rides/manufacturers/{manufacturer-slug}/`
|
||||
- **Companies (Designers)**: `https://domain.com/rides/designers/{designer-slug}/`
|
||||
|
||||
### Domain Separation Rules
|
||||
**CRITICAL**: Company URLs follow strict domain separation:
|
||||
- **Parks Domain**: OPERATOR and PROPERTY_OWNER roles generate URLs under `/parks/`
|
||||
- **Rides Domain**: MANUFACTURER and DESIGNER roles generate URLs under `/rides/`
|
||||
- Companies with multiple roles use their primary role (first in the roles array) for URL generation
|
||||
- URLs are auto-generated when entities are saved and stored in the database
|
||||
|
||||
### Example Response with URL Fields
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Steel Vengeance",
|
||||
"slug": "steel-vengeance",
|
||||
"park": {
|
||||
"id": 1,
|
||||
"name": "Cedar Point",
|
||||
"slug": "cedar-point",
|
||||
"url": "https://thrillwiki.com/parks/cedar-point/"
|
||||
},
|
||||
"url": "https://thrillwiki.com/parks/cedar-point/rides/steel-vengeance/",
|
||||
"manufacturer": {
|
||||
"id": 1,
|
||||
"name": "Rocky Mountain Construction",
|
||||
"slug": "rocky-mountain-construction",
|
||||
"url": "https://thrillwiki.com/rides/manufacturers/rocky-mountain-construction/"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Example Usage
|
||||
|
||||
### Fetch Trending Content
|
||||
```javascript
|
||||
const response = await fetch('/api/v1/trending/content/?limit=10');
|
||||
const data = await response.json();
|
||||
|
||||
// Display trending rides with clickable links
|
||||
data.trending_rides.forEach(ride => {
|
||||
console.log(`${ride.name} at ${ride.park} - opened ${ride.date_opened}`);
|
||||
console.log(`Visit: ${ride.url}`);
|
||||
});
|
||||
```
|
||||
|
||||
### Fetch New Content
|
||||
```javascript
|
||||
const response = await fetch('/api/v1/trending/new/?limit=5&days=7');
|
||||
const data = await response.json();
|
||||
|
||||
// Display newly opened attractions
|
||||
data.newly_opened.forEach(item => {
|
||||
console.log(`${item.name} at ${item.park} - opened ${item.date_opened}`);
|
||||
});
|
||||
```
|
||||
|
||||
### Admin: Trigger Calculation
|
||||
```javascript
|
||||
const response = await fetch('/api/v1/trending/calculate/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer YOUR_ADMIN_TOKEN',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
const result = await response.json();
|
||||
console.log(result.message);
|
||||
|
||||
## Reviews Endpoints
|
||||
- **GET** `/api/v1/trending/`
|
||||
- **Query Parameters**:
|
||||
- `content_type`: Filter by content type (parks, rides, reviews)
|
||||
- `time_period`: Time period for trending (24h, 7d, 30d)
|
||||
|
||||
### Latest Reviews
|
||||
Get the latest reviews from both parks and rides across the platform.
|
||||
- **GET** `/api/v1/reviews/latest/`
|
||||
- **Query Parameters**:
|
||||
- `limit`: Number of reviews to return
|
||||
- `park`: Filter by park slug
|
||||
- `ride`: Filter by ride slug
|
||||
|
||||
**Endpoint:** `GET /reviews/latest/`
|
||||
## Error Handling
|
||||
|
||||
**Parameters:**
|
||||
- `limit` (optional): Number of reviews to return (default: 20, max: 100)
|
||||
All API endpoints return standardized error responses:
|
||||
|
||||
**Response Format:**
|
||||
```json
|
||||
{
|
||||
"count": 15,
|
||||
"results": [
|
||||
{
|
||||
"id": 42,
|
||||
"type": "ride",
|
||||
"title": "Amazing coaster experience!",
|
||||
"content_snippet": "This ride was absolutely incredible. The airtime was perfect and the inversions were smooth...",
|
||||
"rating": 9,
|
||||
"created_at": "2025-08-28T21:30:00Z",
|
||||
"user": {
|
||||
"username": "coaster_fan_2024",
|
||||
"display_name": "Coaster Fan",
|
||||
"avatar_url": "https://media.thrillwiki.com/avatars/user123.jpg"
|
||||
},
|
||||
"subject_name": "Steel Vengeance",
|
||||
"subject_slug": "steel-vengeance",
|
||||
"subject_url": "/parks/cedar-point/rides/steel-vengeance/",
|
||||
"park_name": "Cedar Point",
|
||||
"park_slug": "cedar-point",
|
||||
"park_url": "/parks/cedar-point/"
|
||||
},
|
||||
{
|
||||
"id": 38,
|
||||
"type": "park",
|
||||
"title": "Great family park",
|
||||
"content_snippet": "Had a wonderful time with the family. The park was clean, staff was friendly, and there were rides for all ages...",
|
||||
"rating": 8,
|
||||
"created_at": "2025-08-28T20:15:00Z",
|
||||
"user": {
|
||||
"username": "family_fun",
|
||||
"display_name": "Family Fun",
|
||||
"avatar_url": "/static/images/default-avatar.png"
|
||||
},
|
||||
"subject_name": "Dollywood",
|
||||
"subject_slug": "dollywood",
|
||||
"subject_url": "/parks/dollywood/",
|
||||
"park_name": null,
|
||||
"park_slug": null,
|
||||
"park_url": null
|
||||
}
|
||||
]
|
||||
```typescript
|
||||
interface ApiError {
|
||||
status: "error";
|
||||
error: {
|
||||
code: string;
|
||||
message: string;
|
||||
details?: any;
|
||||
request_user?: string;
|
||||
};
|
||||
data: null;
|
||||
}
|
||||
```
|
||||
|
||||
**Field Descriptions:**
|
||||
- `id`: Unique review identifier
|
||||
- `type`: Review type - "park" or "ride"
|
||||
- `title`: Review title/headline
|
||||
- `content_snippet`: Truncated review content (max 150 characters with smart word breaking)
|
||||
- `rating`: User rating from 1-10
|
||||
- `created_at`: ISO timestamp when review was created
|
||||
- `user`: User information object
|
||||
- `username`: User's unique username
|
||||
- `display_name`: User's display name (falls back to username if not set)
|
||||
- `avatar_url`: URL to user's avatar image (uses default if not set)
|
||||
- `subject_name`: Name of the reviewed item (park or ride)
|
||||
- `subject_slug`: URL slug of the reviewed item
|
||||
- `subject_url`: Frontend URL to the reviewed item's detail page
|
||||
- `park_name`: For ride reviews, the name of the parent park (null for park reviews)
|
||||
- `park_slug`: For ride reviews, the slug of the parent park (null for park reviews)
|
||||
- `park_url`: For ride reviews, the URL to the parent park (null for park reviews)
|
||||
Common error codes:
|
||||
- `NOT_AUTHENTICATED`: User not logged in
|
||||
- `PERMISSION_DENIED`: Insufficient permissions
|
||||
- `NOT_FOUND`: Resource not found
|
||||
- `VALIDATION_ERROR`: Invalid request data
|
||||
- `RATE_LIMITED`: Too many requests
|
||||
|
||||
**Authentication:** None required (public endpoint)
|
||||
## Pagination
|
||||
|
||||
**Example Usage:**
|
||||
```javascript
|
||||
// Fetch latest 10 reviews
|
||||
const response = await fetch('/api/v1/reviews/latest/?limit=10');
|
||||
const data = await response.json();
|
||||
List endpoints use cursor-based pagination:
|
||||
|
||||
// Display reviews
|
||||
data.results.forEach(review => {
|
||||
console.log(`${review.user.display_name} rated ${review.subject_name}: ${review.rating}/10`);
|
||||
console.log(`"${review.title}" - ${review.content_snippet}`);
|
||||
|
||||
if (review.type === 'ride') {
|
||||
console.log(`Ride at ${review.park_name}`);
|
||||
}
|
||||
});
|
||||
```typescript
|
||||
interface PaginatedResponse<T> {
|
||||
status: "success";
|
||||
data: {
|
||||
results: T[];
|
||||
count: number;
|
||||
next: string | null;
|
||||
previous: string | null;
|
||||
};
|
||||
error: null;
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `400 Bad Request`: Invalid limit parameter
|
||||
- `500 Internal Server Error`: Database or server error
|
||||
## Rate Limiting
|
||||
|
||||
**Notes:**
|
||||
- Reviews are filtered to only show published reviews (`is_published=True`)
|
||||
- Results are sorted by creation date (newest first)
|
||||
- Content snippets are intelligently truncated at word boundaries
|
||||
- Avatar URLs fall back to default avatar if user hasn't uploaded one
|
||||
- The endpoint combines reviews from both parks and rides into a single chronological feed
|
||||
API endpoints are rate limited based on user role:
|
||||
- Anonymous users: 100 requests/hour
|
||||
- Authenticated users: 1000 requests/hour
|
||||
- Moderators: 5000 requests/hour
|
||||
- Admins: 10000 requests/hour
|
||||
|
||||
## WebSocket Connections
|
||||
|
||||
Real-time updates are available for:
|
||||
- Moderation queue updates
|
||||
- New reports and actions
|
||||
- Bulk operation progress
|
||||
- Live statistics updates
|
||||
|
||||
Connect to: `ws://localhost:8000/ws/moderation/` (requires authentication)
|
||||
|
||||
Reference in New Issue
Block a user