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 profiles
|
||||
python manage.py makemigrations chat
|
||||
python manage.py makemigrations tournament
|
||||
python manage.py migrate
|
||||
```
|
||||
- Start the developpement server
|
||||
|
@ -33,7 +33,7 @@ class Account
|
||||
|
||||
if (JSON.stringify(response_data) == JSON.stringify({'detail': 'Authentication credentials were not provided.'}))
|
||||
{
|
||||
this.client._logged = false;
|
||||
this.client._update_logged(false);
|
||||
return null;
|
||||
}
|
||||
if (response_data == "user deleted")
|
||||
|
@ -8,7 +8,7 @@ class MatchMaking
|
||||
constructor(client)
|
||||
{
|
||||
/**
|
||||
* @type {client}
|
||||
* @type {Client}
|
||||
*/
|
||||
this.client = client
|
||||
}
|
||||
|
@ -19,6 +19,10 @@ class Profile
|
||||
async init(user_id)
|
||||
{
|
||||
let response = await this.client._get(`/api/profiles/${user_id}`);
|
||||
|
||||
if (response.status === 404)
|
||||
return 1;
|
||||
|
||||
let response_data = await response.json();
|
||||
|
||||
this.user_id = response_data.user_id;
|
||||
|
@ -28,7 +28,8 @@ class Profiles
|
||||
async getProfile(user_id)
|
||||
{
|
||||
let profile = new Profile(this.client);
|
||||
await profile.init(user_id);
|
||||
if (await profile.init(user_id))
|
||||
return null;
|
||||
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);
|
||||
};
|
||||
|
||||
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 routes = [
|
||||
{ path: "/", view: Dashboard },
|
||||
@ -80,14 +93,7 @@ const router = async (uri) => {
|
||||
lastView = view;
|
||||
|
||||
await client.isAuthentificate();
|
||||
let content = await view.getHtml();
|
||||
if (content == null)
|
||||
return 1;
|
||||
|
||||
view.setTitle();
|
||||
document.querySelector("#app").innerHTML = content
|
||||
|
||||
await view.postInit();
|
||||
renderView(view);
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,10 @@ export default class extends AbstractView {
|
||||
async postInit()
|
||||
{
|
||||
let profile = await client.profiles.getProfile(this.user_id);
|
||||
|
||||
if (profile === null)
|
||||
return 1;
|
||||
|
||||
let info = document.getElementById("info");
|
||||
|
||||
// Username
|
||||
@ -18,7 +22,7 @@ export default class extends AbstractView {
|
||||
username.appendChild(document.createTextNode(profile.username));
|
||||
info.appendChild(username);
|
||||
|
||||
info.appendChild(document.createElement("br"));
|
||||
info.appendChild(document.createElement("br"));
|
||||
|
||||
// Avatar
|
||||
let avatar = document.createElement("img");
|
||||
|
@ -2,12 +2,19 @@ from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
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]):
|
||||
self.save()
|
||||
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
|
||||
|
||||
def get_users(self):
|
||||
return list(GameMembersModel.objects.filter(self.pk))
|
||||
|
||||
class GameMembersModel(models.Model):
|
||||
game_id = models.IntegerField()
|
||||
|
@ -7,8 +7,8 @@ class ProfileTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user: User = User.objects.create(username='bozo', password='password')
|
||||
self.user.save()
|
||||
self.expected_response = {"name": "bozo",
|
||||
"title": ""}
|
||||
self.expected_response = {'avatar_url': '/static/avatars/default.avif', 'user_id': 1, 'username': 'bozo'}
|
||||
|
||||
self.url = "/api/profiles/"
|
||||
|
||||
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:]
|
||||
return Response(serializer.data)
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(user=self.request.user)
|
||||
|
||||
class MyProfileViewSet(viewsets.ModelViewSet):
|
||||
|
||||
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',
|
||||
'daphne',
|
||||
|
||||
'tournament.apps.TournamentConfig',
|
||||
'matchmaking.apps.MatchmakingConfig',
|
||||
'games.apps.GamesConfig',
|
||||
'accounts.apps.AccountsConfig',
|
||||
|
@ -22,5 +22,6 @@ urlpatterns = [
|
||||
path('api/profiles/', include('profiles.urls')),
|
||||
path('api/accounts/', include('accounts.urls')),
|
||||
path('api/chat/', include('chat.urls')),
|
||||
path('api/tournaments/', include('tournament.urls')),
|
||||
path('', include('frontend.urls')),
|
||||
]
|
||||
|
Reference in New Issue
Block a user