from django.db import models from django.contrib.auth.models import User class Intent(models.Model): name = models.CharField(max_length=100) icon = models.CharField(max_length=50, blank=True, help_text="Bootstrap icon class name") def __str__(self): return str(self.name) class ValueTag(models.Model): name = models.CharField(max_length=100) def __str__(self): return str(self.name) class Profile(models.Model): TRANSITION_CHOICES = [ ('none', 'Stable'), ('post-divorce', 'Post-Divorce'), ('relocating', 'Relocating'), ('career-change', 'Career Change'), ('new-in-town', 'New in Town'), ] user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') professional_headline = models.CharField(max_length=255, blank=True) transition_status = models.CharField(max_length=50, choices=TRANSITION_CHOICES, default='none') bio = models.TextField(blank=True) location_city = models.CharField(max_length=100, blank=True) intents = models.ManyToManyField(Intent, blank=True) value_tags = models.ManyToManyField(ValueTag, blank=True) avatar = models.ImageField(upload_to='avatars/', blank=True, null=True) # Momentum & Engagement accountability_streak = models.IntegerField(default=0) # Auth & Security is_email_verified = models.BooleanField(default=False) two_factor_enabled = models.BooleanField(default=False) onboarding_completed = models.BooleanField(default=False) # Multitenancy (Future Proofing) organization_id = models.IntegerField(null=True, blank=True) @property def get_avatar_url(self): if self.avatar and hasattr(self.avatar, 'url'): return self.avatar.url return f"https://i.pravatar.cc/150?u={self.user.username}" @property def connection_count(self): return Connection.objects.filter(models.Q(user1=self.user) | models.Q(user2=self.user)).count() @property def following_count(self): return Follow.objects.filter(follower=self.user).count() @property def followers_count(self): return Follow.objects.filter(followed=self.user).count() @property def events_attended_count(self): return self.user.attending_events.count() @property def profile_completion_percentage(self): steps = 0 total_steps = 5 if self.professional_headline: steps += 1 if self.bio: steps += 1 if self.location_city: steps += 1 if self.intents.exists(): steps += 1 if self.avatar: steps += 1 return int((steps / total_steps) * 100) def __str__(self): return f"{self.user.username}'s Profile" class Connection(models.Model): user1 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='connections1') user2 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='connections2') created_at = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('user1', 'user2') def __str__(self): return f"{self.user1.username} <-> {self.user2.username}" class Follow(models.Model): follower = models.ForeignKey(User, on_delete=models.CASCADE, related_name='following_relations') followed = models.ForeignKey(User, on_delete=models.CASCADE, related_name='follower_relations') created_at = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('follower', 'followed') def __str__(self): return f"{self.follower.username} follows {self.followed.username}" class Group(models.Model): name = models.CharField(max_length=255) description = models.TextField() is_private = models.BooleanField(default=False) moderators = models.ManyToManyField(User, related_name='moderated_groups') members = models.ManyToManyField(User, related_name='joined_groups') organization_id = models.IntegerField(null=True, blank=True) def __str__(self): return str(self.name) class Event(models.Model): title = models.CharField(max_length=255) description = models.TextField() start_time = models.DateTimeField() end_time = models.DateTimeField() location = models.CharField(max_length=255) group = models.ForeignKey(Group, on_delete=models.CASCADE, related_name='events', null=True, blank=True) organizer = models.ForeignKey(User, on_delete=models.CASCADE) attendees = models.ManyToManyField(User, related_name='attending_events') organization_id = models.IntegerField(null=True, blank=True) def __str__(self): return str(self.title) class Report(models.Model): reporter = models.ForeignKey(User, on_delete=models.CASCADE, related_name='reports_made') reported_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='reports_received', null=True, blank=True) content = models.TextField() timestamp = models.DateTimeField(auto_now_add=True) resolved = models.BooleanField(default=False) organization_id = models.IntegerField(null=True, blank=True) def __str__(self): return f"Report by {self.reporter.username} at {self.timestamp}" class Message(models.Model): sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sent_messages') recipient = models.ForeignKey(User, on_delete=models.CASCADE, related_name='received_messages') body = models.TextField() timestamp = models.DateTimeField(auto_now_add=True) is_read = models.BooleanField(default=False) class Meta: ordering = ['timestamp'] def __str__(self): return f"From {self.sender.username} to {self.recipient.username} at {self.timestamp}" class Post(models.Model): POST_TYPE_CHOICES = [ ('reflection', 'Reflection'), ('looking_for', 'Looking For'), ('offering', 'Offering'), ('event_invite', 'Event Invite'), ('progress_update', 'Progress Update'), ('skill_share', 'Skill Share'), ] author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts') content = models.TextField() image = models.ImageField(upload_to='posts/', blank=True, null=True) post_type = models.CharField(max_length=20, choices=POST_TYPE_CHOICES, default='reflection') timestamp = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-timestamp'] def __str__(self): return f"Post by {self.author.username} at {self.timestamp}" def user_has_reacted(self, user, reaction_type='heart'): if user.is_authenticated: return self.reactions.filter(user=user, reaction_type=reaction_type).exists() return False class Comment(models.Model): post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments') author = models.ForeignKey(User, on_delete=models.CASCADE) content = models.TextField() timestamp = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['timestamp'] def __str__(self): return f"Comment by {self.author.username} on {self.post}" class Reaction(models.Model): REACTION_CHOICES = [ ('heart', 'Heart'), ('like', 'Like'), ('smile', 'Smile'), ] post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='reactions') user = models.ForeignKey(User, on_delete=models.CASCADE) reaction_type = models.CharField(max_length=20, choices=REACTION_CHOICES, default='heart') class Meta: unique_together = ('post', 'user', 'reaction_type') def __str__(self): return f"{self.user.username} {self.reaction_type}ed {self.post}" class HiddenPost(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='hidden_posts') post = models.ForeignKey(Post, on_delete=models.CASCADE) class Meta: unique_together = ('user', 'post')