Add null checks and handle empty lists in broadcast templates

apikeys
Razmig Sarkissian 2 months ago
parent 1e5bd9a072
commit 34530f94c5
  1. 2
      tournaments/templates/tournaments/broadcast/broadcast_base.html
  2. 28
      tournaments/templates/tournaments/broadcast/broadcasted_auto.html
  3. 2
      tournaments/templates/tournaments/broadcast/broadcasted_bracket.html
  4. 2
      tournaments/templates/tournaments/broadcast/broadcasted_group_stages.html
  5. 2
      tournaments/templates/tournaments/broadcast/broadcasted_matches.html
  6. 2
      tournaments/templates/tournaments/broadcast/broadcasted_planning.html
  7. 2
      tournaments/templates/tournaments/broadcast/broadcasted_prog.html
  8. 121
      tournaments/views.py

@ -6,7 +6,7 @@
<head>
{% include 'tournaments/broadcast/base_head.html' %}
<script src="{% static 'tournaments/js/alpine.min.js' %}"></script>
<script src="{% static 'tournaments/js/alpine.min.js' %}" defer></script>
<title>{% block head_title %}Page Title{% endblock %}</title>

@ -6,7 +6,7 @@
<head>
{% include 'tournaments/broadcast/base_head.html' %}
<script src="{% static 'tournaments/js/alpine.min.js' %}"></script>
<script src="{% static 'tournaments/js/alpine.min.js' %}" defer></script>
<title>Broadcast</title>
@ -127,14 +127,18 @@
}, 15000)
},
pageCount() {
return this.paginatedMatches.length + this.paginatedGroupStages.length + this.paginatedSummons.length + this.paginatedRankings.length
return (this.paginatedMatches?.length || 0) + (this.paginatedGroupStages?.length || 0) + (this.paginatedSummons?.length || 0) + (this.paginatedRankings?.length || 0)
},
setPrefixTitle() {
if (this.active < 1 + this.paginatedSummons.length) {
const summonsLength = this.paginatedSummons?.length || 0;
const matchesLength = this.paginatedMatches?.length || 0;
const groupStagesLength = this.paginatedGroupStages?.length || 0;
if (this.active < 1 + summonsLength) {
this.prefixTitle = 'Convocations'
} else if (this.active < 1 + this.paginatedSummons.length + this.paginatedMatches.length) {
} else if (this.active < 1 + summonsLength + matchesLength) {
this.prefixTitle = 'Matchs'
} else if (this.active < 1 + this.paginatedSummons.length + this.paginatedMatches.length + this.paginatedGroupStages.length) {
} else if (this.active < 1 + summonsLength + matchesLength + groupStagesLength) {
this.prefixTitle = 'Poules'
} else {
this.prefixTitle = 'Classement'
@ -162,7 +166,7 @@
<main>
<div class="grid-x">
<template x-for="i in paginatedSummons.length">
<template x-for="i in (paginatedSummons?.length || 0)">
<template x-for="column in paginatedSummons[i-1]">
<div class="cell medium-6 large-6 topblock padding10" x-show="active === i">
{% include 'tournaments/broadcast/broadcasted_summon.html' %}
@ -170,25 +174,25 @@
</template>
</template>
<template x-for="i in paginatedMatches.length" >
<template x-for="i in (paginatedMatches?.length || 0)" >
<template x-for="match in paginatedMatches[i-1]" >
<div class="cell medium-6 large-3 padding10" x-show="active === i + paginatedSummons.length">
<div class="cell medium-6 large-3 padding10" x-show="active === i + (paginatedSummons?.length || 0)">
{% include 'tournaments/broadcast/broadcasted_match.html' %}
</div>
</template>
</template>
<template x-for="i in paginatedGroupStages.length">
<template x-for="i in (paginatedGroupStages?.length || 0)">
<template x-for="group_stage in paginatedGroupStages[i-1]">
<div class="cell medium-6 large-3 padding10" x-show="active === i + paginatedSummons.length + paginatedMatches.length">
<div class="cell medium-6 large-3 padding10" x-show="active === i + (paginatedSummons?.length || 0) + (paginatedMatches?.length || 0)">
{% include 'tournaments/broadcast/broadcasted_group_stage.html' %}
</div>
</template>
</template>
<template x-for="i in paginatedRankings.length">
<template x-for="i in (paginatedRankings?.length || 0)">
<template x-for="column in paginatedRankings[i-1]">
<div class="cell medium-6 large-6 topblock padding10" x-show="active === i + paginatedSummons.length + paginatedMatches.length + paginatedGroupStages.length">
<div class="cell medium-6 large-6 topblock padding10" x-show="active === i + (paginatedSummons?.length || 0) + (paginatedMatches?.length || 0) + (paginatedGroupStages?.length || 0)">
{% include 'tournaments/broadcast/broadcasted_ranking.html' %}
</div>
</template>

@ -15,7 +15,7 @@
<title>Tableau</title>
<script src="{% static 'tournaments/js/alpine.min.js' %}"></script>
<script src="{% static 'tournaments/js/alpine.min.js' %}" defer></script>
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];

@ -14,7 +14,7 @@
<title>Poules</title>
<script src="{% static 'tournaments/js/alpine.min.js' %}"></script>
<script src="{% static 'tournaments/js/alpine.min.js' %}" defer></script>
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];

@ -13,7 +13,7 @@
<title>Matchs</title>
<script src="{% static 'tournaments/js/alpine.min.js' %}"></script>
<scriptt src="{% static 'tournaments/js/alpine.min.js' %}" defer></scriptt>
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];

@ -126,7 +126,7 @@
<title>Programmation</title>
<script src="{% static 'tournaments/js/alpine.min.js' %}"></script>
<script src="{% static 'tournaments/js/alpine.min.js' %}" defer></script>
<script>
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */

@ -13,7 +13,7 @@
<title>Matchs</title>
<script src="{% static 'tournaments/js/alpine.min.js' %}"></script>
<script src="{% static 'tournaments/js/alpine.min.js' %}" defer></script>
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];

@ -533,7 +533,25 @@ def automatic_broadcast(request, tournament_id):
def automatic_broadcast_event(request, event_id):
event = get_object_or_404(Event, pk=event_id)
tournaments = Tournament.objects.filter(event=event)
tournament_ids = [str(tournament.id) for tournament in tournaments]
# Filter tournaments that have broadcast content
tournaments_with_content = []
for tournament in tournaments:
try:
content = tournament.broadcast_content()
has_content = (
len(content.get('matches', [])) > 0 or
len(content.get('group_stages', [])) > 0 or
len(content.get('summons', [])) > 0 or
len(content.get('rankings', [])) > 0
)
if has_content:
tournaments_with_content.append(tournament)
except:
# Skip tournaments that error when getting content
continue
tournament_ids = [str(tournament.id) for tournament in tournaments_with_content]
# Create QR code URL for the event broadcast
qr_code_url_val = reverse('automatic-broadcast-event', args=[event_id])
@ -767,30 +785,115 @@ def club_broadcast(request, broadcast_code):
def club_broadcast_auto(request, broadcast_code):
club = get_object_or_404(Club, broadcast_code=broadcast_code)
q_not_deleted = Q(is_deleted=False, event__club=club)
q_not_deleted = Q(is_deleted=False, event__club=club, is_private=False)
now = timezone.now().replace(hour=0, minute=0, second=0, microsecond=0)
# Primary selection: Active tournaments (current logic)
recent_time_window = now - timedelta(hours=4)
tournaments = Tournament.objects.filter(
active_tournaments = Tournament.objects.filter(
q_not_deleted,
Q(is_private=False), # Exclude private tournaments
(
(
Q(end_date__isnull=True) & # Include ongoing tournaments
(Q(start_date__gte=now - timedelta(days=3)) & Q(start_date__lt=now + timedelta(days=3))) # Include tournaments that are ongoing and start within 3 days
(Q(start_date__gte=now - timedelta(days=3)) & Q(start_date__lt=now + timedelta(days=3)))
) |
(Q(end_date__isnull=False) & Q(end_date__gte=recent_time_window)) # Include tournaments finished within the last 4 hours
(Q(end_date__isnull=False) & Q(end_date__gte=recent_time_window)) # Finished within 4 hours
)
)
).select_related('event').distinct()
# Smart fallback: If we have few active tournaments, add recent/upcoming ones
tournaments_set = set()
tournaments_list = []
# Add active tournaments first
for tournament in active_tournaments:
if tournament.id not in tournaments_set:
tournaments_set.add(tournament.id)
tournaments_list.append(tournament)
# If we have less than 3 tournaments, add recent finished tournaments
if len(tournaments_list) < 3:
recent_finished = Tournament.objects.filter(
q_not_deleted,
Q(end_date__isnull=False),
Q(end_date__gte=now - timedelta(days=7)) # Finished within last 7 days
).select_related('event').order_by('-end_date')[:3]
for tournament in recent_finished:
if tournament.id not in tournaments_set and len(tournaments_list) < 5:
tournaments_set.add(tournament.id)
tournaments_list.append(tournament)
# If we still have less than 3 tournaments, add upcoming tournaments
if len(tournaments_list) < 3:
upcoming = Tournament.objects.filter(
q_not_deleted,
Q(start_date__gt=now + timedelta(days=3)), # Starting more than 3 days from now
Q(start_date__lte=now + timedelta(days=30)) # But within next 30 days
).select_related('event').order_by('start_date')[:3]
for tournament in upcoming:
if tournament.id not in tournaments_set and len(tournaments_list) < 5:
tournaments_set.add(tournament.id)
tournaments_list.append(tournament)
# Filter tournaments that have broadcast content (or at least some basic info to show)
tournaments_with_content = []
for tournament in tournaments_list:
try:
content = tournament.broadcast_content()
has_content = (
len(content.get('matches', [])) > 0 or
len(content.get('group_stages', [])) > 0 or
len(content.get('summons', [])) > 0 or
len(content.get('rankings', [])) > 0
)
# For upcoming tournaments, show them even without content (they'll show basic info)
is_upcoming = tournament.start_date > now + timedelta(days=3)
is_recent_finished = tournament.end_date and tournament.end_date >= now - timedelta(days=7)
tournament_ids = [str(tournament.id) for tournament in tournaments]
if has_content or is_upcoming or is_recent_finished:
tournaments_with_content.append(tournament)
except:
# For tournaments that error, still include if they're upcoming/recent
is_upcoming = tournament.start_date > now + timedelta(days=3)
is_recent_finished = tournament.end_date and tournament.end_date >= now - timedelta(days=7)
if is_upcoming or is_recent_finished:
tournaments_with_content.append(tournament)
# Sort tournaments: Active first, then by start date
def tournament_priority(t):
now_time = timezone.now()
if t.end_date is None and t.start_date <= now_time + timedelta(days=3):
return (0, t.start_date) # Active tournaments first
elif t.end_date and t.end_date >= now_time - timedelta(hours=4):
return (1, -t.end_date.timestamp()) # Recently finished, newest first
elif t.start_date > now_time:
return (2, t.start_date) # Upcoming tournaments by start date
else:
return (3, -t.end_date.timestamp() if t.end_date else 0) # Other finished tournaments
tournaments_with_content.sort(key=tournament_priority)
tournament_ids = [str(tournament.id) for tournament in tournaments_with_content]
print(f"Club '{club.name}' auto broadcast:")
print(f"Found {len(active_tournaments)} active, total {len(tournaments_with_content)} tournaments to display")
for i, tournament in enumerate(tournaments_with_content):
status = "ACTIVE" if (tournament.end_date is None and tournament.start_date <= timezone.now() + timedelta(days=3)) else \
"RECENT" if (tournament.end_date and tournament.end_date >= timezone.now() - timedelta(days=7)) else \
"UPCOMING" if tournament.start_date > timezone.now() else "FINISHED"
# Fix: Convert UUID to string before slicing
tournament_id_short = str(tournament.id)[:8]
print(f" {i+1}. {tournament_id_short} ({tournament.event.display_name()}) - {tournament.name or 'Unnamed'} [{status}]")
return render(request, 'tournaments/broadcast/broadcasted_club_auto.html', {
'tournament_ids': tournament_ids,
'club_name': club.name,
})
def download(request):
return render(request, 'tournaments/download.html')

Loading…
Cancel
Save