import uuid from django.db import models from django.contrib.auth import get_user_model from django.contrib.postgres.fields import ArrayField from django.forms import ValidationError from django_resized import ResizedImageField ADVENTURE_TYPES = [ ('general', 'General 🌍'), ('outdoor', 'Outdoor 🏞️'), ('lodging', 'Lodging 🛌'), ('dining', 'Dining 🍽️'), ('activity', 'Activity 🏄'), ('attraction', 'Attraction 🎢'), ('shopping', 'Shopping 🛍️'), ('nightlife', 'Nightlife 🌃'), ('event', 'Event 🎉'), ('transportation', 'Transportation 🚗'), ('culture', 'Culture 🎭'), ('water_sports', 'Water Sports 🚤'), ('hiking', 'Hiking 🥾'), ('wildlife', 'Wildlife 🦒'), ('historical_sites', 'Historical Sites 🏛️'), ('music_concerts', 'Music & Concerts 🎶'), ('fitness', 'Fitness 🏋️'), ('art_museums', 'Art & Museums 🎨'), ('festivals', 'Festivals 🎪'), ('spiritual_journeys', 'Spiritual Journeys 🧘‍♀️'), ('volunteer_work', 'Volunteer Work 🤝'), ('other', 'Other') ] TRANSPORTATION_TYPES = [ ('car', 'Car'), ('plane', 'Plane'), ('train', 'Train'), ('bus', 'Bus'), ('boat', 'Boat'), ('bike', 'Bike'), ('walking', 'Walking'), ('other', 'Other') ] # Assuming you have a default user ID you want to use default_user_id = 1 # Replace with an actual user ID User = get_user_model() class Visit(models.Model): id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True) adventure = models.ForeignKey('Adventure', on_delete=models.CASCADE, related_name='visits') start_date = models.DateField(null=True, blank=True) end_date = models.DateField(null=True, blank=True) notes = models.TextField(blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def clean(self): if self.start_date > self.end_date: raise ValidationError('The start date must be before or equal to the end date.') 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) type = models.CharField(max_length=100, choices=ADVENTURE_TYPES, default='general') name = models.CharField(max_length=200) location = models.CharField(max_length=200, blank=True, null=True) activity_types = ArrayField(models.CharField( max_length=100), blank=True, null=True) description = models.TextField(blank=True, null=True) rating = models.FloatField(blank=True, null=True) link = models.URLField(blank=True, null=True, max_length=2083) is_public = models.BooleanField(default=False) longitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True) latitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True) collection = models.ForeignKey('Collection', on_delete=models.CASCADE, blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) # DEPRECATED FIELDS - TO BE REMOVED IN FUTURE VERSIONS # Migrations performed in this version will remove these fields # image = ResizedImageField(force_format="WEBP", quality=75, null=True, blank=True, upload_to='images/') # date = models.DateField(blank=True, null=True) # 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) if self.user_id != self.collection.user_id: raise ValidationError('Adventures must be associated with collections owned by the same user. Collection owner: ' + self.collection.user_id.username + ' Adventure owner: ' + self.user_id.username) 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) name = models.CharField(max_length=200) description = models.TextField(blank=True, null=True) is_public = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) start_date = models.DateField(blank=True, null=True) end_date = models.DateField(blank=True, null=True) updated_at = models.DateTimeField(auto_now=True) is_archived = models.BooleanField(default=False) shared_with = models.ManyToManyField(User, related_name='shared_with', blank=True) link = models.URLField(blank=True, null=True, max_length=2083) # if connected adventures are private and collection is public, raise an error def clean(self): if self.is_public and self.pk: # Only check if the instance has a primary key for adventure in self.adventure_set.all(): if not adventure.is_public: raise ValidationError('Public collections cannot be associated with private adventures. Collection: ' + self.name + ' Adventure: ' + adventure.name) 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) type = models.CharField(max_length=100, choices=TRANSPORTATION_TYPES) name = models.CharField(max_length=200) description = models.TextField(blank=True, null=True) rating = models.FloatField(blank=True, null=True) link = models.URLField(blank=True, null=True) date = models.DateTimeField(blank=True, null=True) end_date = models.DateTimeField(blank=True, null=True) flight_number = models.CharField(max_length=100, blank=True, null=True) from_location = models.CharField(max_length=200, blank=True, null=True) to_location = models.CharField(max_length=200, blank=True, null=True) is_public = models.BooleanField(default=False) collection = models.ForeignKey('Collection', on_delete=models.CASCADE, blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def clean(self): print(self.date) 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.collection: if self.collection.is_public and not self.is_public: raise ValidationError('Transportations associated with a public collection must be public. Collection: ' + self.collection.name + ' Transportation: ' + self.name) if self.user_id != self.collection.user_id: raise ValidationError('Transportations must be associated with collections owned by the same user. Collection owner: ' + self.collection.user_id.username + ' Transportation owner: ' + self.user_id.username) 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) name = models.CharField(max_length=200) content = models.TextField(blank=True, null=True) links = ArrayField(models.URLField(), blank=True, null=True) date = models.DateField(blank=True, null=True) is_public = models.BooleanField(default=False) collection = models.ForeignKey('Collection', on_delete=models.CASCADE, blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def clean(self): if self.collection: if self.collection.is_public and not self.is_public: raise ValidationError('Notes associated with a public collection must be public. Collection: ' + self.collection.name + ' Transportation: ' + self.name) if self.user_id != self.collection.user_id: raise ValidationError('Notes must be associated with collections owned by the same user. Collection owner: ' + self.collection.user_id.username + ' Transportation owner: ' + self.user_id.username) 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) name = models.CharField(max_length=200) date = models.DateField(blank=True, null=True) is_public = models.BooleanField(default=False) collection = models.ForeignKey('Collection', on_delete=models.CASCADE, blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def clean(self): if self.collection: if self.collection.is_public and not self.is_public: raise ValidationError('Checklists associated with a public collection must be public. Collection: ' + self.collection.name + ' Checklist: ' + self.name) if self.user_id != self.collection.user_id: raise ValidationError('Checklists must be associated with collections owned by the same user. Collection owner: ' + self.collection.user_id.username + ' Checklist owner: ' + self.user_id.username) 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) name = models.CharField(max_length=200) is_checked = models.BooleanField(default=False) checklist = models.ForeignKey('Checklist', on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def clean(self): if self.checklist.is_public and not self.checklist.is_public: raise ValidationError('Checklist items associated with a public checklist must be public. Checklist: ' + self.checklist.name + ' Checklist item: ' + self.name) if self.user_id != self.checklist.user_id: raise ValidationError('Checklist items must be associated with checklists owned by the same user. Checklist owner: ' + self.checklist.user_id.username + ' Checklist item owner: ' + self.user_id.username) def __str__(self): return self.name class AdventureImage(models.Model): 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) image = ResizedImageField(force_format="WEBP", quality=75, upload_to='images/') adventure = models.ForeignKey(Adventure, related_name='images', on_delete=models.CASCADE) def __str__(self): return self.image.url