Add Team/TeamRole/TeamMembership/TeamPicture models and fix two test bugs

- Fix Member.create(): post_save signal creates Member immediately on User creation,
  so new users always hit the hasattr branch; check `created` flag to set initial
  password and notes for genuinely new users
- Fix Season.for_date(): replace get() with filter().order_by("-start_date").first()
  to handle overlapping seasons gracefully and raise DoesNotExist when none match
- Add TeamRole, Team, TeamMembership, TeamPicture models with rules permissions
- Add migration 0002 for new models
- Add test suites for members and teams covering all new model behaviour

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 08:53:05 +02:00
parent a02f234411
commit 6c0115d4a2
7 changed files with 572 additions and 12 deletions

43
teams/rules.py Normal file
View File

@@ -0,0 +1,43 @@
from typing import TYPE_CHECKING
import rules
from django.contrib.auth.models import AbstractUser
if TYPE_CHECKING:
from .models import TeamMembership, Season
@rules.predicate
def is_team_admin(user: AbstractUser | None, teammembership: "TeamMembership | None") -> bool:
"""
Determine if a user is a team admin within a specific team membership context.
:param user: The user to check for team admin privileges; can be None.
:param teammembership: The specific team membership to evaluate; can be None.
:return: A boolean indicating whether the user is a team admin for the given
team membership.
"""
from .models import TeamMembership, Season
if user is None or teammembership is None:
return False
return TeamMembership.objects.filter(team=teammembership.team, member__user=user, role__admin_role=True, season=Season.for_date()).exists()
@rules.predicate
def is_a_team_admin(user: AbstractUser | None) -> bool:
"""
Determine if a user is a team admin.
:param user: The user to check for team admin privileges; can be None.
:return: A boolean indicating whether the user is a team admin for the given
team membership.
"""
from .models import Season, TeamMembership
if user is None:
return False
return TeamMembership.objects.filter(member__user=user, role__admin_role=True, season=Season.for_date()).exists()