import uuid from django.conf import settings from django.db import models class GroupRole(models.TextChoices): ADMIN = "admin", "Admin" MEMBER = "member", "Member" class JoinRequestStatus(models.TextChoices): PENDING = "pending", "Pending" APPROVED = "approved", "Approved" REJECTED = "rejected", "Rejected" class Group(models.Model): name = models.CharField(max_length=256, db_index=True) description = models.TextField(blank=True, default="") created_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="created_groups", ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: db_table = "groups_group" verbose_name = "Group" verbose_name_plural = "Groups" ordering = ["-created_at"] def __str__(self) -> str: return self.name class GroupMember(models.Model): group = models.ForeignKey( Group, on_delete=models.CASCADE, related_name="memberships", ) user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="group_memberships", ) role = models.CharField( max_length=16, choices=GroupRole.choices, default=GroupRole.MEMBER, ) joined_at = models.DateTimeField(auto_now_add=True) class Meta: db_table = "groups_member" verbose_name = "Group Member" verbose_name_plural = "Group Members" ordering = ["joined_at"] unique_together = [("group", "user")] def __str__(self) -> str: return f"{self.user} in {self.group} ({self.role})" class GroupInvite(models.Model): group = models.ForeignKey( Group, on_delete=models.CASCADE, related_name="invites", ) created_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="created_invites", ) code = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, db_index=True) max_uses = models.PositiveIntegerField(default=0, help_text="0 = unlimited") use_count = models.PositiveIntegerField(default=0) is_active = models.BooleanField(default=True, db_index=True) created_at = models.DateTimeField(auto_now_add=True) class Meta: db_table = "groups_invite" verbose_name = "Group Invite" verbose_name_plural = "Group Invites" ordering = ["-created_at"] def __str__(self) -> str: return f"Invite for {self.group.name} ({self.code})" class JoinRequest(models.Model): group = models.ForeignKey( Group, on_delete=models.CASCADE, related_name="join_requests", ) user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="join_requests", ) invite = models.ForeignKey( GroupInvite, on_delete=models.SET_NULL, null=True, blank=True, related_name="join_requests", ) status = models.CharField( max_length=16, choices=JoinRequestStatus.choices, default=JoinRequestStatus.PENDING, db_index=True, ) created_at = models.DateTimeField(auto_now_add=True) class Meta: db_table = "groups_join_request" verbose_name = "Join Request" verbose_name_plural = "Join Requests" ordering = ["-created_at"] unique_together = [("group", "user")] def __str__(self) -> str: return f"{self.user} → {self.group.name} ({self.status})"