Add comprehensive API documentation for ThrillWiki integration and features

- Introduced Next.js integration guide for ThrillWiki API, detailing authentication, core domain APIs, data structures, and implementation patterns.
- Documented the migration to Rich Choice Objects, highlighting changes for frontend developers and enhanced metadata availability.
- Fixed the missing `get_by_slug` method in the Ride model, ensuring proper functionality of ride detail endpoints.
- Created a test script to verify manufacturer syncing with ride models, ensuring data integrity across related models.
This commit is contained in:
pacnpal
2025-09-16 11:29:17 -04:00
parent 61d73a2147
commit c2c26cfd1d
98 changed files with 11476 additions and 4803 deletions

View File

@@ -23,6 +23,7 @@ from django.contrib.auth.models import AnonymousUser
from datetime import timedelta
import pghistory
from apps.core.history import TrackedModel
from apps.core.choices.fields import RichChoiceField
UserType = Union[AbstractBaseUser, AnonymousUser]
@@ -33,17 +34,6 @@ UserType = Union[AbstractBaseUser, AnonymousUser]
@pghistory.track() # Track all changes by default
class EditSubmission(TrackedModel):
STATUS_CHOICES = [
("PENDING", "Pending"),
("APPROVED", "Approved"),
("REJECTED", "Rejected"),
("ESCALATED", "Escalated"),
]
SUBMISSION_TYPE_CHOICES = [
("EDIT", "Edit Existing"),
("CREATE", "Create New"),
]
# Who submitted the edit
user = models.ForeignKey(
@@ -60,8 +50,11 @@ class EditSubmission(TrackedModel):
content_object = GenericForeignKey("content_type", "object_id")
# Type of submission
submission_type = models.CharField(
max_length=10, choices=SUBMISSION_TYPE_CHOICES, default="EDIT"
submission_type = RichChoiceField(
choice_group="submission_types",
domain="moderation",
max_length=10,
default="EDIT"
)
# The actual changes/data
@@ -81,7 +74,12 @@ class EditSubmission(TrackedModel):
source = models.TextField(
blank=True, help_text="Source of information (if applicable)"
)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="PENDING")
status = RichChoiceField(
choice_group="edit_submission_statuses",
domain="moderation",
max_length=20,
default="PENDING"
)
created_at = models.DateTimeField(auto_now_add=True)
# Review details
@@ -124,11 +122,11 @@ class EditSubmission(TrackedModel):
field = model_class._meta.get_field(field_name)
if isinstance(field, models.ForeignKey) and value is not None:
try:
related_obj = field.related_model.objects.get(pk=value)
related_obj = field.related_model.objects.get(pk=value) # type: ignore
resolved_data[field_name] = related_obj
except ObjectDoesNotExist:
raise ValueError(
f"Related object {field.related_model.__name__} with pk={value} does not exist"
f"Related object {field.related_model.__name__} with pk={value} does not exist" # type: ignore
)
except FieldDoesNotExist:
# Field doesn't exist on model, skip it
@@ -258,37 +256,24 @@ class ModerationReport(TrackedModel):
or behavior that needs moderator attention.
"""
STATUS_CHOICES = [
('PENDING', 'Pending Review'),
('UNDER_REVIEW', 'Under Review'),
('RESOLVED', 'Resolved'),
('DISMISSED', 'Dismissed'),
]
PRIORITY_CHOICES = [
('LOW', 'Low'),
('MEDIUM', 'Medium'),
('HIGH', 'High'),
('URGENT', 'Urgent'),
]
REPORT_TYPE_CHOICES = [
('SPAM', 'Spam'),
('HARASSMENT', 'Harassment'),
('INAPPROPRIATE_CONTENT', 'Inappropriate Content'),
('MISINFORMATION', 'Misinformation'),
('COPYRIGHT', 'Copyright Violation'),
('PRIVACY', 'Privacy Violation'),
('HATE_SPEECH', 'Hate Speech'),
('VIOLENCE', 'Violence or Threats'),
('OTHER', 'Other'),
]
# Report details
report_type = models.CharField(max_length=50, choices=REPORT_TYPE_CHOICES)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='PENDING')
priority = models.CharField(
max_length=10, choices=PRIORITY_CHOICES, default='MEDIUM')
report_type = RichChoiceField(
choice_group="report_types",
domain="moderation",
max_length=50
)
status = RichChoiceField(
choice_group="moderation_report_statuses",
domain="moderation",
max_length=20,
default='PENDING'
)
priority = RichChoiceField(
choice_group="priority_levels",
domain="moderation",
max_length=10,
default='MEDIUM'
)
# What is being reported
reported_entity_type = models.CharField(
@@ -339,7 +324,7 @@ class ModerationReport(TrackedModel):
]
def __str__(self):
return f"{self.get_report_type_display()} report by {self.reported_by.username}"
return f"{self.get_report_type_display()} report by {self.reported_by.username}" # type: ignore
@pghistory.track()
@@ -351,34 +336,24 @@ class ModerationQueue(TrackedModel):
separate from the initial reports.
"""
STATUS_CHOICES = [
('PENDING', 'Pending'),
('IN_PROGRESS', 'In Progress'),
('COMPLETED', 'Completed'),
('CANCELLED', 'Cancelled'),
]
PRIORITY_CHOICES = [
('LOW', 'Low'),
('MEDIUM', 'Medium'),
('HIGH', 'High'),
('URGENT', 'Urgent'),
]
ITEM_TYPE_CHOICES = [
('CONTENT_REVIEW', 'Content Review'),
('USER_REVIEW', 'User Review'),
('BULK_ACTION', 'Bulk Action'),
('POLICY_VIOLATION', 'Policy Violation'),
('APPEAL', 'Appeal'),
('OTHER', 'Other'),
]
# Queue item details
item_type = models.CharField(max_length=50, choices=ITEM_TYPE_CHOICES)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='PENDING')
priority = models.CharField(
max_length=10, choices=PRIORITY_CHOICES, default='MEDIUM')
item_type = RichChoiceField(
choice_group="queue_item_types",
domain="moderation",
max_length=50
)
status = RichChoiceField(
choice_group="moderation_queue_statuses",
domain="moderation",
max_length=20,
default='PENDING'
)
priority = RichChoiceField(
choice_group="priority_levels",
domain="moderation",
max_length=10,
default='MEDIUM'
)
title = models.CharField(max_length=200, help_text="Brief title for the queue item")
description = models.TextField(
@@ -439,7 +414,7 @@ class ModerationQueue(TrackedModel):
]
def __str__(self):
return f"{self.get_item_type_display()}: {self.title}"
return f"{self.get_item_type_display()}: {self.title}" # type: ignore
@pghistory.track()
@@ -451,19 +426,12 @@ class ModerationAction(TrackedModel):
warnings, suspensions, content removal, etc.
"""
ACTION_TYPE_CHOICES = [
('WARNING', 'Warning'),
('USER_SUSPENSION', 'User Suspension'),
('USER_BAN', 'User Ban'),
('CONTENT_REMOVAL', 'Content Removal'),
('CONTENT_EDIT', 'Content Edit'),
('CONTENT_RESTRICTION', 'Content Restriction'),
('ACCOUNT_RESTRICTION', 'Account Restriction'),
('OTHER', 'Other'),
]
# Action details
action_type = models.CharField(max_length=50, choices=ACTION_TYPE_CHOICES)
action_type = RichChoiceField(
choice_group="moderation_action_types",
domain="moderation",
max_length=50
)
reason = models.CharField(max_length=200, help_text="Brief reason for the action")
details = models.TextField(help_text="Detailed explanation of the action")
@@ -513,7 +481,7 @@ class ModerationAction(TrackedModel):
]
def __str__(self):
return f"{self.get_action_type_display()} against {self.target_user.username} by {self.moderator.username}"
return f"{self.get_action_type_display()} against {self.target_user.username} by {self.moderator.username}" # type: ignore
def save(self, *args, **kwargs):
# Set expiration time if duration is provided
@@ -531,37 +499,24 @@ class BulkOperation(TrackedModel):
imports, exports, or mass moderation actions.
"""
STATUS_CHOICES = [
('PENDING', 'Pending'),
('RUNNING', 'Running'),
('COMPLETED', 'Completed'),
('FAILED', 'Failed'),
('CANCELLED', 'Cancelled'),
]
PRIORITY_CHOICES = [
('LOW', 'Low'),
('MEDIUM', 'Medium'),
('HIGH', 'High'),
('URGENT', 'Urgent'),
]
OPERATION_TYPE_CHOICES = [
('UPDATE_PARKS', 'Update Parks'),
('UPDATE_RIDES', 'Update Rides'),
('IMPORT_DATA', 'Import Data'),
('EXPORT_DATA', 'Export Data'),
('MODERATE_CONTENT', 'Moderate Content'),
('USER_ACTIONS', 'User Actions'),
('CLEANUP', 'Cleanup'),
('OTHER', 'Other'),
]
# Operation details
operation_type = models.CharField(max_length=50, choices=OPERATION_TYPE_CHOICES)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='PENDING')
priority = models.CharField(
max_length=10, choices=PRIORITY_CHOICES, default='MEDIUM')
operation_type = RichChoiceField(
choice_group="bulk_operation_types",
domain="moderation",
max_length=50
)
status = RichChoiceField(
choice_group="bulk_operation_statuses",
domain="moderation",
max_length=20,
default='PENDING'
)
priority = RichChoiceField(
choice_group="priority_levels",
domain="moderation",
max_length=10,
default='MEDIUM'
)
description = models.TextField(help_text="Description of what this operation does")
# Operation parameters and results
@@ -614,7 +569,7 @@ class BulkOperation(TrackedModel):
]
def __str__(self):
return f"{self.get_operation_type_display()}: {self.description[:50]}"
return f"{self.get_operation_type_display()}: {self.description[:50]}" # type: ignore
@property
def progress_percentage(self):
@@ -626,12 +581,6 @@ class BulkOperation(TrackedModel):
@pghistory.track() # Track all changes by default
class PhotoSubmission(TrackedModel):
STATUS_CHOICES = [
("PENDING", "Pending"),
("APPROVED", "Approved"),
("REJECTED", "Rejected"),
("ESCALATED", "Escalated"),
]
# Who submitted the photo
user = models.ForeignKey(
@@ -655,7 +604,12 @@ class PhotoSubmission(TrackedModel):
date_taken = models.DateField(null=True, blank=True)
# Metadata
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="PENDING")
status = RichChoiceField(
choice_group="photo_submission_statuses",
domain="moderation",
max_length=20,
default="PENDING"
)
created_at = models.DateTimeField(auto_now_add=True)
# Review details