diff --git a/frontend/static/js/api/Client.js b/frontend/static/js/api/Client.js index 5341b08..3732b9f 100644 --- a/frontend/static/js/api/Client.js +++ b/frontend/static/js/api/Client.js @@ -4,7 +4,7 @@ import { Profiles } from "./Profiles.js"; import { Channels } from './chat/Channels.js'; import { MyProfile } from "./MyProfile.js"; import { Tourmanents } from "./tournament/Tournaments.js"; -import { Notice } from "./chat/Notice.js"; +import Notice from "./notice/Notice.js"; import { Channel } from "./chat/Channel.js"; import LanguageManager from './LanguageManager.js'; @@ -83,7 +83,7 @@ class Client { if (this._logged == undefined) this._logged = await this._test_logged(); - return this._logged; + return this._logged; } /** @@ -217,7 +217,7 @@ class Client { this.me = new MyProfile(this); await this.me.init(); - this.notice.connect(); + this.notice.start(); document.getElementById('navbarLoggedOut').classList.add('d-none'); document.getElementById('navbarLoggedIn').classList.remove('d-none'); document.getElementById('navbarDropdownButton').innerHTML = this.me.username; @@ -226,7 +226,7 @@ class Client else { this.me = undefined; - this.notice.disconnect(); + this.notice.stop(); document.getElementById('navbarLoggedOut').classList.remove('d-none'); document.getElementById('navbarLoggedIn').classList.add('d-none'); document.getElementById('navbarDropdownButton').innerHTML = 'Me'; diff --git a/frontend/static/js/api/MyProfile.js b/frontend/static/js/api/MyProfile.js index ef2e694..17dd2df 100644 --- a/frontend/static/js/api/MyProfile.js +++ b/frontend/static/js/api/MyProfile.js @@ -40,26 +40,26 @@ class MyProfile extends Profile async getBlockedUsers() { const response = await this.client._get('/api/profiles/block'); const data = await response.json(); - data.forEach(profileData => this.blockedUsers.push(new Profile(this.client, profileData.username, profileData.user_id, profileData.avatar))); + data.forEach(profileData => this.blockedUsers.push(new Profile(this.client, profileData.username, profileData.id, profileData.avatar))); } async getFriends() { const response = await this.client._get('/api/profiles/friends'); const data = await response.json(); - data.forEach(profileData => this.friendList.push(new Profile(this.client, profileData.username, profileData.user_id, profileData.avatar))); + data.forEach(profileData => this.friendList.push(new Profile(this.client, profileData.username, profileData.id, profileData.avatar))); } async getIncomingFriendRequests() { const response = await this.client._get('/api/profiles/incoming_friend_requests'); const data = await response.json(); data.forEach(profileData => this.incomingFriendRequests.push( - new Profile(this.client, profileData.username, profileData.user_id, profileData.avatar) + new Profile(this.client, profileData.username, profileData.id, profileData.avatar) )); } async getOutgoingFriendRequests() { const response = await this.client._get('/api/profiles/outgoing_friend_requests'); const data = await response.json(); data.forEach(profileData => this.outgoingFriendRequests.push( - new Profile(this.client, profileData.username, profileData.user_id, profileData.avatar) + new Profile(this.client, profileData.username, profileData.id, profileData.avatar) )); } diff --git a/frontend/static/js/api/Profile.js b/frontend/static/js/api/Profile.js index feb9570..a1e553d 100644 --- a/frontend/static/js/api/Profile.js +++ b/frontend/static/js/api/Profile.js @@ -55,17 +55,17 @@ export class Profile extends AExchangeable return response.status; let response_data = await response.json(); - this.id = response_data.user_id; + this.id = response_data.id; this.username = response_data.username; this.avatar = response_data.avatar; if (!this.client.me || this.client.me.id === this.id) return; - this.isFriend = this.client.me._isFriend(this); this.isBlocked = this.client.me._isBlocked(this); this.hasIncomingRequest = this.client.me._hasIncomingRequestFrom(this); this.hasOutgoingRequest = this.client.me._hasOutgoingRequestTo(this); + this.isFriend = this.client.me._isFriend(this); } /** diff --git a/frontend/static/js/api/Profiles.js b/frontend/static/js/api/Profiles.js index 796abc7..04d1666 100644 --- a/frontend/static/js/api/Profiles.js +++ b/frontend/static/js/api/Profiles.js @@ -24,7 +24,7 @@ class Profiles let profiles = []; response_data.forEach((profile) => { - profiles.push(new Profile(this.client, profile.username, profile.user_id, profile.avatar)); + profiles.push(new Profile(this.client, profile.username, profile.id, profile.avatar)); }); return profiles; } diff --git a/frontend/static/js/api/chat/Notice.js b/frontend/static/js/api/chat/Notice.js deleted file mode 100644 index 9448e2a..0000000 --- a/frontend/static/js/api/chat/Notice.js +++ /dev/null @@ -1,308 +0,0 @@ -import { navigateTo } from "../../index.js"; -import {createNotification} from "../../utils/noticeUtils.js"; - -class Notice { - constructor(client) { - this.client = client; - this.data = {}; - - // users online, invited by ..., asked by ..., asker to ... - let data_variable = ["online", "invited", "asked", "asker"]; - for (let i in data_variable) - this.data[data_variable[i]] = []; - - //this.connect(); - - } - - async connect() { - return - let url = `${window.location.protocol[4] === 's' ? 'wss' : 'ws'}://${window.location.host}/ws/chat/notice`; - - this.chatSocket = new WebSocket(url); - this.chatSocket.onmessage = (event) =>{ - let send = JSON.parse(event.data); - //console.log("notice: ", send); - - try { - this["receive_" + send.type](send); - } - catch (error) { - console.log("receive_" + send.type + ": Function not found"); - } - - }; - this.chatSocket.onopen = (event) => { - this.getOnlineUser(); - this.ask_friend(); - }; - } - - async disconnect() { - if (this.chatSocket == undefined) - return ; - - this.chatSocket.close(); - } - - async reconnect() { - this.disconnect(); - this.connect(); - } - - async accept_invite(invitedBy) { - - this.sendRequest({ - type: "accept_invite", - targets: [invitedBy], - }); - - } - - async receive_accept_invite(send) { - - this.data.invited = send.invites; - let id_game = send.id_game; - navigateTo("/game/" + id_game); - - } - - async refuse_invite(invitedBy) { - - this.sendRequest({ - type: "refuse_invite", - targets: [invitedBy], - }); - - - } - async receive_refuse_invite(send) { - - this.data.invited = send.invites; - - if (send.author_id == this.client.me.id) { - if (this.rewrite_invite !== undefined) - this.rewrite_invite(); - } - else { - let sender = await this.client.profiles.getProfileId(send.author_id); - createNotification(sender.username + " refuse your invitation"); - } - - } - - - async send_invite(id_inviteds) { - - this.sendRequest({ - type: "invite", - targets: id_inviteds, - time: new Date().getTime(), - }); - - } - - async receive_invite(send) { - - if (this.client.me == undefined) - return ; - - let content = send.invites; - - if (send.author_id == this.client.me.id) { - if (send.status == 200) { - for (let target in send.targets) - return createNotification("Invitation send"); - } - else if (send.status == 444) - return createNotification("User not connected"); - else if (send.status == 409) - return createNotification("Already invited"); - } - else { - - // Regarder qu'il est bien invité par l'auteur - // Et qu'il n'est pas déjà invité - if (!content.includes(send.author_id) || - this.data.invited.includes(send.author_id)) - return; - - this.data.invited = content; - let sender = await this.client.profiles.getProfileId(send.author_id); - - createNotification("Invitation received by " + sender.username); - - if (this.rewrite_invite !== undefined) - this.rewrite_invite(); - } - } - - async getOnlineUser() { - - this.online_users = {}; - - this.sendRequest({ - type: "online_users", - targets: [], - time: new Date().getTime(), - }); - - } - - async receive_online_users(send) { - let content = send.online; - if (content !== undefined) { - - if (this.data.online.length > 0) { - // get all disconnect user - //let disconnects = this.data["online"].filter(id => !Object.keys(content).includes(id)); - - let disconnects = []; - - for (const [key, value] of Object.entries(this.data.online)) { - if (content[key] == "red" && value == "green") - disconnects.push(key); - } - - // delete invite - this.data.invited = this.data.invited.filter(id => !disconnects.includes(id)); - - //console.log(this.data["invited"]); - } - - this.data.online = content; - - if (this.rewrite_usernames !== undefined) - this.rewrite_usernames(); - } - } - - async ask_friend(user_id=undefined) { - this.sendRequest({ - type: "ask_friend", - targets: [user_id], - time: new Date().getTime(), - }); - } - - async receive_ask_friend(send) { - - let my_id = (this.client.me && this.client.me.id) || send.author_id; - if (send.author_id == my_id) { - if (send.status == 400) - createNotification("Friend ask error"); - else if (send.status == 409) - createNotification("Already asked friend"); - } - - //if (!send.asked.includes(send.author_id) || - //this.data["asked"].includes(send.author_id)) - //return; - - //if (!send.asker.includes(send.author_id) || - //this.data["asker"].includes(send.author_id)) - //return; - - this.data.asked = send.asked; - this.data.asker = send.asker; - - if (send.author_id != my_id) { - let sender = await this.client.profiles.getProfileId(send.author_id); - if (this.data.asker.includes(send.author_id)) - createNotification(sender.username + " ask you as friend"); - if (this.rewrite_profile !== undefined) - await this.rewrite_profile(); - } - - } - - async remove_friend(user_id) { - this.sendRequest({ - type: "remove_friend", - targets: [user_id], - time: new Date().getTime(), - }); - } - - async receive_remove_friend(send) { - - if (send.author_id == this.client.me.id) { - if (send.status == 400) - createNotification("Error remove Friend"); - else if (send.status == 409) - createNotification("Not friend, wtf"); - - } - - if (this.rewrite_profile !== undefined) - await this.rewrite_profile(); - - this.receive_online_users(send); - } - - async accept_friend(user_id) { - this.sendRequest({ - type: "accept_friend", - targets: [user_id], - time: new Date().getTime(), - }); - } - - async receive_accept_friend(send) { - this.data.asked = send.asked; - this.data.asker = send.asker; - let sender = await this.client.profiles.getProfileId(send.author_id); - - if (send.author_id == this.client.me.id) { - if (send.status == 400) - createNotification("Error accept Friend"); - else if (send.status == 404) - createNotification("Not found request Friend"); - else if (send.status == 409) - createNotification("Already Friend, wtf"); - } - else { - createNotification(sender.username + " accept your friend request"); - } - - if (this.rewrite_profile !== undefined) - await this.rewrite_profile(); - - this.receive_online_users(send); - } - - async refuse_friend(user_id) { - this.sendRequest({ - type: "refuse_friend", - targets: [user_id], - time: new Date().getTime(), - }); - } - - async receive_refuse_friend(send) { - this.data.asked = send.asked; - this.data.asker = send.asker; - let sender = await this.client.profiles.getProfileId(send.author_id); - - if (send.author_id == this.client.me.id) { - if (send.status == 400) - createNotification("Error refuse Friend"); - else if (send.status == 404) - createNotification("Not found request Friend"); - else if (send.status == 409) - createNotification("Already Friend, WTF"); - - } - if (this.rewrite_profile !== undefined) - await this.rewrite_profile(); - } - - async sendRequest(content) { - if (this.chatSocket == undefined) - return; - - this.chatSocket.send(JSON.stringify(content)); - } -} - -export {Notice}; diff --git a/frontend/static/js/api/notice/Notice.js b/frontend/static/js/api/notice/Notice.js new file mode 100644 index 0000000..e2407e4 --- /dev/null +++ b/frontend/static/js/api/notice/Notice.js @@ -0,0 +1,83 @@ +import {Client} from '../Client.js'; +import {createNotification} from '../../utils/noticeUtils.js' +import { client, lastView } from '../../index.js'; +import { Profile } from '../Profile.js'; +import ProfilePageView from '../../views/ProfilePageView.js'; + +export default class Notice { + + /** + * @param {Client} client + */ + constructor(client) { + /** + * @type {Client} + */ + this.client = client; + this.url = location.origin.replace('http', 'ws') + '/ws/notice'; + } + + start() { + this._socket = new WebSocket(this.url); + + this._socket.onclose = _ => this._socket = undefined; + this._socket.onmessage = message => { + const data = JSON.parse(message.data); + console.log(data) + + if (data.type === 'friend_request') { + this.friend_request(data.author); + } else if (data.type === 'new_friend') { + this.new_friend(data.friend); + } else if (data.type === 'friend_removed') { + this.friend_removed(data.friend); + } else if (data.type === 'friend_request_canceled') { + this.friend_request_canceled(data.author); + } + }; + } + + stop() { + if (this._socket) { + this._socket.close(); + this._socket = undefined; + } + } + + friend_request(author) { + console.log('hey') + client.me.incomingFriendRequests.push(new Profile(author.username, author.id, author.avatar)); + createNotification('Friend Request', `${author.username} sent you a friend request.`); + if (lastView instanceof ProfilePageView && lastView.profile.id === author.id) { + lastView.profile.hasIncomingRequest = true; + lastView.loadFriendshipStatus(); + } + } + + new_friend(friend) { + client.me.friendList.push(new Profile(friend.username, friend.id, friend.avatar)); + createNotification('New Friend', `${friend.username} accepted your friend request.`); + if (lastView instanceof ProfilePageView && lastView.profile.id === friend.id) { + lastView.profile.isFriend = true; + lastView.profile.hasIncomingRequest = false; + lastView.profile.hasOutgoingRequest = false; + lastView.loadFriendshipStatus(); + } + } + + friend_removed(exFriend) { + client.me.friendList = client.me.friendList.filter(friend => friend.id !== exFriend.id); + if (lastView instanceof ProfilePageView && lastView.profile.id === exFriend.id) { + lastView.profile.isFriend = false; + lastView.loadFriendshipStatus(); + } + } + + friend_request_canceled(author) { + client.me.incomingFriendRequests = client.me.incomingFriendRequests.filter(user => user.id !== author.id); + if (lastView instanceof ProfilePageView && lastView.profile.id === author.id) { + lastView.profile.hasIncomingRequest = false; + lastView.loadFriendshipStatus(); + } + } +} diff --git a/frontend/static/js/index.js b/frontend/static/js/index.js index 81a72fe..8b5c5e0 100644 --- a/frontend/static/js/index.js +++ b/frontend/static/js/index.js @@ -167,4 +167,4 @@ document.addEventListener("DOMContentLoaded", async () => { document.querySelector('a[href=\'' + location.pathname + '\']')?.classList.add('active'); }); -export { client, lang, navigateTo, reloadView }; +export { client, lang, lastView, navigateTo, reloadView }; diff --git a/frontend/static/js/utils/noticeUtils.js b/frontend/static/js/utils/noticeUtils.js index b604de1..f5e1eb7 100644 --- a/frontend/static/js/utils/noticeUtils.js +++ b/frontend/static/js/utils/noticeUtils.js @@ -1,22 +1,15 @@ -export function createNotification(text, timer = 3000) { +export function createNotification(title = 'New notification', content, delay = 3000) { - if (!createNotification.templateToast) { - createNotification.templateToast = new DOMParser().parseFromString(` - - `, 'text/html') - .querySelector('body') - .firstChild; - } - - const toastElement = createNotification.templateToast.cloneNode(true); - toastElement.getElementsByClassName('toast-body')[0].innerHTML = text; + const toastElement = document.createElement('div'); + toastElement.classList.add('toast'); + toastElement.role = 'alert'; + toastElement.setAttribute('data-bs-delay', delay); + toastElement.innerHTML = + `
+ ${title} + +
+
${content}
` toastElement.addEventListener('hidden.bs.toast', e => e.target.remove()); new bootstrap.Toast(toastElement).show(); diff --git a/frontend/static/js/views/ProfilePageView.js b/frontend/static/js/views/ProfilePageView.js index 65e94fa..63a2168 100644 --- a/frontend/static/js/views/ProfilePageView.js +++ b/frontend/static/js/views/ProfilePageView.js @@ -16,23 +16,15 @@ export default class extends AbstractView { if (!this.profile) return 404; + if (this.profile.id === client.me.id) + return; + const addFriendButton = document.getElementById('addFriendButton'), removeFriendButton = document.getElementById('removeFriendButton'), blockButton = document.getElementById('blockButton'), unblockButton = document.getElementById('unblockButton'); - if (this.profile.hasIncomingRequest) { - addFriendButton.classList.remove('d-none'); - addFriendButton.innerHTML = 'Accept Request'; - } else if (this.profile.hasOutgoingRequest) { - removeFriendButton.classList.remove('d-none'); - removeFriendButton.classList.replace('btn-danger', 'btn-secondary'); - removeFriendButton.innerHTML = 'Cancel Request' - } else if (this.profile.isFriend) - removeFriendButton.classList.remove('d-none'); - else - addFriendButton.classList.remove('d-none'); - + this.loadFriendshipStatus(); if (this.profile.isBlocked) unblockButton.classList.remove('d-none'); else @@ -44,6 +36,31 @@ export default class extends AbstractView { blockButton.onclick = _ => this.blockUser(); } + loadFriendshipStatus() { + const addFriendButton = document.getElementById('addFriendButton'), + removeFriendButton = document.getElementById('removeFriendButton'); + + if (this.profile.hasIncomingRequest) { + removeFriendButton.classList.add('d-none'); + addFriendButton.classList.remove('d-none'); + addFriendButton.innerHTML = 'Accept Request'; + } else if (this.profile.hasOutgoingRequest) { + addFriendButton.classList.add('d-none'); + removeFriendButton.classList.remove('d-none'); + removeFriendButton.classList.replace('btn-danger', 'btn-secondary'); + removeFriendButton.innerHTML = 'Cancel Request'; + } else if (this.profile.isFriend) { + addFriendButton.classList.add('d-none'); + removeFriendButton.classList.remove('d-none'); + removeFriendButton.classList.replace('btn-secondary', 'btn-danger'); + removeFriendButton.innerHTML = 'Remove Friend'; + } else { + addFriendButton.innerHTML = 'Add Friend'; + removeFriendButton.classList.add('d-none'); + addFriendButton.classList.remove('d-none'); + } + } + async getHtml() { this.profile = await client.profiles.getProfile(this.username); diff --git a/frontend/static/js/views/accounts/LogoutView.js b/frontend/static/js/views/accounts/LogoutView.js index 18360a3..933dcb5 100644 --- a/frontend/static/js/views/accounts/LogoutView.js +++ b/frontend/static/js/views/accounts/LogoutView.js @@ -10,7 +10,6 @@ export default class extends AbstractAuthenticatedView async postInit() { await client.logout(); - await client.notice.disconnect(); navigateTo(this.lastPageUrl); } } diff --git a/frontend/templates/index.html b/frontend/templates/index.html index 8c9b1f5..96aeaa1 100644 --- a/frontend/templates/index.html +++ b/frontend/templates/index.html @@ -45,9 +45,8 @@ +
-
-
diff --git a/games/serializers.py b/games/serializers.py index b0338bb..746b02d 100644 --- a/games/serializers.py +++ b/games/serializers.py @@ -4,7 +4,7 @@ from django.contrib.auth.models import User from django.db.models import QuerySet from .models import GameModel -from profiles.serializers.ProfileSerializer import ProfileSerializer +from profiles.serializers import ProfileSerializer class GameSerializer(serializers.ModelSerializer): @@ -29,4 +29,4 @@ class GameSerializer(serializers.ModelSerializer): return "waiting" def get_players(self, instance: GameModel): - return ProfileSerializer(instance.get_players_profiles(), many=True).data \ No newline at end of file + return ProfileSerializer(instance.get_players_profiles(), many=True).data diff --git a/notice/__init__.py b/notice/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/notice/admin.py b/notice/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/notice/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/notice/apps.py b/notice/apps.py new file mode 100644 index 0000000..f945881 --- /dev/null +++ b/notice/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class NoticeConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'notice' diff --git a/notice/consumers.py b/notice/consumers.py new file mode 100644 index 0000000..02aca83 --- /dev/null +++ b/notice/consumers.py @@ -0,0 +1,68 @@ +from __future__ import annotations +import json + +from channels.generic.websocket import WebsocketConsumer +from django.contrib.auth.models import User + +from profiles.serializers import ProfileSerializer +from profiles.models import ProfileModel +from .models import NoticeModel + + +class NoticeManager: + def __init__(self): + self._list: list[NoticeConsumer] = [] + + def add(self, consumer: NoticeConsumer): + self._list.append(consumer) + + unsend_notices = NoticeModel.objects.filter(user=consumer.user) + for notice in unsend_notices: + self.notify_user(consumer.user, json_data=notice.data) + notice.delete() + + def remove(self, consumer: NoticeConsumer): + self._list.remove(consumer) + + def get_consumer_by_user(self, user: User): + for consumer in self._list: + if consumer.user == user: + return consumer + + def notify_user(self, user: User, data: dict = None, json_data: str = None): + consumer = self.get_consumer_by_user(user) + data_str: str = json.dumps(data) if json_data is None else json_data + if consumer: + consumer.send(data_str) + else: + NoticeModel(user=user, data=data_str).save() + + def notify_friend_request(self, user: User, friend: ProfileModel): + self.notify_user(user, {'type': 'friend_request', 'author': ProfileSerializer(friend).data}) + + def notify_friend_request_canceled(self, user: User, friend: ProfileModel): + self.notify_user(user, {'type': 'friend_request_canceled', 'author': ProfileSerializer(friend).data}) + + def notify_new_friend(self, user: User, friend: ProfileModel): + self.notify_user(user, {'type': 'new_friend', 'friend': ProfileSerializer(friend).data}) + + def notify_friend_removed(self, user: User, friend: ProfileModel): + self.notify_user(user, {'type': 'friend_removed', 'friend': ProfileSerializer(friend).data}) + + +notice_manager = NoticeManager() + + +class NoticeConsumer(WebsocketConsumer): + def connect(self): + self.user: User = self.scope['user'] + if not self.user.is_authenticated: + self.close() + return + + self.accept() + notice_manager.add(self) + + def disconnect(self, code): + notice_manager.remove(self) + super().disconnect(code) diff --git a/notice/models.py b/notice/models.py new file mode 100644 index 0000000..cf26f6a --- /dev/null +++ b/notice/models.py @@ -0,0 +1,7 @@ +from django.db.models import Model, ForeignKey, CharField, CASCADE +from django.contrib.auth.models import User + + +class NoticeModel(Model): + user = ForeignKey(User, on_delete=CASCADE) + data = CharField(max_length=100) diff --git a/notice/routing.py b/notice/routing.py new file mode 100644 index 0000000..2e3460a --- /dev/null +++ b/notice/routing.py @@ -0,0 +1,7 @@ +from django.urls import re_path + +from .consumers import NoticeConsumer + +websocket_urlpatterns = [ + re_path(r'ws/notice$', NoticeConsumer.as_asgi()), +] diff --git a/notice/tests.py b/notice/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/notice/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/notice/views.py b/notice/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/notice/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/profiles/serializers/ProfileSerializer.py b/profiles/serializers.py similarity index 90% rename from profiles/serializers/ProfileSerializer.py rename to profiles/serializers.py index fffa21e..972c3d8 100644 --- a/profiles/serializers/ProfileSerializer.py +++ b/profiles/serializers.py @@ -3,7 +3,7 @@ from django.utils.translation import gettext as _ from rest_framework import serializers -from ..models import ProfileModel +from .models import ProfileModel class ProfileSerializer(serializers.ModelSerializer): @@ -13,7 +13,7 @@ class ProfileSerializer(serializers.ModelSerializer): class Meta: model = ProfileModel - fields = ["username", "avatar", "user_id"] + fields = ["username", "avatar", "id"] def validate_avatar(self, value): ''' diff --git a/profiles/views/blocks.py b/profiles/views/blocks.py index 6907f1c..4d37471 100644 --- a/profiles/views/blocks.py +++ b/profiles/views/blocks.py @@ -8,7 +8,7 @@ from django.utils.translation import gettext as _ from django.shortcuts import get_object_or_404 from ..models import BlockModel, ProfileModel -from ..serializers.ProfileSerializer import ProfileSerializer +from ..serializers import ProfileSerializer class GetBlocksView(APIView): diff --git a/profiles/views/friends.py b/profiles/views/friends.py index 125b061..a2ea4f9 100644 --- a/profiles/views/friends.py +++ b/profiles/views/friends.py @@ -7,7 +7,8 @@ from django.utils.translation import gettext as _ from django.shortcuts import get_object_or_404 from ..models import ProfileModel, FriendRequestModel -from ..serializers.ProfileSerializer import ProfileSerializer +from ..serializers import ProfileSerializer +from notice.consumers import notice_manager class GetFriendsView(APIView): @@ -41,9 +42,11 @@ class EditFriendView(APIView): incoming_request = user_profile.get_received_friend_request_from(friend_profile) if incoming_request: incoming_request.accept() - return Response(_('Friendship succssfully created.'), status.HTTP_201_CREATED) + notice_manager.notify_new_friend(friend_profile.user, user_profile) + return Response(_('Friendship successfully created.'), status.HTTP_201_CREATED) FriendRequestModel(author=user_profile, target=friend_profile).save() + notice_manager.notify_friend_request(friend_profile.user, user_profile) return Response(_('Friend request sent.'), status.HTTP_200_OK) def delete(self, request, pk=None): @@ -53,13 +56,15 @@ class EditFriendView(APIView): outgoing_request = user_profile.get_outgoing_friend_request_to(friend_profile) if outgoing_request: outgoing_request.delete() + notice_manager.notify_friend_request_canceled(friend_profile.user, user_profile) return Response(_('Friend request cancelled.')) if not user_profile.is_friend(friend_profile): return Response(_('You are not friend with this user.'), status.HTTP_400_BAD_REQUEST) user_profile.delete_friend(friend_profile) - return Response(_('Friendship succssfully deleted.'), status.HTTP_201_CREATED) + notice_manager.notify_friend_removed(friend_profile.user, user_profile) + return Response(_('Friendship successfully deleted.'), status.HTTP_201_CREATED) class GetIncomingFriendRequestView(APIView): diff --git a/profiles/viewsets/MyProfileViewSet.py b/profiles/viewsets/MyProfileViewSet.py index fbc034a..97a7b6a 100644 --- a/profiles/viewsets/MyProfileViewSet.py +++ b/profiles/viewsets/MyProfileViewSet.py @@ -3,7 +3,7 @@ from rest_framework import viewsets from rest_framework.response import Response from rest_framework.authentication import SessionAuthentication -from ..serializers.ProfileSerializer import ProfileSerializer +from ..serializers import ProfileSerializer from ..models import ProfileModel diff --git a/profiles/viewsets/ProfileViewSet.py b/profiles/viewsets/ProfileViewSet.py index b476d71..2aa0aa0 100644 --- a/profiles/viewsets/ProfileViewSet.py +++ b/profiles/viewsets/ProfileViewSet.py @@ -5,7 +5,7 @@ from rest_framework import permissions from rest_framework import viewsets from rest_framework.response import Response -from ..serializers.ProfileSerializer import ProfileSerializer +from ..serializers import ProfileSerializer from ..models import ProfileModel diff --git a/tournament/consumers.py b/tournament/consumers.py index fe52b90..a26a89a 100644 --- a/tournament/consumers.py +++ b/tournament/consumers.py @@ -9,7 +9,7 @@ from django.utils.translation import gettext as _ from games.models import GameModel from games.serializers import GameSerializer from profiles.models import ProfileModel -from profiles.serializers.ProfileSerializer import ProfileSerializer +from profiles.serializers import ProfileSerializer from .models import TournamentModel import json @@ -228,4 +228,4 @@ class TournamentWebConsumer(WebsocketConsumer): self.room.leave(self.member) - super().disconnect(close_code) # proutman à encore frappé \ No newline at end of file + super().disconnect(close_code) # proutman à encore frappé diff --git a/tournament/serializers.py b/tournament/serializers.py index 012aab6..82e12b3 100644 --- a/tournament/serializers.py +++ b/tournament/serializers.py @@ -2,7 +2,7 @@ from rest_framework import serializers from .models import TournamentModel, TournamentGameModel -from profiles.serializers.ProfileSerializer import ProfileSerializer +from profiles.serializers import ProfileSerializer from games.serializers import GameSerializer nb_participants = [2 ** i for i in range(2, 6)] @@ -58,4 +58,4 @@ class TournamentGameSerializer(serializers.ModelSerializer): return "waiting" def get_players(self, instance: TournamentGameModel): - return ProfileSerializer(instance.get_players_profiles(), many=True).data \ No newline at end of file + return ProfileSerializer(instance.get_players_profiles(), many=True).data diff --git a/transcendence/asgi.py b/transcendence/asgi.py index 8d907a4..11ca834 100644 --- a/transcendence/asgi.py +++ b/transcendence/asgi.py @@ -15,20 +15,21 @@ import chat.routing import matchmaking.routing import tournament.routing import games.routing +import notice.routing from django.core.asgi import get_asgi_application os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'trancendence.settings') application = ProtocolTypeRouter({ - 'http':get_asgi_application(), - 'websocket':AuthMiddlewareStack( + 'http': get_asgi_application(), + 'websocket': AuthMiddlewareStack( URLRouter( chat.routing.websocket_urlpatterns + matchmaking.routing.websocket_urlpatterns + tournament.routing.websocket_urlpatterns + - games.routing.websocket_urlpatterns + games.routing.websocket_urlpatterns + + notice.routing.websocket_urlpatterns ) ) }) - diff --git a/transcendence/settings.py b/transcendence/settings.py index 8d55720..6e7f774 100644 --- a/transcendence/settings.py +++ b/transcendence/settings.py @@ -51,6 +51,7 @@ INSTALLED_APPS = [ 'profiles.apps.ProfilesConfig', 'frontend.apps.FrontendConfig', 'chat.apps.ChatConfig', + 'notice.apps.NoticeConfig', 'corsheaders', 'rest_framework',