from django.db import models from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.utils import timezone from taggit.managers import TaggableManager class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) bio = models.TextField(blank=True) interests = models.CharField(max_length=255, blank=True) industry = models.CharField(max_length=255, blank=True) is_verified = models.BooleanField(default=False) tags = TaggableManager(blank=True) def __str__(self): return self.user.username class Opportunity(models.Model): title = models.CharField(max_length=255) description = models.TextField() created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return self.title class IntroductionRequest(models.Model): from_user = models.ForeignKey(User, related_name='sent_requests', on_delete=models.CASCADE) to_user = models.ForeignKey(User, related_name='received_requests', on_delete=models.CASCADE) message = models.TextField() is_accepted = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f'Introduction request from {self.from_user} to {self.to_user}' class BenefitEvent(models.Model): """Immutable ledger of user-to-user benefit/help actions. benefactor: the user who provided value/help. beneficiary: the user who received value. points: positive integer weight for the action. kind: action type (accepted_answer, review_helpful, referral, recommendation). meta: optional JSON metadata (e.g., related object ids). """ KIND_ACCEPTED_ANSWER = "accepted_answer" KIND_REVIEW_HELPFUL = "review_helpful" KIND_REFERRAL = "referral" KIND_RECOMMENDATION = "recommendation" KIND_CHOICES = ( (KIND_ACCEPTED_ANSWER, "Accepted Answer"), (KIND_REVIEW_HELPFUL, "Review Marked Helpful"), (KIND_REFERRAL, "Referral"), (KIND_RECOMMENDATION, "Recommendation"), ) benefactor = models.ForeignKey( User, on_delete=models.CASCADE, related_name="benefit_given" ) beneficiary = models.ForeignKey( User, on_delete=models.CASCADE, related_name="benefit_received" ) points = models.IntegerField() kind = models.CharField(max_length=32, choices=KIND_CHOICES) meta = models.JSONField(default=dict, blank=True) # Use default=timezone.now so tests and backfills can set explicit timestamps created_at = models.DateTimeField(default=timezone.now, db_index=True) class Meta: indexes = [ models.Index(fields=["benefactor", "created_at"]), models.Index(fields=["beneficiary", "created_at"]), models.Index(fields=["kind", "created_at"]), ] ordering = ("-created_at", "-id") def clean(self): if self.benefactor_id and self.beneficiary_id and self.benefactor_id == self.beneficiary_id: raise ValidationError("Self-benefit is not allowed.") if self.points is None or self.points <= 0: raise ValidationError("Points must be a positive integer.") def save(self, *args, **kwargs): # Ensure validation always runs to enforce integrity self.full_clean() return super().save(*args, **kwargs) def __str__(self): return f"{self.kind} +{self.points} from {self.benefactor_id} to {self.beneficiary_id}"