@ -17,7 +17,7 @@ from apps.course.models import Course, CourseLiveSession, Participant, LiveSessi
from apps.course.serializers import LiveSessionRoomCreateSerializer , LiveSessionTokenSerializer , LiveSessionRecordedFileSerializer , LiveSessionRecordingSerializer
from apps.course.services.plugnmeet import PlugNMeetClient , PlugNMeetError
from utils.exceptions import AppAPIException
from django.conf import settings
logger = logging . getLogger ( __name__ )
@ -45,69 +45,70 @@ class CourseLiveSessionRoomCreateAPIView(GenericAPIView):
)
def post ( self , request , slug , * args , * * kwargs ) :
# 1. Validation and Permission Logic
# 1. Standard Permissions Logic
course = get_object_or_404 ( Course , slug = slug )
if not request . user . can_manage_course ( course ) :
raise AppAPIException ( { ' message ' : ' Permission denied ' } , status_code = status . HTTP_403_FORBIDDEN )
raise AppAPIException ( { ' message ' : ' Permission denied ' } , status_code = 403 )
# 2. Build Safe Room ID (Prefix with 'room-' to satisfy NATS rules)
# OLD: f"{course.id}-imamjavad" -> "9-imamjavad" (Risk of NATS errors)
# NEW: f"room-{course.id}-imamjavad" -> "room-9-imamjavad" (Safe)
room_id = f " room-{course.id}-imamjavad "
# 2. Setup ID and Metadata
room_id = f " room-{course.id}-imamjavad "
subject = f " {course.title} Live Session "
metadata = self . _build_metadata ( subject )
# 3. Create Room via PlugNMeet API
# 3. Use your CLEAN PlugNMeetClient
try :
client = PlugNMeetClient ( )
client = PlugNMeetClient ( ) # Loads keys from settings automatically
# Note: client.create_room only CREATES the room.
# It does not give you a token to join it.
# This uses the keys internally to talk to the server
plugnmeet_response = client . create_room ( {
' room_id ' : room_id ,
' metadata ' : metadata ,
} )
# 4. Generate the JOIN TOKEN (The Entry Ticket)
# Users CANNOT enter without this.
token_payload = {
" room_id " : room_id ,
" user_info " : {
" name " : f " {request.user.first_name} {request.user.last_name} " ,
" user_id " : str ( request . user . id ) ,
" is_admin " : True ,
" is_hidden " : False
}
}
# Check if your client has a method for this, otherwise use manual:
# access_token = client.get_join_token(token_payload)
# If not, we do it manually here using the SAME secret from settings:
pnm_token = jwt . encode (
{
" iss " : settings . PLUGNMEET_API_KEY ,
" exp " : int ( time . time ( ) ) + 3600 ,
" sub " : str ( request . user . id ) ,
* * token_payload
} ,
settings . PLUGNMEET_API_SECRET ,
algorithm = " HS256 "
)
except Exception as exc :
logger . error ( f " PlugNMeet Error: {exc} " )
raise AppAPIException ( { ' message ' : str ( exc ) } , status_code = 500 )
# 4. Save to Database
# 5. Database Logic
session , created = CourseLiveSession . objects . get_or_create (
course = course ,
room_id = room_id ,
defaults = { ' subject ' : subject , ' started_at ' : timezone . now ( ) } ,
course = course , room_id = room_id ,
defaults = { ' subject ' : subject , ' started_at ' : timezone . now ( ) }
)
# 5. GENERATE JOIN TOKEN (Critical for User Access)
# You must fetch these exactly as they are in your config.yaml
PNM_API_KEY = " habibmeet_api_key_2024 "
PNM_SECRET = " habibmeet_secret_zumyyYWqv7KR2kUqvYdq4z4sXg7XTBD2ljT6_2024 "
token_payload = {
" iss " : PNM_API_KEY , # Issuer must be the API Key
" exp " : int ( time . time ( ) ) + 3600 , # 1 hour expiry
" sub " : str ( request . user . id ) ,
" room_id " : room_id ,
" name " : f " {request.user.first_name} {request.user.last_name} " ,
" is_admin " : True , # Gives moderator privileges
" user_id " : str ( request . user . id ) ,
}
# SIGN with the SECRET, not the key
token = jwt . encode ( token_payload , PNM_SECRET , algorithm = " HS256 " )
return Response ( {
' success ' : True ,
' session ' : {
' id ' : session . id ,
' room_id ' : session . room_id ,
' started_at ' : session . started_at ,
} ,
# Frontend uses this to connect:
# https://meet.newhorizonco.uk/?access_token={access_token}
' access_token ' : token
} , status = status . HTTP_201_CREATED )
' session ' : { ' id ' : session . id , ' room_id ' : session . room_id } ,
' access_token ' : pnm_token # <--- REQUIRED for frontend
} , status = 201 )
# def post(self, request, slug, *args, **kwargs):
# logger.info(f"[LiveSession Create] Request from user_id={request.user.id} for course={slug}")