import strawberry from typing import List, Optional from strawberry.types import Info from channels.db import database_sync_to_async from django.contrib.contenttypes.models import ContentType from core.graphql.types.event import EventType, NotificationRuleType, NotificationType, NotificationDeliveryType from core.models.events import Event, NotificationRule, Notification, NotificationDelivery from core.models.enums import NotificationStatusChoices @strawberry.type class Query: @strawberry.field(description="Get all events") async def events( self, info: Info, limit: Optional[int] = 50, offset: Optional[int] = 0 ) -> List[EventType]: profile = getattr(info.context.request, 'profile', None) if not profile: raise PermissionError("Authentication required") events = await database_sync_to_async( lambda: list(Event.objects.all().order_by('-created_at')[offset:offset + limit]) )() return events @strawberry.field(description="Get event by ID") async def event( self, info: Info, id: strawberry.ID ) -> Optional[EventType]: profile = getattr(info.context.request, 'profile', None) if not profile: raise PermissionError("Authentication required") try: event = await database_sync_to_async(Event.objects.get)(pk=id) return event except Event.DoesNotExist: return None @strawberry.field(description="Get all notification rules") async def notification_rules( self, info: Info, is_active: Optional[bool] = None ) -> List[NotificationRuleType]: profile = getattr(info.context.request, 'profile', None) if not profile: raise PermissionError("Authentication required") # Only admins can view notification rules from core.models.profile import TeamProfile from core.models.enums import RoleChoices if not isinstance(profile, TeamProfile) or profile.role != RoleChoices.ADMIN: raise PermissionError("Admin access required") queryset = NotificationRule.objects.prefetch_related( 'target_team_profiles', 'target_customer_profiles' ) if is_active is not None: queryset = queryset.filter(is_active=is_active) rules = await database_sync_to_async(lambda: list(queryset.order_by('name')))() return rules @strawberry.field(description="Get notification rule by ID") async def notification_rule( self, info: Info, id: strawberry.ID ) -> Optional[NotificationRuleType]: profile = getattr(info.context.request, 'profile', None) if not profile: raise PermissionError("Authentication required") # Only admins can view notification rules from core.models.profile import TeamProfile from core.models.enums import RoleChoices if not isinstance(profile, TeamProfile) or profile.role != RoleChoices.ADMIN: raise PermissionError("Admin access required") try: rule = await database_sync_to_async( lambda: NotificationRule.objects.prefetch_related( 'target_team_profiles', 'target_customer_profiles' ).get(pk=id) )() return rule except NotificationRule.DoesNotExist: return None @strawberry.field(description="Get notifications for current user") async def my_notifications( self, info: Info, unread_only: Optional[bool] = False, limit: Optional[int] = 50, offset: Optional[int] = 0 ) -> List[NotificationType]: profile = getattr(info.context.request, 'profile', None) if not profile: raise PermissionError("Authentication required") @database_sync_to_async def get_notifications(): # Get content type for the profile content_type = ContentType.objects.get_for_model(type(profile)) # Build query queryset = Notification.objects.filter( recipient_content_type=content_type, recipient_object_id=profile.id ) if unread_only: queryset = queryset.filter(read_at__isnull=True) # Get notifications return list( queryset.select_related('event', 'rule') .order_by('-created_at')[offset:offset + limit] ) return await get_notifications() @strawberry.field(description="Get unread notification count for current user") async def my_unread_notification_count(self, info: Info) -> int: profile = getattr(info.context.request, 'profile', None) if not profile: return 0 # Get content type for the profile content_type = await database_sync_to_async(ContentType.objects.get_for_model)(profile) # Count unread notifications count = await database_sync_to_async( Notification.objects.filter( recipient_content_type=content_type, recipient_object_id=profile.id, read_at__isnull=True ).count )() return count @strawberry.field(description="Get notification by ID") async def notification( self, info: Info, id: strawberry.ID ) -> Optional[NotificationType]: profile = getattr(info.context.request, 'profile', None) if not profile: raise PermissionError("Authentication required") @database_sync_to_async def get_and_verify(): notification = Notification.objects.select_related('event', 'rule').get(pk=id) # Verify user has access to this notification content_type = ContentType.objects.get_for_model(type(profile)) if (notification.recipient_content_type != content_type or str(notification.recipient_object_id) != str(profile.id)): raise PermissionError("Not authorized to view this notification") return notification try: return await get_and_verify() except Notification.DoesNotExist: return None @strawberry.field(description="Get notification delivery status") async def notification_deliveries( self, info: Info, notification_id: strawberry.ID ) -> List[NotificationDeliveryType]: profile = getattr(info.context.request, 'profile', None) if not profile: raise PermissionError("Authentication required") # Only admins can view delivery status from core.models.profile import TeamProfile from core.models.enums import RoleChoices if not isinstance(profile, TeamProfile) or profile.role != RoleChoices.ADMIN: raise PermissionError("Admin access required") deliveries = await database_sync_to_async( lambda: list( NotificationDelivery.objects.filter(notification_id=notification_id) .select_related('notification') .order_by('-created_at') ) )() return deliveries