diff --git a/backend/server/adventures/serializers.py b/backend/server/adventures/serializers.py index 622e2eb..7a22d38 100644 --- a/backend/server/adventures/serializers.py +++ b/backend/server/adventures/serializers.py @@ -1,6 +1,6 @@ from django.utils import timezone import os -from .models import Adventure, AdventureImage, ChecklistItem, Collection, Note, Transportation, Checklist, Visit, Category, Attachment, Lodging +from .models import Location, LocationImage, ChecklistItem, Collection, Note, Transportation, Checklist, Visit, Category, Attachment, Lodging from rest_framework import serializers from main.utils import CustomModelSerializer from users.serializers import CustomUserDetailsSerializer @@ -9,17 +9,17 @@ from geopy.distance import geodesic from integrations.models import ImmichIntegration -class AdventureImageSerializer(CustomModelSerializer): +class LocationImageSerializer(CustomModelSerializer): class Meta: - model = AdventureImage - fields = ['id', 'image', 'adventure', 'is_primary', 'user_id', 'immich_id'] - read_only_fields = ['id', 'user_id'] + model = LocationImage + fields = ['id', 'image', 'location', 'is_primary', 'user', 'immich_id'] + read_only_fields = ['id', 'user'] def to_representation(self, instance): # If immich_id is set, check for user integration once integration = None if instance.immich_id: - integration = ImmichIntegration.objects.filter(user=instance.user_id).first() + integration = ImmichIntegration.objects.filter(user=instance.user).first() if not integration: return None # Skip if Immich image but no integration @@ -42,8 +42,8 @@ class AttachmentSerializer(CustomModelSerializer): extension = serializers.SerializerMethodField() class Meta: model = Attachment - fields = ['id', 'file', 'adventure', 'extension', 'name', 'user_id'] - read_only_fields = ['id', 'user_id'] + fields = ['id', 'file', 'location', 'extension', 'name', 'user'] + read_only_fields = ['id', 'user'] def get_extension(self, obj): return obj.file.name.split('.')[-1] @@ -59,11 +59,11 @@ class AttachmentSerializer(CustomModelSerializer): return representation class CategorySerializer(serializers.ModelSerializer): - num_adventures = serializers.SerializerMethodField() + num_locations = serializers.SerializerMethodField() class Meta: model = Category - fields = ['id', 'name', 'display_name', 'icon', 'num_adventures'] - read_only_fields = ['id', 'num_adventures'] + fields = ['id', 'name', 'display_name', 'icon', 'num_locations'] + read_only_fields = ['id', 'num_locations'] def validate_name(self, value): return value.lower() @@ -71,7 +71,7 @@ class CategorySerializer(serializers.ModelSerializer): def create(self, validated_data): user = self.context['request'].user validated_data['name'] = validated_data['name'].lower() - return Category.objects.create(user_id=user, **validated_data) + return Category.objects.create(user=user, **validated_data) def update(self, instance, validated_data): for attr, value in validated_data.items(): @@ -81,8 +81,8 @@ class CategorySerializer(serializers.ModelSerializer): instance.save() return instance - def get_num_adventures(self, obj): - return Adventure.objects.filter(category=obj, user_id=obj.user_id).count() + def get_num_locations(self, obj): + return Location.objects.filter(category=obj, user=obj.user).count() class VisitSerializer(serializers.ModelSerializer): @@ -91,13 +91,12 @@ class VisitSerializer(serializers.ModelSerializer): fields = ['id', 'start_date', 'end_date', 'timezone', 'notes'] read_only_fields = ['id'] -class AdventureSerializer(CustomModelSerializer): +class LocationSerializer(CustomModelSerializer): images = serializers.SerializerMethodField() visits = VisitSerializer(many=True, read_only=False, required=False) attachments = AttachmentSerializer(many=True, read_only=True) category = CategorySerializer(read_only=False, required=False) is_visited = serializers.SerializerMethodField() - user = serializers.SerializerMethodField() country = CountrySerializer(read_only=True) region = RegionSerializer(read_only=True) city = CitySerializer(read_only=True) @@ -108,16 +107,22 @@ class AdventureSerializer(CustomModelSerializer): ) class Meta: - model = Adventure + model = Location fields = [ - 'id', 'user_id', 'name', 'description', 'rating', 'activity_types', 'location', + 'id', 'name', 'description', 'rating', 'tags', 'location', 'is_public', 'collections', 'created_at', 'updated_at', 'images', 'link', 'longitude', 'latitude', 'visits', 'is_visited', 'category', 'attachments', 'user', 'city', 'country', 'region' ] - read_only_fields = ['id', 'created_at', 'updated_at', 'user_id', 'is_visited', 'user'] + read_only_fields = ['id', 'created_at', 'updated_at', 'user', 'is_visited'] + + # Makes it so the whole user object is returned in the serializer instead of just the user uuid + def to_representation(self, instance): + representation = super().to_representation(instance) + representation['user'] = CustomUserDetailsSerializer(instance.user, context=self.context).data + return representation def get_images(self, obj): - serializer = AdventureImageSerializer(obj.images.all(), many=True, context=self.context) + serializer = LocationImageSerializer(obj.images.all(), many=True, context=self.context) # Filter out None values from the serialized data return [image for image in serializer.data if image is not None] @@ -128,7 +133,7 @@ class AdventureSerializer(CustomModelSerializer): user = self.context['request'].user for collection in collections: - if collection.user_id != user and not collection.shared_with.filter(id=user.id).exists(): + if collection.user != user and not collection.shared_with.filter(id=user.id).exists(): raise serializers.ValidationError( f"Collection '{collection.name}' does not belong to the current user." ) @@ -140,7 +145,7 @@ class AdventureSerializer(CustomModelSerializer): if category_data: user = self.context['request'].user name = category_data.get('name', '').lower() - existing_category = Category.objects.filter(user_id=user, name=name).first() + existing_category = Category.objects.filter(user=user, name=name).first() if existing_category: return existing_category category_data['name'] = name @@ -162,7 +167,7 @@ class AdventureSerializer(CustomModelSerializer): icon = category_data.icon category, created = Category.objects.get_or_create( - user_id=user, + user=user, name=name, defaults={ 'display_name': display_name, @@ -171,10 +176,6 @@ class AdventureSerializer(CustomModelSerializer): ) return category - def get_user(self, obj): - user = obj.user_id - return CustomUserDetailsSerializer(user).data - def get_is_visited(self, obj): return obj.is_visited_status() @@ -184,24 +185,24 @@ class AdventureSerializer(CustomModelSerializer): collections_data = validated_data.pop('collections', []) print(category_data) - adventure = Adventure.objects.create(**validated_data) + location = Location.objects.create(**validated_data) # Handle visits for visit_data in visits_data: - Visit.objects.create(adventure=adventure, **visit_data) + Visit.objects.create(location=location, **visit_data) # Handle category if category_data: category = self.get_or_create_category(category_data) - adventure.category = category + location.category = category - # Handle collections - set after adventure is saved + # Handle collections - set after location is saved if collections_data: - adventure.collections.set(collections_data) + location.collections.set(collections_data) - adventure.save() + location.save() - return adventure + return location def update(self, instance, validated_data): has_visits = 'visits' in validated_data @@ -214,9 +215,9 @@ class AdventureSerializer(CustomModelSerializer): for attr, value in validated_data.items(): setattr(instance, attr, value) - # Handle category - ONLY allow the adventure owner to change categories + # Handle category - ONLY allow the location owner to change categories user = self.context['request'].user - if category_data and instance.user_id == user: + if category_data and instance.user == user: # Only the owner can set categories category = self.get_or_create_category(category_data) instance.category = category @@ -241,13 +242,13 @@ class AdventureSerializer(CustomModelSerializer): visit.save() updated_visit_ids.add(visit_id) else: - new_visit = Visit.objects.create(adventure=instance, **visit_data) + new_visit = Visit.objects.create(location=instance, **visit_data) updated_visit_ids.add(new_visit.id) visits_to_delete = current_visit_ids - updated_visit_ids instance.visits.filter(id__in=visits_to_delete).delete() - # call save on the adventure to update the updated_at field and trigger any geocoding + # call save on the location to update the updated_at field and trigger any geocoding instance.save() return instance @@ -258,13 +259,13 @@ class TransportationSerializer(CustomModelSerializer): class Meta: model = Transportation fields = [ - 'id', 'user_id', 'type', 'name', 'description', 'rating', + 'id', 'user', 'type', 'name', 'description', 'rating', 'link', 'date', 'flight_number', 'from_location', 'to_location', 'is_public', 'collection', 'created_at', 'updated_at', 'end_date', 'origin_latitude', 'origin_longitude', 'destination_latitude', 'destination_longitude', - 'start_timezone', 'end_timezone', 'distance' # ✅ Add distance here + 'start_timezone', 'end_timezone', 'distance' ] - read_only_fields = ['id', 'created_at', 'updated_at', 'user_id', 'distance'] + read_only_fields = ['id', 'created_at', 'updated_at', 'user', 'distance'] def get_distance(self, obj): if ( @@ -284,29 +285,29 @@ class LodgingSerializer(CustomModelSerializer): class Meta: model = Lodging fields = [ - 'id', 'user_id', 'name', 'description', 'rating', 'link', 'check_in', 'check_out', + 'id', 'user', 'name', 'description', 'rating', 'link', 'check_in', 'check_out', 'reservation_number', 'price', 'latitude', 'longitude', 'location', 'is_public', 'collection', 'created_at', 'updated_at', 'type', 'timezone' ] - read_only_fields = ['id', 'created_at', 'updated_at', 'user_id'] + read_only_fields = ['id', 'created_at', 'updated_at', 'user'] class NoteSerializer(CustomModelSerializer): class Meta: model = Note fields = [ - 'id', 'user_id', 'name', 'content', 'date', 'links', + 'id', 'user', 'name', 'content', 'date', 'links', 'is_public', 'collection', 'created_at', 'updated_at' ] - read_only_fields = ['id', 'created_at', 'updated_at', 'user_id'] + read_only_fields = ['id', 'created_at', 'updated_at', 'user'] class ChecklistItemSerializer(CustomModelSerializer): class Meta: model = ChecklistItem fields = [ - 'id', 'user_id', 'name', 'is_checked', 'checklist', 'created_at', 'updated_at' + 'id', 'user', 'name', 'is_checked', 'checklist', 'created_at', 'updated_at' ] - read_only_fields = ['id', 'created_at', 'updated_at', 'user_id', 'checklist'] + read_only_fields = ['id', 'created_at', 'updated_at', 'user', 'checklist'] class ChecklistSerializer(CustomModelSerializer): items = ChecklistItemSerializer(many=True, source='checklistitem_set') @@ -314,21 +315,21 @@ class ChecklistSerializer(CustomModelSerializer): class Meta: model = Checklist fields = [ - 'id', 'user_id', 'name', 'date', 'is_public', 'collection', 'created_at', 'updated_at', 'items' + 'id', 'user', 'name', 'date', 'is_public', 'collection', 'created_at', 'updated_at', 'items' ] - read_only_fields = ['id', 'created_at', 'updated_at', 'user_id'] + read_only_fields = ['id', 'created_at', 'updated_at', 'user'] def create(self, validated_data): items_data = validated_data.pop('checklistitem_set') checklist = Checklist.objects.create(**validated_data) for item_data in items_data: - # Remove user_id from item_data to avoid constraint issues - item_data.pop('user_id', None) - # Set user_id from the parent checklist + # Remove user from item_data to avoid constraint issues + item_data.pop('user', None) + # Set user from the parent checklist ChecklistItem.objects.create( checklist=checklist, - user_id=checklist.user_id, + user=checklist.user, **item_data ) return checklist @@ -348,8 +349,8 @@ class ChecklistSerializer(CustomModelSerializer): # Update or create items updated_item_ids = set() for item_data in items_data: - # Remove user_id from item_data to avoid constraint issues - item_data.pop('user_id', None) + # Remove user from item_data to avoid constraint issues + item_data.pop('user', None) item_id = item_data.get('id') if item_id: @@ -363,14 +364,14 @@ class ChecklistSerializer(CustomModelSerializer): # If ID is provided but doesn't exist, create new item ChecklistItem.objects.create( checklist=instance, - user_id=instance.user_id, + user=instance.user, **item_data ) else: # If no ID is provided, create new item ChecklistItem.objects.create( checklist=instance, - user_id=instance.user_id, + user=instance.user, **item_data ) @@ -391,7 +392,7 @@ class ChecklistSerializer(CustomModelSerializer): return data class CollectionSerializer(CustomModelSerializer): - adventures = AdventureSerializer(many=True, read_only=True) + locations = LocationSerializer(many=True, read_only=True) transportations = TransportationSerializer(many=True, read_only=True, source='transportation_set') notes = NoteSerializer(many=True, read_only=True, source='note_set') checklists = ChecklistSerializer(many=True, read_only=True, source='checklist_set') @@ -399,8 +400,8 @@ class CollectionSerializer(CustomModelSerializer): class Meta: model = Collection - fields = ['id', 'description', 'user_id', 'name', 'is_public', 'adventures', 'created_at', 'start_date', 'end_date', 'transportations', 'notes', 'updated_at', 'checklists', 'is_archived', 'shared_with', 'link', 'lodging'] - read_only_fields = ['id', 'created_at', 'updated_at', 'user_id'] + fields = ['id', 'description', 'user', 'name', 'is_public', 'locations', 'created_at', 'start_date', 'end_date', 'transportations', 'notes', 'updated_at', 'checklists', 'is_archived', 'shared_with', 'link', 'lodging'] + read_only_fields = ['id', 'created_at', 'updated_at', 'user'] def to_representation(self, instance): representation = super().to_representation(instance)