1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-25 07:49:37 +02:00

Refactor adventure category handling: update type definitions, enhance category management in UI components, and implement user-specific category deletion logic in the backend

This commit is contained in:
Sean Morley 2024-11-23 13:42:41 -05:00
parent 736ede2417
commit 8e5a20ec62
12 changed files with 324 additions and 93 deletions

View file

@ -21,18 +21,28 @@ class AdventureImageSerializer(CustomModelSerializer):
representation['image'] = f"{public_url}/media/{instance.image.name}"
return representation
class CategorySerializer(CustomModelSerializer):
class CategorySerializer(serializers.ModelSerializer):
num_adventures = serializers.SerializerMethodField()
class Meta:
model = Category
fields = ['id', 'name', 'display_name', 'icon', 'user_id', 'num_adventures']
read_only_fields = ['id', 'user_id', 'num_adventures']
fields = ['id', 'name', 'display_name', 'icon', 'num_adventures']
read_only_fields = ['id', 'num_adventures']
def validate_name(self, value):
if Category.objects.filter(name=value).exists():
raise serializers.ValidationError('Category with this name already exists.')
return value
return value.lower()
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)
def update(self, instance, validated_data):
for attr, value in validated_data.items():
setattr(instance, attr, value)
if 'name' in validated_data:
instance.name = validated_data['name'].lower()
instance.save()
return instance
def get_num_adventures(self, obj):
return Adventure.objects.filter(category=obj, user_id=obj.user_id).count()
@ -46,13 +56,8 @@ class VisitSerializer(serializers.ModelSerializer):
class AdventureSerializer(CustomModelSerializer):
images = AdventureImageSerializer(many=True, read_only=True)
visits = VisitSerializer(many=True, read_only=False)
category = serializers.PrimaryKeyRelatedField(
queryset=Category.objects.all(),
write_only=True,
required=False
)
category_object = CategorySerializer(source='category', read_only=True)
visits = VisitSerializer(many=True, read_only=False, required=False)
category = CategorySerializer(read_only=False, required=False)
is_visited = serializers.SerializerMethodField()
class Meta:
@ -60,19 +65,45 @@ class AdventureSerializer(CustomModelSerializer):
fields = [
'id', 'user_id', 'name', 'description', 'rating', 'activity_types', 'location',
'is_public', 'collection', 'created_at', 'updated_at', 'images', 'link', 'longitude',
'latitude', 'visits', 'is_visited', 'category', 'category_object'
'latitude', 'visits', 'is_visited', 'category'
]
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id', 'is_visited']
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['category'] = representation.pop('category_object')
return representation
def validate_category(self, category_data):
if isinstance(category_data, Category):
return category_data
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()
if existing_category:
return existing_category
category_data['name'] = name
return category_data
def validate_category(self, category):
# Check that the category belongs to the same user
if category.user_id != self.context['request'].user:
raise serializers.ValidationError('Category does not belong to the user.')
def get_or_create_category(self, category_data):
user = self.context['request'].user
if isinstance(category_data, Category):
return category_data
if isinstance(category_data, dict):
name = category_data.get('name', '').lower()
display_name = category_data.get('display_name', name)
icon = category_data.get('icon', '🌎')
else:
name = category_data.name.lower()
display_name = category_data.display_name
icon = category_data.icon
category, created = Category.objects.get_or_create(
user_id=user,
name=name,
defaults={
'display_name': display_name,
'icon': icon
}
)
return category
def get_is_visited(self, obj):
@ -86,16 +117,28 @@ class AdventureSerializer(CustomModelSerializer):
def create(self, validated_data):
visits_data = validated_data.pop('visits', [])
category_data = validated_data.pop('category', None)
adventure = Adventure.objects.create(**validated_data)
for visit_data in visits_data:
Visit.objects.create(adventure=adventure, **visit_data)
if category_data:
category = self.get_or_create_category(category_data)
adventure.category = category
adventure.save()
return adventure
def update(self, instance, validated_data):
visits_data = validated_data.pop('visits', [])
category_data = validated_data.pop('category', None)
for attr, value in validated_data.items():
setattr(instance, attr, value)
if category_data:
category = self.get_or_create_category(category_data)
instance.category = category
instance.save()
current_visits = instance.visits.all()

View file

@ -614,23 +614,42 @@ class ActivityTypesView(viewsets.ViewSet):
return Response(allTypes)
class CategoryViewSet(viewsets.ViewSet):
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Category.objects.all()
serializer_class = CategorySerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
return Category.objects.filter(user_id=self.request.user)
@action(detail=False, methods=['get'])
def categories(self, request):
"""
Retrieve a list of distinct categories for adventures associated with the current user.
Args:
request (HttpRequest): The HTTP request object.
Returns:
Response: A response containing a list of distinct categories.
"""
categories = Category.objects.filter(user_id=request.user.id).distinct()
serializer = CategorySerializer(categories, many=True)
categories = self.get_queryset().distinct()
serializer = self.get_serializer(categories, many=True)
return Response(serializer.data)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.user_id != request.user:
return Response({"error": "User does not own this category"}, status
=400)
if instance.name == 'general':
return Response({"error": "Cannot delete the general category"}, status=400)
# set any adventures with this category to a default category called general before deleting the category, if general does not exist create it for the user
general_category = Category.objects.filter(user_id=request.user, name='general').first()
if not general_category:
general_category = Category.objects.create(user_id=request.user, name='general', icon='🌎', display_name='General')
Adventure.objects.filter(category=instance).update(category=general_category)
return super().destroy(request, *args, **kwargs)
class TransportationViewSet(viewsets.ModelViewSet):
queryset = Transportation.objects.all()
@ -1129,12 +1148,13 @@ class ReverseGeocodeViewSet(viewsets.ViewSet):
print(iso_code)
country_code = iso_code[:2]
if city:
display_name = f"{city}, {region.name}, {country_code}"
elif town and region.name:
display_name = f"{town}, {region.name}, {country_code}"
elif county and region.name:
display_name = f"{county}, {region.name}, {country_code}"
if region:
if city:
display_name = f"{city}, {region.name}, {country_code}"
elif town:
display_name = f"{town}, {region.name}, {country_code}"
elif county:
display_name = f"{county}, {region.name}, {country_code}"
if visited_region:
is_visited = True