merge de con?

This commit is contained in:
Xamora 2024-04-16 19:22:37 +02:00
commit 8087f305fc
20 changed files with 211 additions and 256 deletions

View File

@ -2,7 +2,7 @@ from rest_framework import serializers
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from profiles.models.ProfileModel import ProfileModel from profiles.models import ProfileModel
from .models import ChatChannelModel, ChatMessageModel from .models import ChatChannelModel, ChatMessageModel

View File

@ -9,13 +9,13 @@ class Tourmanent
* @param {Number} name * @param {Number} name
* @param {Number} nb_players * @param {Number} nb_players
* @param {Number} nb_players_by_game * @param {Number} nb_players_by_game
* @param {Number} level * @param {Number} round
* @param {Boolean} started * @param {Boolean} started
* @param {Boolean} finished * @param {Boolean} finished
* @param {[]} levels * @param {[]} rounds
* @param {String} state * @param {String} state
*/ */
constructor(client, id, name = undefined, nb_players = undefined, nb_players_by_game = undefined, level = undefined, started = undefined, finished = undefined, levels = undefined, state = undefined) constructor(client, id, name = undefined, nb_players = undefined, round = undefined, started = undefined, finished = undefined, rounds = undefined, state = undefined)
{ {
/** /**
* @type {Client} * @type {Client}
@ -35,12 +35,7 @@ class Tourmanent
/** /**
* @type {Number} * @type {Number}
*/ */
this.nb_players_by_game = nb_players_by_game; this.round = round;
/**
* @type {Number}
*/
this.level = level;
/** /**
* @type {Number} * @type {Number}
@ -55,7 +50,7 @@ class Tourmanent
/** /**
* @type {[]} * @type {[]}
*/ */
this.levels = levels; this.rounds = rounds;
/** /**
* @type {String} must be "finished", or "started", or "waiting". Any other return all elements * @type {String} must be "finished", or "started", or "waiting". Any other return all elements
@ -86,13 +81,12 @@ class Tourmanent
let response_data = await response.json(); let response_data = await response.json();
this.name = response_data.name || `${response_data.nb_players_by_game}x1, ${response_data.nb_players} players`; this.name = response_data.name || `${response_data.nb_players} players tournament`;
this.nb_players = response_data.nb_players; this.nb_players = response_data.nb_players;
this.nb_players_by_game = response_data.nb_players_by_game; this.round = response_data.round;
this.level = response_data.level;
this.started = response_data.started; this.started = response_data.started;
this.finished = response_data.finished; this.finished = response_data.finished;
this.levels = response_data.levels; this.rounds = response_data.rounds;
this.state = response_data.state; this.state = response_data.state;
} }
@ -112,11 +106,11 @@ class Tourmanent
this._socket.send(JSON.stringify({participate: ""})); this._socket.send(JSON.stringify({participate: ""}));
} }
async onParticipantsUpdate(data) async onPlayersUpdate(data)
{ {
oldParticipantList = this.par oldPlayerList = this.par
await this.participantsUpdateHandler(); await this.playersUpdateHandler();
} }
async onError(data) async onError(data)
@ -134,18 +128,18 @@ class Tourmanent
if (data?.detail === "error") if (data?.detail === "error")
this.onError(data); this.onError(data);
else if (data?.detail === "participants_update") else if (data?.detail === "players_update")
this.onParticipantsUpdate(data); this.onPlayersUpdate(data);
} }
/** /**
* Join the tournament Websocket * Join the tournament Websocket
* @param {CallableFunction} errorHandler * @param {CallableFunction} errorHandler
* @param {CallableFunction} participantsUpdateHandler * @param {CallableFunction} playersUpdateHandler
* @param {CallableFunction} disconnectHandler * @param {CallableFunction} disconnectHandler
* @returns {?} * @returns {?}
*/ */
async join(participantsUpdateHandler, errorHandler, disconnectHandler) async join(playersUpdateHandler, errorHandler, disconnectHandler)
{ {
if (!await this.client.isAuthenticated()) if (!await this.client.isAuthenticated())
return null; return null;
@ -157,7 +151,7 @@ class Tourmanent
this.connected = true; this.connected = true;
this.isParticipating = false; this.isParticipating = false;
this.participantsUpdateHandler = participantsUpdateHandler; this.playersUpdateHandler = playersUpdateHandler;
this.errorHandler = errorHandler; this.errorHandler = errorHandler;
this.disconnectHandler = disconnectHandler; this.disconnectHandler = disconnectHandler;

View File

@ -30,13 +30,12 @@ class Tourmanents
/** /**
* *
* @param {Number} nb_players * @param {Number} nb_players
* @param {Number} nb_players_by_game
* @param {String} name * @param {String} name
* @returns {Response} * @returns {Response}
*/ */
async createTournament(nb_players, nb_players_by_game, name = "") async createTournament(nb_players, name = "")
{ {
let response = await this.client._post("/api/tournaments/", {nb_players: nb_players, nb_players_by_game: nb_players_by_game, name: name}); let response = await this.client._post("/api/tournaments/", {nb_players: nb_players, name: name});
return response; return response;
} }
@ -56,17 +55,16 @@ class Tourmanents
return null; return null;
} }
let tournaments = []; let tournaments = [];``
response_data.forEach(tournament_data => { response_data.forEach(tournament_data => {
tournaments.push(new Tourmanent(this.client, tournaments.push(new Tourmanent(this.client,
tournament_data.name, tournament_data.name,
tournament_data.nb_players, tournament_data.nb_players,
tournament_data.nb_players_by_game, tournament_data.round,
tournament_data.level,
tournament_data.started, tournament_data.started,
tournament_data.finished, tournament_data.finished,
tournament_data.levels, tournament_data.rounds,
tournament_data.id, tournament_data.id,
tournament_data.state)); tournament_data.state));
}); });

View File

@ -14,9 +14,8 @@ export default class extends AbstractAuthenticatedView
{ {
let name = document.getElementById("name-input").value; let name = document.getElementById("name-input").value;
let nb_players = document.getElementById("nb-players-input").value; let nb_players = document.getElementById("nb-players-input").value;
let nb_players_by_game = document.getElementById("nb-players-by-game-input").value;
let response = await client.tournaments.createTournament(nb_players, nb_players_by_game, name); let response = await client.tournaments.createTournament(nb_players, name);
let response_data = await response.json(); let response_data = await response.json();
let id = response_data.id; let id = response_data.id;
@ -26,7 +25,7 @@ export default class extends AbstractAuthenticatedView
return; return;
} }
clearIds("innerHTML", ["name", "nb_players", "nb_players_by_game"]); clearIds("innerHTML", ["name", "nb_players"]);
fill_errors(response_data, "innerHTML"); fill_errors(response_data, "innerHTML");
} }
@ -46,11 +45,6 @@ export default class extends AbstractAuthenticatedView
<label for='name-input' id='name-label'>${lang.get("TournamentCreateTournamentName")}</label> <label for='name-input' id='name-label'>${lang.get("TournamentCreateTournamentName")}</label>
<span class='text-danger' id='name'></span> <span class='text-danger' id='name'></span>
</div> </div>
<div class='form-floating mb-2'>
<input type='number' class='form-control' min='2' max='4' value='2' id='nb-players-by-game-input' placeholder='${lang.get("TournamentCreateNbPlayerByGame")}'>
<label for='nb-players-by-game-input' id='nb-players-by-game-label'>${lang.get("TournamentCreateNbPlayerByGame")}</label>
<span class='text-danger' id='nb_players_by_game'></span>
</div>
<div class='form-floating mb-2'> <div class='form-floating mb-2'>
<input type='number' class='form-control' min='2' value='4' id='nb-players-input' placeholder='${lang.get("TournamentCreateNbPlayer")}'> <input type='number' class='form-control' min='2' value='4' id='nb-players-input' placeholder='${lang.get("TournamentCreateNbPlayer")}'>
<label for='nb-players-input' id='nb-players-label'>${lang.get("TournamentCreateNbPlayer")}</label> <label for='nb-players-input' id='nb-players-label'>${lang.get("TournamentCreateNbPlayer")}</label>

View File

@ -1,8 +1,9 @@
from __future__ import annotations from __future__ import annotations
from django.db import models from django.db import models
from django.db.models import QuerySet, CASCADE
from django.db.models import QuerySet from profiles.models import ProfileModel
import time import time
@ -12,16 +13,15 @@ class GameModel(models.Model):
finished = models.BooleanField(default = False) finished = models.BooleanField(default = False)
started = models.BooleanField(default = False) started = models.BooleanField(default = False)
winner_id = models.IntegerField(default = -1) winner = models.ForeignKey(ProfileModel, on_delete=CASCADE, null=True, blank=True)
start_timestamp = models.BigIntegerField(null = True, blank = True) start_timestamp = models.BigIntegerField(null = True, blank = True)
stop_timestamp = models.BigIntegerField(null = True, blank = True) stop_timestamp = models.BigIntegerField(null = True, blank = True)
game_type = models.CharField(max_length = 60, default = "pong") game_type = models.CharField(max_length = 60, default = "pong")
def create(self, game_type: str, players_id: list[int]): def create(self, players: list[ProfileModel]):
self.game_type = game_type
self.save() self.save()
for player_id in players_id: for player in players:
GameMembersModel(game_id = self.pk, player_id = player_id).save() GameMembersModel(game = self.pk, player=player).save()
return self.pk return self.pk
def start(self): def start(self):
@ -35,8 +35,8 @@ class GameModel(models.Model):
self.stop_timestamp = round(time.time() * 1000, 1) self.stop_timestamp = round(time.time() * 1000, 1)
self.save() self.save()
def get_players_id(self): def get_players(self) -> list[ProfileModel]:
return [game_player.player_id for game_player in GameMembersModel.objects.filter(game_id = self.pk)] return [game_player.player for game_player in GameMembersModel.objects.filter(game = self)]
def get_score_by_player_id(self, player_id: int) -> list[int]: def get_score_by_player_id(self, player_id: int) -> list[int]:
query: QuerySet = GameGoalModel.objects.filter(game_id = self.pk, player_id = player_id) query: QuerySet = GameGoalModel.objects.filter(game_id = self.pk, player_id = player_id)
@ -55,11 +55,11 @@ class GameModel(models.Model):
return timestamp return timestamp
class GameMembersModel(models.Model): class GameMembersModel(models.Model):
game_id = models.IntegerField() game = models.ForeignKey(GameModel, on_delete=CASCADE)
player_id = models.IntegerField() player = models.ForeignKey(ProfileModel, on_delete=CASCADE)
class GameGoalModel(models.Model): class GameGoalModel(models.Model):
game_id = models.IntegerField() game = models.ForeignKey(GameModel, on_delete=CASCADE)
player_id = models.IntegerField() player = models.ForeignKey(ProfileModel, on_delete=CASCADE)
timestamp = models.IntegerField() timestamp = models.IntegerField()

View File

@ -1,12 +1,9 @@
from django.contrib import admin from django.contrib import admin
from .models.BlockModel import BlockModel from .models import ProfileModel, FriendModel, FriendRequestModel, BlockModel
from .models.FriendModel import FriendModel
# from .models.FriendRequestModel import FriendRequestModel
from .models.ProfileModel import ProfileModel
# Register your models here. # Register your models here.
admin.site.register(ProfileModel) admin.site.register(ProfileModel)
admin.site.register(BlockModel) admin.site.register(BlockModel)
admin.site.register(FriendModel) admin.site.register(FriendModel)
# admin.site.register(AskFriendModel) admin.site.register(FriendRequestModel)

View File

@ -6,19 +6,16 @@ from django.db.models import Q, Model, CASCADE, ForeignKey, ImageField
from django.db.models.signals import post_save, pre_delete from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver from django.dispatch import receiver
from games.consumers import game_manager
from . import FriendModel
def upload_to(instance, filename: str): def upload_to(instance, filename: str):
return f"./profiles/static/avatars/{instance.pk}{splitext(filename)[1]}" return f"./profiles/static/avatars/{instance.pk}{splitext(filename)[1]}"
class ProfileModel(Model): class ProfileModel(Model):
user = ForeignKey(User, on_delete=CASCADE) user = ForeignKey(User, on_delete=CASCADE)
avatar = ImageField(upload_to=upload_to, default="./profiles/static/avatars/default.avif") avatar = ImageField(upload_to=upload_to, default="./profiles/static/avatars/default.avif")
def get_game(self) -> int: def get_game(self) -> int:
from games.consumers import game_manager
for game in game_manager._game_list: for game in game_manager._game_list:
for player in game.get_players_connected(): for player in game.get_players_connected():
if (player.user_id == self.user.pk): if (player.user_id == self.user.pk):
@ -28,21 +25,38 @@ class ProfileModel(Model):
def get_friends(self) -> list[ProfileModel]: def get_friends(self) -> list[ProfileModel]:
friends: list[ProfileModel] = [] friends: list[ProfileModel] = []
for friendship in FriendModel.FriendModel.objects.filter(Q(friend1=self) | Q(friend2=self)): for friendship in FriendModel.objects.filter(Q(friend1=self) | Q(friend2=self)):
friends.append(friendship.friend1 if friendship.friend1 != self else friendship.friend2) friends.append(friendship.friend1 if friendship.friend1 != self else friendship.friend2)
return friends return friends
def is_friend(self, friend): def is_friend(self, friend):
return friend in self.get_friends() return FriendModel.objects.filter(
(Q(friend1=self) & Q(friend2=friend)) |
(Q(friend2=self) & Q(friend1=friend))
).exists()
def delete_friend(self, friend): def delete_friend(self, friend):
print(friend) FriendModel.objects.get(
FriendModel.FriendModel.objects.get(
(Q(friend1=self) & Q(friend2=friend)) | (Q(friend1=self) & Q(friend2=friend)) |
(Q(friend2=self) & Q(friend1=friend)) (Q(friend2=self) & Q(friend1=friend))
).delete() ).delete()
def is_friend_requested_by(self, profile):
return self.get_received_friend_request_from(profile) is None
def get_received_friend_request_from(self, profile):
return FriendRequestModel.objects.filter(author=profile, target=self).first()
def is_friend_requesting(self, profile):
return FriendRequestModel.objects.filter(author=self, target=profile).exists()
def get_sent_friend_requests(self) -> list[ProfileModel]:
return FriendRequestModel.objects.filter(author=self)
def get_received_friend_requests(self) -> list[ProfileModel]:
return FriendRequestModel.objects.filter(target=self)
@receiver(pre_delete, sender=ProfileModel) @receiver(pre_delete, sender=ProfileModel)
def delete_profile_picture(sender, instance, **kwargs): def delete_profile_picture(sender, instance, **kwargs):
@ -55,3 +69,22 @@ def on_user_created(sender, instance, created, **kwargs):
if created: if created:
profile: ProfileModel = ProfileModel.objects.create(pk=instance.pk, user=instance) profile: ProfileModel = ProfileModel.objects.create(pk=instance.pk, user=instance)
profile.save() profile.save()
class FriendModel(Model):
friend1 = ForeignKey(ProfileModel, on_delete=CASCADE, related_name='friend1')
friend2 = ForeignKey(ProfileModel, on_delete=CASCADE, related_name='friend2')
class FriendRequestModel(Model):
author = ForeignKey(ProfileModel, on_delete=CASCADE, related_name='author')
target = ForeignKey(ProfileModel, on_delete=CASCADE, related_name='target')
def accept(self):
FriendModel(friend1=self.author, friend2=self.target).save()
self.delete()
class BlockModel(Model):
blocker = ForeignKey(ProfileModel, on_delete=CASCADE, related_name='blocker')
blocked = ForeignKey(ProfileModel, on_delete=CASCADE, related_name='blocked')

View File

@ -1,7 +0,0 @@
from django.db import models
from django.contrib.auth.models import User
class BlockModel(models.Model):
blocker = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blocker')
blocked = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blocked')

View File

@ -1,8 +0,0 @@
from django.db import models
from . import ProfileModel
class FriendModel(models.Model):
friend1 = models.ForeignKey(ProfileModel.ProfileModel, on_delete=models.CASCADE, related_name='friend1')
friend2 = models.ForeignKey(ProfileModel.ProfileModel, on_delete=models.CASCADE, related_name='friend2')

View File

@ -3,7 +3,7 @@ from django.utils.translation import gettext as _
from rest_framework import serializers from rest_framework import serializers
from ..models.ProfileModel import ProfileModel from ..models import ProfileModel
class ProfileSerializer(serializers.ModelSerializer): class ProfileSerializer(serializers.ModelSerializer):

View File

@ -7,8 +7,7 @@ from rest_framework.request import Request
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from ..models.BlockModel import BlockModel from ..models import BlockModel, ProfileModel
from ..models.ProfileModel import ProfileModel
from ..serializers.ProfileSerializer import ProfileSerializer from ..serializers.ProfileSerializer import ProfileSerializer
@ -17,14 +16,10 @@ class GetBlocksView(APIView):
authentication_classes = (SessionAuthentication,) authentication_classes = (SessionAuthentication,)
def get(self, request: Request): def get(self, request: Request):
profiles = [] blocks = BlockModel.objects.filter(blocker=ProfileModel.objects.filter(user=request.user).first())
blocks = BlockModel.objects.filter(blocker=request.user) bloked_profiles = [block.blocked for block in blocks]
for block in blocks:
profile = ProfileModel.objects.filter(user=block.blocked)
if (profile.exists()):
profiles.append(profile[0])
return Response(ProfileSerializer(profiles, many=True).data) return Response(ProfileSerializer(bloked_profiles, many=True).data)
class EditBlocksView(APIView): class EditBlocksView(APIView):

View File

@ -7,8 +7,7 @@ from django.utils.translation import gettext as _
from django.db.models import Q from django.db.models import Q
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from ..models.FriendModel import FriendModel from ..models import ProfileModel, FriendModel
from ..models.ProfileModel import ProfileModel
from ..serializers.ProfileSerializer import ProfileSerializer from ..serializers.ProfileSerializer import ProfileSerializer

View File

@ -4,7 +4,7 @@ from rest_framework.response import Response
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
from ..serializers.ProfileSerializer import ProfileSerializer from ..serializers.ProfileSerializer import ProfileSerializer
from ..models.ProfileModel import ProfileModel from ..models import ProfileModel
class MyProfileViewSet(viewsets.ModelViewSet): class MyProfileViewSet(viewsets.ModelViewSet):

View File

@ -6,7 +6,7 @@ from rest_framework import viewsets
from rest_framework.response import Response from rest_framework.response import Response
from ..serializers.ProfileSerializer import ProfileSerializer from ..serializers.ProfileSerializer import ProfileSerializer
from ..models.ProfileModel import ProfileModel from ..models import ProfileModel
class ProfileViewSet(viewsets.ModelViewSet): class ProfileViewSet(viewsets.ModelViewSet):

View File

@ -6,27 +6,20 @@ from games.models import GameModel
import json import json
from .models import tournament_manager, TournamentMember, TournamentRoom, TournamentRoomManager from .models import tournament_manager, TournamentPlayer, TournamentSpectator, TournamentRoom, TournamentRoomManager
class TournamentWebConsumer(WebsocketConsumer): class TournamentWebConsumer(WebsocketConsumer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.channel_name = "tournament"
self.group_name = "tournament"
def connect(self): def connect(self):
self.user: User = self.scope["user"] self.user: User = self.scope["user"]
if (self.user.is_anonymous or not self.user.is_authenticated): if (self.user.is_anonymous or not self.user.is_authenticated):
return return
self.channel_layer.group_add(self.group_name, self.channel_name)
self.tournament_id = int(self.scope['url_route']['kwargs']['tournament_id']) self.tournament_id = int(self.scope['url_route']['kwargs']['tournament_id'])
self.room = tournament_manager.get(self.tournament_id) self.room = tournament_manager.get(self.tournament_id)
self.member = TournamentMember(self.user.pk, self, self.room) self.member: TournamentPlayer | TournamentSpectator = self.room(self.user.pk, self, self.room)
if (self.room is None): if (self.room is None):
self.member.send("Tournament not found") self.member.send("Tournament not found")

View File

@ -1,155 +1,127 @@
from __future__ import annotations
from django.db import models from django.db import models
from channels.generic.websocket import WebsocketConsumer
from games.models import GameModel
import json
from transcendence.abstract.AbstractRoomMember import AbstractRoomMember from transcendence.abstract.AbstractRoomMember import AbstractRoomMember
from transcendence.abstract.AbstractRoom import AbstractRoom from transcendence.abstract.AbstractRoom import AbstractRoom
from transcendence.abstract.AbstractRoomManager import AbstractRoomManager from transcendence.abstract.AbstractRoomManager import AbstractRoomManager
from profiles.models import ProfileModel
from games.models import GameModel
from django.contrib.auth.models import User
from django.db.models import CASCADE
from channels.generic.websocket import WebsocketConsumer
# Create your models here.tu # Create your models here.tu
class TournamentModel(models.Model): class TournamentModel(models.Model):
name = models.CharField(max_length = 100) name = models.CharField(max_length = 100)
nb_players = models.IntegerField() nb_players = models.IntegerField()
nb_players_by_game = models.IntegerField() rounds = models.IntegerField()
level = models.IntegerField()
started = models.BooleanField(default = False) started = models.BooleanField(default = False)
finished = models.BooleanField(default = False) finished = models.BooleanField(default = False)
gamemode = models.CharField(max_length = 50, default = "pong") winner = models.ForeignKey(ProfileModel, on_delete=CASCADE)
def create_game(self, level, players_id): def _add_player(self, player: ProfileModel) -> None:
game_id = GameModel().create(self.gamemode, players_id = players_id) TournamentPlayerModel(player=player, tournament=self).save()
TournamentGamesModel(game_id = game_id, tournament_id = self.pk, tournament_level = level).save()
return game_id
def get_games_id_by_level(self, level): def start(self, players: list[ProfileModel]) -> None:
tmp = TournamentGamesModel.objects.filter(tournament_id = self.pk, tournament_level = level)
return [instance.game_id for instance in tmp]
def get_games_id(self): self.started = False
return [tournament_game.game_id for tournament_game in TournamentGamesModel.objects.filter(tournament_id = self.pk)]
def get_participants_id(self): for player in players:
return [model.participant_id for model in TournamentParticipantsModel.objects.filter(tournament_id=self.pk)] self._add_player(player)
def is_a_participant(self, participant_id: int): for (player1, player2) in zip(players[0::2], players[1::2]):
return TournamentParticipantsModel.objects.filter(participant_id = participant_id, tournament_id = self.pk).exists() self.create_game([player1, player2], round=1)
def add_participants(self, participants_id: [int]):
for participant_id in participants_id:
TournamentParticipantsModel(tournament_id = self.pk, participant_id = participant_id).save()
def start(self, participants_id: [int]):
self.started = True
self.add_participants(participants_id)
games_id = [int]
for i in range(0, len(participants_id), self.nb_players_by_game):
game_id = self.create_game(0, participants_id[i : i + self.nb_players_by_game])
games_id.append(game_id)
self.save() self.save()
return games_id
class TournamentParticipantsModel(models.Model): def create_game(self, players: list[ProfileModel], round: int) -> GameModel:
tournament_id = models.IntegerField()
participant_id = models.IntegerField()
class TournamentGamesModel(models.Model): if (self.started == False):
return None
tournament_id = models.IntegerField() if (len(players) != 2):
tournament_level = models.IntegerField() return None
game_id = models.IntegerField()
class TournamentMember(AbstractRoomMember): from games.models import GameModel
def __init__(self, user_id: int, socket: WebsocketConsumer, room): game: GameModel = GameModel().create(players=players)
super().__init__(user_id, socket)
self.participate = False
self.room = room
def receive(self, text_data: str = None, byte_dates: bytes = None): TournamentGameModel(tournament=self, game=game, round=round).save()
if (text_data is None): return game
return
data: dict = json.loads(text_data) def start(self, players: list[ProfileModel]) -> int:
if (data.get("participate") is not None): if (len(players) != self.nb_players):
self.room.update_participants(self) return 1
def send_error_message(self, message: str): for player in players:
self.send("error", {"error_message": message}) TournamentPlayerModel(tournament=self, player=player).save()
def go_to(self, url: str): return 0
self.send("go_to", {"url": url})
def send_participating(self): def get_games(self) -> list[GameModel]:
self.send("is_participant", {"is_participant": self.participate}) return [tournament_game.game for tournament_game in TournamentGameModel.objects.filter(tournament=self)]
def get_games_by_round(self, round: int) -> list[GameModel]:
return [tournament_game.game for tournament_game in TournamentGameModel.objects.filter(tournament=self, round=round)]
def get_players_by_round(self, round: int) -> list[ProfileModel]:
return [game.get_players() for game in self.get_games_by_round(round)]
def get_winners_by_round(self, round: int) -> list[ProfileModel]:
return [game.winner for game in self.get_games_by_round(round)]
def get_players(self) -> list[TournamentPlayerModel]:
return TournamentPlayerModel.objects.filter(tournament=self.pk)
def get_state(self) -> str:
return ("waiting to start", "in progress", "finish")[self.started + self.finished]
def is_player(self, profile: ProfileModel) -> bool:
return TournamentPlayerModel.objects.filter(player=profile, tournament=self).exists()
class TournamentPlayerModel(models.Model):
player = models.ForeignKey(ProfileModel, on_delete=CASCADE)
tournament = models.ForeignKey(TournamentModel, on_delete=CASCADE)
class TournamentGameModel(models.Model):
tournament = models.ForeignKey(TournamentModel, on_delete=CASCADE, null=True, blank=True)
round = models.IntegerField()
game = models.ForeignKey(GameModel, on_delete=CASCADE)
class TournamentSpectator(AbstractRoomMember):
pass
class TournamentPlayer(TournamentSpectator):
pass
class TournamentRoom(AbstractRoom): class TournamentRoom(AbstractRoom):
def __init__(self, room_manager, tournament_id: int): def __init__(self, room_manager: TournamentRoomManager, tournament_id: int):
super().__init__(room_manager) super().__init__(room_manager)
self.tournament_id = tournament_id self.room_manager: TournamentRoomManager
self.tournament = TournamentModel.objects.get(pk = tournament_id) self.id: int = id
self.model: TournamentModel = TournamentModel.objects.get(pk=tournament_id)
def start(self):
self.broadcast("tournament_start")
games_id = self.tournament.start(self.get_participants_id())
for i, participant in enumerate(self.get_participants()):
participant: TournamentMember
participant.go_to(f"games/{games_id[i // self.tournament.nb_players_by_game]}")
def update_participants(self, member: TournamentMember): def join(self, profile: ProfileModel, socket: WebsocketConsumer) -> TournamentPlayer | TournamentSpectator:
if (self.tournament.started): if (self.model.started):
member.send_error_message("Tournament already started") if (self.model.is_player(profile)):
return return TournamentPlayer(profile.pk, socket)
member.participate = not member.participate else:
nb_participants = self.get_nb_participants() return TournamentSpectator(profile.pk, socket)
self.broadcast("update_participants", {"nb_participants": nb_participants}) else:
member.send_participating() return TournamentSpectator(profile.pk, socket)
if (nb_participants == self.tournament.nb_players):
self.start()
def get_nb_participants(self):
if (self.tournament.started):
return self.tournament.nb_players
nb_participants = 0
for member in self._member_list:
member: TournamentMember
if (member.participate):
nb_participants += 1
return nb_participants
def get_participants(self):
return [member for member in self._member_list if member.participate]
def get_participants_id(self):
return [member.user_id for member in self._member_list if member.participate]
def append(self, member: TournamentMember):
super().append(member)
if self.tournament.started:
member.participate = self.tournament.is_a_participant(member.user_id)
member.send_participating()
self.broadcast("update_participants", {"participants": [self.get_participants_id()]})
class TournamentRoomManager(AbstractRoomManager): class TournamentRoomManager(AbstractRoomManager):
pass
def get(self, tournament_id: int):
for room in self._room_list:
if (room.tournament_id == tournament_id):
return room
if (TournamentModel.objects.filter(pk = tournament_id).exists()):
room = TournamentRoom(self, tournament_id)
self.append(room)
return room
return None
tournament_manager: TournamentRoomManager = TournamentRoomManager() tournament_manager: TournamentRoomManager = TournamentRoomManager()

View File

@ -7,35 +7,35 @@ from django.contrib.auth.models import User
from .models import TournamentModel, tournament_manager from .models import TournamentModel, tournament_manager
from profiles.models import ProfileModel from profiles.models import ProfileModel
from profiles.serializers import ProfileSerializer from profiles.serializers.ProfileSerializer import ProfileSerializer
from games.serializers import GameSerializer from games.serializers import GameSerializer
class TournamentSerializer(serializers.ModelSerializer): class TournamentSerializer(serializers.ModelSerializer):
levels = serializers.SerializerMethodField(read_only=True, required=False) rounds = serializers.SerializerMethodField(read_only=True, required=False)
state = serializers.SerializerMethodField(read_only=True, required=False) state = serializers.SerializerMethodField(read_only=True, required=False)
participants = serializers.SerializerMethodField(read_only=True, required=False) players = serializers.SerializerMethodField(read_only=True, required=False)
level = serializers.ReadOnlyField() round = serializers.ReadOnlyField()
started = serializers.ReadOnlyField() started = serializers.ReadOnlyField()
finished = serializers.ReadOnlyField() finished = serializers.ReadOnlyField()
name = serializers.CharField(default="") name = serializers.CharField(default="")
class Meta: class Meta:
model = TournamentModel model = TournamentModel
fields = ["name", "nb_players", "nb_players_by_game", "level", "started", "finished", "levels", "id", "state", "participants"] fields = ["name", "nb_players", "nb_players_by_game", "round", "started", "finished", "rounds", "id", "state", "players"]
def get_participants(self, instance: TournamentModel): def get_players(self, instance: TournamentModel):
participants_id: list[ProfileModel] players_id: list[ProfileModel]
if (instance.started): if (instance.started):
participants_id = instance.get_participants_id() players_id = instance.get_players_id()
else: else:
participants_id = tournament_manager.get(instance.pk).get_participants_id() players_id = tournament_manager.get(instance.pk).get_players_id()
participants_profile: list[ProfileModel] = [] players_profile: list[ProfileModel] = []
for participant_id in participants_id: for player_id in players_id:
query: QuerySet = ProfileModel.objects.filter(user_id = participant_id) query: QuerySet = ProfileModel.objects.filter(user_id = player_id)
profile_data: dict profile_data: dict
if query.exists(): if query.exists():
profile_data = ProfileSerializer(query[0]).data profile_data = ProfileSerializer(query[0]).data
@ -43,23 +43,24 @@ class TournamentSerializer(serializers.ModelSerializer):
profile_data = { profile_data = {
"username": "deleted_user", "username": "deleted_user",
"avatar": "/static/avatars/default.avif", "avatar": "/static/avatars/default.avif",
"user_id": participants_id "user_id": players_id
} }
participants_profile.append(profile_data) players_profile.append(profile_data)
return players_profile
return participants_profile
def get_state(self, instance: TournamentModel): def get_state(self, instance: TournamentModel):
return ["waiting", "started", "finished"][instance.started + instance.finished] return ["waiting", "started", "finished"][instance.started + instance.finished]
def get_levels(self, instance: TournamentModel): def get_rounds(self, instance: TournamentModel):
levels: list[list[int]] = [] rounds: list[list[int]] = []
for i in range(instance.level): for i in range(instance.round):
games_id: [int] = instance.get_games_id_by_level(i) games_id: list[int] = instance.get_games_id_by_round(i)
if (games_id == []): if (games_id == []):
break break
levels.append(games_id) rounds.append(games_id)
return levels return rounds
def validate_nb_players(self, value: int): def validate_nb_players(self, value: int):
if (value < 2): if (value < 2):

View File

@ -21,14 +21,8 @@ class TournamentViewSet(viewsets.ModelViewSet):
def perform_create(self, serializer: TournamentSerializer): def perform_create(self, serializer: TournamentSerializer):
nb_players = serializer.validated_data["nb_players"] nb_players = serializer.validated_data["nb_players"]
nb_players_by_game = serializer.validated_data["nb_players_by_game"] name = serializer.validated_data["name"]
level = 1 tournament = serializer.save(name=name, nb_players=nb_players, round=1)
number: int = nb_players
while (number != nb_players_by_game):
number = number // 2 + (number % 2)
level += 1
tournament = serializer.save(level = level)
return Response(self.serializer_class(tournament).data, status=status.HTTP_201_CREATED) return Response(self.serializer_class(tournament).data, status=status.HTTP_201_CREATED)

View File

@ -3,7 +3,7 @@ from .AbstractRoom import AbstractRoom
class AbstractRoomManager: class AbstractRoomManager:
def __init__(self): def __init__(self):
self._room_list: [AbstractRoom] = [] self._room_list: list[AbstractRoom] = []
def remove(self, room: AbstractRoom): def remove(self, room: AbstractRoom):
self._room_list.remove(room) self._room_list.remove(room)