diff --git a/.env.prod b/.env.prod index 2ad18bc..84bda00 100644 --- a/.env.prod +++ b/.env.prod @@ -23,5 +23,5 @@ PLAUSIBLE_DOMAIN='http://127.0.0.1:8000/' #[captcha] captcha_public_key="6LdgCjseAAAAAIwg41-kyyulmwDtqD2Gk3THIwy2" captcha_private_key="6LdgCjseAAAAAPHMsIHuQgYAGTJ7_QlhqG4G0NyS" -ONLINE_CLASS_FRONTEND_DOMAIN="imamjavad.newhorizonco.uk" +ONLINE_CLASS_FRONTEND_DOMAIN="meet.imamjavad.online" FCM_API_KEY="" diff --git a/apps/course/views/course.py b/apps/course/views/course.py index c57dcba..4096e0f 100644 --- a/apps/course/views/course.py +++ b/apps/course/views/course.py @@ -48,6 +48,19 @@ from utils.redis import OnlineClassTokenManager UserModel = get_user_model() +def get_course_slug_value(course: Course) -> str: + slug_data = course.slug + if isinstance(slug_data, list) and slug_data: + first_item = slug_data[0] + if isinstance(first_item, dict): + first_title = first_item.get('title') + if first_title: + return str(first_title) + if isinstance(slug_data, str): + return slug_data + return str(slug_data or '') + + class CourseCategoryAPIView(ListAPIView): queryset = CourseCategory.objects.all() serializer_class = CourseCategorySerializer @@ -439,7 +452,7 @@ class CourseOnlineClassTokenAPIView(GenericAPIView): 'course_id': course.id, 'user_id': request.user.id, 'user_token': user_token.key, - 'course_slug': course.slug, + 'course_slug': get_course_slug_value(course), 'extra': { 'professor_in_class': False, }, @@ -447,7 +460,8 @@ class CourseOnlineClassTokenAPIView(GenericAPIView): # ساخت URL ثابت با token و course slug frontend_base = getattr(settings, "ONLINE_CLASS_FRONTEND_DOMAIN", getattr(settings, "SITE_DOMAIN", "")).rstrip("/") - entry_url = f"{frontend_base}/join-class?token={token}&slug={course.slug}" + course_slug = get_course_slug_value(course) + entry_url = f"{frontend_base}/?token={token}&slug={course_slug}" return Response({ 'token': token, diff --git a/docs/online_class_entry_endpoints_guide.md b/docs/online_class_entry_endpoints_guide.md new file mode 100644 index 0000000..8a9e319 --- /dev/null +++ b/docs/online_class_entry_endpoints_guide.md @@ -0,0 +1,237 @@ +# راهنمای استفاده از endpoint های ورود به کلاس آنلاین + +این فایل برای تیم‌های `frontend` و `flutter` نوشته شده و فقط توضیح می‌دهد: + +- هر endpoint چه کاری انجام می‌دهد +- در چه شرایطی باید از آن استفاده شود +- ترتیب درست استفاده از endpoint ها چیست + +این راهنما وارد کدنویسی React یا Flutter نمی‌شود و فقط منطق استفاده را توضیح می‌دهد. + +## هدف کلی + +کاربر برای ورود به کلاس آنلاین دو حالت دارد: + +1. کلاس هنوز توسط استاد شروع نشده است +2. کلاس از قبل شروع شده و room فعال است + +رفتار درست فرانت باید بر اساس همین دو حالت تعیین شود. + +## اصل مهم + +فرانت نباید با درخواست اشتباه باعث ساختن کلاس توسط دانشجو شود. + +بنابراین: + +- اگر کلاس شروع نشده باشد، کاربر باید وارد `waiting page` شود +- اگر کلاس شروع شده باشد، کاربر باید مستقیم `join token` واقعی بگیرد و وارد کلاس شود + +## endpoint ها + +### 1. بررسی وضعیت کلاس + +#### Endpoint + +`GET /api/courses//online/validate/` + +#### کاربرد + +این endpoint برای تصمیم‌گیری اولیه فرانت است. + +با این endpoint می‌توان فهمید: + +- آیا کلاس الان آنلاین است یا نه +- آیا کاربر اجازه ورود به کلاس را دارد یا نه +- آیا کاربر استاد است و می‌تواند کلاس را شروع کند یا نه + +#### خروجی مهم + +فیلدهای مهم در `metadata`: + +- `is_online` +- `can_join_live_session` +- `can_create_live_session` +- `has_finished` + +#### زمان استفاده + +این endpoint باید قبل از تصمیم نهایی برای ورود به کلاس صدا زده شود. + +#### تصمیم‌گیری بر اساس پاسخ + +- اگر `is_online = true` و `can_join_live_session = true` + فرانت باید مستقیم به سراغ گرفتن `join token` واقعی برود + +- اگر `is_online = false` + فرانت نباید مستقیم سراغ `room/token` برود و باید از flow صفحه انتظار استفاده کند + +- اگر `can_create_live_session = true` +کاربر استاد است و فرانت باید مستقیم به سراغ گرفتن `join token` واقعی برود + +--- + +### 2. ساخت لینک ورود موقت برای waiting page + +#### Endpoint + +`POST /api/courses//online/token/` + +#### کاربرد + +این endpoint برای ورود به waiting flow استفاده می‌شود. + +این endpoint: + +- یک `temporary token` می‌سازد +- یک URL ورود به `conference_client` برمی‌گرداند + +#### چه زمانی باید استفاده شود + +فقط وقتی که کلاس هنوز شروع نشده است. + +#### چه زمانی نباید استفاده شود + +اگر کلاس از قبل شروع شده و room فعال است، نباید این endpoint مسیر اصلی ورود باشد. + +در آن حالت باید مستقیم `join token` واقعی گرفته شود. + +#### ورودی + +- `course_id` در URL +- هدر احراز هویت کاربر + +بدنه عملا می‌تواند خالی باشد. + +#### خروجی + +پاسخ شامل این فیلدهاست: + +- `token` +- `url` +- `expires_in` + + +### 3. گرفتن join token واقعی برای ورود مستقیم به کلاس + +#### Endpoint + +`POST /api/courses/online/room/token/` + +#### کاربرد + +این endpoint `access_token` واقعی PlugNMeet را می‌سازد. + +با این token کاربر مستقیم وارد کلاس می‌شود. + +#### چه زمانی باید استفاده شود + +وقتی که کلاس از قبل شروع شده و room فعال است. + +#### چه زمانی نباید استفاده شود + +وقتی هنوز کلاس شروع نشده است. + +در آن حالت این endpoint مسیر مناسب ورود نیست و باید از waiting flow استفاده شود. + +#### ورودی + +بدنه: + +`course_slug` + +به همراه هدر احراز هویت کاربر + +#### خروجی + +پاسخ شامل: + +- `room_id` +- `token` + +#### رفتار درست بعد از دریافت پاسخ + +کاربر باید مستقیم به `conference_client` با `access_token` هدایت شود. + +مثال: + +`https://meet.imamjavad.online/?access_token=` + + +## ترتیب درست استفاده در فرانت + +### سناریو 1: کاربر روی دکمه ورود به کلاس می‌زند + +ترتیب درست: + +1. فرانت وضعیت کلاس را با `online/validate` بررسی کند +2. اگر کلاس فعال بود: + - `online/room/token/` + - هدایت مستقیم با `access_token` +3. اگر کلاس فعال نبود: + - `online/token/` + - هدایت کاربر به waiting page + +## منطق تصمیم‌گیری پیشنهادی + +- `is_online = true` + مسیر درست: ورود مستقیم به کلاس + +- `is_online = false` + مسیر درست: waiting page + +## رفتار داخل conference_client + +`conference_client` الان دو ورودی را می‌فهمد: + +### حالت اول: ورود مستقیم + +اگر URL شامل این باشد: + +- `access_token` + +کاربر مستقیم وارد flow اصلی کلاس می‌شود. + +### حالت دوم: waiting flow + +اگر URL شامل این باشد: + +- `token` +- `slug` + +کاربر وارد waiting/pre-join flow می‌شود. + +در این حالت: + +1. temporary token به auth token واقعی تبدیل می‌شود +2. وضعیت کلاس از Django خوانده می‌شود +3. اگر کلاس هنوز شروع نشده باشد، waiting page نمایش داده می‌شود +4. اگر کلاس شروع شده باشد، دکمه ورود به کلاس نمایش داده می‌شود +5. اگر کاربر استاد باشد و کلاس شروع نشده باشد، دکمه شروع کلاس نمایش داده می‌شود + +## آپدیت خودکار وضعیت + +در waiting flow، وضعیت کلاس به صورت polling دوره‌ای از Django بررسی می‌شود. + +بنابراین: + +- اگر استاد کلاس را شروع کند، صفحه انتظار به‌روزرسانی می‌شود +- اگر استاد کلاس را ببندد، وضعیت صفحه دوباره به حالت انتظار/پایان بازمی‌گردد + +## جمع‌بندی نهایی + +### برای فرانت اصلی سایت یا اپ + +- ابتدا همیشه `online/validate` +- اگر کلاس فعال بود: `online/room/token/` +- اگر کلاس فعال نبود: `online/token/` + +### برای conference_client + +- اگر `access_token` داشت: ورود مستقیم +- اگر `token + slug` داشت: waiting flow + +### قاعده مهم + +`online/token/` برای قبل از شروع کلاس است + +`online/room/token/` برای وقتی است که کلاس واقعا شروع شده است