38531-vm/groups/models.py
2026-02-17 18:44:08 +00:00

101 lines
3.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.db import models
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
class Group(models.Model):
GROUP_TYPE_CHOICES = [
('squad', 'Squad (412 members)'),
('community', 'Community (Open)'),
('mastermind', 'Pro Squad (Structured)'),
('tournament', 'Tournament Team'),
('private', 'Private Invite'),
]
INTENT_TYPE_CHOICES = [
('ranked', 'Ranked Squad'),
('duo', 'Duo'),
('casual', 'Casual'),
('tournament', 'Tournament'),
('practice', 'Practice'),
]
VISIBILITY_CHOICES = [
('public_members', 'Public (Members Only)'),
('private_request', 'Private (Request to Join)'),
('invite_only', 'Invite Only'),
]
LOCATION_SCOPE_CHOICES = [
('local', 'Local'),
('virtual', 'Virtual'),
]
name = models.CharField(max_length=255)
description = models.TextField()
group_type = models.CharField(max_length=50, choices=GROUP_TYPE_CHOICES)
intent_type = models.CharField(max_length=50, choices=INTENT_TYPE_CHOICES)
focus_game = models.CharField(max_length=100, blank=True, null=True)
visibility = models.CharField(max_length=50, choices=VISIBILITY_CHOICES, default='public_members')
capacity = models.PositiveIntegerField(null=True, blank=True)
location_scope = models.CharField(max_length=20, choices=LOCATION_SCOPE_CHOICES, default='local')
city = models.CharField(max_length=100, blank=True, null=True)
state = models.CharField(max_length=100, blank=True, null=True)
recurring_schedule = models.TextField(blank=True, null=True, help_text="Required for Mastermind groups. Use structured text or JSON.")
created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='created_groups_v2')
created_at = models.DateTimeField(auto_now_add=True)
cover_image = models.ImageField(upload_to='groups/covers/', blank=True, null=True)
def __str__(self):
return str(self.name)
def clean(self):
super().clean()
if self.group_type == 'circle':
if self.capacity and self.capacity > 12:
raise ValidationError({'capacity': 'Circles cannot have more than 12 members.'})
if not self.capacity:
self.capacity = 12
if self.group_type == 'mastermind' and not self.recurring_schedule:
raise ValidationError({'recurring_schedule': 'Mastermind groups require a structured schedule.'})
def save(self, *args, **kwargs):
self.full_clean()
super().save(*args, **kwargs)
class GroupMember(models.Model):
ROLE_CHOICES = [
('member', 'Member'),
('moderator', 'Moderator'),
('owner', 'Owner'),
]
STATUS_CHOICES = [
('active', 'Active'),
('pending', 'Pending'),
]
group = models.ForeignKey(Group, on_delete=models.CASCADE, related_name='memberships')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='group_memberships')
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:
unique_together = ('group', 'user')
def __str__(self):
return f"{self.user.username} in {self.group.name}"
def save(self, *args, **kwargs):
self.full_clean()
super().save(*args, **kwargs)
def clean(self):
super().clean()
if self.status == 'active':
# Use filter().count() instead of exclude() for new objects
current_count = GroupMember.objects.filter(group=self.group, status='active').exclude(id=self.id).count()
if self.group.capacity and current_count >= self.group.capacity:
raise ValidationError('This group has reached its maximum capacity.')