mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 21:11:11 -05:00
feat: Refactor rides app with unique constraints, mixins, and enhanced documentation
- Added migration to convert unique_together constraints to UniqueConstraint for RideModel. - Introduced RideFormMixin for handling entity suggestions in ride forms. - Created comprehensive code standards documentation outlining formatting, docstring requirements, complexity guidelines, and testing requirements. - Established error handling guidelines with a structured exception hierarchy and best practices for API and view error handling. - Documented view pattern guidelines, emphasizing the use of CBVs, FBVs, and ViewSets with examples. - Implemented a benchmarking script for query performance analysis and optimization. - Developed security documentation detailing measures, configurations, and a security checklist. - Compiled a database optimization guide covering indexing strategies, query optimization patterns, and computed fields.
This commit is contained in:
@@ -3,16 +3,21 @@ Services for park-related business logic.
|
||||
Following Django styleguide pattern for business logic encapsulation.
|
||||
"""
|
||||
|
||||
from typing import Optional, Dict, Any, TYPE_CHECKING
|
||||
import logging
|
||||
from typing import Optional, Dict, Any, List, TYPE_CHECKING
|
||||
from django.db import transaction
|
||||
from django.db.models import Q
|
||||
from django.core.files.uploadedfile import UploadedFile
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
|
||||
from ..models import Park, ParkArea
|
||||
from ..models import Park, ParkArea, ParkPhoto
|
||||
from ..models.location import ParkLocation
|
||||
from .location_service import ParkLocationService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ParkService:
|
||||
"""Service for managing park operations."""
|
||||
@@ -226,3 +231,282 @@ class ParkService:
|
||||
park.save()
|
||||
|
||||
return park
|
||||
|
||||
@staticmethod
|
||||
def create_park_with_moderation(
|
||||
*,
|
||||
changes: Dict[str, Any],
|
||||
submitter: "AbstractUser",
|
||||
reason: str = "",
|
||||
source: str = "",
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Create a park through the moderation system.
|
||||
|
||||
Args:
|
||||
changes: Dictionary of park data
|
||||
submitter: User submitting the park
|
||||
reason: Reason for submission
|
||||
source: Source of information
|
||||
|
||||
Returns:
|
||||
Dictionary with status and created object (if auto-approved)
|
||||
"""
|
||||
from apps.moderation.services import ModerationService
|
||||
|
||||
return ModerationService.create_edit_submission_with_queue(
|
||||
content_object=None,
|
||||
changes=changes,
|
||||
submitter=submitter,
|
||||
submission_type="CREATE",
|
||||
reason=reason,
|
||||
source=source,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def update_park_with_moderation(
|
||||
*,
|
||||
park: Park,
|
||||
changes: Dict[str, Any],
|
||||
submitter: "AbstractUser",
|
||||
reason: str = "",
|
||||
source: str = "",
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Update a park through the moderation system.
|
||||
|
||||
Args:
|
||||
park: Park instance to update
|
||||
changes: Dictionary of changes
|
||||
submitter: User submitting the update
|
||||
reason: Reason for submission
|
||||
source: Source of information
|
||||
|
||||
Returns:
|
||||
Dictionary with status and updated object (if auto-approved)
|
||||
"""
|
||||
from apps.moderation.services import ModerationService
|
||||
|
||||
return ModerationService.create_edit_submission_with_queue(
|
||||
content_object=park,
|
||||
changes=changes,
|
||||
submitter=submitter,
|
||||
submission_type="EDIT",
|
||||
reason=reason,
|
||||
source=source,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def create_or_update_location(
|
||||
*,
|
||||
park: Park,
|
||||
latitude: Optional[float],
|
||||
longitude: Optional[float],
|
||||
street_address: str = "",
|
||||
city: str = "",
|
||||
state: str = "",
|
||||
country: str = "USA",
|
||||
postal_code: str = "",
|
||||
) -> Optional[ParkLocation]:
|
||||
"""
|
||||
Create or update a park's location.
|
||||
|
||||
Args:
|
||||
park: Park instance
|
||||
latitude: Latitude coordinate
|
||||
longitude: Longitude coordinate
|
||||
street_address: Street address
|
||||
city: City name
|
||||
state: State/region
|
||||
country: Country (default: USA)
|
||||
postal_code: Postal/ZIP code
|
||||
|
||||
Returns:
|
||||
ParkLocation instance or None if no coordinates provided
|
||||
"""
|
||||
if not latitude or not longitude:
|
||||
return None
|
||||
|
||||
try:
|
||||
park_location = park.location
|
||||
# Update existing location
|
||||
park_location.street_address = street_address
|
||||
park_location.city = city
|
||||
park_location.state = state
|
||||
park_location.country = country or "USA"
|
||||
park_location.postal_code = postal_code
|
||||
park_location.set_coordinates(float(latitude), float(longitude))
|
||||
park_location.save()
|
||||
return park_location
|
||||
except ParkLocation.DoesNotExist:
|
||||
# Create new location
|
||||
park_location = ParkLocation.objects.create(
|
||||
park=park,
|
||||
street_address=street_address,
|
||||
city=city,
|
||||
state=state,
|
||||
country=country or "USA",
|
||||
postal_code=postal_code,
|
||||
)
|
||||
park_location.set_coordinates(float(latitude), float(longitude))
|
||||
park_location.save()
|
||||
return park_location
|
||||
|
||||
@staticmethod
|
||||
def upload_photos(
|
||||
*,
|
||||
park: Park,
|
||||
photos: List[UploadedFile],
|
||||
uploaded_by: "AbstractUser",
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Upload multiple photos for a park.
|
||||
|
||||
Args:
|
||||
park: Park instance
|
||||
photos: List of uploaded photo files
|
||||
uploaded_by: User uploading the photos
|
||||
|
||||
Returns:
|
||||
Dictionary with uploaded_count and errors list
|
||||
"""
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
uploaded_count = 0
|
||||
errors: List[str] = []
|
||||
|
||||
for photo_file in photos:
|
||||
try:
|
||||
ParkPhoto.objects.create(
|
||||
image=photo_file,
|
||||
uploaded_by=uploaded_by,
|
||||
park=park,
|
||||
)
|
||||
uploaded_count += 1
|
||||
except Exception as e:
|
||||
error_msg = f"Error uploading photo {photo_file.name}: {str(e)}"
|
||||
errors.append(error_msg)
|
||||
logger.warning(error_msg)
|
||||
|
||||
return {
|
||||
"uploaded_count": uploaded_count,
|
||||
"errors": errors,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def handle_park_creation_result(
|
||||
*,
|
||||
result: Dict[str, Any],
|
||||
form_data: Dict[str, Any],
|
||||
photos: List[UploadedFile],
|
||||
user: "AbstractUser",
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Handle the result of park creation through moderation.
|
||||
|
||||
Args:
|
||||
result: Result from create_park_with_moderation
|
||||
form_data: Cleaned form data containing location info
|
||||
photos: List of uploaded photo files
|
||||
user: User who submitted
|
||||
|
||||
Returns:
|
||||
Dictionary with status, park (if created), uploaded_count, and errors
|
||||
"""
|
||||
response: Dict[str, Any] = {
|
||||
"status": result["status"],
|
||||
"park": None,
|
||||
"uploaded_count": 0,
|
||||
"errors": [],
|
||||
}
|
||||
|
||||
if result["status"] == "auto_approved":
|
||||
park = result["created_object"]
|
||||
response["park"] = park
|
||||
|
||||
# Create location
|
||||
ParkService.create_or_update_location(
|
||||
park=park,
|
||||
latitude=form_data.get("latitude"),
|
||||
longitude=form_data.get("longitude"),
|
||||
street_address=form_data.get("street_address", ""),
|
||||
city=form_data.get("city", ""),
|
||||
state=form_data.get("state", ""),
|
||||
country=form_data.get("country", "USA"),
|
||||
postal_code=form_data.get("postal_code", ""),
|
||||
)
|
||||
|
||||
# Upload photos
|
||||
if photos:
|
||||
photo_result = ParkService.upload_photos(
|
||||
park=park,
|
||||
photos=photos,
|
||||
uploaded_by=user,
|
||||
)
|
||||
response["uploaded_count"] = photo_result["uploaded_count"]
|
||||
response["errors"] = photo_result["errors"]
|
||||
|
||||
elif result["status"] == "failed":
|
||||
response["message"] = result.get("message", "Creation failed")
|
||||
|
||||
return response
|
||||
|
||||
@staticmethod
|
||||
def handle_park_update_result(
|
||||
*,
|
||||
result: Dict[str, Any],
|
||||
park: Park,
|
||||
form_data: Dict[str, Any],
|
||||
photos: List[UploadedFile],
|
||||
user: "AbstractUser",
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Handle the result of park update through moderation.
|
||||
|
||||
Args:
|
||||
result: Result from update_park_with_moderation
|
||||
park: Original park instance (for queued submissions)
|
||||
form_data: Cleaned form data containing location info
|
||||
photos: List of uploaded photo files
|
||||
user: User who submitted
|
||||
|
||||
Returns:
|
||||
Dictionary with status, park, uploaded_count, and errors
|
||||
"""
|
||||
response: Dict[str, Any] = {
|
||||
"status": result["status"],
|
||||
"park": park,
|
||||
"uploaded_count": 0,
|
||||
"errors": [],
|
||||
}
|
||||
|
||||
if result["status"] == "auto_approved":
|
||||
updated_park = result["created_object"]
|
||||
response["park"] = updated_park
|
||||
|
||||
# Update location
|
||||
ParkService.create_or_update_location(
|
||||
park=updated_park,
|
||||
latitude=form_data.get("latitude"),
|
||||
longitude=form_data.get("longitude"),
|
||||
street_address=form_data.get("street_address", ""),
|
||||
city=form_data.get("city", ""),
|
||||
state=form_data.get("state", ""),
|
||||
country=form_data.get("country", ""),
|
||||
postal_code=form_data.get("postal_code", ""),
|
||||
)
|
||||
|
||||
# Upload photos
|
||||
if photos:
|
||||
photo_result = ParkService.upload_photos(
|
||||
park=updated_park,
|
||||
photos=photos,
|
||||
uploaded_by=user,
|
||||
)
|
||||
response["uploaded_count"] = photo_result["uploaded_count"]
|
||||
response["errors"] = photo_result["errors"]
|
||||
|
||||
elif result["status"] == "failed":
|
||||
response["message"] = result.get("message", "Update failed")
|
||||
|
||||
return response
|
||||
|
||||
Reference in New Issue
Block a user