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:
pacnpal
2025-12-22 11:17:31 -05:00
parent 45d97b6e68
commit 2e35f8c5d9
71 changed files with 8036 additions and 1462 deletions

View File

@@ -1,3 +1,11 @@
"""
Photo upload and management views for ThrillWiki.
Security Note:
All uploads are validated for file type, size, and content before being saved.
Rate limiting is enforced to prevent abuse.
"""
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from django.contrib.auth.decorators import login_required
@@ -7,6 +15,12 @@ import json
import logging
from .models import Photo
from apps.core.utils.file_scanner import (
validate_image_upload,
FileValidationError,
check_upload_rate_limit,
increment_upload_count,
)
logger = logging.getLogger(__name__)
@@ -14,18 +28,37 @@ logger = logging.getLogger(__name__)
@login_required
@require_http_methods(["POST"])
def upload_photo(request):
"""Handle photo upload for any model"""
"""
Handle photo upload for any model.
Security measures:
- Rate limiting to prevent abuse
- File type validation (extension, MIME type, magic number)
- File size validation
- Image integrity validation
- Permission checks
"""
try:
# Security: Check rate limiting before processing upload
is_allowed, rate_limit_message = check_upload_rate_limit(request.user.id)
if not is_allowed:
logger.warning(
f"User {request.user} exceeded upload rate limit"
)
return JsonResponse(
{"error": rate_limit_message},
status=429, # Too Many Requests
)
# Get app label, model, and object ID
app_label = request.POST.get("app_label")
model = request.POST.get("model")
object_id = request.POST.get("object_id")
# Log received data
# Log received data (don't log file contents for security)
logger.debug(
f"Received upload request - app_label: {app_label}, model: {model}, object_id: {object_id}"
)
logger.debug(f"Files in request: {request.FILES}")
# Validate required fields
missing_fields = []
@@ -44,6 +77,19 @@ def upload_photo(request):
status=400,
)
# Security: Validate uploaded file before processing
uploaded_file = request.FILES["image"]
try:
validate_image_upload(uploaded_file)
except FileValidationError as e:
logger.warning(
f"User {request.user} attempted to upload invalid file: {str(e)}"
)
return JsonResponse(
{"error": str(e)},
status=400,
)
# Get content type
try:
content_type = ContentType.objects.get(
@@ -87,17 +133,19 @@ def upload_photo(request):
# Create the photo
photo = Photo.objects.create(
image=request.FILES["image"],
image=uploaded_file,
content_type=content_type,
object_id=obj.pk,
uploaded_by=request.user, # Add the user who uploaded the photo
uploaded_by=request.user,
is_primary=not Photo.objects.filter(
content_type=content_type, object_id=obj.pk
).exists(),
is_approved=is_approved,
# Auto-approve if the user is a moderator, admin, or superuser
)
# Security: Increment upload count for rate limiting
increment_upload_count(request.user.id)
return JsonResponse(
{
"id": photo.pk,
@@ -111,7 +159,7 @@ def upload_photo(request):
except Exception as e:
logger.error(f"Error in upload_photo: {str(e)}", exc_info=True)
return JsonResponse(
{"error": f"An error occurred while uploading the photo: {str(e)}"},
{"error": "An error occurred while uploading the photo"},
status=400,
)