djbrown/hbscorez

View on GitHub
src/teams/views.py

Summary

Maintainability
A
45 mins
Test Coverage
F
27%
from datetime import timedelta
from enum import Enum, auto
 
from django.db.models import Count, F, Q, Sum
from django.db.models.functions import Coalesce
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, render
from django.utils import timezone
from icalendar import Calendar, Event, vText
from returns.result import Result
 
from base.logic import add_ranking_place
from games.models import Game, TeamOutcome
from players.models import Player
from teams.models import Team
 
 
def detail(request, bhv_id):
team = get_object_or_404(Team, bhv_id=bhv_id)
return render(request, "teams/detail.j2", {"team": team})
 
 
def games(request, bhv_id):
team = get_object_or_404(Team, bhv_id=bhv_id)
team_games = Game.objects.filter(Q(home_team=team) | Q(guest_team=team)).order_by("opening_whistle")
return render(request, "teams/games.j2", {"team": team, "games": team_games})
 
 
def players(request, bhv_id):
team = get_object_or_404(Team, bhv_id=bhv_id)
team_players = Player.objects.filter(team=team).annotate(games=Count("score")).order_by("name")
return render(request, "teams/players.j2", {"team": team, "players": team_players})
 
 
def scorers(request, bhv_id):
team = get_object_or_404(Team, bhv_id=bhv_id)
team_players = (
Player.objects.filter(team=team)
.annotate(games=Count("score"))
.annotate(total_goals=Coalesce(Sum("score__goals"), 0))
.filter(total_goals__gt=0)
.annotate(total_penalty_goals=Sum("score__penalty_goals"))
.annotate(total_field_goals=F("total_goals") - F("total_penalty_goals"))
.order_by("-total_goals")
)
add_ranking_place(team_players, "total_goals")
return render(request, "teams/scorers.j2", {"team": team, "players": team_players})
 
 
def offenders(request, bhv_id):
team = get_object_or_404(Team, bhv_id=bhv_id)
team_offenders = (
Player.objects.filter(team=team)
.annotate(games=Count("score"))
.annotate(warnings=Count("score__warning_time"))
.annotate(
suspensions=Count("score__first_suspension_time")
+ Count("score__second_suspension_time")
+ Count("score__third_suspension_time")
)
.annotate(disqualifications=Count("score__disqualification_time"))
.annotate(offender_points=F("warnings") + 2 * F("suspensions") + 3 * F("disqualifications"))
.filter(offender_points__gt=0)
.order_by("-offender_points")
)
add_ranking_place(team_offenders, "offender_points")
return render(request, "teams/offenders.j2", {"team": team, "offenders": team_offenders})
 
 
def calendar(_, bhv_id):
team = get_object_or_404(Team, bhv_id=bhv_id)
team_games = Game.objects.filter(Q(home_team=team) | Q(guest_team=team))
 
cal = Calendar()
cal.add("PRODID", "-//HbScorez//Mannschaftskalender 1.0//DE")
cal.add("VERSION", "2.0")
cal.add("CALSCALE", "GREGORIAN")
cal.add("METHOD", "PUBLISH")
cal.add("X-WR-CALNAME", f"Spielplan {team.league.abbreviation} {team.short_name}")
cal.add("X-WR-TIMEZONE", "Europe/Berlin")
cal.add(
"X-WR-CALDESC",
f'Spielplan der Mannschaft "{team.name}"'
+ f" in der Saison {team.league.season.start_year}/{team.league.season.start_year + 1}"
+ f' in der Liga "{team.league.name}" des Bezirks "{team.league.district.name}"',
)
 
for game in team_games:
result = _create_event(team, game)
result.bind(cal.add_component)
 
return HttpResponse(cal.to_ical(), "text/calendar")
 
 
class ErrCode(Enum):
MISSING_OPENING_WHISTLE = auto()
 
 
Cyclomatic complexity is too high in function _create_event. (8)
Function `_create_event` has a Cognitive Complexity of 8 (exceeds 5 allowed). Consider refactoring.
def _create_event(team: Team, game: Game) -> Result[Event, ErrCode]:
if not game.opening_whistle:
return Result.from_failure(ErrCode.MISSING_OPENING_WHISTLE)
 
venue = "Heimspiel" if game.home_team == team else "Auswärtsspiel"
summary = f"{venue} - {game.opponent_of(team).short_name}"
 
leg_title = game.leg_title()
description = f"{leg_title} gegen {game.opponent_of(team).name}"
if game.sports_hall:
description += "\nSporthalle: " + str(game.sports_hall.name)
 
dated_games = game.other_games().filter(opening_whistle__isnull=False)
for other in sorted(dated_games, key=lambda g: g.opening_whistle):
if other.home_goals is not None:
description += f"\n{other.leg_title()}: {other.home_goals}:{other.guest_goals} ({_outcome(other, team)})"
 
start = game.opening_whistle
end = start + timedelta(minutes=90)
dtstamp = timezone.now()
location = game.sports_hall.address if game.sports_hall else None
uid = f"game/{game.number}@hbscorez.de"
 
event = Event()
event.add("summary", summary)
event.add("description", description)
event.add("dtstart", start)
event.add("dtend", end)
event.add("dtstamp", dtstamp)
if location:
event["location"] = vText(location)
event["uid"] = uid
 
return Result.from_value(event)
 
 
def _outcome(game, team):
mapping = {
TeamOutcome.WIN: "Sieg",
TeamOutcome.LOSS: "Niederlage",
TeamOutcome.TIE: "Unentschieden",
}
outcome = game.outcome_for(team)
return mapping.get(outcome)