mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2026-05-08 23:15:11 -04:00
feat(itinerary): add validation for global and dated itinerary items
This commit is contained in:
@@ -1060,6 +1060,7 @@ class CollectionItineraryDaySerializer(CustomModelSerializer):
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
class CollectionItineraryItemSerializer(CustomModelSerializer):
|
||||
date = serializers.DateField(required=False, allow_null=True)
|
||||
item = serializers.SerializerMethodField()
|
||||
start_datetime = serializers.ReadOnlyField()
|
||||
end_datetime = serializers.ReadOnlyField()
|
||||
@@ -1069,6 +1070,33 @@ class CollectionItineraryItemSerializer(CustomModelSerializer):
|
||||
model = CollectionItineraryItem
|
||||
fields = ['id', 'collection', 'content_type', 'object_id', 'item', 'date', 'is_global', 'order', 'start_datetime', 'end_datetime', 'created_at', 'object_name']
|
||||
read_only_fields = ['id', 'created_at', 'start_datetime', 'end_datetime', 'item', 'object_name']
|
||||
|
||||
def validate(self, attrs):
|
||||
data = super().validate(attrs)
|
||||
|
||||
is_global = data.get('is_global')
|
||||
if is_global is None and self.instance is not None:
|
||||
is_global = self.instance.is_global
|
||||
|
||||
if 'date' in data:
|
||||
date = data.get('date')
|
||||
elif self.instance is not None:
|
||||
date = self.instance.date
|
||||
else:
|
||||
date = None
|
||||
|
||||
if is_global and date is not None:
|
||||
raise serializers.ValidationError({
|
||||
'date': 'Global items must not have a date.',
|
||||
'is_global': 'Provide either a date or set is_global, not both.',
|
||||
})
|
||||
|
||||
if not is_global and date is None and self.instance is None:
|
||||
raise serializers.ValidationError({
|
||||
'date': 'Dated items must include a date. To create a trip-wide item, set is_global=true.',
|
||||
})
|
||||
|
||||
return data
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
# Security: Prevent changing collection, content_type, or object_id after creation
|
||||
|
||||
@@ -1,3 +1,57 @@
|
||||
from django.test import TestCase
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
# Create your tests here.
|
||||
from adventures.models import Collection, CollectionItineraryItem, Location
|
||||
from users.models import CustomUser
|
||||
|
||||
|
||||
class ItineraryAPITestCase(APITestCase):
|
||||
def setUp(self):
|
||||
self.user = CustomUser.objects.create_user(
|
||||
username='itinerary-user',
|
||||
email='itinerary-user@example.com',
|
||||
password='testpassword123',
|
||||
)
|
||||
self.collection = Collection.objects.create(user=self.user, name='Test Trip')
|
||||
self.location = Location.objects.create(user=self.user, name='Test Location', is_public=True)
|
||||
self.client.force_authenticate(user=self.user)
|
||||
|
||||
def test_create_global_itinerary_item_without_date(self):
|
||||
response = self.client.post(
|
||||
'/api/itineraries/',
|
||||
{
|
||||
'collection': str(self.collection.id),
|
||||
'content_type': 'location',
|
||||
'object_id': str(self.location.id),
|
||||
'is_global': True,
|
||||
'order': 0,
|
||||
},
|
||||
format='json',
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 201)
|
||||
self.assertEqual(CollectionItineraryItem.objects.count(), 1)
|
||||
|
||||
item = CollectionItineraryItem.objects.get()
|
||||
self.assertTrue(item.is_global)
|
||||
self.assertIsNone(item.date)
|
||||
self.assertEqual(item.collection, self.collection)
|
||||
|
||||
payload = response.json()
|
||||
self.assertTrue(payload['is_global'])
|
||||
self.assertIsNone(payload['date'])
|
||||
|
||||
def test_create_dated_itinerary_item_without_date_is_rejected(self):
|
||||
response = self.client.post(
|
||||
'/api/itineraries/',
|
||||
{
|
||||
'collection': str(self.collection.id),
|
||||
'content_type': 'location',
|
||||
'object_id': str(self.location.id),
|
||||
'is_global': False,
|
||||
'order': 0,
|
||||
},
|
||||
format='json',
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(response.json()['date'][0], 'Dated items must include a date. To create a trip-wide item, set is_global=true.')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export let appVersion = 'v0.12.0-dev-042426';
|
||||
export let appVersion = 'v0.12.0-dev-050726';
|
||||
export let versionChangelog = 'https://github.com/seanmorley15/AdventureLog/releases/tag/v0.12.0';
|
||||
export let appTitle = 'AdventureLog';
|
||||
export let copyrightYear = '2023-2026';
|
||||
|
||||
Reference in New Issue
Block a user