128 lines
4.8 KiB
Python
128 lines
4.8 KiB
Python
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 gallery.models import Gallery
|
|
from gallery.tasks import process_uploaded_image
|
|
from api.authentication import jwt_auth
|
|
from api.schemas import GallerySchema, GalleryCreateSchema, MessageSchema, ErrorSchema
|
|
|
|
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."}
|