diff --git a/game/forms.py b/game/forms.py index f305315..24d2b38 100644 --- a/game/forms.py +++ b/game/forms.py @@ -13,3 +13,16 @@ class GroupAddMembersForm(forms.ModelForm): class Meta: model = models.Group fields = ["members"] + + +class MusikGameForm(forms.ModelForm): + class Meta: + model = models.MusikGame + fields = ["players", "n"] + + def __init__(self, *args, **kwargs): + group = models.Group.objects.get(pk=kwargs.pop("group", None)) + super().__init__(*args, **kwargs) + self.fields["players"].queryset = ( + group.members.all() | models.User.objects.filter(id=group.owner.id) + ) diff --git a/game/migrations/0005_musicvideo_date_added_musikgame.py b/game/migrations/0005_musicvideo_date_added_musikgame.py new file mode 100644 index 0000000..d6bf7b6 --- /dev/null +++ b/game/migrations/0005_musicvideo_date_added_musikgame.py @@ -0,0 +1,47 @@ +# Generated by Django 5.2.3 on 2025-06-13 17:23 + +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("game", "0004_musicvideo_title"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name="musicvideo", + name="date_added", + field=models.DateTimeField( + auto_now_add=True, default=django.utils.timezone.now + ), + preserve_default=False, + ), + migrations.CreateModel( + name="MusikGame", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("date", models.DateTimeField(auto_now_add=True)), + ( + "group", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="game.group" + ), + ), + ("music_videos", models.ManyToManyField(to="game.musicvideo")), + ("players", models.ManyToManyField(to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/game/migrations/0006_musikgame_n_alter_musikgame_players.py b/game/migrations/0006_musikgame_n_alter_musikgame_players.py new file mode 100644 index 0000000..b40d843 --- /dev/null +++ b/game/migrations/0006_musikgame_n_alter_musikgame_players.py @@ -0,0 +1,28 @@ +# Generated by Django 5.2.3 on 2025-06-13 18:41 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("game", "0005_musicvideo_date_added_musikgame"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name="musikgame", + name="n", + field=models.PositiveIntegerField( + default=2, verbose_name="Nombre de musiques" + ), + ), + migrations.AlterField( + model_name="musikgame", + name="players", + field=models.ManyToManyField( + to=settings.AUTH_USER_MODEL, verbose_name="Joueurs" + ), + ), + ] diff --git a/game/migrations/0007_remove_musikgame_music_videos_musicgameorder.py b/game/migrations/0007_remove_musikgame_music_videos_musicgameorder.py new file mode 100644 index 0000000..6c88755 --- /dev/null +++ b/game/migrations/0007_remove_musikgame_music_videos_musicgameorder.py @@ -0,0 +1,61 @@ +# Generated by Django 5.2.3 on 2025-06-13 18:57 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("game", "0006_musikgame_n_alter_musikgame_players"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.RemoveField( + model_name="musikgame", + name="music_videos", + ), + migrations.CreateModel( + name="MusicGameOrder", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("order", models.PositiveIntegerField()), + ( + "game", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="game.musikgame" + ), + ), + ( + "music_video", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="game.musicvideo", + ), + ), + ( + "player", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "ordering": ["order"], + "unique_together": { + ("game", "order"), + ("game", "player", "music_video"), + }, + }, + ), + ] diff --git a/game/models.py b/game/models.py index 1bb21d4..5b3c947 100644 --- a/game/models.py +++ b/game/models.py @@ -20,9 +20,31 @@ class Group(models.Model): class MusicVideo(models.Model): yt_id = models.CharField(max_length=16) title = models.CharField(blank=True) + date_added = models.DateTimeField(auto_now_add=True) owner = models.ForeignKey(User, on_delete=models.CASCADE) group = models.ForeignKey(Group, on_delete=models.CASCADE) blacklisted = models.BooleanField(default=False) class Meta: unique_together = ["yt_id", "owner", "group"] + + +class MusikGame(models.Model): + group = models.ForeignKey(Group, on_delete=models.CASCADE) + date = models.DateTimeField(auto_now_add=True) + n = models.PositiveIntegerField(default=2, verbose_name="Nombre de musiques") + players = models.ManyToManyField(User, verbose_name="Joueurs") + + def get_absolute_url(self): + return reverse("game_detail", kwargs={"pk": self.pk}) + + +class MusicGameOrder(models.Model): + game = models.ForeignKey(MusikGame, on_delete=models.CASCADE) + player = models.ForeignKey(User, on_delete=models.CASCADE) + music_video = models.ForeignKey(MusicVideo, on_delete=models.CASCADE) + order = models.PositiveIntegerField() + + class Meta: + unique_together = [["game", "player", "music_video"], ["game", "order"]] + ordering = ["order"] diff --git a/game/templates/game/group_detail.html b/game/templates/game/group_detail.html index 9245ca6..1365394 100644 --- a/game/templates/game/group_detail.html +++ b/game/templates/game/group_detail.html @@ -8,8 +8,25 @@

Modifier le groupe

+

+ Lancer une partie +

{% endif %} -

Membres

+ {% if group.musikgame_set %} +

+ Parties +

+ + {% endif %} +

+ Membres +

{% if group.owner == user %}

Modifier les membres @@ -21,7 +38,9 @@ {% for member in members.all %}

  • {{ member }} ({{ member.count }})
  • {% endfor %} -

    Mes musiques ({{ musics.count }})

    +

    + Mes musiques ({{ musics.count }}) +

    diff --git a/game/templates/game/musikgame_detail.html b/game/templates/game/musikgame_detail.html new file mode 100644 index 0000000..8a2d195 --- /dev/null +++ b/game/templates/game/musikgame_detail.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} +{% block content %} +

    + {{ musikgame.date }} +

    +

    + Joueurs +

    + +

    + Musiques +

    +
      + {% for music in musikgame.musicgameorder_set.all %} +
    1. + {{ music.music_video.title }} +
    2. + {% endfor %} +
    +{% endblock content %} diff --git a/game/templates/game/musikgame_form.html b/game/templates/game/musikgame_form.html new file mode 100644 index 0000000..3e6d4ed --- /dev/null +++ b/game/templates/game/musikgame_form.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} +{% load form %} +{% block content %} +

    + {{ group.name }} +

    + {% form form %} + {% endblock content %} diff --git a/game/urls.py b/game/urls.py index 383c6c3..6ad87f0 100644 --- a/game/urls.py +++ b/game/urls.py @@ -26,4 +26,8 @@ urlpatterns = [ views.GroupRemoveMusicView.as_view(), name="group_remove_music", ), + path( + "group//start_game/", views.GameCreateView.as_view(), name="start_game" + ), + path("group/game//", views.GameDetailView.as_view(), name="game_detail"), ] diff --git a/game/views.py b/game/views.py index 1574493..f55e95b 100644 --- a/game/views.py +++ b/game/views.py @@ -1,3 +1,5 @@ +import random + from django.contrib.auth.mixins import LoginRequiredMixin from django.db.models import Count, Q from django.http import JsonResponse @@ -88,3 +90,50 @@ class GroupRemoveMusicView(OwnerFilterMixin, SingleObjectMixin, View): group = music.group music.delete() return redirect(group) + + +class GameCreateView(LoginRequiredMixin, CreateView): + model = models.MusikGame + form_class = forms.MusikGameForm + + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + kwargs["group"] = self.kwargs["pk"] + return kwargs + + def get_context_data(self, **kwargs): + data = super().get_context_data(**kwargs) + data["group"] = models.Group.objects.filter(owner=self.request.user).get( + pk=self.kwargs["pk"] + ) + return data + + def form_valid(self, form): + group = models.Group.objects.get(pk=self.kwargs["pk"]) + form.instance.group = group + res = super().form_valid(form) + players = [] + musics = [] + for player in form.instance.players.all(): + players += 2 * [player] + musics += random.sample( + list( + player.musicvideo_set.filter(group=group, blacklisted=False).all() + ), + form.instance.n, + ) + + pm_list = list(zip(players, musics)) + random.shuffle(pm_list) + for (player, music), order in zip(pm_list, range(len(pm_list))): + models.MusicGameOrder.objects.create( + game=form.instance, player=player, music_video=music, order=order + ) + return res + + +class GameDetailView(LoginRequiredMixin, DetailView): + model = models.MusikGame + + def get_queryset(self): + return super().get_queryset().filter(group__owner=self.request.user)