from django.shortcuts import get_object_or_404 from django.core.files.base import ContentFile from ninja import Router, Query, File, UploadedFile from typing import List import uuid from apps.gallery.api.schemas import GalleryCreateSchema, GallerySchema from apps.gallery.models import Gallery from apps.gallery.tasks import process_uploaded_image from core.api.schemas import ErrorSchema, MessageSchema from core.authentication import jwt_auth gallery_router = Router() @gallery_router.get("/images", response=List[GallerySchema]) def list_gallery_images( request, page: int = Query(1, ge=1), limit: int = Query(20, ge=1, le=50), public_only: bool = Query(True) ): """List gallery images""" queryset = Gallery.objects.select_related('uploaded_by') if public_only: queryset = queryset.filter(is_public=True) # Pagination offset = (page - 1) * limit images = queryset[offset:offset + limit] return images @gallery_router.get("/images/{image_id}", response=GallerySchema) def get_gallery_image(request, image_id: int): """Get single gallery image""" image = get_object_or_404(Gallery, id=image_id, is_public=True) return image @gallery_router.post("/images", response={201: GallerySchema, 400: ErrorSchema}, auth=jwt_auth) def upload_image(request, file: UploadedFile = File(...), data: GalleryCreateSchema = None): """Upload image to gallery (committee members only)""" user = request.auth if not (user.is_superuser or user.is_staff): return 400, {"error": "Only committee members can upload images"} # Validate file type if not file.content_type.startswith('image/'): return 400, {"error": "File must be an image"} # Validate file size (10MB max) if file.size > 10 * 1024 * 1024: return 400, {"error": "File size must be less than 10MB"} try: # Create gallery item gallery_item = Gallery.objects.create( title=data.title if data else file.name, description=data.description if data else "", uploaded_by=user, alt_text=data.alt_text if data else "", is_public=data.is_public if data else True ) # Save image filename = f"gallery/{uuid.uuid4().hex}.{file.name.split('.')[-1]}" gallery_item.image.save(filename, ContentFile(file.read())) # Process image asynchronously process_uploaded_image.delay(gallery_item.id) return 201, gallery_item except Exception as e: return 400, {"error": "Failed to upload image", "details": str(e)} @gallery_router.put("/images/{image_id}", response={200: GallerySchema, 400: ErrorSchema}, auth=jwt_auth) def update_image(request, image_id: int, data: GalleryCreateSchema): """Update gallery image metadata""" user = request.auth image = get_object_or_404(Gallery, id=image_id) if not (image.uploaded_by == user or user.is_superuser or user.is_staff): return 400, {"error": "You can only edit your own images"} try: for field, value in data.dict(exclude_unset=True).items(): setattr(image, field, value) image.save() return 200, image except Exception as e: return 400, {"error": "Failed to update image", "details": str(e)} @gallery_router.delete("/images/{image_id}", response={200: MessageSchema, 400: ErrorSchema}, auth=jwt_auth) def delete_image(request, image_id: int): """Soft delete a gallery image owned by the requester or committee.""" user = request.auth image = get_object_or_404(Gallery, id=image_id) if not (image.uploaded_by == user or user.is_superuser or user.is_staff): return 400, {"error": "You can only delete your own images"} image.delete() return 200, {"message": "Image deleted successfully"} @gallery_router.get("/deleted/images", response=List[GallerySchema], auth=jwt_auth) def list_deleted_gallery_images(request): """List all soft-deleted gallery images (Admin/Committee only)""" if not (request.auth.is_staff or request.auth.is_superuser): return 403, {"error": "Permission denied"} return Gallery.deleted_objects.all().select_related('uploaded_by') @gallery_router.post("/deleted/images/{image_id}/restore", response={200: MessageSchema, 400: ErrorSchema}, auth=jwt_auth) def restore_gallery_image(request, image_id: int): """Restore a soft-deleted gallery image (Admin/Committee only)""" if not (request.auth.is_staff or request.auth.is_superuser): return 403, {"error": "Permission denied"} try: image = Gallery.deleted_objects.get(id=image_id) image.restore() return 200, {"message": f"Gallery image '{image.title}' restored successfully."} except Gallery.DoesNotExist: return 400, {"error": "Gallery image not found or not soft-deleted."}