17 Commits

Author SHA1 Message Date
8e0514514b fix: check if profile existe befort render profile page 2023-12-21 00:05:54 +01:00
0626faae7f core: edit renderView engine
to display 404 error on not found page
2023-12-21 00:04:48 +01:00
5ba432e9fd add: default value to tournament.name 2023-12-20 22:49:48 +01:00
789a83cb41 add: test to tournament 2023-12-20 22:49:29 +01:00
35cd728b3c core: move tournament url 2023-12-20 22:49:18 +01:00
be43e45947 fix: profiles test 2023-12-20 22:37:44 +01:00
9bdd07d59e change tounament: viewset, serializer, models
simply the code and use django feat
2023-12-20 21:58:52 +01:00
9523ac4554 change url patern to tournament 2023-12-20 21:57:16 +01:00
56cfd563d7 fix: model, limite length of
tournament.name and winner_id can be null now
2023-12-20 21:11:37 +01:00
288252ab37 remove: useless function 2023-12-20 21:10:24 +01:00
adf0c5ceed core: change tournament api url 2023-12-20 21:10:12 +01:00
1032a8fd98 core: recreation of tournament view by using
queryset
2023-12-20 21:09:31 +01:00
9714918de9 Merge remote-tracking branch 'refs/remotes/origin/server' into server 2023-12-20 19:15:59 +01:00
bfcfabb35a init: tournament 2023-12-20 19:15:47 +01:00
8ed9deab2d add: attribute game state to gamemodel 2023-12-20 19:11:56 +01:00
4f0b2250bd fix 2023-12-20 19:10:26 +01:00
0e946b3bb8 fix: gameModel.create is not cringe now 2023-12-18 23:18:39 +01:00
23 changed files with 290 additions and 18 deletions

View File

@ -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

View File

@ -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")

View File

@ -8,7 +8,7 @@ class MatchMaking
constructor(client)
{
/**
* @type {client}
* @type {Client}
*/
this.client = client
}

View File

@ -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;

View File

@ -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;
}

View File

@ -0,0 +1,19 @@
import { Client } from "./client.js";
class Tourmanent
{
/**
* @param {Client} client
*/
constructor(client)
{
/**
* @type {Client}
*/
this.client = client
}
}
export { Tourmanent }

View 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 }

View File

@ -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;
};

View File

@ -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");

View File

@ -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()

View File

@ -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):

View File

@ -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
View File

3
tournament/admin.py Normal file
View File

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

6
tournament/apps.py Normal file
View 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
View 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
View 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
View 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
View File

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

11
tournament/urls.py Normal file
View 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
View 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)

View File

@ -43,6 +43,7 @@ INSTALLED_APPS = [
'channels',
'daphne',
'tournament.apps.TournamentConfig',
'matchmaking.apps.MatchmakingConfig',
'games.apps.GamesConfig',
'accounts.apps.AccountsConfig',

View File

@ -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')),
]