149 lines
5.2 KiB
Python
149 lines
5.2 KiB
Python
from typing import List, Optional, Iterable
|
|
import strawberry
|
|
import strawberry_django as sd
|
|
from strawberry import ID
|
|
from strawberry_django.relay import DjangoCursorConnection
|
|
from django.contrib.contenttypes.models import ContentType
|
|
|
|
from core.graphql.filters.messaging import ConversationFilter, MessageFilter
|
|
from core.graphql.types.messaging import ConversationType, MessageType
|
|
from core.models.messaging import Conversation, Message
|
|
from core.models.profile import TeamProfile, CustomerProfile
|
|
|
|
|
|
@strawberry.type
|
|
class Query:
|
|
"""Messaging queries"""
|
|
|
|
conversation: Optional[ConversationType] = sd.node()
|
|
conversations: List[ConversationType] = sd.field(filters=ConversationFilter)
|
|
|
|
message: Optional[MessageType] = sd.node()
|
|
messages: List[MessageType] = sd.field(filters=MessageFilter)
|
|
|
|
@sd.connection(
|
|
DjangoCursorConnection["ConversationType"],
|
|
name="getMyConversations",
|
|
description="Return conversations for the authenticated user (inbox)",
|
|
filters=ConversationFilter,
|
|
)
|
|
def get_my_conversations(
|
|
self,
|
|
info,
|
|
include_archived: bool = False,
|
|
) -> Iterable["Conversation"]:
|
|
"""
|
|
Get all conversations for the current authenticated user.
|
|
Returns conversations ordered by last message timestamp.
|
|
"""
|
|
# Get profile directly from context (not Django User model)
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
if not profile:
|
|
return Conversation.objects.none()
|
|
|
|
# Determine the profile's content type
|
|
content_type = ContentType.objects.get_for_model(type(profile))
|
|
|
|
# Build query
|
|
queryset = Conversation.objects.filter(
|
|
participants__participant_content_type=content_type,
|
|
participants__participant_object_id=profile.id,
|
|
)
|
|
|
|
# Filter archived conversations unless explicitly requested
|
|
if not include_archived:
|
|
queryset = queryset.filter(participants__is_archived=False)
|
|
|
|
return queryset.prefetch_related(
|
|
'participants',
|
|
'participants__participant_content_type',
|
|
).distinct().order_by('-last_message_at', '-created_at')
|
|
|
|
@sd.connection(
|
|
DjangoCursorConnection["ConversationType"],
|
|
name="getConversationsByEntity",
|
|
description="Return conversations linked to a specific entity (Project, Service, Account, etc.)",
|
|
filters=ConversationFilter,
|
|
)
|
|
def get_conversations_by_entity(
|
|
self,
|
|
entity_type: str,
|
|
entity_id: ID,
|
|
) -> Iterable["Conversation"]:
|
|
"""
|
|
Get all conversations linked to a specific entity.
|
|
entity_type: Model name (e.g., 'Project', 'Service', 'Account')
|
|
entity_id: UUID of the entity
|
|
"""
|
|
from django.apps import apps
|
|
|
|
try:
|
|
# Get the content type for the entity
|
|
model = apps.get_model('core', entity_type)
|
|
content_type = ContentType.objects.get_for_model(model)
|
|
|
|
return Conversation.objects.filter(
|
|
entity_content_type=content_type,
|
|
entity_object_id=entity_id
|
|
).prefetch_related(
|
|
'participants',
|
|
'participants__participant_content_type',
|
|
).order_by('-last_message_at')
|
|
except Exception:
|
|
return Conversation.objects.none()
|
|
|
|
@strawberry.field(description="Get unread message count for the authenticated user")
|
|
async def unread_message_count(self, info) -> int:
|
|
"""
|
|
Get total unread message count across all conversations for the current user.
|
|
"""
|
|
from channels.db import database_sync_to_async
|
|
|
|
# Get profile directly from context (not Django User model)
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
if not profile:
|
|
return 0
|
|
|
|
@database_sync_to_async
|
|
def get_count():
|
|
# Determine the profile's content type
|
|
content_type = ContentType.objects.get_for_model(type(profile))
|
|
|
|
# Sum unread counts from all participant records
|
|
from core.models.messaging import ConversationParticipant
|
|
from django.db.models import Sum
|
|
|
|
total = ConversationParticipant.objects.filter(
|
|
participant_content_type=content_type,
|
|
participant_object_id=profile.id,
|
|
is_archived=False
|
|
).aggregate(total=Sum('unread_count'))['total']
|
|
|
|
return total if total else 0
|
|
|
|
return await get_count()
|
|
|
|
@sd.connection(
|
|
DjangoCursorConnection["MessageType"],
|
|
name="getMessagesByConversation",
|
|
description="Return messages for a specific conversation",
|
|
filters=MessageFilter,
|
|
)
|
|
def get_messages_by_conversation(
|
|
self,
|
|
conversation_id: ID,
|
|
include_system: bool = True,
|
|
) -> Iterable["Message"]:
|
|
"""
|
|
Get all messages for a specific conversation.
|
|
"""
|
|
queryset = Message.objects.filter(conversation_id=conversation_id)
|
|
|
|
if not include_system:
|
|
queryset = queryset.filter(is_system_message=False)
|
|
|
|
return queryset.prefetch_related(
|
|
'read_receipts',
|
|
'sender_content_type',
|
|
).order_by('created_at')
|