ajout de match régulier pour les équipes et de pratiques

Ajout d'un profil public cliquable pour les utilisateurs
déplacement du profil
This commit is contained in:
cedrick2711
2026-07-28 12:39:53 -04:00
parent 69b6e217ae
commit b982cd0318
20 changed files with 2132 additions and 225 deletions
+159 -13
View File
@@ -175,9 +175,18 @@ class User(UserMixin, db.Model):
if self.role == 'manager' and (tryout.created_by == self.id or tryout.manager_id == self.id):
return True
if self.role == 'coach':
org_team = OrgTeam.query.filter_by(coach_id=self.id).first()
if org_team and tryout.target_org_team_id == org_team.id:
return True
# Check if coach belongs to the target org team (many-to-many)
if tryout.target_org_team_id:
is_coach_of_target = OrgTeam.query.filter(
OrgTeam.id == tryout.target_org_team_id,
OrgTeam.coaches.any(id=self.id)
).first() is not None
if is_coach_of_target:
return True
# Fallback to legacy coach_id
org_team = OrgTeam.query.filter_by(coach_id=self.id).first()
if org_team and tryout.target_org_team_id == org_team.id:
return True
if tryout.coach_id == self.id:
return True
return False
@@ -186,7 +195,7 @@ class User(UserMixin, db.Model):
"""Check if user can manage a specific org team.
Presidents can manage all org teams. Managers can manage all org teams.
Coaches can only manage their own coached team.
Coaches can only manage their own coached team (via many-to-many or legacy).
Args:
org_team: The OrgTeam object to check permissions for.
@@ -198,8 +207,13 @@ class User(UserMixin, db.Model):
return True
if self.role == 'manager':
return True # Managers can manage all org teams (create/edit/delete)
if self.role == 'coach' and org_team.coach_id == self.id:
return True
if self.role == 'coach':
# Check many-to-many coaches
if org_team.coaches.filter_by(id=self.id).first():
return True
# Fallback to legacy coach_id
if org_team.coach_id == self.id:
return True
return False
def get_gamertags(self):
@@ -338,31 +352,87 @@ class TeamPlayer(db.Model):
)
# Many-to-many association tables for multiple coaches and managers per team
org_team_coaches = db.Table('org_team_coaches',
db.Column('org_team_id', db.Integer, db.ForeignKey('org_teams.id', ondelete='CASCADE'), primary_key=True),
db.Column('coach_id', db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), primary_key=True)
)
org_team_managers = db.Table('org_team_managers',
db.Column('org_team_id', db.Integer, db.ForeignKey('org_teams.id', ondelete='CASCADE'), primary_key=True),
db.Column('manager_id', db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), primary_key=True)
)
class OrgTeam(db.Model):
"""Persistent organization teams (e.g., Varsity, JV) that exist across tryouts.
These teams are long-term organizational structures that persist beyond
individual tryouts, unlike tryout-specific Team entities.
Supports multiple coaches and managers per team through many-to-many
junction tables (org_team_coaches, org_team_managers).
Attributes:
id: Unique identifier.
name: Team name (e.g., "Varsity", "Junior Varsity").
coach_id: Foreign key to the assigned coach.
manager_id: Foreign key to the assigned manager.
created_by: Foreign key to the user who created the team.
created_at: Timestamp of team creation.
coaches: Many-to-many relationship to User (coaches).
managers: Many-to-many relationship to User (managers).
"""
__tablename__ = 'org_teams'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False, unique=True)
coach_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
manager_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
# Legacy single coach/manager columns kept for backward compatibility during migration
# These will be removed in a future migration after existing data is migrated
coach_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
manager_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
coach = db.relationship('User', foreign_keys=[coach_id], backref='coached_org_team', uselist=False)
manager = db.relationship('User', foreign_keys=[manager_id], backref='managed_org_team', uselist=False)
creator = db.relationship('User', foreign_keys=[created_by])
# New many-to-many relationships for multiple coaches/managers
coaches = db.relationship('User', secondary=org_team_coaches, lazy='dynamic',
backref=db.backref('coached_org_teams', lazy='dynamic'))
managers = db.relationship('User', secondary=org_team_managers, lazy='dynamic',
backref=db.backref('managed_org_teams', lazy='dynamic'))
# Legacy single relationships — now properties that use the many-to-many lists
coach = db.relationship('User', foreign_keys=[coach_id],
backref=db.backref('coached_org_team_legacy', uselist=False), viewonly=True)
manager = db.relationship('User', foreign_keys=[manager_id],
backref=db.backref('managed_org_team_legacy', uselist=False), viewonly=True)
def get_coaches(self):
"""Get the list of coaches for display/handling.
Returns coaches from the many-to-many relationship, falling back to
the legacy single coach for backward compatibility.
Returns:
list: List of User objects who are coaches for this team.
"""
coach_list = self.coaches.all()
if not coach_list and self.coach:
return [self.coach]
return coach_list
def get_managers(self):
"""Get the list of managers for display/handling.
Returns managers from the many-to-many relationship, falling back to
the legacy single manager for backward compatibility.
Returns:
list: List of User objects who are managers for this team.
"""
manager_list = self.managers.all()
if not manager_list and self.manager:
return [self.manager]
return manager_list
@property
def players(self):
@@ -862,4 +932,80 @@ class OneOnOneRequest(db.Model):
player = db.relationship('User', foreign_keys=[player_id], backref='one_on_one_requests')
coach = db.relationship('User', foreign_keys=[coach_id])
team = db.relationship('OrgTeam', foreign_keys=[org_team_id])
team = db.relationship('OrgTeam', foreign_keys=[org_team_id])
class TeamMatch(db.Model):
"""Regular season match for an organization team (not tied to a tryout).
These matches are team-specific, not tryout-specific. The team's roster is
automatically pre-filled as participants. The creator (coach, manager, president)
only needs to select date-time and an optional opponent.
Attributes:
id: Unique identifier.
org_team_id: Foreign key to the organization team.
title: Match title/name.
description: Optional description.
opponent: Optional opponent name.
date: Match date.
start_time: Match start time.
end_time: Match end time.
location: Match location.
status: Match status (scheduled, completed, cancelled).
created_by: Foreign key to the creator.
created_at: Timestamp of creation.
"""
__tablename__ = 'team_matches'
id = db.Column(db.Integer, primary_key=True)
org_team_id = db.Column(db.Integer, db.ForeignKey('org_teams.id'), nullable=False)
title = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text, nullable=True)
opponent = db.Column(db.String(200), nullable=True)
date = db.Column(db.Date, nullable=False)
start_time = db.Column(db.Time, nullable=True)
end_time = db.Column(db.Time, nullable=True)
location = db.Column(db.String(200), nullable=True)
status = db.Column(db.String(20), default='scheduled') # scheduled, completed, cancelled
created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
org_team = db.relationship('OrgTeam', backref='team_matches')
creator = db.relationship('User', backref='created_team_matches')
participants = db.relationship('TeamMatchParticipant', backref='team_match', lazy='dynamic', cascade='all, delete-orphan')
def get_confirmed_count(self):
"""Get count of confirmed participants.
Returns:
tuple: (confirmed_count, total_count)
"""
all_p = self.participants.all()
confirmed = sum(1 for p in all_p if p.is_confirmed)
return confirmed, len(all_p)
class TeamMatchParticipant(db.Model):
"""Participant in a team match (regular season).
Automatically created for all team players when a TeamMatch is created.
Tracks attendance confirmation per player.
Attributes:
id: Unique identifier.
team_match_id: Foreign key to the team match.
player_id: Foreign key to the player.
is_confirmed: Whether attendance is confirmed (manual toggle or Discord reaction).
added_at: Timestamp when added.
"""
__tablename__ = 'team_match_participants'
id = db.Column(db.Integer, primary_key=True)
team_match_id = db.Column(db.Integer, db.ForeignKey('team_matches.id'), nullable=False)
player_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
is_confirmed = db.Column(db.Boolean, default=False)
added_at = db.Column(db.DateTime, default=datetime.utcnow)
player = db.relationship('User')
__table_args__ = (
db.UniqueConstraint('team_match_id', 'player_id', name='unique_team_match_player'),
)