# State Transition API Endpoints This document describes the API endpoints for performing state transitions on various models in ThrillWiki. ## Overview State transitions are performed via POST requests to specific action endpoints. All transition endpoints: - Require authentication - Return the updated object on success - Return appropriate error codes on failure - Log the transition in the StateLog ## Authentication All endpoints require a valid JWT token in the Authorization header: ``` Authorization: Bearer ``` ## Error Responses | Status Code | Meaning | |-------------|---------| | 400 | Invalid transition (state not allowed) | | 401 | Not authenticated | | 403 | Permission denied (insufficient role) | | 404 | Object not found | | 422 | Validation error (missing required fields) | --- ## EditSubmission Transitions ### Approve Submission Approve an edit submission and apply changes to the target object. ```http POST /api/moderation/submissions/{id}/approve/ ``` **Permissions**: MODERATOR or above **Request Body**: ```json { "notes": "Optional approval notes" } ``` **Response** (200 OK): ```json { "id": 123, "status": "APPROVED", "handled_by": { "id": 456, "username": "moderator" }, "handled_at": "2025-01-15T10:30:00Z", "notes": "Looks good, approved" } ``` ### Reject Submission Reject an edit submission with a reason. ```http POST /api/moderation/submissions/{id}/reject/ ``` **Permissions**: MODERATOR or above **Request Body**: ```json { "reason": "Required rejection reason" } ``` **Response** (200 OK): ```json { "id": 123, "status": "REJECTED", "handled_by": { "id": 456, "username": "moderator" }, "handled_at": "2025-01-15T10:30:00Z", "notes": "Rejected: Insufficient evidence" } ``` ### Escalate Submission Escalate a submission to admin review. ```http POST /api/moderation/submissions/{id}/escalate/ ``` **Permissions**: MODERATOR or above **Request Body**: ```json { "reason": "Reason for escalation" } ``` **Response** (200 OK): ```json { "id": 123, "status": "ESCALATED", "handled_by": { "id": 456, "username": "moderator" }, "handled_at": "2025-01-15T10:30:00Z", "notes": "Escalated: Needs admin approval for sensitive change" } ``` --- ## ModerationReport Transitions ### Start Review Claim a report and start reviewing it. ```http POST /api/moderation/reports/{id}/start_review/ ``` **Permissions**: MODERATOR or above **Request Body**: None **Response** (200 OK): ```json { "id": 123, "status": "UNDER_REVIEW", "assigned_moderator": { "id": 456, "username": "moderator" } } ``` ### Resolve Report Mark a report as resolved. ```http POST /api/moderation/reports/{id}/resolve/ ``` **Permissions**: MODERATOR or above (must be assigned) **Request Body**: ```json { "resolution_action": "CONTENT_REMOVED", "resolution_notes": "Description of action taken" } ``` **Response** (200 OK): ```json { "id": 123, "status": "RESOLVED", "resolution_action": "CONTENT_REMOVED", "resolution_notes": "Description of action taken", "resolved_at": "2025-01-15T10:30:00Z" } ``` ### Dismiss Report Dismiss a report as invalid. ```http POST /api/moderation/reports/{id}/dismiss/ ``` **Permissions**: MODERATOR or above (must be assigned) **Request Body**: ```json { "resolution_notes": "Reason for dismissal" } ``` **Response** (200 OK): ```json { "id": 123, "status": "DISMISSED", "resolution_notes": "Report did not violate guidelines", "resolved_at": "2025-01-15T10:30:00Z" } ``` --- ## Park Transitions ### Close Temporarily Temporarily close a park. ```http POST /api/parks/{slug}/close_temporarily/ ``` **Permissions**: Authenticated user **Request Body**: None **Response** (200 OK): ```json { "id": 123, "slug": "example-park", "name": "Example Park", "status": "CLOSED_TEMP" } ``` ### Reopen Reopen a temporarily closed park. ```http POST /api/parks/{slug}/reopen/ ``` **Permissions**: Authenticated user **Request Body**: None **Response** (200 OK): ```json { "id": 123, "slug": "example-park", "name": "Example Park", "status": "OPERATING" } ``` ### Close Permanently Permanently close a park. ```http POST /api/parks/{slug}/close_permanently/ ``` **Permissions**: MODERATOR or above **Request Body**: ```json { "closing_date": "2025-12-31" } ``` **Response** (200 OK): ```json { "id": 123, "slug": "example-park", "name": "Example Park", "status": "CLOSED_PERM", "closing_date": "2025-12-31" } ``` ### Demolish Mark a park as demolished. ```http POST /api/parks/{slug}/demolish/ ``` **Permissions**: MODERATOR or above **Request Body**: None **Response** (200 OK): ```json { "id": 123, "slug": "example-park", "name": "Example Park", "status": "DEMOLISHED" } ``` ### Relocate Mark a park as relocated. ```http POST /api/parks/{slug}/relocate/ ``` **Permissions**: MODERATOR or above **Request Body**: ```json { "new_location_notes": "Optional notes about new location" } ``` **Response** (200 OK): ```json { "id": 123, "slug": "example-park", "name": "Example Park", "status": "RELOCATED" } ``` --- ## Ride Transitions ### Open Open a ride (from CLOSED_TEMP, SBNO, or UNDER_CONSTRUCTION). ```http POST /api/parks/{park_slug}/rides/{ride_slug}/open/ ``` **Permissions**: Authenticated user (CLOSED_TEMP), MODERATOR+ (SBNO) **Request Body**: None **Response** (200 OK): ```json { "id": 123, "slug": "example-ride", "name": "Example Coaster", "status": "OPERATING" } ``` ### Close Temporarily Temporarily close a ride. ```http POST /api/parks/{park_slug}/rides/{ride_slug}/close_temporarily/ ``` **Permissions**: Authenticated user **Request Body**: None **Response** (200 OK): ```json { "id": 123, "slug": "example-ride", "name": "Example Coaster", "status": "CLOSED_TEMP" } ``` ### Mark SBNO Mark a ride as Standing But Not Operating. ```http POST /api/parks/{park_slug}/rides/{ride_slug}/mark_sbno/ ``` **Permissions**: MODERATOR or above **Request Body**: None **Response** (200 OK): ```json { "id": 123, "slug": "example-ride", "name": "Example Coaster", "status": "SBNO" } ``` ### Mark Closing Mark a ride as scheduled for closure. ```http POST /api/parks/{park_slug}/rides/{ride_slug}/mark_closing/ ``` **Permissions**: MODERATOR or above **Request Body**: ```json { "closing_date": "2025-12-31", "post_closing_status": "DEMOLISHED" } ``` **Valid post_closing_status values**: - `SBNO` - Will become Standing But Not Operating - `CLOSED_PERM` - Will be permanently closed - `DEMOLISHED` - Will be demolished - `RELOCATED` - Will be relocated **Response** (200 OK): ```json { "id": 123, "slug": "example-ride", "name": "Example Coaster", "status": "CLOSING", "closing_date": "2025-12-31", "post_closing_status": "DEMOLISHED" } ``` ### Close Permanently Permanently close a ride. ```http POST /api/parks/{park_slug}/rides/{ride_slug}/close_permanently/ ``` **Permissions**: MODERATOR or above **Request Body**: ```json { "closing_date": "2025-12-31" } ``` **Response** (200 OK): ```json { "id": 123, "slug": "example-ride", "name": "Example Coaster", "status": "CLOSED_PERM", "closing_date": "2025-12-31" } ``` ### Demolish Mark a ride as demolished. ```http POST /api/parks/{park_slug}/rides/{ride_slug}/demolish/ ``` **Permissions**: MODERATOR or above **Request Body**: None **Response** (200 OK): ```json { "id": 123, "slug": "example-ride", "name": "Example Coaster", "status": "DEMOLISHED" } ``` ### Relocate Mark a ride as relocated. ```http POST /api/parks/{park_slug}/rides/{ride_slug}/relocate/ ``` **Permissions**: MODERATOR or above **Request Body**: ```json { "new_park_slug": "destination-park", "notes": "Optional relocation notes" } ``` **Response** (200 OK): ```json { "id": 123, "slug": "example-ride", "name": "Example Coaster", "status": "RELOCATED" } ``` --- ## Transition History ### Get Object History Get the state transition history for any object. ```http GET /api/moderation/history/{content_type}/{object_id}/ ``` **Permissions**: MODERATOR or above **Response** (200 OK): ```json { "count": 3, "results": [ { "id": 1, "timestamp": "2025-01-10T08:00:00Z", "source_state": "PENDING", "state": "ESCALATED", "transition": "transition_to_escalated", "by": { "id": 456, "username": "moderator" }, "description": null }, { "id": 2, "timestamp": "2025-01-15T10:30:00Z", "source_state": "ESCALATED", "state": "APPROVED", "transition": "transition_to_approved", "by": { "id": 789, "username": "admin" }, "description": "Approved after escalation review" } ] } ``` ### Get All History (Admin) Get all recent transition history across all models. ```http GET /api/moderation/reports/all_history/ ``` **Permissions**: ADMIN or above **Query Parameters**: - `page` - Page number (default: 1) - `page_size` - Items per page (default: 20) - `model` - Filter by model name (optional) - `user` - Filter by user ID (optional) - `from_date` - Filter from date (optional) - `to_date` - Filter to date (optional) **Response** (200 OK): ```json { "count": 100, "next": "/api/moderation/reports/all_history/?page=2", "previous": null, "results": [ { "id": 1, "content_type": "moderation.editsubmission", "object_id": 123, "timestamp": "2025-01-15T10:30:00Z", "source_state": "PENDING", "state": "APPROVED", "transition": "transition_to_approved", "by": { "id": 456, "username": "moderator" } } ] } ``` --- ## Mandatory API Rules 1. **Trailing Slashes**: All endpoints MUST include trailing forward slashes 2. **HTTP Methods**: All transitions use POST 3. **Authentication**: All endpoints require valid JWT token 4. **Content-Type**: Request bodies must be `application/json` ## Error Response Format All error responses follow this format: ```json { "error": "Error code", "message": "Human-readable error message", "details": { "field_name": ["Specific field errors"] } } ``` ### Example Error Responses **Invalid Transition (400)**: ```json { "error": "TRANSITION_NOT_ALLOWED", "message": "Cannot transition from APPROVED to REJECTED" } ``` **Permission Denied (403)**: ```json { "error": "PERMISSION_DENIED", "message": "This action requires moderator privileges" } ``` **Validation Error (422)**: ```json { "error": "VALIDATION_ERROR", "message": "Missing required fields", "details": { "post_closing_status": ["This field is required when marking as CLOSING"] } }