from channels.generic.websocket import AsyncJsonWebsocketConsumer from channels.db import database_sync_to_async from django.core.exceptions import PermissionDenied from boxofficefantasy.models import League, Season from boxofficefantasy.views import parse_season_slug from draft.models import DraftSession, DraftPick, DraftMoviePool, DraftParticipant import random class DraftConsumer(AsyncJsonWebsocketConsumer): async def connect(self): draft_session_id_hashed = self.scope["url_route"]["kwargs"].get("draft_session_id_hashed") league_slug = self.scope["url_route"]["kwargs"].get("league_slug") season_slug = self.scope["url_route"]["kwargs"].get("season_slug") self.draft_session = await self.get_draft_session(draft_session_id_hashed=draft_session_id_hashed, league_slug=league_slug, season_slug=season_slug) self.room_group_name = f"draft_{self.draft_session.season.league.slug}_{self.draft_session.season.slug}" # Auth check (optional) self.user = self.scope["user"] if not self.user.is_authenticated: await self.close() return try: await self.add_draft_participant() except Exception as e: await self.close() return await self.channel_layer.group_add(self.room_group_name, self.channel_name) await self.accept() await self.send_json({"type": "connection.accepted", "user": self.user.username, "budget": self.participant.budget}) # Notify others (optional) await self.channel_layer.group_send( self.room_group_name, { "type": "user.joined", "user": self.user.username, "budget": self.participant.budget } ) async def disconnect(self, close_code): await self.channel_layer.group_discard(self.room_group_name, self.channel_name) async def receive_json(self, content): event_type = content.get("type") user = self.scope["user"] if event_type == "start_draft": if user.is_staff: await self.start_draft() else: await self.send_json({ "type": "error", "message": "insufficient privelleges" }) elif event_type == "nominate": await self.nominate(content.get("movie")) elif event_type == "bid": await self.place_bid(content.get("amount"), self.scope["user"].username) elif event_type == "message": await self.channel_layer.group_send( self.room_group_name, { "type": "chat.message", "user": self.scope["user"].username, "message": content.get("message"), }, ) # === Broadcast handlers === async def user_joined(self, event): await self.send_json({ "type": "user.joined", "user": event["user"] }) async def chat_message(self, event): await self.send_json({ "type": "chat.message", "user": event["user"], "message": event["message"], }) async def draft_update(self, event): await self.send_json({ "type": "draft.update", "state": event["state"], }) # === Draft logic (stubbed for now) === async def start_draft(self): # Example: shuffle draft order players = await self.get_draft_participants() draft_order = random.sample(players, len(players)) await self.channel_layer.group_send( self.room_group_name, { "type": "draft.update", "state": { "status": "started", "order": [p.user.username for p in draft_order], } } ) async def nominate(self, movie_title): await self.channel_layer.group_send( self.room_group_name, { "type": "draft.update", "state": { "status": "nominating", "movie": movie_title, } } ) async def place_bid(self, amount, user): await self.channel_layer.group_send( self.room_group_name, { "type": "draft.update", "state": { "status": "bidding", "bid": {"amount": amount, "user": user} } } ) # === Example DB Access === @database_sync_to_async def add_draft_participant(self): self.participant, _ = DraftParticipant.objects.get_or_create( user=self.user, draft=self.draft_session, defaults={ "budget":self.draft_session.settings.starting_budget } ) @database_sync_to_async def get_draft_participants(self): # Replace this with real queryset to fetch users in draft return list(DraftParticipant.objects.select_related('user').filter(draft=self.draft_session).all()) @database_sync_to_async def get_draft_session(self, draft_session_id_hashed, league_slug, season_slug): draft_session_id = DraftSession.decode_id(draft_session_id_hashed) if draft_session_id: draft_session = DraftSession.objects.select_related('season', 'season__league').get(pk=draft_session_id) elif league_slug and season_slug: label, year = parse_season_slug(season_slug) season = Season.objects.filter(label=label, year=year).first() draft_session = DraftSession.objects.select_related('season', 'season__league').filter(season=season).first() else: raise Exception() return draft_session