213 lines
7.8 KiB
Python
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')
|