From 3f1a396975b08eedd3cdb604d9d8f8a87a7c4aea Mon Sep 17 00:00:00 2001 From: Xamora Date: Tue, 14 May 2024 03:30:42 +0200 Subject: [PATCH] merge --- chat/models.py | 8 ++ chat/serializers/ask.py | 10 +++ chat/{serializers.py => serializers/chat.py} | 3 +- chat/urls.py | 7 +- chat/views/ask.py | 78 ++++++++++++++++++++ chat/{views.py => views/chat.py} | 4 +- frontend/static/js/api/Notice.js | 6 +- frontend/static/js/views/ProfilePageView.js | 10 +-- frontend/static/js/views/Search.js | 59 +++++++++------ notice/consumers.py | 11 +++ 10 files changed, 161 insertions(+), 35 deletions(-) create mode 100644 chat/serializers/ask.py rename chat/{serializers.py => serializers/chat.py} (95%) create mode 100644 chat/views/ask.py rename chat/{views.py => views/chat.py} (93%) diff --git a/chat/models.py b/chat/models.py index a53d15c..3045bd0 100644 --- a/chat/models.py +++ b/chat/models.py @@ -30,3 +30,11 @@ class ChatMessageModel(models.Model): def __str__(self): return "author_id: " + str(self.author_id) + ", channel_id: " + str(self.channel_id) + ", content: " + self.content + +class AskModel(models.Model): + asker_id = IntegerField(primary_key=False) + asked_id = IntegerField(primary_key=False) + + # return if the asker ask the asked to play a game + def is_asked(self, asker_id, asked_id): + return AskModel.objects.get(asker_id=asker_id, asked_id=asked_id) != None diff --git a/chat/serializers/ask.py b/chat/serializers/ask.py new file mode 100644 index 0000000..5efeb57 --- /dev/null +++ b/chat/serializers/ask.py @@ -0,0 +1,10 @@ +from rest_framework import serializers + +from django.utils.translation import gettext as _ + +from profiles.models import ProfileModel +from ..models import ChatChannelModel, ChatMessageModel + +class AskSerializer(serializers.ModelSerializer): + + members_id = serializers.ListField(child=serializers.IntegerField()) diff --git a/chat/serializers.py b/chat/serializers/chat.py similarity index 95% rename from chat/serializers.py rename to chat/serializers/chat.py index b75b4ea..689547b 100644 --- a/chat/serializers.py +++ b/chat/serializers/chat.py @@ -3,8 +3,7 @@ from rest_framework import serializers from django.utils.translation import gettext as _ from profiles.models import ProfileModel -from .models import ChatChannelModel, ChatMessageModel - +from ..models import ChatChannelModel, ChatMessageModel class ChatChannelSerializer(serializers.ModelSerializer): diff --git a/chat/urls.py b/chat/urls.py index 4dce2f3..bc3d701 100644 --- a/chat/urls.py +++ b/chat/urls.py @@ -2,8 +2,11 @@ from django.urls import path from django.conf import settings from django.conf.urls.static import static -from . import views +from .views import chat +from .views import ask urlpatterns = [ - path("", views.ChannelView.as_view(), name="chats_page"), + path("", chat.ChannelView.as_view(), name="chats_page"), + path("ask/", ask.AskView.as_view(), name="chats_ask"), + path("ask/accept", ask.AskAccepteView.as_view(), name="chats_ask_accept"), ] diff --git a/chat/views/ask.py b/chat/views/ask.py new file mode 100644 index 0000000..19fe7f4 --- /dev/null +++ b/chat/views/ask.py @@ -0,0 +1,78 @@ +from rest_framework.views import APIView +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 django.core import serializers + +from chat.models import AskModel +from profiles.models import ProfileModel + +from ..serializers.ask import AskSerializer + +from notice.consumers import notice_manager + +from django.contrib.auth.models import User + +class AskView(APIView): + + serializer_class = AskSerializer + permission_classes = (permissions.IsAuthenticated,) + authentication_classes = (SessionAuthentication,) + + def post(self, request): + data : dict = request.data + if (data["asked"] == None): + return + + asker_id = request.user.pk + asked_id = data["asked"] + + if AskModel().is_asked(asker_id, asked_id): + return Response(status=status.HTTP_208_ALREADY_REPORTED) + + AskModel(asker_id=asker_id, asked_id=asked_id).save() + return Response(status=status.HTTP_201_CREATED) + + def delete(self, request): + data : dict = request.data + if (data["asker"] == None): + return + + asker_id = data["asker"] + asked_id = request.user.pk + + if not AskModel().is_asked(asker_id, asked_id): + return Response(status=status.HTTP_404_NOT_FOUND) + + asker = User.objects.filter(pk=asked_id)[0] + notice_manager.refuse_game(request.user, asker) + + AskModel(asker_id=asker_id, asked_id=asked_id).delete() + + return Response(status=status.HTTP_200_OK) + +class AskAccepteView(APIView): + + serializer_class = AskSerializer + permission_classes = (permissions.IsAuthenticated,) + authentication_classes = (SessionAuthentication,) + + def post(self, request): + data : dict = request.data + if (data["asker"] == None): + return + + asker_id = data["asker"] + asked_id = request.user.pk + + if not AskModel().is_asked(asker_id, asked_id): + return Response(status=status.HTTP_404_NOT_FOUND) + + notice_manager.accept_game(asker=User.objects.filter(pk=asker_id)[0], asked=User.objects.filter(pk=asked_id)[0]) + + AskModel(asker_id=asker_id, asked_id=asked_id).delete() + return Response(status=status.HTTP_200_OK) diff --git a/chat/views.py b/chat/views/chat.py similarity index 93% rename from chat/views.py rename to chat/views/chat.py index 4b73cbf..e9b49b2 100644 --- a/chat/views.py +++ b/chat/views/chat.py @@ -9,8 +9,8 @@ from django.db.models import QuerySet from django.core import serializers -from .models import ChatChannelModel, ChatMemberModel, ChatMessageModel -from .serializers import ChatChannelSerializer, ChatMessageSerializer +from ..models import ChatChannelModel, ChatMemberModel, ChatMessageModel +from ..serializers.chat import ChatChannelSerializer, ChatMessageSerializer class ChannelView(APIView): diff --git a/frontend/static/js/api/Notice.js b/frontend/static/js/api/Notice.js index 67b4b55..5b78ac9 100644 --- a/frontend/static/js/api/Notice.js +++ b/frontend/static/js/api/Notice.js @@ -2,6 +2,7 @@ import {Client} from './Client.js'; import {createNotification} from '../utils/noticeUtils.js' import { lastView } from '../index.js'; import ProfilePageView from '../views/ProfilePageView.js'; +import Search from '../views/Search.js'; export default class Notice { @@ -22,7 +23,7 @@ export default class Notice { this._socket.onclose = _ => this._socket = undefined; this._socket.onmessage = message => { const data = JSON.parse(message.data); - console.log(data) + //console.log(data) if (data.type === 'friend_request') { this.friend_request(data.author); @@ -52,6 +53,9 @@ export default class Notice { lastView.profile.online = status; lastView.loadFriendshipStatus(); } + else if (lastView instanceof Search) { + lastView.display_specific_user(user.id); + } } online(user) { diff --git a/frontend/static/js/views/ProfilePageView.js b/frontend/static/js/views/ProfilePageView.js index 41405c8..08a4bc6 100644 --- a/frontend/static/js/views/ProfilePageView.js +++ b/frontend/static/js/views/ProfilePageView.js @@ -18,8 +18,6 @@ export default class extends AbstractView { const games = await this.profile.getGameHistory(); - console.log(games) - await this.fillHistory(games); await this.fillStatistics(games); @@ -80,10 +78,10 @@ export default class extends AbstractView { */ async fillStatistics(games) { - const winrateDiv = document.getElementById("winrate"); + let winrateDiv = document.getElementById("winrate"); - const win = 0; - const lose = 0; + let win = 0; + let lose = 0; games.forEach(game => { if (game.finished === false) @@ -100,7 +98,7 @@ export default class extends AbstractView { async fillHistory(games) { - const game_list = document.getElementById("game-list"); + let game_list = document.getElementById("game-list"); games.forEach(game => { diff --git a/frontend/static/js/views/Search.js b/frontend/static/js/views/Search.js index fc69916..ebb9092 100644 --- a/frontend/static/js/views/Search.js +++ b/frontend/static/js/views/Search.js @@ -9,30 +9,30 @@ export default class extends AbstractView { async postInit() { - let logged = await client.isAuthenticated(); - let profiles = await client.profiles.all(); + this.logged = await client.isAuthenticated(); + this.profiles = await client.profiles.all(); let search = document.getElementById("input_user"); if (search != undefined) - search.oninput = () => this.display_users(logged, profiles); + search.oninput = () => this.display_users(); let chat_input = document.getElementById("input_chat"); this.last_add_chat = undefined; - this.display_users(logged, profiles); - this.display_chat(logged, profiles); + this.display_users(); + this.display_chat(); } - async display_users(logged, profiles) { + async display_users() { let search = document.getElementById("input_user").value.toLowerCase(); let list_users = document.getElementById('list_users'); list_users.innerHTML = ""; - 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) => { if (user.id == null) { console.log("list User one with id null;"); @@ -46,14 +46,14 @@ export default class extends AbstractView { username.setAttribute('data-link', ''); username.id = `username${user.id}`; username.href = `/profiles/${user.username}`; - if (logged && user.id == client.me.id) + if (this.logged && user.id == client.me.id) username.style.color = "green"; else { let profile = await client.profiles.getProfileId(user.id); let online = profile.online; if (online == undefined) username.style.color = "gray"; - if (online == true) + else if (online == true) username.style.color = "green"; else username.style.color = "red"; @@ -65,7 +65,7 @@ export default class extends AbstractView { new_user.appendChild(document.createTextNode(" ")); // button chat - if (logged && client.me.id != user.id) { + if (this.logged && client.me.id != user.id) { let add_chat = document.createElement("a"); add_chat.id = "add_chat_off"; add_chat.onclick = async () => { @@ -86,7 +86,7 @@ export default class extends AbstractView { await client.channels.channel.disconnect(); } client.channels.channel = await client.channels.createChannel([client.me.id , user.id], () => this.reload_display_messages()); - this.display_chat(logged, profiles); + this.display_chat(); if (this.last_add_chat != undefined) this.last_add_chat.id = "add_chat_off"; this.last_add_chat = add_chat; @@ -113,7 +113,27 @@ export default class extends AbstractView { } - async display_chat(logged, profiles) + async display_specific_user(id) { + + let user = document.getElementById("username" + id); + if (user == undefined) + return ; + + if (this.logged && id == client.me.id) + user.style.color = "green"; + else { + let profile = await client.profiles.getProfileId(id); + let online = profile.online; + if (online == undefined) + user.style.color = "gray"; + else if (online == true) + user.style.color = "green"; + else + user.style.color = "red"; + } + } + + async display_chat() { let reloads = ["members", "messages"]; reloads.forEach(reload => { @@ -121,7 +141,7 @@ export default class extends AbstractView { document.getElementById(reload).remove(); }); - if (client.channels.channel === undefined || logged === false) + if (client.channels.channel === undefined || this.logged === false) return ; let chats = document.getElementById("chats"); @@ -133,7 +153,7 @@ export default class extends AbstractView { } // nom des membres du channel - let members = await this.display_members(chat, profiles); + let members = await this.display_members(chat); // L'affiche des messages let messages = await this.display_messages(chat); @@ -157,7 +177,7 @@ export default class extends AbstractView { let receivers_id = []; members_id.forEach((member_id) => { if (member_id != client.me.id) - receivers_id.push(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); // Reset @@ -215,7 +235,7 @@ export default class extends AbstractView { messages.scrollTop = messages.scrollHeight; } - async display_members(chat, profiles) { + async display_members(chat) { let members_id = client.channels.channel.members_id; @@ -226,7 +246,7 @@ export default class extends AbstractView { if (member_id != client.me.id) { if (usernames.length > 0) usernames += ", "; - usernames += (profiles.filter(user => user.id == member_id)[0].username); + usernames += (this.profiles.filter(user => user.id == member_id)[0].username); } }); members.textContent = usernames; @@ -251,11 +271,6 @@ export default class extends AbstractView { let no = document.getElementById("no") || document.createElement("button"); let invitedBy; - for (let x in others) { - if (client.notice.data.invited.includes(others[x])) { - invitedBy = others[x]; - } - } if (invitedBy == undefined) { diff --git a/notice/consumers.py b/notice/consumers.py index 83b9ee6..b6a79bc 100644 --- a/notice/consumers.py +++ b/notice/consumers.py @@ -65,6 +65,17 @@ class NoticeManager: def notify_friend_removed(self, user: User, friend: ProfileModel): self.notify_user(user, {'type': 'friend_removed', 'friend': ProfileSerializer(friend).data}) + def ask_game(self, asker:User, asked: User): + self.notify_user(asker, {'type': 'game_asked', 'asker': ProfileSerializer(asked).data}) + + def ask_game_canceled(self, asker:User, asked: User): + self.notify_user(asker, {'type': 'game_canceled', 'asker': ProfileSerializer(asked).data}) + + def refuse_game(self, asked: User, asker: User): + self.notify_user(asked, {'type': 'game_refused', 'asker': ProfileSerializer(asker).data}) + + def accept_game(self, asked: User, asker: User): + self.notify_user(asked, {'type': 'game_accepted', 'asker': ProfileSerializer(asker).data}) notice_manager = NoticeManager()