- Add Django Channels 4 + channels-redis to requirements and INSTALLED_APPS
- Upgrade ASGI config to ProtocolTypeRouter with JWT-authenticated WebSocket routing
- Add JWTAuthMiddleware for WebSocket token auth via query param
- Add CallSession, CallParticipant, CallEvent models with migration 0004
- MeetingCallConsumer: join/leave, P2P SDP/ICE relay via per-user groups,
instructor mute/unmute/kick with DB audit and WS broadcast
- REST endpoints: GET/POST/DELETE /meetings/{id}/call/ (session lifecycle),
POST /moderate/ (mute/unmute/kick), POST /screen-share/, GET /events/ (audit log)
- IsMeetingModerator permission (accepts training:signoff or meeting:moderate)
- Services: get_or_create_call_session, end_call_session, apply_moderation_action,
toggle_screen_share with full CallEvent audit trail
- Integration tests covering REST lifecycle, moderation, and WebSocket signaling
Co-Authored-By: Paperclip <noreply@paperclip.ing>
39 lines
1.1 KiB
Python
39 lines
1.1 KiB
Python
from urllib.parse import parse_qs
|
|
|
|
from channels.auth import AuthMiddlewareStack
|
|
from channels.db import database_sync_to_async
|
|
from channels.middleware import BaseMiddleware
|
|
from django.contrib.auth import get_user_model
|
|
from django.contrib.auth.models import AnonymousUser
|
|
from rest_framework_simplejwt.tokens import AccessToken
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
@database_sync_to_async
|
|
def get_user_from_token(token_key):
|
|
try:
|
|
token = AccessToken(token_key)
|
|
user_id = token["user_id"]
|
|
return User.objects.get(pk=user_id)
|
|
except Exception:
|
|
return AnonymousUser()
|
|
|
|
|
|
class JWTAuthMiddleware(BaseMiddleware):
|
|
async def __call__(self, scope, receive, send):
|
|
query_string = scope.get("query_string", b"").decode()
|
|
params = parse_qs(query_string)
|
|
token_list = params.get("token", [])
|
|
|
|
if token_list:
|
|
scope["user"] = await get_user_from_token(token_list[0])
|
|
else:
|
|
scope["user"] = AnonymousUser()
|
|
|
|
return await super().__call__(scope, receive, send)
|
|
|
|
|
|
def JWTAuthMiddlewareStack(inner):
|
|
return JWTAuthMiddleware(AuthMiddlewareStack(inner))
|