from django.db import models from django.core.validators import MinValueValidator, MaxValueValidator class Review(models.Model): STATUS_PENDING = 'pending' STATUS_LIVE = 'live' STATUS_REJECTED = 'rejected' STATUS_CHOICES = [ (STATUS_PENDING, 'Pending'), (STATUS_LIVE, 'Live'), (STATUS_REJECTED, 'Rejected'), ] REJECT_CHOICES = [ ('spam', 'Spam'), ('inappropriate', 'Inappropriate'), ('fake', 'Fake'), ] reviewer = models.ForeignKey( 'accounts.User', on_delete=models.CASCADE, related_name='admin_reviews' ) event = models.ForeignKey( 'events.Event', on_delete=models.CASCADE, related_name='admin_reviews' ) rating = models.IntegerField( validators=[MinValueValidator(1), MaxValueValidator(5)] ) review_text = models.TextField() submission_date = models.DateTimeField(auto_now_add=True) status = models.CharField( max_length=10, choices=STATUS_CHOICES, default=STATUS_PENDING ) reject_reason = models.CharField( max_length=15, choices=REJECT_CHOICES, null=True, blank=True ) display_name = models.CharField(max_length=100, blank=True, default='') is_verified = models.BooleanField(default=False) helpful_count = models.IntegerField(default=0) flag_count = models.IntegerField(default=0) class Meta: ordering = ['-submission_date'] indexes = [ models.Index(fields=['status']), models.Index(fields=['submission_date']), ] def __str__(self): return f'Review #{self.pk} by {self.reviewer_id} — {self.status}' class ReviewInteraction(models.Model): INTERACTION_CHOICES = [('HELPFUL', 'Helpful'), ('FLAG', 'Flag')] review = models.ForeignKey(Review, on_delete=models.CASCADE, related_name='interactions') username = models.CharField(max_length=255) interaction_type = models.CharField(max_length=20, choices=INTERACTION_CHOICES) created_at = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('review', 'username', 'interaction_type') def __str__(self): return f'{self.username} {self.interaction_type} on Review #{self.review_id}' # --------------------------------------------------------------------------- # RBAC Models # --------------------------------------------------------------------------- from accounts.models import User class Department(models.Model): name = models.CharField(max_length=100) slug = models.SlugField(unique=True) description = models.TextField(blank=True, default='') base_scopes = models.JSONField(default=list) color = models.CharField(max_length=7, default='#3B82F6') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ['name'] def __str__(self): return self.name class Squad(models.Model): name = models.CharField(max_length=100) department = models.ForeignKey(Department, on_delete=models.CASCADE, related_name='squads') manager = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='managed_squads') extra_scopes = models.JSONField(default=list) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['name'] def __str__(self): return f"{self.department.name} > {self.name}" class StaffProfile(models.Model): ROLE_CHOICES = [('SUPER_ADMIN', 'Super Admin'), ('MANAGER', 'Manager'), ('MEMBER', 'Member')] STATUS_CHOICES = [('active', 'Active'), ('invited', 'Invited'), ('deactivated', 'Deactivated')] user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='staff_profile') department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True, related_name='staff_members') squad = models.ForeignKey(Squad, on_delete=models.SET_NULL, null=True, blank=True, related_name='members') staff_role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='MEMBER') status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active') joined_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['user__first_name'] def get_effective_scopes(self): if self.staff_role == 'SUPER_ADMIN' or self.user.is_superuser: return ['*'] scopes = set() if self.department: scopes.update(self.department.base_scopes or []) if self.squad: scopes.update(self.squad.extra_scopes or []) if self.staff_role == 'MANAGER': scopes.add('settings.staff') return list(scopes) def get_allowed_modules(self): scopes = self.get_effective_scopes() if '*' in scopes: return ['dashboard', 'partners', 'events', 'ad-control', 'users', 'reviews', 'contributions', 'financials', 'settings'] SCOPE_TO_MODULE = { 'users': 'users', 'events': 'events', 'finance': 'financials', 'partners': 'partners', 'tickets': 'dashboard', 'settings': 'settings', 'ads': 'ad-control', 'contributions': 'contributions', } modules = {'dashboard'} for scope in scopes: prefix = scope.split('.')[0] if prefix in SCOPE_TO_MODULE: modules.add(SCOPE_TO_MODULE[prefix]) return list(modules) def __str__(self): return f"{self.user.username} ({self.staff_role})" class CustomRole(models.Model): name = models.CharField(max_length=100) slug = models.SlugField(unique=True) description = models.TextField(blank=True, default='') scopes = models.JSONField(default=list) is_system = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['name'] def __str__(self): return self.name class AuditLog(models.Model): user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='audit_logs') action = models.CharField(max_length=100) target_type = models.CharField(max_length=50) target_id = models.CharField(max_length=50) details = models.JSONField(default=dict) ip_address = models.GenericIPAddressField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-created_at'] def __str__(self): return f"{self.action} by {self.user} at {self.created_at}"