diff --git a/backend/server/adventures/models.py b/backend/server/adventures/models.py index bbeabe11..e79ef24b 100644 --- a/backend/server/adventures/models.py +++ b/backend/server/adventures/models.py @@ -64,6 +64,7 @@ def __str__(self): return f"{self.adventure.name} - {self.start_date} to {self.end_date}" class Adventure(models.Model): + #id = models.AutoField(primary_key=True) id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True) user_id = models.ForeignKey( User, on_delete=models.CASCADE, default=default_user_id) @@ -89,7 +90,10 @@ class Adventure(models.Model): # end_date = models.DateField(blank=True, null=True) def clean(self): - + if self.date and self.end_date and self.date > self.end_date: + raise ValidationError('The start date must be before the end date. Start date: ' + str(self.date) + ' End date: ' + str(self.end_date)) + if self.end_date and not self.date: + raise ValidationError('Adventures must have an end date. Adventure: ' + self.name) if self.collection: if self.collection.is_public and not self.is_public: raise ValidationError('Adventures associated with a public collection must be public. Collection: ' + self.trip.name + ' Adventure: ' + self.name) @@ -100,6 +104,7 @@ def __str__(self): return self.name class Collection(models.Model): + #id = models.AutoField(primary_key=True) id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True) user_id = models.ForeignKey( User, on_delete=models.CASCADE, default=default_user_id) @@ -125,6 +130,7 @@ def __str__(self): return self.name class Transportation(models.Model): + #id = models.AutoField(primary_key=True) id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True) user_id = models.ForeignKey( User, on_delete=models.CASCADE, default=default_user_id) @@ -158,6 +164,7 @@ def __str__(self): return self.name class Note(models.Model): + #id = models.AutoField(primary_key=True) id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True) user_id = models.ForeignKey( User, on_delete=models.CASCADE, default=default_user_id) @@ -181,6 +188,7 @@ def __str__(self): return self.name class Checklist(models.Model): + # id = models.AutoField(primary_key=True) id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True) user_id = models.ForeignKey( User, on_delete=models.CASCADE, default=default_user_id) @@ -202,6 +210,7 @@ def __str__(self): return self.name class ChecklistItem(models.Model): + #id = models.AutoField(primary_key=True) id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True) user_id = models.ForeignKey( User, on_delete=models.CASCADE, default=default_user_id) @@ -228,5 +237,4 @@ class AdventureImage(models.Model): adventure = models.ForeignKey(Adventure, related_name='images', on_delete=models.CASCADE) def __str__(self): - return self.image.url - + return self.image.url \ No newline at end of file diff --git a/backend/server/adventures/serializers.py b/backend/server/adventures/serializers.py index 4bf7e8c0..77d8d497 100644 --- a/backend/server/adventures/serializers.py +++ b/backend/server/adventures/serializers.py @@ -1,5 +1,5 @@ import os -from .models import Adventure, AdventureImage, ChecklistItem, Collection, Note, Transportation, Checklist, Visit +from .models import Adventure, AdventureImage, ChecklistItem, Collection, Note, Transportation, Checklist from rest_framework import serializers class AdventureImageSerializer(serializers.ModelSerializer): @@ -17,19 +17,14 @@ def to_representation(self, instance): public_url = public_url.replace("'", "") representation['image'] = f"{public_url}/media/{instance.image.name}" return representation - -class VisitSerializer(serializers.ModelSerializer): - class Meta: - model = Visit - fields = ['id', 'start_date', 'end_date', 'notes'] - read_only_fields = ['id'] + + class AdventureSerializer(serializers.ModelSerializer): images = AdventureImageSerializer(many=True, read_only=True) - visits = VisitSerializer(many=True, read_only=False) class Meta: model = Adventure - fields = ['id', 'user_id', 'name', 'description', 'rating', 'activity_types', 'location', 'is_public', 'collection', 'created_at', 'updated_at', 'images', 'link', 'type', 'longitude', 'latitude', 'visits'] + fields = ['id', 'user_id', 'name', 'description', 'rating', 'activity_types', 'location', 'date', 'is_public', 'collection', 'created_at', 'updated_at', 'images', 'link', 'type', 'longitude', 'latitude', 'end_date'] read_only_fields = ['id', 'created_at', 'updated_at', 'user_id'] def to_representation(self, instance): @@ -75,7 +70,7 @@ def update(self, instance, validated_data): instance.visits.filter(id__in=visits_to_delete).delete() return instance - + class TransportationSerializer(serializers.ModelSerializer): class Meta: @@ -104,7 +99,17 @@ class Meta: 'id', 'user_id', 'name', 'is_checked', 'checklist', 'created_at', 'updated_at' ] read_only_fields = ['id', 'created_at', 'updated_at', 'user_id', 'checklist'] - + + # def validate(self, data): + # # Check if the checklist is public and the checklist item is not + # checklist = data.get('checklist') + # is_checked = data.get('is_checked', False) + # if checklist and checklist.is_public and not is_checked: + # raise serializers.ValidationError( + # 'Checklist items associated with a public checklist must be checked.' + # ) + + class ChecklistSerializer(serializers.ModelSerializer): items = ChecklistItemSerializer(many=True, source='checklistitem_set') class Meta: @@ -168,6 +173,9 @@ def validate(self, data): return data + + + class CollectionSerializer(serializers.ModelSerializer): adventures = AdventureSerializer(many=True, read_only=True, source='adventure_set') transportations = TransportationSerializer(many=True, read_only=True, source='transportation_set') diff --git a/backend/server/adventures/views.py b/backend/server/adventures/views.py index 8c71ba31..7f90f736 100644 --- a/backend/server/adventures/views.py +++ b/backend/server/adventures/views.py @@ -72,23 +72,22 @@ def apply_sorting(self, queryset): return queryset.order_by(ordering) def get_queryset(self): - # if the user is not authenticated return only public adventures for retrieve action + # if the user is not authenticated return only public adventures for retrieve action if not self.request.user.is_authenticated: if self.action == 'retrieve': - return Adventure.objects.filter(is_public=True) + return Adventure.objects.filter(is_public=True).distinct().order_by('-updated_at') return Adventure.objects.none() - if self.action == 'retrieve': # For individual adventure retrieval, include public adventures return Adventure.objects.filter( Q(is_public=True) | Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user) - ) + ).distinct().order_by('-updated_at') else: # For other actions, include user's own adventures and shared adventures return Adventure.objects.filter( Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user) - ) + ).distinct().order_by('-updated_at') def retrieve(self, request, *args, **kwargs): queryset = self.get_queryset() @@ -271,6 +270,7 @@ def perform_update(self, serializer): serializer.save() # when creating an adventure, make sure the user is the owner of the collection or shared with the collection + @transaction.atomic def perform_create(self, serializer): # Retrieve the collection from the validated data collection = serializer.validated_data.get('collection') @@ -620,7 +620,7 @@ def get_queryset(self): # if the user is not authenticated return only public transportations for retrieve action if not self.request.user.is_authenticated: if self.action == 'retrieve': - return Transportation.objects.filter(is_public=True) + return Transportation.objects.filter(is_public=True).distinct().order_by('-updated_at') return Transportation.objects.none() @@ -628,12 +628,12 @@ def get_queryset(self): # For individual adventure retrieval, include public adventures return Transportation.objects.filter( Q(is_public=True) | Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user) - ) + ).distinct().order_by('-updated_at') else: # For other actions, include user's own adventures and shared adventures return Transportation.objects.filter( Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user) - ) + ).distinct().order_by('-updated_at') def partial_update(self, request, *args, **kwargs): # Retrieve the current object @@ -742,7 +742,7 @@ def get_queryset(self): # if the user is not authenticated return only public transportations for retrieve action if not self.request.user.is_authenticated: if self.action == 'retrieve': - return Note.objects.filter(is_public=True) + return Note.objects.filter(is_public=True).distinct().order_by('-updated_at') return Note.objects.none() @@ -750,12 +750,12 @@ def get_queryset(self): # For individual adventure retrieval, include public adventures return Note.objects.filter( Q(is_public=True) | Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user) - ) + ).distinct().order_by('-updated_at') else: # For other actions, include user's own adventures and shared adventures return Note.objects.filter( Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user) - ) + ).distinct().order_by('-updated_at') def partial_update(self, request, *args, **kwargs): # Retrieve the current object @@ -864,7 +864,7 @@ def get_queryset(self): # if the user is not authenticated return only public transportations for retrieve action if not self.request.user.is_authenticated: if self.action == 'retrieve': - return Checklist.objects.filter(is_public=True) + return Checklist.objects.filter(is_public=True).distinct().order_by('-updated_at') return Checklist.objects.none() @@ -872,12 +872,12 @@ def get_queryset(self): # For individual adventure retrieval, include public adventures return Checklist.objects.filter( Q(is_public=True) | Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user) - ) + ).distinct().order_by('-updated_at') else: # For other actions, include user's own adventures and shared adventures return Checklist.objects.filter( Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user) - ) + ).distinct().order_by('-updated_at') def partial_update(self, request, *args, **kwargs): # Retrieve the current object