2 Commits

Author SHA1 Message Date
4fd6616786 add block option 2023-12-20 23:48:52 +01:00
57ed6165ea bug issue; rewrite all messages 2023-12-19 12:42:46 +01:00
27 changed files with 161 additions and 256 deletions

View File

@ -25,7 +25,6 @@ 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,6 +2,7 @@ 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):
@ -34,6 +35,9 @@ 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"]
@ -46,9 +50,14 @@ class ChatConsumer(WebsocketConsumer):
if (self.channel_layer == None): if (self.channel_layer == None):
return return
print(message)
message_time : int = int(time.time() * 1000) message_time : int = int(time.time() * 1000)
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
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._update_logged(false); this.client._logged = false;
return null; return null;
} }
if (response_data == "user deleted") if (response_data == "user deleted")

View File

@ -54,13 +54,14 @@ class Channel {
return new_messages; return new_messages;
} }
async sendMessageChannel(message) { async sendMessageChannel(message, receivers_id) {
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,10 +35,11 @@ class Client
return this.logged; return this.logged;
} }
async _get(uri) async _get(uri, data)
{ {
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,8 +12,9 @@ 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)
@ -24,7 +25,21 @@ 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,13 +35,30 @@ class Profiles
async block(user_id) { async block(user_id) {
// blocker & blocked // blocker & blocked
let response = await this.client._post("/api/block/", let response = await this.client._post("/api/profiles/block", {
[this.client.me.user_id, user_id], users_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

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

View File

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

View File

@ -100,6 +100,7 @@ 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)
@ -135,7 +136,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[i] == null || message != messages.children[i].innerText) { if (messages.children[i] == null || message.content != 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)
@ -158,21 +159,25 @@ export default class extends AbstractView {
chat_input.maxLength=255; chat_input.maxLength=255;
chat.appendChild(chat_input); chat.appendChild(chat_input);
chat_input.addEventListener("keydown", async () => { chat_input.onkeydown = 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;
await client.channel.sendMessageChannel(chat_text) let receivers_id = [];
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,19 +2,12 @@ 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).save() GameMembersModel(game_id=self.pk, member_id=user_id)
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,6 +1,7 @@
from django.contrib import admin from django.contrib import admin
from .models import ProfileModel from .models import ProfileModel, BlockModel
# Register your models here. # Register your models here.
admin.site.register(ProfileModel) admin.site.register(ProfileModel)
admin.site.register(BlockModel)

View File

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

View File

View File

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

View File

@ -1,6 +0,0 @@
from django.apps import AppConfig
class TournamentConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'tournament'

View File

@ -1,49 +0,0 @@
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(self, nb_players: int, nb_players_by_game: int, name: str = ""):
self.level = 1
number: int = nb_players
while (number != nb_players_by_game):
number = number // 2 + (number % 2)
self.level += 1
self.nb_players = nb_players
self.nb_players_by_game = nb_players_by_game
self.name = name
self.save()
return self.pk
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()

View File

@ -1,19 +0,0 @@
from rest_framework import serializers
from .models import TournamentModel
class TournamentSerializer(serializers.ModelSerializer):
levels = serializers.SerializerMethodField()
class Meta:
model = TournamentModel
fields = ["name", "nb_players", "nb_players_by_game", "level", "started", "finished", "levels"]
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

View File

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

View File

@ -1,10 +0,0 @@
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", "post": "create"}), name="tournament_page"),
re_path(r"(<str:state>)?", TournamentViewSet.as_view({"get": "list"}), name="tournaments"),
]

View File

@ -1,59 +0,0 @@
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, request: HttpRequest):
data: dict = request.data
nb_players_by_game = data.get("nb_players_by_game")
if (nb_players_by_game is None):
return Response("nb_player_by_game is required.", status=status.HTTP_400_BAD_REQUEST)
nb_players = data.get("nb_players")
if (nb_players is None):
return Response("nb_players is required.", status=status.HTTP_400_BAD_REQUEST)
tournament_id: int = TournamentModel().create(nb_players=nb_players, nb_players_by_game=nb_players_by_game)
return Response({"tournament_id": tournament_id}, 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 "currently":
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,7 +43,6 @@ 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,6 +22,5 @@ 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')),
] ]