2 Commits

Author SHA1 Message Date
4fd6616786 add block option 2023-12-20 23:48:52 +01:00
57ed6165ea bug issue; rewrite all messages 2023-12-19 12:42:46 +01:00
48 changed files with 223 additions and 1162 deletions

View File

@ -25,7 +25,6 @@ pip install -r requirements.txt
python manage.py makemigrations games python manage.py makemigrations games
python manage.py makemigrations profiles python manage.py makemigrations profiles
python manage.py makemigrations chat python manage.py makemigrations chat
python manage.py makemigrations tournament
python manage.py migrate python manage.py migrate
``` ```
- Start the developpement server - Start the developpement server

View File

@ -2,6 +2,7 @@ import json
from channels.generic.websocket import WebsocketConsumer from channels.generic.websocket import WebsocketConsumer
from asgiref.sync import async_to_sync from asgiref.sync import async_to_sync
from .models import MemberModel, MessageModel from .models import MemberModel, MessageModel
from profiles.models import BlockModel
import time import time
class ChatConsumer(WebsocketConsumer): class ChatConsumer(WebsocketConsumer):
@ -34,6 +35,9 @@ class ChatConsumer(WebsocketConsumer):
text_data_json = json.loads(text_data) text_data_json = json.loads(text_data)
message = text_data_json['message'] message = text_data_json['message']
receivers_id = text_data_json['receivers_id']
print(text_data)
channel_id : int = int(self.scope['path'].split('/')[3]) channel_id : int = int(self.scope['path'].split('/')[3])
user = self.scope["user"] user = self.scope["user"]
@ -46,9 +50,14 @@ class ChatConsumer(WebsocketConsumer):
if (self.channel_layer == None): if (self.channel_layer == None):
return return
print(message)
message_time : int = int(time.time() * 1000) message_time : int = int(time.time() * 1000)
if (len(receivers_id) == 1 and
BlockModel.objects.filter(blocker=user.pk, blocked=receivers_id[0]) or
BlockModel.objects.filter(blocker=receivers_id[0], blocked=user.pk)
):
return
async_to_sync(self.channel_layer.group_send)( async_to_sync(self.channel_layer.group_send)(
self.room_group_name, self.room_group_name,
{ {

View File

@ -2,5 +2,5 @@ from django.urls import re_path
from . import consumers from . import consumers
websocket_urlpatterns = [ websocket_urlpatterns = [
re_path(r'ws/chat/(?P<chat_id>\d+)$', consumers.ChatConsumer.as_asgi()) re_path(r'ws/chat/(?P<chat_id>\d+)/$', consumers.ChatConsumer.as_asgi())
] ]

View File

@ -33,7 +33,7 @@ class Account
if (JSON.stringify(response_data) == JSON.stringify({'detail': 'Authentication credentials were not provided.'})) if (JSON.stringify(response_data) == JSON.stringify({'detail': 'Authentication credentials were not provided.'}))
{ {
this.client._update_logged(false); this.client._logged = false;
return null; return null;
} }
if (response_data == "user deleted") if (response_data == "user deleted")

View File

@ -14,7 +14,7 @@ class Channel {
// reload = function to use when we receive a message // reload = function to use when we receive a message
async connect(reload) { async connect(reload) {
let url = `${window.location.protocol[4] === 's' ? 'wss' : 'ws'}://${window.location.host}/ws/chat/${this.channel_id}`; let url = `ws://${window.location.host}/ws/chat/${this.channel_id}/`;
this.chatSocket = new WebSocket(url); this.chatSocket = new WebSocket(url);
this.chatSocket.onmessage = (event) =>{ this.chatSocket.onmessage = (event) =>{
@ -54,13 +54,14 @@ class Channel {
return new_messages; return new_messages;
} }
async sendMessageChannel(message) { async sendMessageChannel(message, receivers_id) {
if (this.chatSocket == undefined) if (this.chatSocket == undefined)
return; return;
this.chatSocket.send(JSON.stringify({ this.chatSocket.send(JSON.stringify({
'message':message 'message':message,
'receivers_id':receivers_id,
})); }));
} }

View File

@ -3,8 +3,6 @@ import { MatchMaking } from "./matchmaking.js";
import { Profiles } from "./profiles.js"; import { Profiles } from "./profiles.js";
import { Channels } from './chat/channels.js'; import { Channels } from './chat/channels.js';
import { MyProfile } from "./MyProfile.js"; import { MyProfile } from "./MyProfile.js";
import { navigateTo } from "../index.js"
import { Tourmanents } from "./tournament/tournaments.js";
function getCookie(name) function getCookie(name)
{ {
@ -24,7 +22,6 @@ class Client
this.account = new Account(this); this.account = new Account(this);
this.profiles = new Profiles(this); this.profiles = new Profiles(this);
this.matchmaking = new MatchMaking(this); this.matchmaking = new MatchMaking(this);
this.tournaments = new Tourmanents(this);
this._logged = undefined; this._logged = undefined;
this.channels = new Channels(this); this.channels = new Channels(this);
@ -38,10 +35,11 @@ class Client
return this.logged; return this.logged;
} }
async _get(uri) async _get(uri, data)
{ {
let response = await fetch(this._url + uri, { let response = await fetch(this._url + uri, {
method: "GET", method: "GET",
body: JSON.stringify(data),
}); });
return response; return response;
} }
@ -104,10 +102,6 @@ class Client
this.me = new MyProfile(this); this.me = new MyProfile(this);
await this.me.init(); await this.me.init();
} }
if (this.logged && !state)
{
navigateTo("/login");
}
this.logged = state; this.logged = state;
} }

View File

@ -8,44 +8,29 @@ class MatchMaking
constructor(client) constructor(client)
{ {
/** /**
* @type {Client} * @type {client}
*/ */
this.client = client this.client = client
this.searching = false;
} }
async start(receive_func, disconnect_func, mode) async start(func)
{ {
if (!await this.client.isAuthentificate()) if (!await this.client.isAuthentificate())
return null; return null;
let url = `${window.location.protocol[4] === 's' ? 'wss' : 'ws'}://${window.location.host}/ws/matchmaking/${mode}`; let url = `wss://${window.location.host}/ws/matchmaking/`;
this._socket = new WebSocket(url); this._chatSocket = new WebSocket(url);
this.searching = true; this._chatSocket.onmessage = function (event) {
this.receive_func = receive_func;
this.disconnect_func = disconnect_func;
this._socket.onmessage = function (event) {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
receive_func(data); func(data.game_id)
}; };
this._socket.onclose = this.onclose.bind(this);
}
onclose(event)
{
this.stop();
this.disconnect_func(event);
} }
async stop() async stop()
{ {
this.searching = false; this._chatSocket.close()
this._socket.close()
} }
} }

View File

@ -12,22 +12,33 @@ class Profile
*/ */
this.client = client; this.client = client;
this.username = username; this.username = username;
this.avatar_url = avatar_url this.avatar_url = avatar_url;
this.user_id = user_id this.user_id = user_id;
this.isBlocked = false;
} }
async init(user_id) async init(user_id)
{ {
let response = await this.client._get(`/api/profiles/${user_id}`); let response = await this.client._get(`/api/profiles/${user_id}`);
if (response.status === 404)
return 1;
let response_data = await response.json(); let response_data = await response.json();
this.user_id = response_data.user_id; this.user_id = response_data.user_id;
this.username = response_data.username; this.username = response_data.username;
this.avatar_url = response_data.avatar_url; this.avatar_url = response_data.avatar_url;
let block_response = await this.client._get("/api/profiles/block");
if (block_response.status == 404)
return
let block_data = await block_response.json();
let block_list = JSON.parse(block_data);
block_list.forEach(block => {
let blocker = block.fields.blocker;
let blocked = block.fields.blocked;
if (blocker == this.client.me.user_id && blocked == user_id)
return this.isBlocked = true;
});
} }
} }

View File

@ -28,19 +28,35 @@ class Profiles
async getProfile(user_id) async getProfile(user_id)
{ {
let profile = new Profile(this.client); let profile = new Profile(this.client);
if (await profile.init(user_id)) await profile.init(user_id);
return null;
return profile; return profile;
} }
async block(user_id) { async block(user_id) {
// blocker & blocked // blocker & blocked
let response = await this.client._post("/api/block/", let response = await this.client._post("/api/profiles/block", {
[this.client.me.user_id, user_id], users_id:[this.client.me.user_id, user_id],
); });
let data = await response.json(); let data = await response.json();
console.log(response.status);
console.log(data);
return data;
}
async deblock(user_id) {
// blocker & blocked
let response = await this.client._delete("/api/profiles/block", {
users_id:[this.client.me.user_id, user_id],
});
let data = await response.json();
console.log(response.status);
console.log(data);
return data;
} }
} }

View File

@ -1,98 +0,0 @@
import { Client } from "../client.js";
class Tourmanent
{
/**
* @param {Client} client
*/
constructor(client, name = undefined, nb_players = undefined, nb_players_by_game = undefined, level = undefined, started = undefined, finished = undefined, levels = undefined, id = undefined)
{
/**
* @type {Client}
*/
this.client = client;
this.name = name || `${nb_players_by_game}x1, ${nb_players} players`;
this.nb_players = nb_players;
this.nb_players_by_game = nb_players_by_game;
this.level = level;
this.started = started;
this.finished = finished;
this.levels = levels;
this.state = this.get_state();
this.id = id
this.connected = false;
}
get_state()
{
if (this.finished)
return "finished";
if (this.started)
return "started";
else
return "waiting";
}
async init(id)
{
let response = await this.client._get(`/api/tournaments/${id}`);
if (response.status === 404)
return 1;
let response_data = await response.json();
this.name = response_data.name || `${response_data.nb_players_by_game}x1, ${response_data.nb_players} players`;
this.nb_players = response_data.nb_players;
this.nb_players_by_game = response_data.nb_players_by_game;
this.level = response_data.level;
this.started = response_data.started;
this.finished = response_data.finished;
this.levels = response_data.levels;
this.id = response_data.id
this.state = this.get_state();
}
leave(event)
{
if (this.connected == false)
return
this.connected = false;
this._socket.close()
this.disconnect_func(event);
}
toggle_participation()
{
if (!this.connected)
return
this._socket.send(JSON.stringify({participate: ""}));
}
async join(receive_func, disconnect_func)
{
if (!await this.client.isAuthentificate())
return null;
let url = `${window.location.protocol[4] === 's' ? 'wss' : 'ws'}://${window.location.host}/ws/tournaments/${this.id}`;
this._socket = new WebSocket(url);
this.connected = true;
this.isParticipating = false;
this.receive_func = receive_func;
this.disconnect_func = disconnect_func;
this._socket.onmessage = function (event) {
const data = JSON.parse(event.data);
receive_func(data);
};
this._socket.onclose = this.leave.bind(this);
}
}
export { Tourmanent }

View File

@ -1,78 +0,0 @@
import { Client } from "../client.js";
import { Tourmanent } from "./tournament.js";
class Tourmanents
{
/**
* @param {Client} client
*/
constructor(client)
{
/**
* @type {Client}
*/
this.client = client
}
async getTournament(id)
{
let tournament = new Tourmanent(this.client);
if (await tournament.init(id))
return null;
return tournament;
}
async createTournament(nb_players, nb_players_by_game, name = "")
{
let response = await this.client._post("/api/tournaments/", {nb_players: nb_players, nb_players_by_game: nb_players_by_game, name: name});
if (response.status === 403)
{
this.client._update_logged(false);
return null;
}
let response_data = await response.json();
return response_data;
}
/**
* @param {string} state must be "finished", or "started", or "waiting". Any other return all elements
*/
async search(state)
{
let response = await this.client._get(`/api/tournaments/search/${state}`);
let response_data = await response.json()
if (response.status === 404)
{
this.client._update_logged(false);
return null;
}
let tournaments = [];
response_data.forEach(tournament_data => {
tournaments.push(new Tourmanent(this.client,
tournament_data.name,
tournament_data.nb_players,
tournament_data.nb_players_by_game,
tournament_data.level,
tournament_data.started,
tournament_data.finished,
tournament_data.levels,
tournament_data.id));
});
return tournaments;
}
async all()
{
return await this.search("");
}
}
export { Tourmanents }

View File

@ -14,9 +14,6 @@ import AbstractRedirectView from "./views/abstracts/AbstractRedirectView.js";
import MeView from "./views/MeView.js"; import MeView from "./views/MeView.js";
import ProfilePageView from "./views/ProfilePageView.js"; import ProfilePageView from "./views/ProfilePageView.js";
import MatchMakingView from "./views/MatchMakingView.js"; import MatchMakingView from "./views/MatchMakingView.js";
import TournamentPageView from "./views/TournamentPageView.js";
import TournamentsView from "./views/TournamentsListView.js";
import TournamentCreateView from "./views/TournamentCreateView.js";
let client = new Client(location.protocol + "//" + location.host) let client = new Client(location.protocol + "//" + location.host)
@ -38,26 +35,10 @@ const navigateTo = async (uri) => {
history.pushState(null, null, uri); history.pushState(null, null, uri);
}; };
async function renderView(view)
{
let content = await view.getHtml();
if (content == null)
return 1;
view.setTitle();
document.querySelector("#app").innerHTML = content
if (await view.postInit())
renderView(new PageNotFoundView());
}
const router = async (uri) => { const router = async (uri) => {
const routes = [ const routes = [
{ path: "/", view: Dashboard }, { path: "/", view: Dashboard },
{ path: "/profiles/:id", view: ProfilePageView }, { path: "/profiles/:id", view: ProfilePageView },
{ path: "/tournaments/create", view: TournamentCreateView },
{ path: "/tournaments/:id", view: TournamentPageView },
{ path: "/tournaments/", view: TournamentsView },
{ path: "/login", view: LoginView }, { path: "/login", view: LoginView },
{ path: "/logout", view: LogoutView }, { path: "/logout", view: LogoutView },
{ path: "/register", view: RegisterView }, { path: "/register", view: RegisterView },
@ -99,7 +80,14 @@ const router = async (uri) => {
lastView = view; lastView = view;
await client.isAuthentificate(); await client.isAuthentificate();
renderView(view); let content = await view.getHtml();
if (content == null)
return 1;
view.setTitle();
document.querySelector("#app").innerHTML = content
await view.postInit();
return 0; return 0;
}; };

View File

@ -1,64 +1,24 @@
import { client, navigateTo } from "../index.js"; import { client, navigateTo } from "../index.js";
import { clear, fill_errors } from "../utils/formUtils.js"; import AbstractView from "./abstracts/AbstractView.js";
import AbstractAuthentifiedView from "./abstracts/AbstractAuthentifiedView.js";
export default class extends AbstractAuthentifiedView { function game_found(game_id)
constructor(params) {
{ navigateTo(`/games/${game_id}`)
super(params, "Matchmaking"); }
}
async press_button() export default class extends AbstractView {
{ constructor(params) {
if (client.matchmaking.searching) super(params, "Dashboard");
{
client.matchmaking.stop();
document.getElementById("button").value = "Find a game"
}
else
{
let nb_players = document.getElementById("nb_players-input").value
await client.matchmaking.start(this.onreceive.bind(this), this.ondisconnect.bind(this), nb_players);
document.getElementById("button").value = "Stop matchmaking"
}
}
ondisconnect(event)
{
if (event.code === 1000)
clear("innerText", ["detail"])
document.getElementById("button").value = "Find a game"
}
onreceive(data)
{
if (data.detail === "game_found")
{
navigateTo(`/games/${data.game_id}`);
return;
}
this.display_data(data)
}
display_data(data)
{
clear("innerText", ["detail"]);
fill_errors(data, "innerText");
} }
async postInit() async postInit()
{ {
document.getElementById("button").onclick = this.press_button.bind(this) await client.matchmaking.start(game_found)
} }
async getHtml() { async getHtml() {
return ` return `
<h1>Select mode</h1> <h1>finding<h1>
<input type="number" value="2" id="nb_players-input">
<input type="button" value="Find a game" id="button">
<span id="detail"></span>
`; `;
} }

View File

@ -9,36 +9,46 @@ export default class extends AbstractView {
async postInit() async postInit()
{ {
let profile = await client.profiles.getProfile(this.user_id); this.profile = await client.profiles.getProfile(this.user_id);
this.info = document.getElementById("info");
if (profile === null)
return 1;
let info = document.getElementById("info");
// Username // Username
let username = document.createElement("a"); let username = document.createElement("a");
username.id = "username"; username.id = "username";
username.appendChild(document.createTextNode(profile.username)); username.appendChild(document.createTextNode(this.profile.username));
info.appendChild(username); this.info.appendChild(username);
info.appendChild(document.createElement("br")); this.info.appendChild(document.createElement("br"));
// Avatar // Avatar
let avatar = document.createElement("img"); let avatar = document.createElement("img");
avatar.id = "avatar"; avatar.id = "avatar";
avatar.src = profile.avatar_url; avatar.src = this.profile.avatar_url;
info.appendChild(avatar); this.info.appendChild(avatar);
// Block option await this.blockButton();
let block = document.createElement("a");
block.id = "block";
block.addEventListener("click", async () => {
if (client.me.user_id != user.user_id) {
} }
});
async blockButton() {
// Block option
if (client.me.user_id != this.user_id) {
let block = document.getElementById("block") || document.createElement("a");
block.id = "block";
block.innerText = "";
block.onclick = async () => {
if (!this.profile.isBlocked)
await client.profiles.block(this.user_id);
else
await client.profiles.deblock(this.user_id);
this.profile = await client.profiles.getProfile(this.user_id);
this.blockButton();
};
if (this.profile.isBlocked)
block.appendChild(document.createTextNode("Deblock"));
else
block.appendChild(document.createTextNode("Block")); block.appendChild(document.createTextNode("Block"));
info.appendChild(block); this.info.appendChild(block);
}
} }
async getHtml() { async getHtml() {

View File

@ -100,6 +100,7 @@ export default class extends AbstractView {
async chat() { async chat() {
let users = await client.profiles.all();
let logged = await client.isAuthentificate(); let logged = await client.isAuthentificate();
/*let reload = document.getElementById("messages"); /*let reload = document.getElementById("messages");
if (reload != null) if (reload != null)
@ -135,7 +136,7 @@ export default class extends AbstractView {
// les messages, réecriture seulement du dernier // les messages, réecriture seulement du dernier
let i = 0; let i = 0;
client.channel.messages.forEach((message) => { client.channel.messages.forEach((message) => {
if (messages[i] == null || message != messages.children[i].innerText) { if (messages.children[i] == null || message.content != messages.children[i].innerText) {
let text = document.createElement("p"); let text = document.createElement("p");
text.appendChild(document.createTextNode(message.content)); text.appendChild(document.createTextNode(message.content));
if (message.author_id == client.me.user_id) if (message.author_id == client.me.user_id)
@ -158,21 +159,25 @@ export default class extends AbstractView {
chat_input.maxLength=255; chat_input.maxLength=255;
chat.appendChild(chat_input); chat.appendChild(chat_input);
chat_input.addEventListener("keydown", async () => { chat_input.onkeydown = async () => {
if (event.keyCode == 13 && client.channel != undefined) { if (event.keyCode == 13 && client.channel != undefined) {
//let chat_input = document.getElementById("input_chat"); //let chat_input = document.getElementById("input_chat");
let chat_text = chat_input.value; let chat_text = chat_input.value;
await client.channel.sendMessageChannel(chat_text) let receivers_id = [];
client.channel.members_id.forEach((member_id) => {
if (member_id != client.me.user_id)
receivers_id.push(users.filter(user => user.user_id == member_id)[0].user_id);
});
await client.channel.sendMessageChannel(chat_text, receivers_id)
// Reset // Reset
chat_input.value = ""; chat_input.value = "";
} }
}); };
} }
// nom des membres du chat // nom des membres du chat
let users = await client.profiles.all();
let members = document.createElement("h2"); let members = document.createElement("h2");
members.id = "members"; members.id = "members";
let usernames = ""; let usernames = "";

View File

@ -1,52 +0,0 @@
import {client, navigateTo} from "../index.js";
import { clear, fill_errors } from "../utils/formUtils.js";
import AbstractAuthentifiedView from "./abstracts/AbstractAuthentifiedView.js";
export default class extends AbstractAuthentifiedView
{
constructor(params)
{
super(params, "Create tournament");
this.id = params.id;
}
async create()
{
let name = document.getElementById("name-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_data = await client.tournaments.createTournament(nb_players, nb_players_by_game, name);
if (response_data === null)
return;
let id = response_data["id"]
if (id !== undefined)
{
navigateTo(`/tournaments/${id}`);
return;
}
clear("innerHTML", ["name", "nb_players", "nb_players_by_game"]);
fill_errors(response_data, "innerHTML");
}
async postInit()
{
document.getElementById("create-button").onclick = this.create;
}
async getHtml()
{
return `
<input type="text" id="name-input" placeholder="Tournament name">
<span id="name"></span>
<input type="number" id="nb_players-input" placeholder="Number of players in tournament">
<span id="nb_players"></span>
<input type="number" id="nb_players_by_game-input" placeholder="Number of players by game">
<span id="nb_players_by_game"></span>
<input type="button" id="create-button" value="Create tournament">
`
}
}

View File

@ -1,98 +0,0 @@
import {client, navigateTo} from "../index.js";
import AbstractAuthentifiedView from "./abstracts/AbstractAuthentifiedView.js";
export default class extends AbstractAuthentifiedView
{
constructor(params)
{
super(params, "Tournament");
this.id = params.id;
}
pressButton()
{
this.tournament.toggle_participation();
}
async receive(data)
{
if (data.detail === "nb_participants" || data.detail === "update_participants")
document.getElementById("nb_participants").innerText = `${data.nb_participants} / ${this.tournament.nb_players}`
if (data.detail === "go_to")
navigateTo(data.url);
if (data.detail === "is_participant")
this.updateParticipating(data.is_participant)
if (data.detail === "error")
document.getElementById("display").innerText = data.error_message
}
async updateParticipating(state)
{
document.getElementById("button").value = state ? `Leave ${this.tournament.name}` : `Join ${this.tournament.name}`;
document.getElementById("display").innerText = state ? "You are a particpant" : "You are not a participant";
}
async ondisconnect(event)
{
}
async postInit()
{
this.tournament = await client.tournaments.getTournament(this.id);
if (this.tournament === null)
return 1;
this.tournament.join(this.receive.bind(this), this.ondisconnect.bind(this));
let button = document.getElementById("button")
button.onclick = this.pressButton.bind(this);
document.getElementById("name").innerText = this.tournament.name;
document.getElementById("nb_players").innerText = this.tournament.nb_players;
document.getElementById("nb_players_by_game").innerText = this.tournament.nb_players_by_game;
document.getElementById("level").innerText = this.tournament.level;
document.getElementById("state").innerText = this.tournament.state;
if (this.tournament.state === "waiting")
button.disabled = false;
}
async getHtml()
{
return `
<table>
<thead>
<tr>
<th id="name">Loading...</th>
</tr>
</thead>
<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>
<td>Number of round</td>
<td id="level">Loading...</td>
</tr>
<tr>
<td>Number of player</td>
<td id="nb_participants">Loading...</td>
</tr>
<tr>
<td>status</td>
<td id="state">Loading...</td>
</tr>
</tbody>
</table>
<input type="button" id="button" value="Join tournament" disabled>
<span id="display"></span>
`
}
}

View File

@ -1,133 +0,0 @@
import {client} from "../index.js";
import AbstractAuthentifiedView from "./abstracts/AbstractAuthentifiedView.js";
export default class extends AbstractAuthentifiedView
{
constructor(params)
{
super(params, "Tournament");
this.id = params.id;
}
async external_search()
{
let state = document.getElementById("state-select").value;
this.tournaments = await client.tournaments.search(state);
}
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()
{
let nb_players_by_game = document.getElementById("nb-players-by-game-select").value;
this.display_tournaments = [];
this.tournaments.forEach(tournament => {
if (nb_players_by_game === "all" || nb_players_by_game == tournament.nb_players_by_game)
this.display_tournaments.push(tournament);
});
}
display_result()
{
const tournaments_list = document.getElementById("tournaments-list");
const new_children = []
this.display_tournaments.forEach(tournament => {
let tr = document.createElement("tr");
// name
let td = document.createElement("td");
td.innerText = tournament.name;
tr.appendChild(td);
// state
td = document.createElement("td");
td.innerText = tournament.state;
tr.appendChild(td);
// nb_players
td = document.createElement("td");
td.innerText = tournament.nb_players;
tr.appendChild(td);
// nb_players_by_game
td = document.createElement("td");
td.innerText = tournament.nb_players_by_game;
tr.appendChild(td);
new_children.push(tr);
});
tournaments_list.replaceChildren(...new_children);
}
async update_query()
{
this.internal_search();
this.display_result();
}
async update_search()
{
await this.external_search();
this.add_nb_player_by_game_selector();
this.update_query();
}
async postInit()
{
await this.update_search()
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()
{
return `
<select id="state-select">
<option value="waiting">Waiting</option>
<option value="started">Started</option>
<option value="finished">Finished</option>
<option value="all">All</option>
</select>
<select id="nb-players-by-game-select">
</select>
<table>
<thead>
<td>Name</td>
<td>Status</td>
<td>Max numbers of players</td>
<td>Max numbers of players by game</td>
</thead>
<tbody id="tournaments-list">
</tbody>
</table>
`
}
}

View File

@ -3,19 +3,12 @@ from django.db import models
# Create your models here. # Create your models here.
class GameModel(models.Model): class GameModel(models.Model):
finished = models.BooleanField(default = False) def create(self, users_id: [int]):
started = models.BooleanField(default = False)
winner_id = models.IntegerField(default = -1)
def create(self, players_id: [int]):
self.save() self.save()
for player_id in players_id: for user_id in users_id:
GameMembersModel(game_id = self.pk, player_id = player_id).save() GameMembersModel(game_id=self.pk, member_id=user_id)
return self.pk return self.pk
def get_players_id(self):
return [game_member.member_id for game_member in GameMembersModel.objects.filter(game_id = self.pk)]
class GameMembersModel(models.Model): class GameMembersModel(models.Model):
game_id = models.IntegerField() game_id = models.IntegerField()
player_id = models.IntegerField() member_id = models.IntegerField()

View File

@ -1,24 +0,0 @@
from rest_framework import serializers
from .models import GameModel, GameMembersModel
class GameSerializer(serializers.ModelSerializer):
players_id = serializers.SerializerMethodField()
winner_id = serializers.ReadOnlyField()
state = serializers.SerializerMethodField()
started = serializers.ReadOnlyField()
finished = serializers.ReadOnlyField()
class Meta:
model = GameModel
fields = ["id", "winner_id", "state", "started", "finished", "players_id"]
def get_state(self, instance: GameModel):
if (instance.finished):
return "finished"
if (instance.started):
return "started"
return "waiting"
def get_players_id(self, instance: GameModel):
players_id = [player_game.member_id for player_game in GameMembersModel.objects.filter(game_id=instance.pk)]

View File

@ -6,7 +6,7 @@ import sys
def main(): def main():
"""Run administrative tasks.""" """Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'transcendence.settings') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'trancendence.settings')
try: try:
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
except ImportError as exc: except ImportError as exc:

View File

@ -6,7 +6,8 @@ from games.models import GameModel
import json import json
from .models import Waiter, WaitingRoom, WaitingRoomManager, normal queue_id: [int] = []
queue_ws: [WebsocketConsumer] = []
class MatchMaking(WebsocketConsumer): class MatchMaking(WebsocketConsumer):
@ -23,19 +24,25 @@ class MatchMaking(WebsocketConsumer):
self.channel_layer.group_add(self.group_name, self.channel_name) self.channel_layer.group_add(self.group_name, self.channel_name)
self.mode = int(self.scope['url_route']['kwargs']['mode']) self.accept()
self.group_name = self.mode
global queue_id, queue_ws
queue_id.append(user.pk)
queue_ws.append(self)
if len(set(queue_id)) == 2:
game_id: int = GameModel().create(set(queue_id))
event = {"game_id": game_id}
for ws in queue_ws:
ws.send(text_data=json.dumps({'game_id': game_id}))
queue_id.clear()
queue_ws.clear()
waiting_room: WaitingRoom = normal.get(self.mode)
waiting_room.append(Waiter(user.pk, self))
waiting_room.broadcast(f"{len(waiting_room)} / {waiting_room.mode}")
if (len(waiting_room) == waiting_room.mode):
game_id: int = GameModel().create(waiting_room.get_users_id())
waiting_room.broadcast("game_found", {"game_id": game_id})
waiting_room.clear()
def disconnect(self, close_code): def disconnect(self, close_code):
waiting_room: WaitingRoom = normal.get(self.mode) user: User = self.scope["user"]
waiter: Waiter = waiting_room.get_member_by_socket(self) global queue_id, queue_ws
if (waiter is not None): if (user.pk in queue_id):
waiting_room.remove(waiter, 1016) queue_ws.pop(queue_id.index(user.pk))
queue_id.remove(user.pk)
self.channel_layer.group_discard(self.group_name, self.channel_name)

View File

@ -1,39 +1,3 @@
from django.db import models from django.db import models
from channels.generic.websocket import WebsocketConsumer
import json
from transcendence.abstract.AbstractRoom import AbstractRoom
from transcendence.abstract.AbstractRoomManager import AbstractRoomManager
from transcendence.abstract.AbstractRoomMember import AbstractRoomMember
# Create your models here. # Create your models here.
class Waiter(AbstractRoomMember):
pass
class WaitingRoom(AbstractRoom):
def __init__(self, room_manager,mode):
super().__init__(room_manager)
self.mode = mode
def append(self, waiter: Waiter):
tmp: Waiter = self.get_member_by_user_id(waiter.user_id)
if (tmp is not None):
tmp.send("Connection close: Another connection open with the same user id.")
self.remove(tmp)
waiter.accept()
self._member_list.append(waiter)
class WaitingRoomManager(AbstractRoomManager):
def get(self, mode: int):
for waiting_room in self._room_list:
waiting_room: WaitingRoom
if (waiting_room.mode == mode):
return waiting_room
tmp: WaitingRoom = WaitingRoom(self, mode)
super().append(tmp)
return tmp
normal: WaitingRoomManager = WaitingRoomManager()

View File

@ -2,5 +2,5 @@ from django.urls import re_path
from . import consumers from . import consumers
websocket_urlpatterns = [ websocket_urlpatterns = [
re_path(r'ws/matchmaking/(?P<mode>\d+)$', consumers.MatchMaking.as_asgi()) re_path(r'ws/matchmaking/', consumers.MatchMaking.as_asgi())
] ]

View File

@ -1,6 +1,7 @@
from django.contrib import admin from django.contrib import admin
from .models import ProfileModel from .models import ProfileModel, BlockModel
# Register your models here. # Register your models here.
admin.site.register(ProfileModel) admin.site.register(ProfileModel)
admin.site.register(BlockModel)

View File

@ -7,8 +7,8 @@ class ProfileTest(TestCase):
def setUp(self): def setUp(self):
self.user: User = User.objects.create(username='bozo', password='password') self.user: User = User.objects.create(username='bozo', password='password')
self.user.save() self.user.save()
self.expected_response = {'avatar_url': '/static/avatars/default.avif', 'user_id': 1, 'username': 'bozo'} self.expected_response = {"name": "bozo",
"title": ""}
self.url = "/api/profiles/" self.url = "/api/profiles/"
def test_profile_create_on_user_created(self): def test_profile_create_on_user_created(self):

View File

@ -9,5 +9,7 @@ urlpatterns = [
path("me", viewsets.MyProfileViewSet.as_view({'patch': 'partial_update', 'get': 'retrieve'}), name="my_profile_page"), path("me", viewsets.MyProfileViewSet.as_view({'patch': 'partial_update', 'get': 'retrieve'}), name="my_profile_page"),
path("<int:pk>", viewsets.ProfileViewSet.as_view({'get': 'retrieve'}), name="profile_page"), path("<int:pk>", viewsets.ProfileViewSet.as_view({'get': 'retrieve'}), name="profile_page"),
path("", viewsets.ProfileViewSet.as_view({'get': 'list'}), name="profiles_list"), path("", viewsets.ProfileViewSet.as_view({'get': 'list'}), name="profiles_list"),
path("block", views.BlockView.as_view(), name="block_page"), path("block", views.BlocksView.as_view(), name="block_page"),
path("block/<int:pk>", views.BlockView.as_view(), name="block_page"),
] + static("/static/avatars/", document_root="./avatars") ] + static("/static/avatars/", document_root="./avatars")

View File

@ -2,17 +2,65 @@ from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework import authentication, permissions, status from rest_framework import authentication, permissions, status
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
from rest_framework.renderers import JSONRenderer
from django.core import serializers from django.core import serializers
from .models import BlockModel
class BlockView(APIView): class BlockView(APIView):
permission_classes = (permissions.IsAuthenticated,) permission_classes = (permissions.IsAuthenticated,)
authentication_classes = (SessionAuthentication,) authentication_classes = (SessionAuthentication,)
def post(self, request, pk):
pass
def get(self, request, pk): def get(self, request, pk):
pass block = BlockModel.objects.filter(pk=pk)
if (block):
return Response(serializers.serialize("json", block), status=status.HTTP_200_OK)
else:
return Response("Not Found", status=status.HTTP_404_NOT_FOUND)
def delete(self, request, pk):
pass class BlocksView(APIView):
permission_classes = (permissions.IsAuthenticated,)
authentication_classes = (SessionAuthentication,)
def get(self, request):
blocks = BlockModel.objects.filter(blocker=request.user.pk)
if (blocks):
return Response(serializers.serialize("json", BlockModel.objects.filter(blocker=request.user.pk)), status=status.HTTP_200_OK)
else:
return Response({}, status=status.HTTP_404_NOT_FOUND)
def post(self, request):
data: dict = request.data
users_id = request.data.get("users_id", None)
if (users_id == None):
return Response({"Error"}, status=status.HTTP_400_BAD_REQUEST)
if (BlockModel.objects.filter(blocker=users_id[0], blocked=users_id[1])):
return Response({"Already Exist"}, status=status.HTTP_409_CONFLICT)
new_block = BlockModel()
new_block.blocker = users_id[0]
new_block.blocked = users_id[1]
new_block.save()
return Response({"block_id": new_block.pk}, status=status.HTTP_201_CREATED)
def delete(self, request):
data: dict = request.data
users_id = request.data.get("users_id", None)
if (users_id == None):
return Response({"Error"}, status=status.HTTP_400_BAD_REQUEST)
block = BlockModel.objects.filter(blocker=users_id[0], blocked=users_id[1])
print(list(block))
if (block.count() > 1):
return Response("Not normal >:[", status=status.HTTP_500_INTERNAL_SERVER_ERROR)
if (not block):
return Response("Don't exist", status=status.HTTP_404_NOT_FOUND)
block.delete()
return Response("Deleted", status=status.HTTP_200_OK)

View File

@ -31,6 +31,9 @@ class ProfileViewSet(viewsets.ModelViewSet):
profile["avatar_url"] = profile["avatar_url"][profile["avatar_url"].find("static") - 1:] profile["avatar_url"] = profile["avatar_url"][profile["avatar_url"].find("static") - 1:]
return Response(serializer.data) return Response(serializer.data)
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class MyProfileViewSet(viewsets.ModelViewSet): class MyProfileViewSet(viewsets.ModelViewSet):
permission_classes = (permissions.IsAuthenticated,) permission_classes = (permissions.IsAuthenticated,)

View File

@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View File

@ -1,6 +0,0 @@
from django.apps import AppConfig
class TournamentConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'tournament'

View File

@ -1,43 +0,0 @@
from channels.generic.websocket import WebsocketConsumer
from django.contrib.auth.models import User
from games.models import GameModel
import json
from .models import tournament_manager, TournamentMember, TournamentRoom, TournamentRoomManager
class TournamentWebConsumer(WebsocketConsumer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.channel_name = "tournament"
self.group_name = "tournament"
def connect(self):
self.user: User = self.scope["user"]
if (self.user.is_anonymous or not self.user.is_authenticated):
return
self.channel_layer.group_add(self.group_name, self.channel_name)
self.tournament_id = int(self.scope['url_route']['kwargs']['tournament_id'])
self.room = tournament_manager.get(self.tournament_id)
self.member = TournamentMember(self.user.pk, self, self.room)
if (self.room is None):
self.member.send("Tournament not found")
self.disconnect(1017)
self.room.append(self.member)
def receive(self, text_data: str = None, bytes_data: bytes = None):
self.member.receive(text_data, bytes_data)
def disconnect(self, close_code):
member = self.room.get_member_by_socket(self)
if (member is not None):
self.room.remove(self.member, close_code)

View File

@ -1,154 +0,0 @@
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.AbstractRoom import AbstractRoom
from transcendence.abstract.AbstractRoomManager import AbstractRoomManager
# Create your models here.tu
class TournamentModel(models.Model):
name = models.CharField(max_length = 100)
nb_players = models.IntegerField()
nb_players_by_game = models.IntegerField()
level = models.IntegerField()
started = models.BooleanField(default = False)
finished = models.BooleanField(default = False)
def create_game(self, level, players_id):
game_id = GameModel().create(players_id = players_id)
TournamentGamesModel(game_id = game_id, tournament_id = self.pk, tournament_level = level).save()
return game_id
def get_games_id_by_level(self, level):
tmp = TournamentGamesModel.objects.filter(tournament_id = self.pk, tournament_level = level)
return [instance.game_id for instance in tmp]
def get_games_id(self):
return [tournament_game.game_id for tournament_game in TournamentGamesModel.objects.filter(tournament_id = self.pk)]
def get_players_id(self):
return [model.participant_id for model in TournamentParticipantsModel.objects.filter(tournament_id=self.pk)]
def is_a_participant(self, participant_id: int):
return TournamentParticipantsModel.objects.filter(participant_id = participant_id, tournament_id = self.pk).exists()
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()
return games_id
class TournamentParticipantsModel(models.Model):
tournament_id = models.IntegerField()
participant_id = models.IntegerField()
class TournamentGamesModel(models.Model):
tournament_id = models.IntegerField()
tournament_level = models.IntegerField()
game_id = models.IntegerField()
class TournamentMember(AbstractRoomMember):
def __init__(self, user_id: int, socket: WebsocketConsumer, room):
super().__init__(user_id, socket)
self.participate = False
self.room = room
def receive(self, text_data: str = None, byte_dates: bytes = None):
if (text_data is None):
return
data: dict = json.loads(text_data)
if (data.get("participate") is not None):
self.room.update_participants(self)
def send_error_message(self, message: str):
self.send("error", {"error_message": message})
def go_to(self, url: str):
self.send("go_to", {"url": url})
def send_participating(self):
self.send("is_participant", {"is_participant": self.participate})
class TournamentRoom(AbstractRoom):
def __init__(self, room_manager, tournament_id: int):
super().__init__(room_manager)
self.tournament_id = tournament_id
self.tournament = 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):
if (self.tournament.started):
member.send_error_message("Tournament already started")
return
member.participate = not member.participate
nb_participants = self.get_nb_participants()
self.broadcast("update_participants", {"nb_participants": nb_participants})
member.send_participating()
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()
member.send("nb_participants", {"nb_participants": self.get_nb_participants()})
class TournamentRoomManager(AbstractRoomManager):
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()

View File

@ -1,6 +0,0 @@
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r'ws/tournaments/(?P<tournament_id>\d+)$', consumers.TournamentWebConsumer.as_asgi())
]

View File

@ -1,39 +0,0 @@
from rest_framework import serializers
from .models import TournamentModel
from games.serializers import GameSerializer
class TournamentSerializer(serializers.ModelSerializer):
levels = serializers.SerializerMethodField(read_only=True, required=False)
level = serializers.ReadOnlyField()
started = serializers.ReadOnlyField()
finished = serializers.ReadOnlyField()
name = serializers.CharField(default="")
class Meta:
model = TournamentModel
fields = ["name", "nb_players", "nb_players_by_game", "level", "started", "finished", "levels", "id"]
def get_levels(self, instance: TournamentModel):
levels: [[int]] = []
for i in range(instance.level):
games_id: [int] = instance.get_games_id_by_level(i)
if (games_id == []):
break
levels.append(games_id)
return levels
def validate_nb_players(self, value: int):
if (value < 2):
raise serializers.ValidationError("The numbers of players must be greather than 2.")
return value
def validate_nb_players_by_game(self, value: int):
if (value < 2):
raise serializers.ValidationError("The numbers of players by game must be greather than 2.")
nb_players: str = self.initial_data.get("nb_players")
if (nb_players is not None and nb_players.isnumeric()):
nb_players: int = int(nb_players)
if (value > nb_players):
raise serializers.ValidationError("The numbers of players by game must be smaller than the numbers of players.")
return value

View File

@ -1,44 +0,0 @@
from django.test import TestCase
# Create your tests here.
from django.test.client import Client
from django.http import HttpResponse
from django.contrib.auth.models import User
import json
import uuid
class CreateTest(TestCase):
def setUp(self):
self.client = Client()
self.url = "/api/tournaments/"
self.username = str(uuid.uuid4())
self.password = str(uuid.uuid4())
self.nb_players_by_game = 2
self.nb_players = 8
user: User = User.objects.create_user(username=self.username, password=self.password)
self.client.login(username=self.username, password=self.password)
def test_normal(self):
response: HttpResponse = self.client.post(self.url, {"nb_players_by_game": self.nb_players_by_game, "nb_players": self.nb_players})
response_data: dict = json.loads(response.content)
self.assertDictContainsSubset({"name": ""}, response_data)
def test_too_small_nb_players_by_game(self):
response: HttpResponse = self.client.post(self.url, {"nb_players_by_game": 1, "nb_players": self.nb_players})
response_data = json.loads(response.content)
self.assertDictEqual(response_data, {'nb_players_by_game': ['The numbers of players by game must be greather than 2.']})
def test_too_small_nb_players(self):
response: HttpResponse = self.client.post(self.url, {"nb_players_by_game": self.nb_players_by_game, "nb_players": 1})
response_data = json.loads(response.content)
self.assertDictEqual(response_data, {'nb_players': ['The numbers of players must be greather than 2.'], 'nb_players_by_game': ['The numbers of players by game must be smaller than the numbers of players.']})
def test_nb_players_smaller_nb_players_by_game(self):
response: HttpResponse = self.client.post(self.url, {"nb_players_by_game": 5, "nb_players": 3})
response_data = json.loads(response.content)
self.assertDictEqual(response_data, {'nb_players_by_game': ['The numbers of players by game must be smaller than the numbers of players.']})

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@ -1,11 +0,0 @@
from django.urls import path, re_path
from django.conf import settings
from django.conf.urls.static import static
from .viewset import TournamentViewSet
urlpatterns = [
path("<int:pk>", TournamentViewSet.as_view({"get": "retrieve"}), name="tournament_page"),
path("", TournamentViewSet.as_view({"post": "create"}), name="tournament_page"),
re_path(r"search/(?P<state>\w*)", TournamentViewSet.as_view({"get": "list", }), name="tournaments"),
]

View File

@ -1,56 +0,0 @@
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import permissions, status
from rest_framework.authentication import SessionAuthentication
from django.http import HttpRequest
from django.contrib.auth import login
from django.db.models import QuerySet
from .models import TournamentModel
from .serializers import TournamentSerializer
# Create your views here.
class TournamentViewSet(viewsets.ModelViewSet):
queryset = TournamentModel.objects.all
serializer_class = TournamentSerializer
permission_classes = (permissions.IsAuthenticated,)
authentication_classes = (SessionAuthentication,)
def perform_create(self, serializer: TournamentSerializer):
nb_players = serializer.validated_data["nb_players"]
nb_players_by_game = serializer.validated_data["nb_players_by_game"]
level = 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)
def list(self, request: HttpRequest, state: str = ""):
query: QuerySet
match state:
case "started":
query = TournamentModel.objects.filter(started=True, finished=False)
case "finished":
query = TournamentModel.objects.filter(finished=True)
case "waiting":
query = TournamentModel.objects.filter(started=False, finished=False)
case _:
query = TournamentModel.objects.all()
serializer = TournamentSerializer(query, many=True)
return Response(serializer.data)
def retrieve(self, request: HttpRequest, pk):
if (not TournamentModel.objects.filter(pk=pk).exists()):
return Response({"detail": "Tournament not found."}, status=status.HTTP_404_NOT_FOUND)
tournament = TournamentModel.objects.get(pk=pk)
return Response(self.serializer_class(tournament).data, status=status.HTTP_200_OK)

View File

@ -13,7 +13,6 @@ from channels.auth import AuthMiddlewareStack
import chat.routing import chat.routing
import matchmaking.routing import matchmaking.routing
import tournament.routing
from django.core.asgi import get_asgi_application from django.core.asgi import get_asgi_application
@ -24,8 +23,7 @@ application = ProtocolTypeRouter({
'websocket':AuthMiddlewareStack( 'websocket':AuthMiddlewareStack(
URLRouter( URLRouter(
chat.routing.websocket_urlpatterns + chat.routing.websocket_urlpatterns +
matchmaking.routing.websocket_urlpatterns + matchmaking.routing.websocket_urlpatterns
tournament.routing.websocket_urlpatterns
) )
) )
}) })

View File

@ -1,5 +1,5 @@
""" """
Django settings for transcendence project. Django settings for trancendence project.
Generated by 'django-admin startproject' using Django 4.2.6. Generated by 'django-admin startproject' using Django 4.2.6.
@ -43,7 +43,6 @@ INSTALLED_APPS = [
'channels', 'channels',
'daphne', 'daphne',
'tournament.apps.TournamentConfig',
'matchmaking.apps.MatchmakingConfig', 'matchmaking.apps.MatchmakingConfig',
'games.apps.GamesConfig', 'games.apps.GamesConfig',
'accounts.apps.AccountsConfig', 'accounts.apps.AccountsConfig',
@ -61,7 +60,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles', 'django.contrib.staticfiles',
] ]
ASGI_APPLICATION = 'transcendence.asgi.application' ASGI_APPLICATION = 'trancendence.asgi.application'
CHANNEL_LAYERS = { CHANNEL_LAYERS = {
'default' :{ 'default' :{
@ -81,7 +80,7 @@ MIDDLEWARE = [
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
] ]
ROOT_URLCONF = 'transcendence.urls' ROOT_URLCONF = 'trancendence.urls'
TEMPLATES = [ TEMPLATES = [
{ {
@ -99,7 +98,7 @@ TEMPLATES = [
}, },
] ]
WSGI_APPLICATION = 'transcendence.wsgi.application' WSGI_APPLICATION = 'trancendence.wsgi.application'
# Database # Database

View File

@ -22,6 +22,5 @@ urlpatterns = [
path('api/profiles/', include('profiles.urls')), path('api/profiles/', include('profiles.urls')),
path('api/accounts/', include('accounts.urls')), path('api/accounts/', include('accounts.urls')),
path('api/chat/', include('chat.urls')), path('api/chat/', include('chat.urls')),
path('api/tournaments/', include('tournament.urls')),
path('', include('frontend.urls')), path('', include('frontend.urls')),
] ]

View File

@ -1,51 +0,0 @@
from channels.generic.websocket import WebsocketConsumer
from .AbstractRoomMember import AbstractRoomMember
class AbstractRoom:
def __init__(self, room_manager):
self._member_list: [AbstractRoomMember] = []
self.room_manager = room_manager
def broadcast(self, detail: str, data: dict = {}):
for member in self._member_list:
member: AbstractRoomMember
member.send(detail, data)
def clear(self):
self._member_list.clear()
def get_member_by_socket(self, socket: WebsocketConsumer):
for member in self._member_list:
member: AbstractRoomMember
if (member.socket is socket):
return member
return None
def get_member_by_user_id(self, user_id: int):
for member in self._member_list:
member: AbstractRoomMember
if (member.user_id == user_id):
return member
return None
def append(self, member: AbstractRoomMember):
self._member_list.append(member)
member.accept()
def remove(self, member: AbstractRoomMember, code: int = 1000):
self._member_list.remove(member)
member.disconnect(code)
def empty(self):
for _ in self._member_list:
return False
return True
def get_users_id(self):
return [member.user_id for member in self._member_list]
def __len__(self):
return len(self._member_list)

View File

@ -1,12 +0,0 @@
from .AbstractRoom import AbstractRoom
class AbstractRoomManager:
def __init__(self):
self._room_list: [AbstractRoom] = []
def remove(self, room: AbstractRoom):
self._room_list.remove(room)
def append(self, room: AbstractRoom):
self._room_list.append(room)

View File

@ -1,20 +0,0 @@
from channels.generic.websocket import WebsocketConsumer
import json
class AbstractRoomMember:
def __init__(self, user_id: int, socket: WebsocketConsumer):
self.user_id: int = user_id
self.socket: WebsocketConsumer = socket
def send(self, detail: str, data: dict = {}):
raw_data: dict = {"detail": detail}
raw_data.update(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)