Matthias Nagel 001444e0dd Feat: Implementierung des Abstimmungs-Features (Polls)
Fügt ein neues Abstimmungs-Feature hinzu, das es Head Coaches ermöglicht,
Umfragen innerhalb ihres Teams zu erstellen und zu verwalten.
Teammitglieder können Umfragen ansehen und daran teilnehmen.

Wesentliche Änderungen:
- **Neue 'polls'-App:** Enthält Modelle, Formulare, Views und Templates.
- **Modelle  und :** Definieren die Struktur für Umfragen
  (Frage, Team, Ersteller, Mehrfachauswahl-Option) und die Auswahlmöglichkeiten
  (Text, Stimmen).
- **Formulare  und :** Für die Erstellung von Umfragen
  und deren Auswahlmöglichkeiten.
- **Views:**
    - : Zeigt alle für den Benutzer relevanten Umfragen an.
    - : Ermöglicht Head Coaches das Erstellen neuer Umfragen
      (inkl. Fehlerbehebung bei der Formularinitialisierung).
    - : Zeigt Details einer Umfrage an und ermöglicht die
      Stimmabgabe.
    - : Zeigt die Ergebnisse einer Umfrage an.
    - : Funktion für die Stimmabgabe.
- **Templates:** Spezifische Templates für alle Umfrage-Views.
- **URL-Konfiguration:** Neue URLs für die 'polls'-App und Einbindung in die
  Haupt-URL-Konfiguration.
- **Navigationslink:** Ein neuer Link 'Polls' in der Hauptnavigation für
  authentifizierte Benutzer.
- **Migrationen:** Datenbankmigrationen für die neuen - und -Modelle.
2025-11-21 22:55:07 +01:00

127 lines
4.6 KiB
Python

from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import ListView, CreateView, DetailView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.urls import reverse_lazy, reverse
from django.db import transaction
from .models import Poll, Choice
from .forms import PollForm, ChoiceFormSet
from clubs.models import Team
from accounts.models import CustomUser
class PollListView(LoginRequiredMixin, ListView):
model = Poll
template_name = 'polls/poll_list.html'
context_object_name = 'polls'
def get_queryset(self):
user = self.request.user
user_teams = set()
if user.team:
user_teams.add(user.team)
# Add teams where the user is a coach or assistant
user_teams.update(user.coached_teams.all())
user_teams.update(user.assisted_teams.all())
# Add teams of children for parents
if hasattr(user, 'children'):
for child in user.children.all():
if child.team:
user_teams.add(child.team)
return Poll.objects.filter(team__in=user_teams).order_by('-created_at')
class PollCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
model = Poll
form_class = PollForm
template_name = 'polls/poll_form.html'
def test_func(self):
# Only head coaches can create polls
return self.request.user.coached_teams.exists()
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
if self.request.POST:
data['choice_formset'] = ChoiceFormSet(self.request.POST)
else:
data['choice_formset'] = ChoiceFormSet()
# Filter the team queryset for the form to only show teams the user coaches
data['form'].fields['team'].queryset = self.request.user.coached_teams.all()
return data
def form_valid(self, form):
context = self.get_context_data()
choice_formset = context['choice_formset']
# Set the creator before saving the poll
form.instance.creator = self.request.user
if choice_formset.is_valid():
self.object = form.save()
with transaction.atomic():
for choice_form in choice_formset:
if choice_form.cleaned_data.get('choice_text'):
Choice.objects.create(
poll=self.object,
choice_text=choice_form.cleaned_data['choice_text']
)
return redirect(self.get_success_url())
else:
return self.form_invalid(form)
def get_success_url(self):
return reverse('polls:poll_list')
class PollDetailView(LoginRequiredMixin, UserPassesTestMixin, DetailView):
model = Poll
template_name = 'polls/poll_detail.html'
def test_func(self):
# Check if user is part of the team for which the poll is
poll = self.get_object()
user = self.request.user
user_teams = set()
if user.team:
user_teams.add(user.team)
user_teams.update(user.coached_teams.all())
user_teams.update(user.assisted_teams.all())
if hasattr(user, 'children'):
for child in user.children.all():
if child.team:
user_teams.add(child.team)
return poll.team in user_teams
def vote(request, poll_id):
poll = get_object_or_404(Poll, pk=poll_id)
user = request.user
if request.method == 'POST':
if poll.multiple_choice:
selected_choice_ids = request.POST.getlist('choice')
# First, remove user's previous votes for this poll
poll.choices.filter(votes=user).update(votes=None)
# Then, add new votes
for choice_id in selected_choice_ids:
choice = get_object_or_404(Choice, pk=choice_id)
choice.votes.add(user)
else:
selected_choice_id = request.POST.get('choice')
if selected_choice_id:
# Remove user's vote from all choices in this poll first
for choice in poll.choices.all():
choice.votes.remove(user)
# Add the new vote
choice = get_object_or_404(Choice, pk=selected_choice_id)
choice.votes.add(user)
return redirect('polls:poll_results', pk=poll.id)
class PollResultsView(LoginRequiredMixin, DetailView):
model = Poll
template_name = 'polls/poll_results.html'
context_object_name = 'poll'