tournament in coming

This commit is contained in:
starnakin 2024-04-18 20:08:13 +02:00
parent 630ef709ab
commit ae0a5abfcd
11 changed files with 265 additions and 287 deletions

View File

@ -1,61 +1,17 @@
import { AExchangeable } from "../AExchangable.js";
import { Client } from "../Client.js"; import { Client } from "../Client.js";
import { Profile } from "../Profile.js";
class Tourmanent class Tourmanent extends AExchangeable
{ {
/** /**
* *
* @param {Client} client * @param {Client} client
* @param {Number} id the id of the tournament * @param {Number} id the id of the tournament
* @param {Number} name
* @param {Number} nb_players
* @param {Number} nb_players_by_game
* @param {Number} round
* @param {Boolean} started
* @param {Boolean} finished
* @param {[]} rounds
* @param {String} state
*/ */
constructor(client, id, name = undefined, nb_players = undefined, round = undefined, started = undefined, finished = undefined, rounds = undefined, state = undefined) constructor(client, id)
{ {
/** super();
* @type {Client}
*/
this.client = client;
/**
* @type {String} the name of the tournament
*/
this.name = name || `${nb_players_by_game}x1, ${nb_players} players`;
/**
* @type {Number}
*/
this.nb_players = nb_players;
/**
* @type {Number}
*/
this.round = round;
/**
* @type {Number}
*/
this.started = started;
/**
* @type {Number}
*/
this.finished = finished;
/**
* @type {[]}
*/
this.rounds = rounds;
/**
* @type {String} must be "finished", or "started", or "waiting". Any other return all elements
*/
this.state = state;
/** /**
* @type {Number} * @type {Number}
@ -63,9 +19,35 @@ class Tourmanent
this.id = id; this.id = id;
/** /**
* @type {Boolean} if a websocket connection is enabled * @type {Client}
*/ */
this.connected = false; this.client = client;
/**
* @type {Number}
*/
this.nb_participants;
/**
* @type {[Profile]} proutman à encore frappé
*/
this.participantList = []
/**
* @type {Boolean}
*/
this.started;
/**
* @type {Number}
*/
this.finished;
/**
* @type {"finished" | "started" | "waiting"} must be "finished", or "started", or "waiting". Any other return all elements
*/
this.state;
} }
/** /**
@ -81,13 +63,7 @@ class Tourmanent
let response_data = await response.json(); let response_data = await response.json();
this.name = response_data.name || `${response_data.nb_players} players tournament`; this.import(response_data);
this.nb_players = response_data.nb_players;
this.round = response_data.round;
this.started = response_data.started;
this.finished = response_data.finished;
this.rounds = response_data.rounds;
this.state = response_data.state;
} }
leave(event) leave(event)
@ -99,18 +75,12 @@ class Tourmanent
this.disconnectHandler(event); this.disconnectHandler(event);
} }
toggle_participation() /**
* @param {Object} data
*/
async _receiveParticipantUpdate(data)
{ {
if (!this.connected) this.par
return;
this._socket.send(JSON.stringify({participate: ""}));
}
async onPlayersUpdate(data)
{
oldPlayerList = this.par
await this.playersUpdateHandler();
} }
async onError(data) async onError(data)
@ -126,20 +96,22 @@ class Tourmanent
{ {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
if (data?.detail === "error") if (data.detail === "error")
this.onError(data); this.onError(data);
else if (data?.detail === "players_update") else if (["del_participant", "add_participant"].includes(data.detail))
this.onPlayersUpdate(data); this._receiveParticipantUpdate(data);
} }
/** /**
* Join the tournament Websocket * Join the tournament Websocket
* @param {CallableFunction} errorHandler * @param {CallableFunction} errorHandler
* @param {CallableFunction} playersUpdateHandler * @param {CallableFunction} addParticipantHandler called when a participants join the tournament
* @param {CallableFunction} delParticipantHandler called when a participants leave the tournament
* @param {CallableFunction} disconnectHandler * @param {CallableFunction} disconnectHandler
* @param {CallableFunction} goToHandler called when the next game will start
* @returns {?} * @returns {?}
*/ */
async join(playersUpdateHandler, errorHandler, disconnectHandler) async join(participantsUpdateHandler, errorHandler, goToHandler, disconnectHandler)
{ {
if (!await this.client.isAuthenticated()) if (!await this.client.isAuthenticated())
return null; return null;
@ -151,9 +123,10 @@ class Tourmanent
this.connected = true; this.connected = true;
this.isParticipating = false; this.isParticipating = false;
this.playersUpdateHandler = playersUpdateHandler; this.participantsUpdateHandler = participantsUpdateHandler;
this.errorHandler = errorHandler; this.errorHandler = errorHandler;
this.disconnectHandler = disconnectHandler; this.disconnectHandler = disconnectHandler;
this.goToHandler = goToHandler;
this._socket.onmessage = this.onReceive.bind(this); this._socket.onmessage = this.onReceive.bind(this);

View File

@ -29,13 +29,13 @@ class Tourmanents
/** /**
* *
* @param {Number} nb_players * @param {Number} nb_participants
* @param {String} name * @param {String} name
* @returns {Response} * @returns {Response}
*/ */
async createTournament(nb_players, name = "") async createTournament(nb_participants, name = "")
{ {
let response = await this.client._post("/api/tournaments/", {nb_players: nb_players, name: name}); let response = await this.client._post("/api/tournaments/", {nb_participants: nb_participants, name: name});
return response; return response;
} }
@ -58,15 +58,9 @@ class Tourmanents
let tournaments = [];`` let tournaments = [];``
response_data.forEach(tournament_data => { response_data.forEach(tournament_data => {
tournaments.push(new Tourmanent(this.client, let tournament = new Tourmanent(this.client, tournament_data.id);
tournament_data.name, tournament.import(tournament_data);
tournament_data.nb_players, tournaments.push(tournament);
tournament_data.round,
tournament_data.started,
tournament_data.finished,
tournament_data.rounds,
tournament_data.id,
tournament_data.state));
}); });
return tournaments; return tournaments;

View File

@ -13,6 +13,10 @@ export default class extends AbstractAuthenticatedView
async create() async create()
{ {
let name = document.getElementById("name-input").value; let name = document.getElementById("name-input").value;
if (name.length == 0)
name = lang.get("TournamentCreateTournamentName");
console.log(name);
let nb_players = document.getElementById("nb-players-input").value; let nb_players = document.getElementById("nb-players-input").value;
let response = await client.tournaments.createTournament(nb_players, name); let response = await client.tournaments.createTournament(nb_players, name);

View File

@ -25,7 +25,7 @@ export default class extends AbstractAuthenticatedView
document.getElementById("app").appendChild(tournament_tree); document.getElementById("app").appendChild(tournament_tree);
for (let round_id = 0; round_id < this.tournament.levels.length; round_id++) for (let round_id = 0; round_id < this.tournament.round.length; round_id++)
{ {
let current_round = document.createElement("ul"); let current_round = document.createElement("ul");
@ -33,7 +33,7 @@ export default class extends AbstractAuthenticatedView
current_round.className = `round round-${round_id}`; current_round.className = `round round-${round_id}`;
for (let participant_i = 0; participant_i < this.tournament.levels[round_id].length; participant_i += 2) for (let participant_i = 0; participant_i < this.tournament.round[round_id].length; participant_i += 2)
{ {
let spacer = document.createElement("li"); let spacer = document.createElement("li");
@ -45,7 +45,7 @@ export default class extends AbstractAuthenticatedView
let game_top = document.createElement("li"); let game_top = document.createElement("li");
game_top.className = "game game-top"; game_top.className = "game game-top";
game_top.innerText = `${this.tournament.levels[round_id][participant_i]}`; game_top.innerText = `${this.tournament.round[round_id][participant_i]}`;
current_round.appendChild(game_top); current_round.appendChild(game_top);
@ -59,7 +59,7 @@ export default class extends AbstractAuthenticatedView
let game_bottom = document.createElement("li"); let game_bottom = document.createElement("li");
game_bottom.className = "game game-bottom"; game_bottom.className = "game game-bottom";
game_bottom.innerText = `${this.tournament.levels[round_id][participant_i + 1]}`; game_bottom.innerText = `${this.tournament.round[round_id][participant_i + 1]}`;
current_round.appendChild(game_bottom); current_round.appendChild(game_bottom);
} }
@ -70,7 +70,7 @@ export default class extends AbstractAuthenticatedView
async receive(data) async receive(data)
{ {
if (data.detail === "update_participants") if (data.detail === "update_participants")
document.getElementById("nb_participants").innerText = `${data.participants} / ${this.tournament.nb_players}`; document.getElementById("nb_participants").innerText = `${data.participants} / ${this.tournament.nb_participants}`;
if (data.detail === "go_to") if (data.detail === "go_to")
navigateTo(data.url); navigateTo(data.url);
if (data.detail === "is_participant") if (data.detail === "is_participant")
@ -121,9 +121,8 @@ export default class extends AbstractAuthenticatedView
button.onclick = this.pressButton.bind(this); button.onclick = this.pressButton.bind(this);
document.getElementById("name").innerText = this.tournament.name; document.getElementById("name").innerText = this.tournament.name;
document.getElementById("nb_participants").innerText = this.tournament.nb_players; document.getElementById("nb_participants").innerText = this.tournament.nb_participants;
document.getElementById("nb_players_by_game").innerText = this.tournament.nb_players_by_game; document.getElementById("round").innerText = this.tournament.round;
document.getElementById("level").innerText = this.tournament.level;
document.getElementById("state").innerText = this.tournament.state; document.getElementById("state").innerText = this.tournament.state;
if (this.tournament.started === false) if (this.tournament.started === false)
@ -142,20 +141,12 @@ export default class extends AbstractAuthenticatedView
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr>
<td>Number of players</td>
<td id="nb_players">Loading...</td>
</tr>
<tr>
<td>Number of players by game</td>
<td id="nb_players_by_game">Loading...</td>
</tr>
<tr> <tr>
<td>Number of round</td> <td>Number of round</td>
<td id="level">Loading...</td> <td id="round">Loading...</td>
</tr> </tr>
<tr> <tr>
<td>Number of player</td> <td>Number of participants</td>
<td id="nb_participants">Loading...</td> <td id="nb_participants">Loading...</td>
</tr> </tr>
<tr> <tr>

View File

@ -13,41 +13,14 @@ export default class extends AbstractAuthenticatedView
{ {
let state = document.getElementById("state-select").value; let state = document.getElementById("state-select").value;
this.tournaments = await client.tournaments.search(state); this.tournaments = await client.tournaments.search(state);
} //console.log(this.tournaments);
add_nb_player_by_game_selector()
{
let nb_players_by_game_list = new Set();
this.tournaments.forEach(tournament => {
nb_players_by_game_list.add(tournament.nb_players_by_game);
});
let select = document.getElementById("nb-players-by-game-select");
let new_children = [];
const opt = document.createElement("option");
opt.value = "all";
opt.text = "All";
new_children.push(opt);
nb_players_by_game_list.forEach(nb_players_by_game => {
const opt = document.createElement("option");
opt.value = nb_players_by_game;
opt.text = nb_players_by_game;
new_children.push(opt);
});
select.replaceChildren(...new_children);
} }
internal_search() internal_search()
{ {
let nb_players_by_game = document.getElementById("nb-players-by-game-select").value;
this.display_tournaments = []; this.display_tournaments = [];
this.tournaments.forEach(tournament => { this.tournaments.forEach(tournament => {
if (nb_players_by_game === "all" || nb_players_by_game == tournament.nb_players_by_game)
this.display_tournaments.push(tournament); this.display_tournaments.push(tournament);
}); });
} }
@ -58,6 +31,7 @@ export default class extends AbstractAuthenticatedView
const new_children = []; const new_children = [];
console.log(this.display_tournaments);
this.display_tournaments.forEach(tournament => { this.display_tournaments.forEach(tournament => {
let tr = document.createElement("tr"); let tr = document.createElement("tr");
@ -72,14 +46,9 @@ export default class extends AbstractAuthenticatedView
td.innerText = tournament.state; td.innerText = tournament.state;
tr.appendChild(td); tr.appendChild(td);
// nb_players // nb_participants
td = document.createElement("td"); td = document.createElement("td");
td.innerText = tournament.nb_players; td.innerText = tournament.nb_participants;
tr.appendChild(td);
// nb_players_by_game
td = document.createElement("td");
td.innerText = tournament.nb_players_by_game;
tr.appendChild(td); tr.appendChild(td);
new_children.push(tr); new_children.push(tr);
@ -96,7 +65,6 @@ export default class extends AbstractAuthenticatedView
async update_search() async update_search()
{ {
await this.external_search(); await this.external_search();
this.add_nb_player_by_game_selector();
this.update_query(); this.update_query();
} }
@ -104,7 +72,6 @@ export default class extends AbstractAuthenticatedView
{ {
await this.update_search(); await this.update_search();
document.getElementById("state-select").onchange = this.update_search.bind(this); document.getElementById("state-select").onchange = this.update_search.bind(this);
document.getElementById("nb-players-by-game-select").onchange = this.update_query.bind(this);
} }
async getHtml() async getHtml()
@ -116,14 +83,11 @@ export default class extends AbstractAuthenticatedView
<option value="finished">Finished</option> <option value="finished">Finished</option>
<option value="all">All</option> <option value="all">All</option>
</select> </select>
<select id="nb-players-by-game-select">
</select>
<table> <table>
<thead> <thead>
<td>Name</td> <td>Name</td>
<td>Status</td> <td>Status</td>
<td>Max numbers of players</td> <td>Max numbers of participants</td>
<td>Max numbers of players by game</td>
</thead> </thead>
<tbody id="tournaments-list"> <tbody id="tournaments-list">
</tbody> </tbody>

View File

@ -1,36 +1,168 @@
from __future__ import annotations
from channels.generic.websocket import WebsocketConsumer from channels.generic.websocket import WebsocketConsumer
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db.models import QuerySet
from django.utils.translation import gettext as _
from games.models import GameModel
from profiles.models import ProfileModel
from profiles.serializers.ProfileSerializer import ProfileSerializer
from .models import TournamentModel
import json import json
from .models import tournament_manager, TournamentPlayer, TournamentSpectator, TournamentRoom, TournamentRoomManager class TournamentMember:
def __init__(self, socket: TournamentWebConsumer, room: TournamentRoom, is_participating: bool = False) -> None:
self._socket: TournamentWebConsumer = socket
self._room: TournamentRoom = room
self.is_participating: bool = is_participating
def send(self, detail: str, data: dict = {}):
data_to_send: dict = {"detail": detail}
data_to_send.update(data)
self._socket.send(json.dumps(data_to_send))
def send_error(self, error_message: str, data: dict = {}):
data_to_send: dict = {"error_message": error_message}
data_to_send.update(data)
self.send("error", data_to_send)
def _receive_participating(self, data: dict) -> None:
is_participating: bool | None = data.get("is_participating")
if (is_participating is None):
self.send_error(_("Missing is_participating statement."))
return
self._room.set_participation()
def receive(self, data: dict):
if self.is_participating == False:
return
detail: str | None = data.get("detail")
if (detail is None):
return
match(detail):
case "update_particapating":
self._receive_participating()
case _:
print("bozo_send")
class TournamentRoomManager:
def __init__(self):
self._room_list: list[TournamentRoom] = []
def get(self, tournament: TournamentModel) -> TournamentRoom:
for room in self._room_list:
if room._model is tournament:
return room
room: TournamentRoom = TournamentRoom(self, tournament)
self._room_list.append(room)
return room
def remove(self, room: TournamentRoom) -> None:
self._room_list.remove(room)
class TournamentRoom:
def __init__(self, room_manager: TournamentRoomManager, tournament: TournamentModel):
self._room_manager: TournamentRoomManager = room_manager
self._member_list: list[TournamentMember] = []
self._model: TournamentModel = tournament
def join(self, socket: TournamentWebConsumer) -> TournamentMember:
member: TournamentMember = TournamentMember(socket, self)
self._member_list.append(member)
return member
def leave(self, member: TournamentMember) -> None:
# Delete room if nobody connected, no cringe memory leak
if (len(self._member_list) == 1):
self._room_manager.remove(self)
return
self._member_list.remove(member)
self.set_participation(member, False)
def broadcast(self, detail: str, data: dict, excludes: list[TournamentMember] = []) -> None:
member_list: list[TournamentMember] = [member for member in self._member_list if member not in excludes]
for member in member_list:
member.send(detail, data)
def get_participants(self) -> list[TournamentMember]:
return [member for member in self._member_list if member.is_participating]
def set_participation(self, member: TournamentMember, is_participating: bool) -> None:
if (self._model.started):
return
if (member.is_participating == is_participating):
return
if (is_participating == True):
self.broadcast("add_participant", {"profile", ProfileSerializer(member._socket.user.profilemodel).data})
else:
self.broadcast("del_participant", {"profile", ProfileSerializer(member._socket.user.profilemodel).data})
member.is_participating = is_participating
tournament_manager: TournamentRoomManager = TournamentRoomManager()
class TournamentWebConsumer(WebsocketConsumer): class TournamentWebConsumer(WebsocketConsumer):
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 (not self.user.is_authenticated):
return return
self.tournament_id = int(self.scope['url_route']['kwargs']['tournament_id']) tournament_id: int = int(self.scope['url_route']['kwargs']['tournament_id'])
self.room = tournament_manager.get(self.tournament_id) query: QuerySet = TournamentModel.objects.filter(pk=tournament_id)
self.member: TournamentPlayer | TournamentSpectator = self.room(self.user.pk, self, self.room)
if (self.room is None): if (not query.exists()):
self.member.send("Tournament not found") return
self.disconnect(1017)
self.room.append(self.member) tournament: TournamentModel = query[0]
self.room = tournament_manager.get(tournament)
self.member: TournamentMember = self.room.join(self)
self.accept()
def receive(self, text_data: str = None, bytes_data: bytes = None): def receive(self, text_data: str = None, bytes_data: bytes = None):
self.member.receive(text_data, bytes_data)
user: User = self.scope["user"]
if (user != self.user):
return
data: dict = json.loads(text_data)
self.member.receive(data)
def disconnect(self, close_code): def disconnect(self, close_code):
member = self.room.get_member_by_socket(self)
if (member is not None): self.room.leave(self.member)
self.room.remove(self.member, close_code)
super().disconnect(close_code) # proutman à encore frappé

View File

@ -1,8 +1,5 @@
from __future__ import annotations from __future__ import annotations
from django.db import models
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
@ -13,59 +10,52 @@ from games.models import GameModel
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db.models import CASCADE from django.db.models import CASCADE
from channels.generic.websocket import WebsocketConsumer from channels.generic.websocket import WebsocketConsumer
from django.db import models
import json
# 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_participants = models.IntegerField()
rounds = models.IntegerField() round = models.IntegerField()
started = models.BooleanField(default = False) started = models.BooleanField(default = False)
finished = models.BooleanField(default = False) finished = models.BooleanField(default = False)
winner = models.ForeignKey(ProfileModel, on_delete=CASCADE) winner = models.ForeignKey(ProfileModel, on_delete=CASCADE, blank=True, null=True)
def _add_player(self, player: ProfileModel) -> None: def _register_participant(self, participant: ProfileModel) -> None:
TournamentPlayerModel(player=player, tournament=self).save() TournamentParticipantModel(participant=participant, tournament=self).save()
def start(self, players: list[ProfileModel]) -> None: def start(self, participants: list[ProfileModel]) -> None:
self.started = False self.started = True
for player in players: for player in participants:
self._add_player(player) self._register_participant(player)
for (player1, player2) in zip(players[0::2], players[1::2]): for (participant1, participant2) in zip(participants[0::2], participants[1::2]):
self.create_game([player1, player2], round=1) self.create_game([participant1, participant2], round=1)
self.save() self.save()
def create_game(self, players: list[ProfileModel], round: int) -> GameModel: def create_game(self, participants: list[ProfileModel], round: int) -> GameModel:
if (self.started == False): if (self.started == False):
return None return None
if (len(players) != 2): if (len(participants) != 2):
return None return None
from games.models import GameModel from games.models import GameModel
game: GameModel = GameModel().create(players=players) game: GameModel = GameModel().create(participants)
TournamentGameModel(tournament=self, game=game, round=round).save() TournamentGameModel(tournament=self, game=game, round=round).save()
return game return game
def start(self, players: list[ProfileModel]) -> int:
if (len(players) != self.nb_players):
return 1
for player in players:
TournamentPlayerModel(tournament=self, player=player).save()
return 0
def get_games(self) -> list[GameModel]: def get_games(self) -> list[GameModel]:
return [tournament_game.game for tournament_game in TournamentGameModel.objects.filter(tournament=self)] return [tournament_game.game for tournament_game in TournamentGameModel.objects.filter(tournament=self)]
@ -78,50 +68,22 @@ class TournamentModel(models.Model):
def get_winners_by_round(self, round: int) -> list[ProfileModel]: def get_winners_by_round(self, round: int) -> list[ProfileModel]:
return [game.winner for game in self.get_games_by_round(round)] return [game.winner for game in self.get_games_by_round(round)]
def get_players(self) -> list[TournamentPlayerModel]: def get_participants(self) -> list[TournamentParticipantModel]:
return TournamentPlayerModel.objects.filter(tournament=self.pk) return TournamentParticipantModel.objects.filter(tournament=self.pk)
def get_state(self) -> str: def get_state(self) -> str:
return ("waiting to start", "in progress", "finish")[self.started + self.finished] return ("waiting to start", "in progress", "finish")[self.started + self.finished]
def is_player(self, profile: ProfileModel) -> bool: def is_participanting(self, profile: ProfileModel) -> bool:
return TournamentPlayerModel.objects.filter(player=profile, tournament=self).exists() return TournamentParticipantModel.objects.filter(participant=profile, tournament=self).exists()
class TournamentPlayerModel(models.Model): class TournamentParticipantModel(models.Model):
player = models.ForeignKey(ProfileModel, on_delete=CASCADE) participant = models.ForeignKey(ProfileModel, on_delete=CASCADE)
tournament = models.ForeignKey(TournamentModel, on_delete=CASCADE) tournament = models.ForeignKey(TournamentModel, on_delete=CASCADE)
#prout à encore frappé
class TournamentGameModel(models.Model): class TournamentGameModel(models.Model):
tournament = models.ForeignKey(TournamentModel, on_delete=CASCADE, null=True, blank=True) tournament = models.ForeignKey(TournamentModel, on_delete=CASCADE, null=True, blank=True)
round = models.IntegerField() round = models.IntegerField()
game = models.ForeignKey(GameModel, on_delete=CASCADE) game = models.ForeignKey(GameModel, on_delete=CASCADE)
class TournamentSpectator(AbstractRoomMember):
pass
class TournamentPlayer(TournamentSpectator):
pass
class TournamentRoom(AbstractRoom):
def __init__(self, room_manager: TournamentRoomManager, tournament_id: int):
super().__init__(room_manager)
self.room_manager: TournamentRoomManager
self.id: int = id
self.model: TournamentModel = TournamentModel.objects.get(pk=tournament_id)
def join(self, profile: ProfileModel, socket: WebsocketConsumer) -> TournamentPlayer | TournamentSpectator:
if (self.model.started):
if (self.model.is_player(profile)):
return TournamentPlayer(profile.pk, socket)
else:
return TournamentSpectator(profile.pk, socket)
else:
return TournamentSpectator(profile.pk, socket)
class TournamentRoomManager(AbstractRoomManager):
pass
tournament_manager: TournamentRoomManager = TournamentRoomManager()

View File

@ -4,7 +4,7 @@ from django.db.models.query import QuerySet
from django.contrib.auth.models import User from django.contrib.auth.models import User
from .models import TournamentModel, tournament_manager from .models import TournamentModel
from profiles.models import ProfileModel from profiles.models import ProfileModel
from profiles.serializers.ProfileSerializer import ProfileSerializer from profiles.serializers.ProfileSerializer import ProfileSerializer
@ -12,9 +12,8 @@ from games.serializers import GameSerializer
class TournamentSerializer(serializers.ModelSerializer): class TournamentSerializer(serializers.ModelSerializer):
rounds = serializers.SerializerMethodField(read_only=True, required=False)
state = serializers.SerializerMethodField(read_only=True, required=False) state = serializers.SerializerMethodField(read_only=True, required=False)
players = serializers.SerializerMethodField(read_only=True, required=False) participants = serializers.SerializerMethodField(read_only=True, required=False)
round = serializers.ReadOnlyField() round = serializers.ReadOnlyField()
started = serializers.ReadOnlyField() started = serializers.ReadOnlyField()
finished = serializers.ReadOnlyField() finished = serializers.ReadOnlyField()
@ -22,57 +21,25 @@ class TournamentSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = TournamentModel model = TournamentModel
fields = ["name", "nb_players", "nb_players_by_game", "round", "started", "finished", "rounds", "id", "state", "players"] fields = ["name", "nb_participants", "round", "started", "finished", "id", "state", "participants"]
def get_players(self, instance: TournamentModel):
players_id: list[ProfileModel]
if (instance.started):
players_id = instance.get_players_id()
else:
players_id = tournament_manager.get(instance.pk).get_players_id()
players_profile: list[ProfileModel] = []
for player_id in players_id:
query: QuerySet = ProfileModel.objects.filter(user_id = player_id)
profile_data: dict
if query.exists():
profile_data = ProfileSerializer(query[0]).data
else:
profile_data = {
"username": "deleted_user",
"avatar": "/static/avatars/default.avif",
"user_id": players_id
}
players_profile.append(profile_data)
return players_profile
def get_participants(self, instance: TournamentModel):
return ProfileSerializer(instance.get_participants(), many=True).data
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_rounds(self, instance: TournamentModel): def validate_nb_participants(self, value: int):
rounds: list[list[int]] = []
for i in range(instance.round):
games_id: list[int] = instance.get_games_id_by_round(i)
if (games_id == []):
break
rounds.append(games_id)
return rounds
def validate_nb_players(self, value: int):
if (value < 2): if (value < 2):
raise serializers.ValidationError("The numbers of players must be greather than 2.") raise serializers.ValidationError("The numbers of participants must be greather than 2.")
return value return value
def validate_nb_players_by_game(self, value: int): def validate_nb_participants_by_game(self, value: int):
if (value < 2): if (value < 2):
raise serializers.ValidationError("The numbers of players by game must be greather than 2.") raise serializers.ValidationError("The numbers of participants by game must be greather than 2.")
nb_players: str = self.initial_data.get("nb_players") nb_participants: str = self.initial_data.get("nb_participants")
if (nb_players is not None and nb_players.isnumeric()): if (nb_participants is not None and nb_participants.isnumeric()):
nb_players: int = int(nb_players) nb_participants: int = int(nb_participants)
if (value > nb_players): if (value > nb_participants):
raise serializers.ValidationError("The numbers of players by game must be smaller than the numbers of players.") raise serializers.ValidationError("The numbers of participants by game must be smaller than the numbers of participants.")
return value return value

View File

@ -19,10 +19,7 @@ class TournamentViewSet(viewsets.ModelViewSet):
authentication_classes = (SessionAuthentication,) authentication_classes = (SessionAuthentication,)
def perform_create(self, serializer: TournamentSerializer): def perform_create(self, serializer: TournamentSerializer):
tournament = serializer.save(round=1)
nb_players = serializer.validated_data["nb_players"]
name = serializer.validated_data["name"]
tournament = serializer.save(name=name, nb_players=nb_players, round=1)
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

@ -5,7 +5,7 @@ from .AbstractRoomMember import AbstractRoomMember
class AbstractRoom: class AbstractRoom:
def __init__(self, room_manager): def __init__(self, room_manager):
self._member_list: [AbstractRoomMember] = [] self._member_list: list[AbstractRoomMember] = []
self.room_manager = room_manager self.room_manager = room_manager
def broadcast(self, detail: str, data: dict = {}): def broadcast(self, detail: str, data: dict = {}):

View File

@ -12,9 +12,3 @@ class AbstractRoomMember:
raw_data: dict = {"detail": detail} raw_data: dict = {"detail": detail}
raw_data.update(data) raw_data.update(data)
self.socket.send(text_data=json.dumps(raw_data)) self.socket.send(text_data=json.dumps(raw_data))
def accept(self):
self.socket.accept()
def disconnect(self, code: int = 1000):
self.socket.disconnect(code)