Files
thrillwiki_django_no_react/shared/media/views.py
pacnpal d504d41de2 feat: complete monorepo structure with frontend and shared resources
- Add complete backend/ directory with full Django application
- Add frontend/ directory with Vite + TypeScript setup ready for Next.js
- Add comprehensive shared/ directory with:
  - Complete documentation and memory-bank archives
  - Media files and avatars (letters, park/ride images)
  - Deployment scripts and automation tools
  - Shared types and utilities
- Add architecture/ directory with migration guides
- Configure pnpm workspace for monorepo development
- Update .gitignore to exclude .django_tailwind_cli/ build artifacts
- Preserve all historical documentation in shared/docs/memory-bank/
- Set up proper structure for full-stack development with shared resources
2025-08-23 18:40:07 -04:00

190 lines
6.0 KiB
Python

from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from django.contrib.auth.decorators import login_required
from django.contrib.contenttypes.models import ContentType
from django.shortcuts import get_object_or_404
import json
import logging
from .models import Photo
logger = logging.getLogger(__name__)
@login_required
@require_http_methods(["POST"])
def upload_photo(request):
"""Handle photo upload for any model"""
try:
# 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
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 = []
if not app_label:
missing_fields.append("app_label")
if not model:
missing_fields.append("model")
if not object_id:
missing_fields.append("object_id")
if "image" not in request.FILES:
missing_fields.append("image")
if missing_fields:
return JsonResponse(
{"error": f'Missing required fields: {", ".join(missing_fields)}'},
status=400,
)
# Get content type
try:
content_type = ContentType.objects.get(
app_label=app_label.lower(), model=model.lower()
)
except ContentType.DoesNotExist:
return JsonResponse(
{"error": f"Invalid content type: {app_label}.{model}"},
status=400,
)
# Get the object instance
try:
obj = content_type.get_object_for_this_type(pk=object_id)
except Exception as e:
return JsonResponse(
{
"error": f"Object not found: {app_label}.{model} with id {object_id}. Error: {
str(e)}"
},
status=404,
)
# Check if user has permission to add photos
if not request.user.has_perm("media.add_photo"):
logger.warning(
f"User {
request.user} attempted to upload photo without permission"
)
return JsonResponse(
{"error": "You do not have permission to upload photos"},
status=403,
)
# Determine if the photo should be auto-approved
is_approved = (
request.user.is_superuser
or request.user.is_staff
or request.user.groups.filter(name="Moderators").exists()
)
# Create the photo
photo = Photo.objects.create(
image=request.FILES["image"],
content_type=content_type,
object_id=obj.pk,
uploaded_by=request.user, # Add the user who uploaded the photo
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
)
return JsonResponse(
{
"id": photo.pk,
"url": photo.image.url,
"caption": photo.caption,
"is_primary": photo.is_primary,
"is_approved": photo.is_approved,
}
)
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)}"},
status=400,
)
@login_required
@require_http_methods(["POST"])
def set_primary_photo(request, photo_id):
"""Set a photo as primary"""
try:
photo = get_object_or_404(Photo, pk=photo_id)
# Check if user has permission to edit photos
if not request.user.has_perm("media.change_photo"):
return JsonResponse(
{"error": "You do not have permission to edit photos"},
status=403,
)
# Set this photo as primary
photo.is_primary = True
photo.save() # This will automatically unset other primary photos
return JsonResponse({"status": "success"})
except Exception as e:
logger.error(f"Error in set_primary_photo: {str(e)}", exc_info=True)
return JsonResponse({"error": str(e)}, status=400)
@login_required
@require_http_methods(["POST"])
def update_caption(request, photo_id):
"""Update a photo's caption"""
try:
photo = get_object_or_404(Photo, pk=photo_id)
# Check if user has permission to edit photos
if not request.user.has_perm("media.change_photo"):
return JsonResponse(
{"error": "You do not have permission to edit photos"},
status=403,
)
# Update caption
data = json.loads(request.body)
photo.caption = data.get("caption", "")
photo.save()
return JsonResponse({"id": photo.pk, "caption": photo.caption})
except Exception as e:
logger.error(f"Error in update_caption: {str(e)}", exc_info=True)
return JsonResponse({"error": str(e)}, status=400)
@login_required
@require_http_methods(["DELETE"])
def delete_photo(request, photo_id):
"""Delete a photo"""
try:
photo = get_object_or_404(Photo, pk=photo_id)
# Check if user has permission to delete photos
if not request.user.has_perm("media.delete_photo"):
return JsonResponse(
{"error": "You do not have permission to delete photos"},
status=403,
)
photo.delete()
return JsonResponse({"status": "success"})
except Exception as e:
logger.error(f"Error in delete_photo: {str(e)}", exc_info=True)
return JsonResponse({"error": str(e)}, status=400)