# social/models.py from django.db import models from django.conf import settings from django.utils import timezone from django.contrib.auth import get_user_model # Get the custom User model lazily User = get_user_model() # ============================================================================ # MODEL 1: SocialAccount - One model for all platform accounts # ============================================================================ class SocialAccount(models.Model): """Unified account model for all social platforms""" # FIX: Renamed 'user' to 'owner' to match the logic in views.py owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='social_accounts') PLATFORM_CHOICES = [ ('LI', 'LinkedIn'), ('GO', 'Google'), ('META', 'Meta (Facebook/Instagram)'), ('TT', 'TikTok'), ('X', 'X/Twitter'), ('YT', 'YouTube'), ] platform_type = models.CharField(max_length=4, choices=PLATFORM_CHOICES) platform_id = models.CharField(max_length=255, help_text="Platform-specific account ID") name = models.CharField(max_length=255, help_text="Account name or display name") # Flexible credentials storage access_token = models.TextField(blank=True, null=True) refresh_token = models.TextField(blank=True, null=True) credentials_json = models.JSONField(default=dict, blank=True) # Token management expires_at = models.DateTimeField(null=True, blank=True) is_permanent = models.BooleanField(default=False) # Sync tracking is_active = models.BooleanField(default=True) last_synced_at = models.DateTimeField(null=True, blank=True) updated_at = models.DateTimeField(auto_now=True) created_at = models.DateTimeField(auto_now_add=True) class Meta: unique_together = [['platform_type', 'platform_id']] ordering = ['-created_at'] def __str__(self): return f"{self.get_platform_type_display()}: {self.name}" def is_token_expired(self): """Check if token is expired or needs refresh""" if self.is_permanent: return False if not self.expires_at: return True # Consider expired if within 24 hours of expiration return timezone.now() >= (self.expires_at - timezone.timedelta(hours=24)) # ============================================================================ # MODEL 2: SocialContent - One model for posts/videos/tweets # ============================================================================ class SocialContent(models.Model): """Unified content model for posts, videos, tweets""" account = models.ForeignKey(SocialAccount, on_delete=models.CASCADE, related_name='contents') platform_type = models.CharField(max_length=4) source_platform = models.CharField( max_length=4, blank=True, null=True, help_text="Actual source platform for Meta (FB/IG)" ) content_id = models.CharField(max_length=255, unique=True, db_index=True, help_text="Platform-specific content ID") # Content data title = models.CharField(max_length=255, blank=True, help_text="For videos/titles") text = models.TextField(blank=True, help_text="For posts/tweets") # Delta sync bookmark - CRITICAL for incremental updates last_comment_sync_at = models.DateTimeField(default=timezone.now) # Sync state is_syncing = models.BooleanField(default=False, help_text="Is full sync in progress?") # Platform-specific data content_data = models.JSONField(default=dict) # Timestamps created_at = models.DateTimeField(help_text="Actual content creation time") added_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-created_at'] indexes = [ models.Index(fields=['account', '-created_at']), models.Index(fields=['platform_type', '-created_at']), ] def __str__(self): return f"{self.platform_type} Content: {self.content_id}" # ============================================================================ # MODEL 3: SocialComment - One model for comments/reviews (original comments only) # ============================================================================ class SocialComment(models.Model): """Unified comment model for comments, reviews (original comments only)""" account = models.ForeignKey(SocialAccount, on_delete=models.CASCADE, related_name='comments') content = models.ForeignKey(SocialContent, on_delete=models.CASCADE, related_name='comments') platform_type = models.CharField(max_length=4) source_platform = models.CharField( max_length=4, blank=True, null=True, help_text="Actual source platform for Meta (FB/IG)" ) comment_id = models.CharField(max_length=255, unique=True, db_index=True, help_text="Platform-specific comment ID") # Author information author_name = models.CharField(max_length=255) author_id = models.CharField(max_length=255, blank=True, null=True) # Comment data text = models.TextField() # Platform-specific data comment_data = models.JSONField(default=dict) # --- Engagement Metrics --- like_count = models.IntegerField(default=0, help_text="Number of likes") reply_count = models.IntegerField(default=0, help_text="Number of replies") rating = models.IntegerField( null=True, blank=True, db_index=True, help_text="Star rating (1-5) for review platforms like Google Reviews" ) # --- Media --- media_url = models.URLField( max_length=500, null=True, blank=True, help_text="URL to associated media (images/videos)" ) # --- AI Bilingual Analysis --- ai_analysis = models.JSONField( default=dict, blank=True, db_index=True, help_text="Complete AI analysis in bilingual format (en/ar) with sentiment, summaries, keywords, topics, entities, and emotions" ) # Timestamps created_at = models.DateTimeField(db_index=True) added_at = models.DateTimeField(auto_now_add=True) # Webhook support synced_via_webhook = models.BooleanField(default=False) class Meta: ordering = ['-created_at'] indexes = [ models.Index(fields=['account', '-created_at']), models.Index(fields=['content', '-created_at']), models.Index(fields=['platform_type', '-created_at']), models.Index(fields=['ai_analysis'], name='idx_comment_ai_analysis'), ] def __str__(self): return f"{self.platform_type} Comment by {self.author_name}" @property def is_analyzed(self): """Check if comment has been AI analyzed""" return bool(self.ai_analysis) # ============================================================================ # MODEL 4: SocialReply - Separate model for replies to comments # ============================================================================ class SocialReply(models.Model): """Unified reply model for replies to comments""" account = models.ForeignKey(SocialAccount, on_delete=models.CASCADE, related_name='replies') comment = models.ForeignKey(SocialComment, on_delete=models.CASCADE, related_name='replies') platform_type = models.CharField(max_length=4) source_platform = models.CharField( max_length=4, blank=True, null=True, help_text="Actual source platform for Meta (FB/IG)" ) reply_id = models.CharField(max_length=255, unique=True, db_index=True, help_text="Platform-specific reply ID") # Author information author_name = models.CharField(max_length=255) author_id = models.CharField(max_length=255, blank=True, null=True) # Reply data text = models.TextField() # Platform-specific data reply_data = models.JSONField(default=dict) # Timestamps created_at = models.DateTimeField(db_index=True) added_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-created_at'] indexes = [ models.Index(fields=['comment', '-created_at']), models.Index(fields=['account', '-created_at']), models.Index(fields=['platform_type', '-created_at']), ] def __str__(self): return f"Reply by {self.author_name} to {self.comment}"