38531-vm/core/models.py
2026-02-17 17:27:46 +00:00

213 lines
7.8 KiB
Python

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')