mirror of
https://gitlab.com/animath/si/plateforme.git
synced 2025-06-25 05:00:31 +02:00
Store what messages are read
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
@ -3,6 +3,7 @@
|
||||
|
||||
from channels.generic.websocket import AsyncJsonWebsocketConsumer
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models import Exists, OuterRef, Count, Q
|
||||
from registration.models import Registration
|
||||
|
||||
from .models import Channel, Message
|
||||
@ -34,8 +35,10 @@ class ChatConsumer(AsyncJsonWebsocketConsumer):
|
||||
# Accept the connection
|
||||
await self.accept()
|
||||
|
||||
channels = await Channel.get_accessible_channels(user, 'read')
|
||||
async for channel in channels.all():
|
||||
self.read_channels = await Channel.get_accessible_channels(user, 'read')
|
||||
self.write_channels = await Channel.get_accessible_channels(user, 'write')
|
||||
|
||||
async for channel in self.read_channels.all():
|
||||
await self.channel_layer.group_add(f"chat-{channel.id}", self.channel_name)
|
||||
await self.channel_layer.group_add(f"user-{user.id}", self.channel_name)
|
||||
|
||||
@ -48,8 +51,7 @@ class ChatConsumer(AsyncJsonWebsocketConsumer):
|
||||
# User is not authenticated
|
||||
return
|
||||
|
||||
channels = await Channel.get_accessible_channels(self.scope['user'], 'read')
|
||||
async for channel in channels.all():
|
||||
async for channel in self.read_channels.all():
|
||||
await self.channel_layer.group_discard(f"chat-{channel.id}", self.channel_name)
|
||||
await self.channel_layer.group_discard(f"user-{self.scope['user'].id}", self.channel_name)
|
||||
|
||||
@ -69,6 +71,8 @@ class ChatConsumer(AsyncJsonWebsocketConsumer):
|
||||
await self.delete_message(**content)
|
||||
case 'fetch_messages':
|
||||
await self.fetch_messages(**content)
|
||||
case 'mark_read':
|
||||
await self.mark_read(**content)
|
||||
case 'start_private_chat':
|
||||
await self.start_private_chat(**content)
|
||||
case unknown:
|
||||
@ -77,8 +81,6 @@ class ChatConsumer(AsyncJsonWebsocketConsumer):
|
||||
async def fetch_channels(self) -> None:
|
||||
user = self.scope['user']
|
||||
|
||||
read_channels = await Channel.get_accessible_channels(user, 'read')
|
||||
write_channels = await Channel.get_accessible_channels(user, 'write')
|
||||
message = {
|
||||
'type': 'fetch_channels',
|
||||
'channels': [
|
||||
@ -87,9 +89,11 @@ class ChatConsumer(AsyncJsonWebsocketConsumer):
|
||||
'name': channel.get_visible_name(user),
|
||||
'category': channel.category,
|
||||
'read_access': True,
|
||||
'write_access': await write_channels.acontains(channel),
|
||||
'write_access': await self.write_channels.acontains(channel),
|
||||
'unread_messages': channel.unread_messages,
|
||||
}
|
||||
async for channel in read_channels.prefetch_related('invited').all()
|
||||
async for channel in self.read_channels.prefetch_related('invited') \
|
||||
.annotate(unread_messages=Count('messages', filter=~Q(messages__users_read=user))).all()
|
||||
]
|
||||
}
|
||||
await self.send_json(message)
|
||||
@ -98,8 +102,7 @@ class ChatConsumer(AsyncJsonWebsocketConsumer):
|
||||
user = self.scope['user']
|
||||
channel = await Channel.objects.prefetch_related('tournament__pools__juries', 'pool', 'team', 'invited') \
|
||||
.aget(id=channel_id)
|
||||
write_channels = await Channel.get_accessible_channels(user, 'write')
|
||||
if not await write_channels.acontains(channel):
|
||||
if not await self.write_channels.acontains(channel):
|
||||
return
|
||||
|
||||
message = await Message.objects.acreate(
|
||||
@ -150,13 +153,16 @@ class ChatConsumer(AsyncJsonWebsocketConsumer):
|
||||
|
||||
async def fetch_messages(self, channel_id: int, offset: int = 0, limit: int = 50, **_kwargs) -> None:
|
||||
channel = await Channel.objects.aget(id=channel_id)
|
||||
read_channels = await Channel.get_accessible_channels(self.scope['user'], 'read')
|
||||
if not await read_channels.acontains(channel):
|
||||
if not await self.read_channels.acontains(channel):
|
||||
return
|
||||
|
||||
limit = min(limit, 200) # Fetch only maximum 200 messages at the time
|
||||
|
||||
messages = Message.objects.filter(channel=channel).order_by('-created_at')[offset:offset + limit].all()
|
||||
messages = Message.objects \
|
||||
.filter(channel=channel) \
|
||||
.annotate(read=Exists(User.objects.filter(pk=self.scope['user'].pk) \
|
||||
.filter(pk=OuterRef('users_read')))) \
|
||||
.order_by('-created_at')[offset:offset + limit].all()
|
||||
await self.send_json({
|
||||
'type': 'fetch_messages',
|
||||
'channel_id': channel_id,
|
||||
@ -167,11 +173,27 @@ class ChatConsumer(AsyncJsonWebsocketConsumer):
|
||||
'author_id': message.author_id,
|
||||
'author': await message.aget_author_name(),
|
||||
'content': message.content,
|
||||
'read': message.read,
|
||||
}
|
||||
async for message in messages
|
||||
]))
|
||||
})
|
||||
|
||||
async def mark_read(self, message_ids: list[int], **_kwargs) -> None:
|
||||
messages = Message.objects.filter(id__in=message_ids)
|
||||
async for message in messages.all():
|
||||
await message.users_read.aadd(self.scope['user'])
|
||||
|
||||
unread_messages_by_channel = Message.objects.exclude(users_read=self.scope['user']).values('channel_id') \
|
||||
.annotate(unread_messages=Count('channel_id'))
|
||||
|
||||
await self.send_json({
|
||||
'type': 'mark_read',
|
||||
'messages': [{'id': message.id, 'channel_id': message.channel_id} async for message in messages.all()],
|
||||
'unread_messages': {group['channel_id']: group['unread_messages']
|
||||
async for group in unread_messages_by_channel.all()},
|
||||
})
|
||||
|
||||
async def start_private_chat(self, user_id: int, **kwargs) -> None:
|
||||
user = self.scope['user']
|
||||
other_user = await User.objects.aget(id=user_id)
|
||||
@ -183,7 +205,6 @@ class ChatConsumer(AsyncJsonWebsocketConsumer):
|
||||
private=True,
|
||||
)
|
||||
await channel.invited.aset([user, other_user])
|
||||
await channel.asave()
|
||||
|
||||
await self.channel_layer.group_add(f"chat-{channel.id}", self.channel_name)
|
||||
|
||||
|
Reference in New Issue
Block a user