diff --git a/backend/server/adventures/serializers.py b/backend/server/adventures/serializers.py index 01b58bf..1395afa 100644 --- a/backend/server/adventures/serializers.py +++ b/backend/server/adventures/serializers.py @@ -1,11 +1,11 @@ import os -from .models import Adventure, ChecklistItem, Collection, Note, Transportation, Checklist +from .models import Adventure, AdventureImage, ChecklistItem, Collection, Note, Transportation, Checklist from rest_framework import serializers class AdventureImageSerializer(serializers.ModelSerializer): class Meta: - model = Adventure - fields = ['id', 'image'] + model = AdventureImage + fields = ['id', 'image', 'adventure'] read_only_fields = ['id'] def to_representation(self, instance): diff --git a/backend/server/adventures/urls.py b/backend/server/adventures/urls.py index 8bdd6b7..00e9cd4 100644 --- a/backend/server/adventures/urls.py +++ b/backend/server/adventures/urls.py @@ -1,6 +1,6 @@ from django.urls import include, path from rest_framework.routers import DefaultRouter -from .views import AdventureViewSet, ChecklistViewSet, CollectionViewSet, NoteViewSet, StatsViewSet, GenerateDescription, ActivityTypesView, TransportationViewSet +from .views import AdventureViewSet, ChecklistViewSet, CollectionViewSet, NoteViewSet, StatsViewSet, GenerateDescription, ActivityTypesView, TransportationViewSet, AdventureImageViewSet router = DefaultRouter() router.register(r'adventures', AdventureViewSet, basename='adventures') @@ -11,6 +11,7 @@ router.register(r'activity-types', ActivityTypesView, basename='activity-types') router.register(r'transportations', TransportationViewSet, basename='transportations') router.register(r'notes', NoteViewSet, basename='notes') router.register(r'checklists', ChecklistViewSet, basename='checklists') +router.register(r'images', AdventureImageViewSet, basename='images') urlpatterns = [ diff --git a/backend/server/adventures/views.py b/backend/server/adventures/views.py index 4ba7bf8..1a91b2b 100644 --- a/backend/server/adventures/views.py +++ b/backend/server/adventures/views.py @@ -1,12 +1,13 @@ +import uuid import requests from django.db import transaction from rest_framework.decorators import action from rest_framework import viewsets from django.db.models.functions import Lower from rest_framework.response import Response -from .models import Adventure, Checklist, Collection, Transportation, Note +from .models import Adventure, Checklist, Collection, Transportation, Note, AdventureImage from worldtravel.models import VisitedRegion, Region, Country -from .serializers import AdventureSerializer, CollectionSerializer, NoteSerializer, TransportationSerializer, ChecklistSerializer +from .serializers import AdventureImageSerializer, AdventureSerializer, CollectionSerializer, NoteSerializer, TransportationSerializer, ChecklistSerializer from rest_framework.permissions import IsAuthenticated from django.db.models import Q, Prefetch from .permissions import IsOwnerOrReadOnly, IsPublicReadOnly @@ -528,5 +529,85 @@ class ChecklistViewSet(viewsets.ModelViewSet): user = self.request.user return Checklist.objects.filter(user_id=user) + def perform_create(self, serializer): + serializer.save(user_id=self.request.user) + +class AdventureImageViewSet(viewsets.ModelViewSet): + serializer_class = AdventureImageSerializer + permission_classes = [IsAuthenticated]\ + + # make sure that when creating and updating an image, the user is authenticated and the adventure user is the same as the authenticated user + def create(self, request, *args, **kwargs): + if not request.user.is_authenticated: + return Response({"error": "User is not authenticated"}, status=status.HTTP_401_UNAUTHORIZED) + adventure_id = request.data.get('adventure') + try: + adventure = Adventure.objects.get(id=adventure_id) + except Adventure.DoesNotExist: + return Response({"error": "Adventure not found"}, status=status.HTTP_404_NOT_FOUND) + + if adventure.user_id != request.user: + return Response({"error": "User does not own this adventure"}, status=status.HTTP_403_FORBIDDEN) + + return super().create(request, *args, **kwargs) + + def update(self, request, *args, **kwargs): + if not request.user.is_authenticated: + return Response({"error": "User is not authenticated"}, status=status.HTTP_401_UNAUTHORIZED) + + adventure_id = request.data.get('adventure') + try: + adventure = Adventure.objects.get(id=adventure_id) + except Adventure.DoesNotExist: + return Response({"error": "Adventure not found"}, status=status.HTTP_404_NOT_FOUND) + + if adventure.user_id != request.user: + return Response({"error": "User does not own this adventure"}, status=status.HTTP_403_FORBIDDEN) + + return super().update(request, *args, **kwargs) + + def destroy(self, request, *args, **kwargs): + if not request.user.is_authenticated: + return Response({"error": "User is not authenticated"}, status=status.HTTP_401_UNAUTHORIZED) + + instance = self.get_object() + adventure = instance.adventure + if adventure.user_id != request.user: + return Response({"error": "User does not own this adventure"}, status=status.HTTP_403_FORBIDDEN) + + return super().destroy(request, *args, **kwargs) + + def partial_update(self, request, *args, **kwargs): + if not request.user.is_authenticated: + return Response({"error": "User is not authenticated"}, status=status.HTTP_401_UNAUTHORIZED) + + instance = self.get_object() + adventure = instance.adventure + if adventure.user_id != request.user: + return Response({"error": "User does not own this adventure"}, status=status.HTTP_403_FORBIDDEN) + + return super().partial_update(request, *args, **kwargs) + + @action(detail=False, methods=['GET'], url_path='(?P[0-9a-f-]+)') + def adventure_images(self, request, adventure_id=None, *args, **kwargs): + if not request.user.is_authenticated: + return Response({"error": "User is not authenticated"}, status=status.HTTP_401_UNAUTHORIZED) + + try: + adventure_uuid = uuid.UUID(adventure_id) + except ValueError: + return Response({"error": "Invalid adventure ID"}, status=status.HTTP_400_BAD_REQUEST) + + queryset = AdventureImage.objects.filter( + Q(adventure__id=adventure_uuid) & Q(user_id=request.user) + ) + + serializer = self.get_serializer(queryset, many=True, context={'request': request}) + return Response(serializer.data) + + def get_queryset(self): + # This method is used for list and retrieve actions + return AdventureImage.objects.filter(user_id=self.request.user) + def perform_create(self, serializer): serializer.save(user_id=self.request.user) \ No newline at end of file diff --git a/frontend/src/routes/adventures/+page.server.ts b/frontend/src/routes/adventures/+page.server.ts index ed0e38a..29b12fd 100644 --- a/frontend/src/routes/adventures/+page.server.ts +++ b/frontend/src/routes/adventures/+page.server.ts @@ -159,7 +159,7 @@ export const actions: Actions = { } formDataToSend.append('rating', rating ? rating.toString() : ''); formDataToSend.append('link', link || ''); - formDataToSend.append('image', image); + // formDataToSend.append('image', image); // log each key-value pair in the FormData for (let pair of formDataToSend.entries()) { @@ -233,6 +233,21 @@ export const actions: Actions = { let image_url = new_id.image; let link_url = new_id.link; + if (image && image.size > 0) { + let imageForm = new FormData(); + imageForm.append('image', image); + imageForm.append('adventure', id); + let imageRes = await fetch(`${serverEndpoint}/api/images/`, { + method: 'POST', + headers: { + Cookie: `${event.cookies.get('auth')}` + }, + body: imageForm + }); + let data = await imageRes.json(); + console.log(data); + } + return { id, user_id, image_url, link }; }, edit: async (event) => {