2025-11-19 04:33:49 +01:00

184 lines
7.2 KiB
Python

from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.decorators import login_required
from django.urls import reverse_lazy
from .models import Event, Training, Game, EventParticipation, GameResult
from .forms import EventForm, TrainingForm, GameForm, OpenGameForm, GameResultForm
from accounts.models import CustomUser # Import CustomUser for manage_participation view
from clubs.models import Team
from django.utils import timezone
import datetime
def select_event_type(request):
return render(request, 'calendars/select_event_type.html')
def get_all_child_teams(parent_team):
"""
Iteratively gets all child teams for a given team.
"""
children = []
teams_to_check = list(parent_team.child_teams.all())
while teams_to_check:
team = teams_to_check.pop(0)
if team not in children:
children.append(team)
teams_to_check.extend(list(team.child_teams.all()))
return children
class ManageableTeamsMixin:
def get_form(self, form_class=None):
form = super().get_form(form_class)
user = self.request.user
if not user.is_superuser:
coached_teams_qs = user.coached_teams.all()
expanded_coached_teams = list(coached_teams_qs)
for team in coached_teams_qs:
expanded_coached_teams.extend(get_all_child_teams(team))
assisted_teams_qs = user.assisted_teams.all()
# Combine and get unique teams
managed_teams_ids = {team.id for team in expanded_coached_teams} | {team.id for team in assisted_teams_qs}
form.fields['team'].queryset = Team.objects.filter(id__in=managed_teams_ids)
return form
class CoachCheckMixin(UserPassesTestMixin):
def test_func(self):
user = self.request.user
if user.is_superuser:
return True
team = self.get_object().team
return user == team.head_coach or user in team.assistant_coaches.all()
class EventCreateView(LoginRequiredMixin, ManageableTeamsMixin, CreateView):
model = Event
form_class = EventForm
template_name = 'calendars/event_form.html'
success_url = reverse_lazy('dashboard')
class TrainingCreateView(LoginRequiredMixin, ManageableTeamsMixin, CreateView):
model = Training
form_class = TrainingForm
template_name = 'calendars/event_form.html'
success_url = reverse_lazy('dashboard')
class GameCreateView(LoginRequiredMixin, ManageableTeamsMixin, CreateView):
model = Game
form_class = GameForm
template_name = 'calendars/event_form.html'
success_url = reverse_lazy('dashboard')
class EventUpdateView(LoginRequiredMixin, CoachCheckMixin, UpdateView):
model = Event
template_name = 'calendars/event_form.html'
success_url = reverse_lazy('dashboard')
def get_form_class(self):
if hasattr(self.object, 'game'):
return GameForm
if hasattr(self.object, 'training'):
return TrainingForm
return EventForm
class EventDeleteView(LoginRequiredMixin, CoachCheckMixin, DeleteView):
model = Event
template_name = 'calendars/event_confirm_delete.html'
success_url = reverse_lazy('dashboard')
@login_required
def manage_participation(request, child_id, event_id, status):
child = get_object_or_404(CustomUser, id=child_id)
event = get_object_or_404(Event, id=event_id)
# Check if the logged-in user is a parent of the child
if request.user not in child.parents.all():
# Handle unauthorized access
return redirect('dashboard')
# Check for parallel events if accepting a support game
if status == 'attending' and hasattr(event, 'game') and child.team in event.game.opened_for_teams.all():
# A game's duration is defined as innings * 20 minutes + 1 hour travel.
# I will assume 9 innings for now.
game_duration = datetime.timedelta(minutes=(9 * 20 + 60))
event_start = event.start_time
event_end = event.start_time + game_duration
parallel_events = Event.objects.filter(
eventparticipation__user=child,
eventparticipation__status='attending'
).exclude(id=event.id)
for pe in parallel_events:
pe_duration = datetime.timedelta(minutes=(9 * 20 + 60)) # Assuming 9 innings for all games
pe_start = pe.start_time
pe_end = pe.start_time + pe_duration
# Check for overlap with a tolerance of +/- 2 hours
if (event_start < pe_end + datetime.timedelta(hours=2) and event_end > pe_start - datetime.timedelta(hours=2)):
# Handle parallel event conflict
return redirect('dashboard') # Or show an error message
participation, created = EventParticipation.objects.get_or_create(user=child, event=event)
participation.status = status
participation.save()
return redirect('dashboard')
@login_required
def open_game(request, game_id):
game = get_object_or_404(Game, id=game_id)
club = game.team.club
# Permission check: only head coach of the team's club can open the game
if not request.user.is_superuser and request.user not in club.administrators.all():
return redirect('dashboard')
if request.method == 'POST':
form = OpenGameForm(request.POST, club=club)
if form.is_valid():
teams = form.cleaned_data['teams']
game.opened_for_teams.add(*teams)
return redirect('dashboard')
else:
form = OpenGameForm(club=club)
return render(request, 'calendars/open_game.html', {'form': form, 'game': game})
@login_required
def record_results(request, game_id):
game = get_object_or_404(Game, id=game_id)
game_result, created = GameResult.objects.get_or_create(game=game)
if request.method == 'POST':
form = GameResultForm(request.POST, game=game, instance=game_result)
if form.is_valid():
inning_results = {}
for i in range(1, game.number_of_innings + 1):
inning_results[f'inning_{i}'] = {
'home': form.cleaned_data.get(f'inning_{i}_home'),
'guest': form.cleaned_data.get(f'inning_{i}_guest'),
}
game_result.inning_results = inning_results
game_result.save()
return redirect('dashboard')
else:
initial_data = {}
if game_result.inning_results:
for inning, scores in game_result.inning_results.items():
initial_data[f'{inning}_home'] = scores.get('home')
initial_data[f'{inning}_guest'] = scores.get('guest')
form = GameResultForm(game=game, instance=game_result, initial=initial_data)
form_fields_by_inning = []
for i in range(1, game.number_of_innings + 1):
form_fields_by_inning.append({
'inning': i,
'home': form[f'inning_{i}_home'],
'guest': form[f'inning_{i}_guest'],
})
return render(request, 'calendars/record_results.html', {'form': form, 'game': game, 'form_fields_by_inning': form_fields_by_inning})