etienne apprend à coder pitié

This commit is contained in:
AdrienLSH 2024-05-14 08:16:21 +02:00
parent c4dc5b4e39
commit e2d56cff85
9 changed files with 126 additions and 170 deletions

View File

@ -1,40 +1,41 @@
from django.db import models from django.db.models import Model, IntegerField, ForeignKey, CharField, CASCADE
from django.db.models import IntegerField from django.db.models.signals import post_delete
from django.dispatch import receiver
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib import admin
# Create your models here.
class ChatChannelModel(models.Model):
def create(self, users_id: [int]): class ChatChannelModel(Model):
def create(self, members: [User]):
self.save() self.save()
for user_id in users_id: for member in members:
ChatMemberModel(channel_id = self.pk, member_id = user_id).save() ChatMemberModel(channel=self, member=member).save()
return self.pk return self
def get_members_id(self): def get_members(self):
return [member_channel.member_id for member_channel in ChatMemberModel.objects.filter(channel_id = self.pk)] return [member_channel.member for member_channel in ChatMemberModel.objects.filter(channel=self)]
class ChatMemberModel(models.Model):
member_id = IntegerField(primary_key=False)
channel_id = IntegerField(primary_key=False)
def __str__(self): class ChatMemberModel(Model):
return "member_id: " + str(self.member_id) + ", channel_id: " + str(self.channel_id) member = ForeignKey(User, on_delete=CASCADE)
channel = ForeignKey(ChatChannelModel, on_delete=CASCADE)
class ChatMessageModel(models.Model):
channel_id = IntegerField(primary_key=False) @receiver(post_delete, sender=ChatMemberModel)
author_id = IntegerField(primary_key=False) def delete_channel_when_member_deleted(sender, instance, **kwargs):
content = models.CharField(max_length=255) print(sender, instance)
class ChatMessageModel(Model):
channel = ForeignKey(ChatChannelModel, on_delete=CASCADE)
author = ForeignKey(User, on_delete=CASCADE)
content = CharField(max_length=255)
time = IntegerField(primary_key=False) time = IntegerField(primary_key=False)
def __str__(self):
return "author_id: " + str(self.author_id) + ", channel_id: " + str(self.channel_id) + ", content: " + self.content
class AskModel(models.Model): class AskModel(Model):
asker_id = IntegerField(primary_key=False) asker_id = IntegerField(primary_key=False)
asked_id = IntegerField(primary_key=False) asked_id = IntegerField(primary_key=False)
# return if the asker ask the asked to play a game # return if the asker ask the asked to play a game
def is_asked(self, asker_id, asked_id): def is_asked(self, asker_id, asked_id):
return AskModel.objects.get(asker_id=asker_id, asked_id=asked_id) != None return AskModel.objects.get(asker_id=asker_id, asked_id=asked_id) is not None

View File

@ -1,17 +1,19 @@
from rest_framework import serializers from rest_framework import serializers
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django.contrib.auth.models import User
from profiles.models import ProfileModel
from ..models import ChatChannelModel, ChatMessageModel from ..models import ChatChannelModel, ChatMessageModel
class ChatChannelSerializer(serializers.ModelSerializer): class ChatChannelSerializer(serializers.ModelSerializer):
members_id = serializers.ListField(child=serializers.IntegerField()) members_id = serializers.ListField(child=serializers.IntegerField(), required=True, write_only=True)
messages = serializers.SerializerMethodField()
class Meta: class Meta:
model = ChatChannelModel model = ChatChannelModel
fields = ["members_id", "pk"] fields = ["members_id", "id", 'messages']
def validate_members_id(self, value): def validate_members_id(self, value):
members_id: [int] = value members_id: [int] = value
@ -19,14 +21,20 @@ class ChatChannelSerializer(serializers.ModelSerializer):
raise serializers.ValidationError(_('There is not enough members to create the channel.')) raise serializers.ValidationError(_('There is not enough members to create the channel.'))
if len(set(members_id)) != len(members_id): if len(set(members_id)) != len(members_id):
raise serializers.ValidationError(_('Duplicate in members list.')) raise serializers.ValidationError(_('Duplicate in members list.'))
if self.context.get('user').pk not in members_id:
raise serializers.ValidationError(_('You are trying to create a group chat without you.'))
for member_id in members_id: for member_id in members_id:
if not ProfileModel.objects.filter(pk=member_id).exists(): if not User.objects.filter(pk=member_id).exists():
raise serializers.ValidationError(_(f"The profile {member_id} doesn't exist.")) raise serializers.ValidationError(_(f"The profile {member_id} doesn't exist."))
return members_id return members_id
def get_messages(self, obj: ChatChannelModel):
messages = ChatMessageModel.objects.filter(channel=obj).order_by('time')
return ChatMessageSerializer(messages, many=True).data
class ChatMessageSerializer(serializers.Serializer):
class ChatMessageSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = ChatMessageModel model = ChatMessageModel
fields = ["channel_id", "author_id", "content", "time"] fields = ["channel", "author", "content", "time"]

View File

@ -1,6 +1,4 @@
from django.urls import path from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from .views import chat from .views import chat
from .views import ask from .views import ask

View File

@ -1,48 +1,31 @@
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework import permissions, status from rest_framework import permissions
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
from django.http import HttpRequest from django.contrib.auth.models import User
from django.contrib.auth import login
from django.db.models import QuerySet
from django.core import serializers
from ..models import ChatChannelModel, ChatMemberModel
from ..serializers import ChatChannelSerializer
from ..models import ChatChannelModel, ChatMemberModel, ChatMessageModel
from ..serializers.chat import ChatChannelSerializer, ChatMessageSerializer
class ChannelView(APIView): class ChannelView(APIView):
queryset = ChatChannelModel.objects
serializer_class = ChatChannelSerializer serializer_class = ChatChannelSerializer
permission_classes = (permissions.IsAuthenticated,) permission_classes = (permissions.IsAuthenticated,)
authentication_classes = (SessionAuthentication,) authentication_classes = (SessionAuthentication,)
def post(self, request): def post(self, request):
serializer = self.serializer_class(data=request.data, context={'user': request.user})
serializer = self.serializer_class(data = request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
data: dict = serializer.validated_data members_id = serializer.validated_data.get('members_id')
member_list = [User.objects.get(pk=member_id) for member_id in members_id]
members_id = data.get("members_id") for member_channel in ChatMemberModel.objects.filter(member=member_list[0]):
if members_id == None: channel: ChatChannelModel = member_channel.channel
return Response({"detail": "members_id is None."}, status = status.HTTP_400_BAD_REQUEST) if set(channel.get_members()) == set(member_list):
break
if self.request.user.pk not in members_id: else:
return Response({"detail": "You are trying to create a chat group without you."}, status = status.HTTP_400_BAD_REQUEST) channel = ChatChannelModel().create(member_list)
return Response(self.serializer_class(channel).data)
for member_channel in ChatMemberModel.objects.filter(member_id = members_id[0]):
channel_id: int = member_channel.channel_id
if not ChatChannelModel.objects.filter(pk = channel_id).exists():
continue
channel: ChatChannelModel = ChatChannelModel.objects.get(pk = channel_id)
if set(channel.get_members_id()) == set(members_id):
messages = ChatMessageModel.objects.filter(channel_id = channel_id).order_by("time")
messages = serializers.serialize("json", messages)
return Response({'channel_id': channel_id, 'messages': messages}, status=status.HTTP_200_OK)
new_channel_id = ChatChannelModel().create(members_id)
return Response({'channel_id': new_channel_id}, status=status.HTTP_201_CREATED)

View File

@ -1,9 +1,15 @@
import { Account } from "./Account.js"; import { Account } from "./Account.js";
import { MatchMaking } from "./Matchmaking.js"; import { MatchMaking } from "./Matchmaking.js";
import { Profiles } from "./Profiles.js"; import { Profiles } from "./Profiles.js";
import { Channels } from './chat/Channels.js';
import { MyProfile } from "./MyProfile.js"; import { MyProfile } from "./MyProfile.js";
<<<<<<< Updated upstream
import { Channel } from "./chat/Channel.js"; import { Channel } from "./chat/Channel.js";
||||||| Stash base
import { Tourmanents } from "./tournament/Tournaments.js";
import { Channel } from "./chat/Channel.js";
=======
import { Tourmanents } from "./tournament/Tournaments.js";
>>>>>>> Stashed changes
import Notice from "./Notice.js"; import Notice from "./Notice.js";
import LanguageManager from './LanguageManager.js'; import LanguageManager from './LanguageManager.js';
@ -50,16 +56,6 @@ class Client
*/ */
this._logged = undefined; this._logged = undefined;
/**
* @type {Channels}
*/
this.channels = new Channels(this);
/**
* @type {Channel}
*/
this.channel = undefined;
/** /**
* @type {Notice} * @type {Notice}
*/ */

View File

@ -1,10 +1,10 @@
import {Message} from "./Message.js"; import {Message} from "./Message.js";
class Channel { class Channel {
constructor(client, channel_id, members_id, messages, reload) { constructor(client, channel, members, messages, reload) {
this.client = client; this.client = client;
this.channel_id = channel_id; this.channel = channel;
this.members_id = members_id; this.members = members;
this.messages = []; this.messages = [];
if (messages != undefined) if (messages != undefined)
this.updateMessages(messages); this.updateMessages(messages);
@ -13,16 +13,18 @@ class Channel {
} }
// reload = function to use when we receive a message // reload = function to use when we receive a message
async connect(reload) { connect(reload) {
let url = `${window.location.protocol[4] === 's' ? 'wss' : 'ws'}://${window.location.host}/ws/chat/${this.channel_id}`; const url = location.origin.replace('http', 'ws') +
'/ws/chat/' +
this.channel;
this.chatSocket = new WebSocket(url); this.chatSocket = new WebSocket(url);
this.chatSocket.onmessage = (event) =>{ this.chatSocket.onmessage = (event) =>{
let data = JSON.parse(event.data); let data = JSON.parse(event.data);
this.messages.push(new Message( this.messages.push(new Message(
this.channel_id, this.channel,
data.author_id, data.author,
data.content, data.content,
data.time, data.time,
)); ));
@ -31,28 +33,22 @@ class Channel {
}; };
} }
async disconnect() { disconnect() {
this.chatSocket.close(); this.chatSocket.close();
} }
updateMessages(messages) updateMessages(messages)
{ {
messages = JSON.parse(messages); this.messages = [];
let new_messages = [];
messages.forEach((message) => { messages.forEach((message) => {
message = message.fields; this.messages.push(new Message(
new_messages.push(new Message( message.channel,
message.channel_id, message.author,
message.author_id,
message.content, message.content,
message.time, message.time,
)); ));
}); });
//console.log(new_messages);
this.messages = new_messages;
return new_messages;
} }
async sendMessageChannel(message, receivers_id) { async sendMessageChannel(message, receivers_id) {
@ -65,19 +61,6 @@ class Channel {
'receivers_id':receivers_id, 'receivers_id':receivers_id,
})); }));
} }
async deleteChannel() {
let response = await this.client._delete("/api/chat/" + this.channel_id, {
});
let data = await response.json();
return data;
}
async sendInvite() {
}
} }
export {Channel}; export {Channel};

View File

@ -1,6 +1,6 @@
import {Channel} from "./Channel.js"; import {Channel} from "./Channel.js";
class Channels { export default class Channels {
constructor(client) { constructor(client) {
this.client = client; this.client = client;
this.channel = undefined; this.channel = undefined;
@ -8,32 +8,16 @@ class Channels {
async createChannel(members_id, reload) { async createChannel(members_id, reload) {
let response = await this.client._post("/api/chat/", { const response = await this.client._post("/api/chat/", {
members_id:members_id members_id:members_id
}); });
if (response.status >= 300) if (response.status >= 300)
return undefined; return undefined;
let data = await response.json(); const data = await response.json();
console.log(data)
let messages; this.channel = new Channel(this.client, data.id, members_id, data.messages, reload);
if (response.status == 200)
messages = data.messages;
this.channel = new Channel(this.client, data.channel_id, members_id, messages, reload);
return this.channel;
} }
async deleteChannel(members_id) {
let response = await this.client._delete("/api/chat/", {
members_id:members_id
});
let data = await response.json();
return data;
}
} }
export {Channels};

View File

@ -1,7 +1,7 @@
class Message { class Message {
constructor(channel_id, author_id, content, time) { constructor(channel, author, content, time) {
this.channel_id = channel_id; this.channel = channel;
this.author_id = author_id; this.author = author;
this.content = content; this.content = content;
this.time = time; this.time = time;
} }

View File

@ -1,35 +1,37 @@
import AbstractView from "./abstracts/AbstractView.js"; import AbstractView from "./abstracts/AbstractView.js";
import { client, lang } from "../index.js"; import { client, lang } from "../index.js";
import {Message} from "../api/chat/Message.js"; import Channels from '../api/chat/Channels.js'
export default class extends AbstractView { export default class extends AbstractView {
constructor(params) { constructor(params) {
super(params, 'SearchWindowTitle'); super(params, 'SearchWindowTitle');
this.channelManager = new Channels(client);
} }
async postInit() { async postInit() {
this.profiles = await client.profiles.all();
this.logged = await client.isAuthenticated();
this.logged = await client.isAuthenticated(); this.logged = await client.isAuthenticated();
this.profiles = await client.profiles.all(); this.profiles = await client.profiles.all();
document.getElementById('username-input').oninput = () => this.display_users(this.logged, this.profiles);
let search = document.getElementById("input_user"); let search = document.getElementById("input_user");
if (search != undefined) if (search != undefined)
search.oninput = () => this.display_users(); search.oninput = () => this.display_users();
let chat_input = document.getElementById("input_chat");
this.last_add_chat = undefined; this.last_add_chat = undefined;
this.display_users(); this.display_users();
this.display_chat(); this.display_chat();
} }
async display_users() { async display_users() {
let search = document.getElementById("input_user").value.toLowerCase(); const search = document.getElementById("username-input").value.toLowerCase();
let list_users = document.getElementById('list_users'); let list_users = document.getElementById('user-list');
list_users.innerHTML = ""; list_users.innerHTML = "";
this.profiles.filter(user => user.username.toLowerCase().startsWith(search) == true).forEach(async (user) => { this.profiles.filter(user => user.username.toLowerCase().startsWith(search) == true).forEach(async (user) => {
@ -69,23 +71,23 @@ export default class extends AbstractView {
let add_chat = document.createElement("a"); let add_chat = document.createElement("a");
add_chat.id = "add_chat_off"; add_chat.id = "add_chat_off";
add_chat.onclick = async () => { add_chat.onclick = async () => {
if (client.channels.channel != undefined) { if (this.channelManager.channel != undefined) {
// Permet de savoir si c'est le même channel // Permet de savoir si c'est le même channel
// Check to know if it's the same channel // Check to know if it's the same channel
client.channels.channel.members_id.forEach((member_id) => { this.channelManager.channel.members_id.forEach((member_id) => {
if (member_id == user.id) if (member_id == user.id)
client.channels.channel = undefined; this.channelManager.channel = undefined;
}); });
if (client.channels.channel == undefined) { if (this.channelManager.channel == undefined) {
add_chat.id = "add_chat_off"; add_chat.id = "add_chat_off";
this.last_add_chat = undefined; this.last_add_chat = undefined;
return await this.hide_chat(); return await this.hide_chat();
} }
await client.channels.channel.disconnect(); await this.channelManager.channel.disconnect();
} }
client.channels.channel = await client.channels.createChannel([client.me.id , user.id], () => this.reload_display_messages()); await this.channelManager.createChannel([client.me.id , user.id], () => this.reload_display_messages());
this.display_chat(); this.display_chat();
if (this.last_add_chat != undefined) if (this.last_add_chat != undefined)
this.last_add_chat.id = "add_chat_off"; this.last_add_chat.id = "add_chat_off";
@ -141,7 +143,7 @@ export default class extends AbstractView {
document.getElementById(reload).remove(); document.getElementById(reload).remove();
}); });
if (client.channels.channel === undefined || this.logged === false) if (this.channelManager.channel === undefined || this.logged === false)
return ; return ;
let chats = document.getElementById("chats"); let chats = document.getElementById("chats");
@ -159,19 +161,19 @@ export default class extends AbstractView {
let messages = await this.display_messages(chat); let messages = await this.display_messages(chat);
// Input pour rentrer un message // Input pour rentrer un message
let chat_input = document.getElementById("input_chat") || document.createElement("input"); let chat_input = document.getElementById("chat-input") || document.createElement("input");
chat_input.id="input_chat"; chat_input.id="chat_input";
chat_input.type="text"; chat_input.type="text";
chat_input.name="message"; chat_input.name="message";
chat_input.placeholder="message bozo"; chat_input.placeholder="message bozo";
chat_input.maxLength=255; chat_input.maxLength=255;
chat.appendChild(chat_input); chat.appendChild(chat_input);
let members_id = client.channels.channel.members_id; let members_id = this.channelManager.channel.members_id;
chat_input.onkeydown = async () => { chat_input.onkeydown = async () => {
if (event.keyCode == 13 && client.channels.channel != undefined) { if (event.keyCode == 13 && this.channelManager.channel != undefined) {
//let chat_input = document.getElementById("input_chat"); //let chat_input = document.getElementById("chat-input");
let chat_text = chat_input.value; let chat_text = chat_input.value;
let receivers_id = []; let receivers_id = [];
@ -179,7 +181,7 @@ export default class extends AbstractView {
if (member_id != client.me.id) if (member_id != client.me.id)
receivers_id.push(this.profiles.filter(user => user.id == member_id)[0].id); receivers_id.push(this.profiles.filter(user => user.id == member_id)[0].id);
}); });
await client.channels.channel.sendMessageChannel(chat_text, receivers_id); await this.channelManager.channel.sendMessageChannel(chat_text, receivers_id);
// Reset // Reset
chat_input.value = ""; chat_input.value = "";
} }
@ -190,7 +192,7 @@ export default class extends AbstractView {
// Scroll to the bottom of messages // Scroll to the bottom of messages
messages.scrollTop = messages.scrollHeight; messages.scrollTop = messages.scrollHeight;
this.display_invite(); // this.display_invite();
} }
@ -202,12 +204,13 @@ export default class extends AbstractView {
chat.appendChild(messages); chat.appendChild(messages);
// les messages, réecriture seulement du dernier // les messages, réecriture seulement du dernier
client.channels.channel.messages.forEach((message) => { this.channelManager.channel.messages.forEach((message) => {
let text = document.createElement("p"); let text = document.createElement("p");
let date = new Date(message.time); let date = new Date(message.time);
text.title = date.toLocaleString("fr-FR"); text.title = date.toLocaleString("fr-FR");
text.appendChild(document.createTextNode(message.content)); text.appendChild(document.createTextNode(message.content));
text.id = message.author_id === client.me.id ? "you" : "other"; console.log(message.author, client.me.id)
text.id = message.author === client.me.id ? "you" : "other";
messages.appendChild(text); messages.appendChild(text);
}); });
@ -219,13 +222,13 @@ export default class extends AbstractView {
let messages = document.getElementById("messages"); let messages = document.getElementById("messages");
let i = 0; let i = 0;
client.channels.channel.messages.forEach((message) => { this.channelManager.channel.messages.forEach((message) => {
if (messages.children[i] == null || message.content != 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");
let date = new Date(message.time); let date = new Date(message.time);
text.title = date.toLocaleString("fr-FR"); text.title = date.toLocaleString("fr-FR");
text.appendChild(document.createTextNode(message.content)); text.appendChild(document.createTextNode(message.content));
text.id = message.author_id === client.me.id ? "you" : "other"; text.id = message.author === client.me.id ? "you" : "other";
messages.appendChild(text); messages.appendChild(text);
} }
@ -237,7 +240,7 @@ export default class extends AbstractView {
async display_members(chat) { async display_members(chat) {
let members_id = client.channels.channel.members_id; let members_id = this.channelManager.channel.members_id;
let members = document.createElement("h2"); let members = document.createElement("h2");
members.id = "members"; members.id = "members";
@ -263,7 +266,7 @@ export default class extends AbstractView {
if (chat == undefined) if (chat == undefined)
return ; return ;
let members_id = client.channels.channel.members_id; let members_id = this.channelManager.channel.members_id;
let others = members_id.filter(id => id !== client.me.id); let others = members_id.filter(id => id !== client.me.id);
let invite = document.getElementById("invite") || document.createElement("button"); let invite = document.getElementById("invite") || document.createElement("button");
@ -325,9 +328,9 @@ export default class extends AbstractView {
} }
async leavePage() { async leavePage() {
if (client.channels.channel != undefined) if (this.channelManager.channel != undefined)
client.channels.channel.disconnect(); this.channelManager.channel.disconnect();
client.channels.channel = undefined; this.channelManager.channel = undefined;
} }
@ -337,8 +340,8 @@ export default class extends AbstractView {
<div id="chats"> <div id="chats">
<div id="users"> <div id="users">
<input id="input_user" type="text" name="message" placeholder="userbozo"/> <input id="username-input" type="text" name="message" placeholder="userbozo"/>
<ul id="list_users"> <ul id='user-list'>
</ul> </ul>
</div> </div>
</div> </div>