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

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

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 = {"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):

View File

@ -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
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', 'channels',
'daphne', 'daphne',
'tournament.apps.TournamentConfig',
'matchmaking.apps.MatchmakingConfig', 'matchmaking.apps.MatchmakingConfig',
'games.apps.GamesConfig', 'games.apps.GamesConfig',
'accounts.apps.AccountsConfig', 'accounts.apps.AccountsConfig',

View File

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