Compare commits
17 Commits
Chatte
...
8e0514514b
Author | SHA1 | Date | |
---|---|---|---|
8e0514514b | |||
0626faae7f | |||
5ba432e9fd | |||
789a83cb41 | |||
35cd728b3c | |||
be43e45947 | |||
9bdd07d59e | |||
9523ac4554 | |||
56cfd563d7 | |||
288252ab37 | |||
adf0c5ceed | |||
1032a8fd98 | |||
9714918de9 | |||
bfcfabb35a | |||
8ed9deab2d | |||
4f0b2250bd | |||
0e946b3bb8 |
@ -25,6 +25,7 @@ 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
|
||||||
|
@ -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._logged = false;
|
this.client._update_logged(false);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (response_data == "user deleted")
|
if (response_data == "user deleted")
|
||||||
|
@ -8,7 +8,7 @@ class MatchMaking
|
|||||||
constructor(client)
|
constructor(client)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @type {client}
|
* @type {Client}
|
||||||
*/
|
*/
|
||||||
this.client = client
|
this.client = client
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,10 @@ class Profile
|
|||||||
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;
|
||||||
|
@ -28,7 +28,8 @@ class Profiles
|
|||||||
async getProfile(user_id)
|
async getProfile(user_id)
|
||||||
{
|
{
|
||||||
let profile = new Profile(this.client);
|
let profile = new Profile(this.client);
|
||||||
await profile.init(user_id);
|
if (await profile.init(user_id))
|
||||||
|
return null;
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
frontend/static/js/api/tournament/tournament.js
Normal file
19
frontend/static/js/api/tournament/tournament.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { Client } from "./client.js";
|
||||||
|
|
||||||
|
class Tourmanent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param {Client} client
|
||||||
|
*/
|
||||||
|
constructor(client)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @type {Client}
|
||||||
|
*/
|
||||||
|
this.client = client
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Tourmanent }
|
33
frontend/static/js/api/tournament/tournaments.js
Normal file
33
frontend/static/js/api/tournament/tournaments.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { Client } from "./client.js";
|
||||||
|
|
||||||
|
class Tourmanents
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param {Client} client
|
||||||
|
*/
|
||||||
|
constructor(client)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @type {Client}
|
||||||
|
*/
|
||||||
|
this.client = client
|
||||||
|
}
|
||||||
|
|
||||||
|
async createTournament(nb_players, online)
|
||||||
|
{
|
||||||
|
if (online)
|
||||||
|
return "offline";
|
||||||
|
let response = await this.client._post("/api/tournaments/", {numbers_of_players: nb_players});
|
||||||
|
let response_data = await response.json();
|
||||||
|
|
||||||
|
if (JSON.stringify(response_data) === JSON.stringify({'detail': 'Authentication credentials were not provided.'}))
|
||||||
|
{
|
||||||
|
this.client._update_logged(false);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return response_data.tournament_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Tourmanents }
|
@ -35,6 +35,19 @@ 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 },
|
||||||
@ -80,14 +93,7 @@ const router = async (uri) => {
|
|||||||
lastView = view;
|
lastView = view;
|
||||||
|
|
||||||
await client.isAuthentificate();
|
await client.isAuthentificate();
|
||||||
let content = await view.getHtml();
|
renderView(view);
|
||||||
if (content == null)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
view.setTitle();
|
|
||||||
document.querySelector("#app").innerHTML = content
|
|
||||||
|
|
||||||
await view.postInit();
|
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,6 +10,10 @@ export default class extends AbstractView {
|
|||||||
async postInit()
|
async postInit()
|
||||||
{
|
{
|
||||||
let profile = await client.profiles.getProfile(this.user_id);
|
let profile = await client.profiles.getProfile(this.user_id);
|
||||||
|
|
||||||
|
if (profile === null)
|
||||||
|
return 1;
|
||||||
|
|
||||||
let info = document.getElementById("info");
|
let info = document.getElementById("info");
|
||||||
|
|
||||||
// Username
|
// Username
|
||||||
@ -18,7 +22,7 @@ export default class extends AbstractView {
|
|||||||
username.appendChild(document.createTextNode(profile.username));
|
username.appendChild(document.createTextNode(profile.username));
|
||||||
info.appendChild(username);
|
info.appendChild(username);
|
||||||
|
|
||||||
info.appendChild(document.createElement("br"));
|
info.appendChild(document.createElement("br"));
|
||||||
|
|
||||||
// Avatar
|
// Avatar
|
||||||
let avatar = document.createElement("img");
|
let avatar = document.createElement("img");
|
||||||
|
@ -2,12 +2,19 @@ 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)
|
||||||
|
started = models.BooleanField(default=False)
|
||||||
|
winner_id = models.IntegerField(null=True, blank=True)
|
||||||
|
|
||||||
def create(self, users_id: [int]):
|
def create(self, users_id: [int]):
|
||||||
self.save()
|
self.save()
|
||||||
for user_id in users_id:
|
for user_id in users_id:
|
||||||
GameMembersModel(game_id=self.pk, member_id=user_id)
|
GameMembersModel(game_id=self.pk, member_id=user_id).save()
|
||||||
return self.pk
|
return self.pk
|
||||||
|
|
||||||
|
def get_users(self):
|
||||||
|
return list(GameMembersModel.objects.filter(self.pk))
|
||||||
|
|
||||||
class GameMembersModel(models.Model):
|
class GameMembersModel(models.Model):
|
||||||
game_id = models.IntegerField()
|
game_id = models.IntegerField()
|
||||||
|
@ -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 = {"name": "bozo",
|
self.expected_response = {'avatar_url': '/static/avatars/default.avif', 'user_id': 1, 'username': '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):
|
||||||
|
@ -31,9 +31,6 @@ 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,)
|
||||||
|
0
tournament/__init__.py
Normal file
0
tournament/__init__.py
Normal file
3
tournament/admin.py
Normal file
3
tournament/admin.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
6
tournament/apps.py
Normal file
6
tournament/apps.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class TournamentConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'tournament'
|
36
tournament/models.py
Normal file
36
tournament/models.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
from games.models import GameModel
|
||||||
|
|
||||||
|
# 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, users_id):
|
||||||
|
game_id = GameModel.create(users_id=users_id)
|
||||||
|
TournamentGamesModel(game_id=game_id, tournament_id=self.pk).save()
|
||||||
|
return game_id
|
||||||
|
|
||||||
|
def get_games_id_by_level(self, level):
|
||||||
|
return list(TournamentGamesModel.objects.filter(tournament_id=self.pk, tournament_level=level))
|
||||||
|
|
||||||
|
def get_games_id(self):
|
||||||
|
return list(TournamentGamesModel.objects.filter(tournament_id=self.pk))
|
||||||
|
|
||||||
|
def get_players_id(self):
|
||||||
|
lst: [int] = []
|
||||||
|
for game_id in self.get_games_id():
|
||||||
|
lst.append(GameMembersModel.objects.filter(game_id=game_id))
|
||||||
|
return lst
|
||||||
|
|
||||||
|
class TournamentGamesModel(models.Model):
|
||||||
|
|
||||||
|
tournament_id = models.IntegerField()
|
||||||
|
tournament_level = models.IntegerField()
|
||||||
|
game_id = models.IntegerField()
|
38
tournament/serializers.py
Normal file
38
tournament/serializers.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
from .models import TournamentModel
|
||||||
|
|
||||||
|
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):
|
||||||
|
levels: [[int]] = []
|
||||||
|
for i in range(instance.level):
|
||||||
|
level: [int] = instance.get_games_id_by_level(i)
|
||||||
|
if (level == []):
|
||||||
|
break
|
||||||
|
levels.append(level)
|
||||||
|
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
|
44
tournament/test.py
Normal file
44
tournament/test.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
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.']})
|
3
tournament/tests.py
Normal file
3
tournament/tests.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
11
tournament/urls.py
Normal file
11
tournament/urls.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
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"),
|
||||||
|
]
|
57
tournament/viewset.py
Normal file
57
tournament/viewset.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
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 matchmaking.models import in_matchmaking
|
||||||
|
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)
|
@ -43,6 +43,7 @@ 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',
|
||||||
|
@ -22,5 +22,6 @@ 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')),
|
||||||
]
|
]
|
||||||
|
Reference in New Issue
Block a user