Add game end functionality with view and URL routing, update models and templates for game state management

This commit is contained in:
Edgar P. Burkhart 2025-06-15 13:02:31 +02:00
parent d03d3b48d4
commit f9ed70d386
Signed by: edpibu
GPG key ID: 9833D3C5A25BD227
9 changed files with 181 additions and 89 deletions

View file

@ -117,6 +117,9 @@ h6,
i.i {
margin-right: .5em;
}
i.hl {
color: var(--pico-primary);
}
footer {
text-align: center;

View file

@ -0,0 +1,21 @@
# Generated by Django 5.2.3 on 2025-06-15 10:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("game", "0018_musicgameanswer"),
]
operations = [
migrations.AlterModelOptions(
name="musikgame",
options={"ordering": ["-over", "-date"]},
),
migrations.AddField(
model_name="musikgame",
name="over",
field=models.BooleanField(default=False),
),
]

View file

@ -0,0 +1,16 @@
# Generated by Django 5.2.3 on 2025-06-15 10:59
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("game", "0019_alter_musikgame_options_musikgame_over"),
]
operations = [
migrations.AlterModelOptions(
name="musikgame",
options={"ordering": ["over", "-date"]},
),
]

View file

@ -74,10 +74,14 @@ class MusikGame(models.Model):
players = models.ManyToManyField(User, verbose_name="Joueurs")
playlist = models.CharField(blank=True, verbose_name="Playlist YouTube")
playlist_loading = models.BooleanField(default=False)
over = models.BooleanField(default=False)
def get_absolute_url(self):
return reverse("game_detail", kwargs={"pk": self.pk})
class Meta:
ordering = ["over", "-date"]
@receiver(post_save, sender=MusikGame)
def generateYoutubePlaylist(sender, instance, created, **kwargs):

View file

@ -10,52 +10,7 @@
{{ group.name }}
</h1>
{% include "game/include/group_buttons.html" %}
{% if group.musikgame_set.exists %}
<h2>
<i class="ri-play-circle-fill"></i> Parties
</h2>
<form method="post">
{% csrf_token %}
<table>
<thead>
{% if group.owner == user %}<th></th>{% endif %}
<th>Date</th>
<th>
<i class="ri-youtube-fill"></i> Playlists
</th>
<th>Joueurs</th>
</thead>
<tbody>
{% for game in group.musikgame_set.all %}
<tr>
{% if group.owner == user %}
<td>
<input type="checkbox" name="game" value="{{ game.pk }}">
</td>
{% endif %}
<td>
<a href="{% url "game_detail" pk=game.pk %}">{{ game.date }}</a>
</td>
<td>
{% if game.playlist %}
<a href="{% yt_playlist game %}"
{% if game.playlist_loading %}aria-busy="true"{% endif %}><i class="ri-youtube-fill"></i> Playlist</a>
{% endif %}
</td>
<td>{{ game.players.all|join:", " }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if group.owner == user %}
<button type="submit"
class="secondary"
formaction="{% url "group_remove_game" pk=group.pk %}">
<i class="ri-delete-bin-fill"></i> Supprimer les parties sélectionnées
</button>
{% endif %}
</form>
{% endif %}
{% include "game/include/group_games.html" %}
{% include "game/include/group_members.html" %}
<h2>
<i class="ri-music-2-fill"></i> Mes musiques <span class="music-count">{{ musics.count }}</span>

View file

@ -0,0 +1,57 @@
{% load form youtube %}
{% if group.musikgame_set.exists %}
<h2>
<i class="ri-play-circle-fill"></i> Parties
</h2>
<form method="post">
{% csrf_token %}
<table>
<thead>
{% if group.owner == user %}<th></th>{% endif %}
<th>
<i class="ri-play-circle-fill"></i>
</th>
<th>Date</th>
<th>
<i class="ri-youtube-fill"></i> Playlists
</th>
<th>Joueurs</th>
</thead>
<tbody>
{% for game in group.musikgame_set.all %}
<tr>
{% if group.owner == user %}
<td>
<input type="checkbox" name="game" value="{{ game.pk }}">
</td>
{% endif %}
<td>
{% if game.over %}
<i class="ri-stop-circle-fill"></i>
{% else %}
<i class="ri-play-circle-fill hl"></i>
{% endif %}
</td>
<td>
<a href="{% url "game_detail" pk=game.pk %}">{{ game.date }}</a>
</td>
<td>
{% if game.playlist %}
<a href="{% yt_playlist game %}"
{% if game.playlist_loading %}aria-busy="true"{% endif %}><i class="ri-youtube-fill"></i> Playlist</a>
{% endif %}
</td>
<td>{{ game.players.all|join:", " }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if group.owner == user %}
<button type="submit"
class="secondary"
formaction="{% url "group_remove_game" pk=group.pk %}">
<i class="ri-delete-bin-fill"></i> Supprimer les parties sélectionnées
</button>
{% endif %}
</form>
{% endif %}

View file

@ -2,18 +2,33 @@
{% load youtube %}
{% block content %}
<h1>
<i class="ri-play-circle-fill"></i> {{ musikgame.date }}
{% if musikgame.over %}
<i class="ri-stop-circle-fill"></i>
{% else %}
<i class="ri-play-circle-fill hl"></i>
{% endif %}
{{ musikgame.date }}
</h1>
{% if musikgame.playlist or musikgame.playlist_loading %}
<p>
<a target="_blank"
href="{% yt_playlist musikgame %}"
role="button"
{% if musikgame.playlist_loading %}aria-busy="true"{% endif %}><i class="ri-youtube-fill"></i> Playlist</a>
<a target="_blank"
href="{% url "game_answer" musikgame.pk %}"
role="button"><i class="ri-play-list-2-fill"></i> Répondre</a>
</p>
<form method="post">
{% csrf_token %}
<fieldset role="group">
<a target="_blank"
href="{% yt_playlist musikgame %}"
role="button"
{% if musikgame.playlist_loading %}aria-busy="true"{% endif %}><i class="ri-youtube-fill"></i> Playlist</a>
{% if not musikgame.over %}
<a href="{% url "game_answer" musikgame.pk %}" role="button"><i class="ri-play-list-2-fill"></i> Répondre</a>
{% endif %}
</fieldset>
{% if is_leader and not musikgame.over %}
<fieldset>
<button type="submit" formaction="{% url "game_end" musikgame.pk %}">
<i class="ri-stop-circle-fill"></i> Finir la partie
</button>
</fieldset>
{% endif %}
</form>
{% endif %}
<h2>
<i class="ri-group-2-fill"></i> Joueurs
@ -34,38 +49,40 @@
{% endfor %}
</ol>
</details>
<h2>
<i class="ri-list-ordered"></i> Résultats
</h2>
<details>
<summary role="button">
<i class="ri-list-ordered-2"></i> Résultats
</summary>
<table class="striped">
<thead>
<tr>
<th>
<i class="ri-list-ordered-2"></i>
</th>
<th>
<i class="ri-music-2-fill"></i> Musique
</th>
<th>
<i class="ri-user-line"></i> Joueur
</th>
</tr>
</thead>
<tbody>
{% for music in musikgame.musicgameorder_set.all %}
{% if musikgame.over %}
<h2>
<i class="ri-list-ordered"></i> Résultats
</h2>
<details>
<summary role="button">
<i class="ri-list-ordered-2"></i> Résultats
</summary>
<table class="striped">
<thead>
<tr>
<td>{{ music.order }}</td>
<td>
<a href="https://youtu.be/{{ music.music_video.yt_id }}">{{ music.music_video.title }}</a>
</td>
<td>{{ music.player }}</td>
<th>
<i class="ri-list-ordered-2"></i>
</th>
<th>
<i class="ri-music-2-fill"></i> Musique
</th>
<th>
<i class="ri-user-line"></i> Joueur
</th>
</tr>
{% endfor %}
</tbody>
</table>
</details>
</thead>
<tbody>
{% for music in musikgame.musicgameorder_set.all %}
<tr>
<td>{{ music.order }}</td>
<td>
<a href="https://youtu.be/{{ music.music_video.yt_id }}">{{ music.music_video.title }}</a>
</td>
<td>{{ music.player }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</details>
{% endif %}
{% endblock content %}

View file

@ -68,4 +68,5 @@ urlpatterns = [
views.GameAnswerView.as_view(),
name="game_answer",
),
path("group/game/<int:pk>/end/", views.GameEndView.as_view(), name="game_end"),
]

View file

@ -344,6 +344,12 @@ class GameDetailView(LoginRequiredMixin, DetailView):
.distinct()
)
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
data["is_leader"] = data["musikgame"].group.is_leader(self.request.user)
data["is_owner"] = data["musikgame"].group.is_owner(self.request.user)
return data
class YoutubeCallbackView(LoginRequiredMixin, View):
def get(self, request):
@ -428,7 +434,7 @@ class GameAnswerView(LoginRequiredMixin, DetailView):
template_name = "game/musikgame_answer.html"
def get_queryset(self):
return super().get_queryset().filter(players=self.request.user)
return super().get_queryset().filter(over=False, players=self.request.user)
def get_context_data(self, **kwargs):
return super().get_context_data(**kwargs) | {
@ -452,3 +458,15 @@ class GameAnswerView(LoginRequiredMixin, DetailView):
defaults={"answer": None},
)
return redirect("game_answer", pk)
class GameEndView(LoginRequiredMixin, SingleObjectMixin, View):
model = models.MusikGame
def post(self, request, pk):
game = self.get_object()
if not game.group.is_leader(request.user):
raise PermissionDenied()
game.over = True
game.save()
return redirect("game_detail", pk)