Please update collection list page to update the style of collection and make sure each collection has the same width and height regardless the image size

This commit is contained in:
2024-11-17 16:53:24 +11:00
parent 96a0c8db65
commit faf44abe96
4 changed files with 213 additions and 9 deletions
BIN
View File
Binary file not shown.
+73 -8
View File
@@ -1,29 +1,51 @@
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from .models import ImageCollection, Image
from .serializers import ImageCollectionSerializer, ImageSerializer
from .storage import R2Storage
import uuid
import logging
import os
logger = logging.getLogger(__name__)
class ImageCollectionViewSet(viewsets.ModelViewSet):
queryset = ImageCollection.objects.all()
serializer_class = ImageCollectionSerializer
def create(self, request, *args, **kwargs):
"""Create a new collection"""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(
{
'status': 'success',
'message': 'Collection created successfully',
'data': serializer.data
},
status=status.HTTP_201_CREATED,
headers=headers
)
@action(detail=True, methods=['post'])
def upload_images(self, request, pk=None):
"""API endpoint to upload images to a collection"""
"""Upload images to a collection"""
collection = self.get_object()
files = request.FILES.getlist('file')
storage = R2Storage()
logger.debug(f"Processing upload request for collection {collection.id}")
logger.debug(f"Number of files: {len(files)}")
uploaded_images = []
for file in files:
try:
logger.info(os.environ.get('R2_ENDPOINT_URL'))
logger.debug(f"Processing file: {file.name}")
logger.debug(f"File size: {file.size}")
logger.debug(f"Content type: {file.content_type}")
# Generate unique file key
file_key = f"images/{collection.id}/{uuid.uuid4()}/{file.name}"
@@ -51,25 +73,68 @@ class ImageCollectionViewSet(viewsets.ModelViewSet):
size=file.size
)
logger.debug(f"Created image record: {image.id}")
uploaded_images.append(ImageSerializer(image).data)
except Exception as e:
logger.error(f"Upload failed for {file.name}", exc_info=True)
return Response({
'error': str(e)
'status': 'error',
'message': str(e)
}, status=status.HTTP_400_BAD_REQUEST)
return Response(uploaded_images, status=status.HTTP_201_CREATED)
return Response({
'status': 'success',
'message': f'Successfully uploaded {len(uploaded_images)} images',
'data': uploaded_images
}, status=status.HTTP_201_CREATED)
@action(detail=True, methods=['delete'])
def delete_image(self, request, pk=None):
"""Delete an image from a collection"""
collection = self.get_object()
image_id = request.data.get('image_id')
try:
image = collection.images.get(id=image_id)
storage = R2Storage()
# Delete from storage
if image.file_key:
try:
storage.delete_file(image.file_key)
except Exception as e:
logger.error(f"Failed to delete from storage: {e}")
# Delete from database
image.delete()
return Response({
'status': 'success',
'message': 'Image deleted successfully'
})
except Image.DoesNotExist:
return Response({
'status': 'error',
'message': 'Image not found'
}, status=status.HTTP_404_NOT_FOUND)
except Exception as e:
return Response({
'status': 'error',
'message': str(e)
}, status=status.HTTP_400_BAD_REQUEST)
class ImageViewSet(viewsets.ModelViewSet):
queryset = Image.objects.all()
serializer_class = ImageSerializer
def perform_destroy(self, instance):
# Delete from R2 before deleting record
"""Delete image from storage when deleting record"""
storage = R2Storage()
try:
storage.delete_file(instance.file_key)
if instance.file_key:
storage.delete_file(instance.file_key)
except Exception as e:
pass # Continue with deletion even if R2 delete fails
logger.error(f"Failed to delete from storage: {e}")
instance.delete()
+1 -1
View File
@@ -33,7 +33,7 @@
class="object-cover w-full h-full">
</div>
{% empty %}
<div class="col-span-2 flex flex-col items-center justify-center h-full bg-gradient-to-br from-gray-50 to-gray-100 rounded-lg border-2 border-dashed border-gray-200">
<div class="col-span-2 flex flex-col items-center justify-center h-full bg-gradient-to-br from-gray-50 to-gray-100 rounded-lg">
<svg class="w-8 h-8 sm:w-12 sm:h-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/>
+139
View File
@@ -213,6 +213,145 @@ curl -X POST http://localhost:8000/api/newsletters \
}'
```
## Collection API Usage
GoLinks provides RESTful APIs for managing image collections. Here are the available endpoints and their usage:
### List Collections
Retrieve a paginated list of all collections:
```
GET /api/collections
GET /api/collections?page=2
GET /api/collections?page_size=20
```
Response example:
```json
{
"count": 10,
"next": "http://localhost:8000/api/collections?page=2",
"previous": null,
"results": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My Collection",
"description": "A collection of images",
"image_count": 5,
"created_at": "2024-01-01T00:00:00Z"
},
// ... more collections
]
}
```
### Create a Collection
Create a new image collection:
```
POST /api/collections
Content-Type: application/json
{
"name": "My Collection",
"description": "A collection of images"
}
```
Response example:
```json
{
"status": "success",
"message": "Collection created successfully",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My Collection",
"description": "A collection of images",
"image_count": 0,
"created_at": "2024-01-01T00:00:00Z"
}
}
```
### Upload Images to Collection
Upload one or multiple images to a collection:
```
POST /api/collections/{collection_id}/upload_images
Content-Type: multipart/form-data
file: image1.jpg
file: image2.jpg
```
Response example:
```json
{
"status": "success",
"message": "Successfully uploaded 2 images",
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"title": "image1.jpg",
"content_type": "image/jpeg",
"size": 1024000,
"url": "https://your-r2-domain.com/images/...",
"created_at": "2024-01-01T00:00:00Z"
},
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"title": "image2.jpg",
"content_type": "image/jpeg",
"size": 2048000,
"url": "https://your-r2-domain.com/images/...",
"created_at": "2024-01-01T00:00:00Z"
}
]
}
```
### Delete an Image
Delete a specific image from a collection:
```
DELETE /api/images/{image_id}
```
Response example:
```json
{
"status": "success",
"message": "Image deleted successfully"
}
```
### Delete a Collection
Delete a collection and all its images:
```
DELETE /api/collections/{collection_id}
```
Response example:
```json
{
"status": "success",
"message": "Collection deleted successfully"
}
```
### Error Responses
In case of errors, the API will return appropriate status codes and error messages:
```json
{
"status": "error",
"message": "Error description here"
}
```
Common status codes:
- 200: Success
- 201: Created
- 400: Bad Request
- 404: Not Found
- 500: Internal Server Error
{% endfilter %}
</div>
</div>