11 Commits

Author SHA1 Message Date
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
27 changed files with 244 additions and 161 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

@ -2,7 +2,6 @@ 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):
@ -35,9 +34,6 @@ 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"]
@ -50,14 +46,9 @@ class ChatConsumer(WebsocketConsumer):
if (self.channel_layer == None): if (self.channel_layer == None):
return return
message_time : int = int(time.time() * 1000) print(message)
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
message_time : int = int(time.time() * 1000)
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

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

@ -54,14 +54,13 @@ class Channel {
return new_messages; return new_messages;
} }
async sendMessageChannel(message, receivers_id) { async sendMessageChannel(message) {
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

@ -35,11 +35,10 @@ class Client
return this.logged; return this.logged;
} }
async _get(uri, data) async _get(uri)
{ {
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;
} }

View File

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

View File

@ -12,9 +12,8 @@ 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)
@ -25,21 +24,7 @@ class Profile
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;
});
} }
} }
export {Profile} export {Profile}

View File

@ -35,30 +35,13 @@ class Profiles
async block(user_id) { async block(user_id) {
// blocker & blocked // blocker & blocked
let response = await this.client._post("/api/profiles/block", { let response = await this.client._post("/api/block/",
users_id:[this.client.me.user_id, user_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;
}
} }
export {Profiles} export {Profiles}

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

@ -9,47 +9,33 @@ export default class extends AbstractView {
async postInit() async postInit()
{ {
this.profile = await client.profiles.getProfile(this.user_id); let profile = await client.profiles.getProfile(this.user_id);
this.info = document.getElementById("info"); 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(this.profile.username)); username.appendChild(document.createTextNode(profile.username));
this.info.appendChild(username); info.appendChild(username);
this.info.appendChild(document.createElement("br")); 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 = this.profile.avatar_url; avatar.src = profile.avatar_url;
this.info.appendChild(avatar); info.appendChild(avatar);
await this.blockButton();
}
async blockButton() {
// Block option // Block option
if (client.me.user_id != this.user_id) { let block = document.createElement("a");
let block = document.getElementById("block") || document.createElement("a"); block.id = "block";
block.id = "block"; block.addEventListener("click", async () => {
block.innerText = ""; if (client.me.user_id != user.user_id) {
block.onclick = async () => { }
if (!this.profile.isBlocked) });
await client.profiles.block(this.user_id); block.appendChild(document.createTextNode("Block"));
else info.appendChild(block);
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"));
this.info.appendChild(block);
}
}
async getHtml() { async getHtml() {
return ` return `

View File

@ -100,7 +100,6 @@ 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)
@ -136,7 +135,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.children[i] == null || message.content != messages.children[i].innerText) { if (messages[i] == null || message != 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)
@ -159,25 +158,21 @@ export default class extends AbstractView {
chat_input.maxLength=255; chat_input.maxLength=255;
chat.appendChild(chat_input); chat.appendChild(chat_input);
chat_input.onkeydown = async () => { chat_input.addEventListener("keydown", 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;
let receivers_id = []; await client.channel.sendMessageChannel(chat_text)
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

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

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

View File

@ -9,7 +9,5 @@ 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.BlocksView.as_view(), name="block_page"), path("block", views.BlockView.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,65 +2,17 @@ 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):
block = BlockModel.objects.filter(pk=pk) pass
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):
class BlocksView(APIView): pass
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,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()

22
tournament/serializers.py Normal file
View File

@ -0,0 +1,22 @@
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()
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

3
tournament/tests.py Normal file
View File

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

10
tournament/urls.py Normal file
View File

@ -0,0 +1,10 @@
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"),
re_path(r"search/(?P<state>\w*)", TournamentViewSet.as_view({"get": "list", "post": "create"}), 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')),
] ]