mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-24 07:19:36 +02:00
feat: enhance Immich integration to support image downloading for shared users and improve access control for adventure images
This commit is contained in:
parent
b336a24401
commit
442a7724a0
2 changed files with 125 additions and 14 deletions
|
@ -3,9 +3,14 @@ from rest_framework.decorators import action
|
|||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from django.db.models import Q
|
||||
from django.core.files.base import ContentFile
|
||||
from adventures.models import Adventure, AdventureImage
|
||||
from adventures.serializers import AdventureImageSerializer
|
||||
from integrations.models import ImmichIntegration
|
||||
import uuid
|
||||
import requests
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
class AdventureImageViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = AdventureImageSerializer
|
||||
|
@ -56,6 +61,77 @@ class AdventureImageViewSet(viewsets.ModelViewSet):
|
|||
else:
|
||||
return Response({"error": "User does not own this adventure"}, status=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
# Handle Immich ID for shared users by downloading the image
|
||||
if (request.user != adventure.user_id and
|
||||
'immich_id' in request.data and
|
||||
request.data.get('immich_id')):
|
||||
|
||||
immich_id = request.data.get('immich_id')
|
||||
|
||||
# Get the shared user's Immich integration
|
||||
try:
|
||||
user_integration = ImmichIntegration.objects.get(user_id=request.user)
|
||||
except ImmichIntegration.DoesNotExist:
|
||||
return Response({
|
||||
"error": "No Immich integration found for your account. Please set up Immich integration first.",
|
||||
"code": "immich_integration_not_found"
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# Download the image from the shared user's Immich server
|
||||
try:
|
||||
immich_response = requests.get(
|
||||
f'{user_integration.server_url}/assets/{immich_id}/thumbnail?size=preview',
|
||||
headers={'x-api-key': user_integration.api_key},
|
||||
timeout=10
|
||||
)
|
||||
immich_response.raise_for_status()
|
||||
|
||||
# Create a temporary file with the downloaded content
|
||||
content_type = immich_response.headers.get('Content-Type', 'image/jpeg')
|
||||
if not content_type.startswith('image/'):
|
||||
return Response({
|
||||
"error": "Invalid content type returned from Immich server.",
|
||||
"code": "invalid_content_type"
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# Determine file extension from content type
|
||||
ext_map = {
|
||||
'image/jpeg': '.jpg',
|
||||
'image/png': '.png',
|
||||
'image/webp': '.webp',
|
||||
'image/gif': '.gif'
|
||||
}
|
||||
file_ext = ext_map.get(content_type, '.jpg')
|
||||
filename = f"immich_{immich_id}{file_ext}"
|
||||
|
||||
# Create a Django ContentFile from the downloaded image
|
||||
image_file = ContentFile(immich_response.content, name=filename)
|
||||
|
||||
# Modify request data to use the downloaded image instead of immich_id
|
||||
request_data = request.data.copy()
|
||||
request_data.pop('immich_id', None) # Remove immich_id
|
||||
|
||||
# Create the serializer with the modified data
|
||||
serializer = self.get_serializer(data=request_data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# Save with the downloaded image
|
||||
adventure = serializer.validated_data['adventure']
|
||||
serializer.save(user_id=adventure.user_id, image=image_file)
|
||||
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
return Response({
|
||||
"error": f"Failed to fetch image from Immich server: {str(e)}",
|
||||
"code": "immich_fetch_failed"
|
||||
}, status=status.HTTP_502_BAD_GATEWAY)
|
||||
except Exception as e:
|
||||
return Response({
|
||||
"error": f"Unexpected error processing Immich image: {str(e)}",
|
||||
"code": "immich_processing_error"
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
return super().create(request, *args, **kwargs)
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
|
@ -110,15 +186,25 @@ class AdventureImageViewSet(viewsets.ModelViewSet):
|
|||
except ValueError:
|
||||
return Response({"error": "Invalid adventure ID"}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# Updated queryset to include images from adventures the user owns OR has shared access to
|
||||
queryset = AdventureImage.objects.filter(
|
||||
Q(adventure__id=adventure_uuid) & Q(user_id=request.user)
|
||||
)
|
||||
Q(adventure__id=adventure_uuid) & (
|
||||
Q(adventure__user_id=request.user) | # User owns the adventure
|
||||
Q(adventure__collection__shared_with=request.user) # User has shared access via collection
|
||||
)
|
||||
).distinct()
|
||||
|
||||
serializer = self.get_serializer(queryset, many=True, context={'request': request})
|
||||
return Response(serializer.data)
|
||||
|
||||
def get_queryset(self):
|
||||
return AdventureImage.objects.filter(user_id=self.request.user)
|
||||
# Updated to include images from adventures the user owns OR has shared access to
|
||||
return AdventureImage.objects.filter(
|
||||
Q(adventure__user_id=self.request.user) | # User owns the adventure
|
||||
Q(adventure__collection__shared_with=self.request.user) # User has shared access via collection
|
||||
).distinct()
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(user_id=self.request.user)
|
||||
# Always set the image owner to the adventure owner, not the current user
|
||||
adventure = serializer.validated_data['adventure']
|
||||
serializer.save(user_id=adventure.user_id)
|
Loading…
Add table
Add a link
Reference in a new issue