ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Open edX Course Live 插件深度解析:在课程中集成 Zoom 等视频会议工具的 LTI 实现

Open edX Course Live 插件深度解析:在课程中集成 Zoom 等视频会议工具的 LTI 实现 Open edX Course Live 插件深度解析在课程中集成 Zoom 等视频会议工具的 LTI 实现【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform导读Course Live 是 Open edX 平台中负责课程内实时视频会议集成的 Django 插件应用通过启用/禁用课程的 Live 标签页将 Zoom 等视频会议工具以 LTI 1.1 标准接入课程体验。本文将基于openedx/core/djangoapps/course_live/README.rst及其设计决策文档ADR结合仓库内的模型、视图、序列化器、Provider 抽象与测试源码完整剖析该插件的架构设计、配置流程、API 接口与扩展方式帮助你理解并掌握如何在 Open edX 中启用、配置与二次开发 Course Live。一、插件定位为课程注入Live标签页根据 Course Live README 的定义这是一个插件应用plugin app核心职责是允许你在课程中启用/禁用 Live 标签页。该标签页用于集成 Zoom 等视频会议工具。也就是说Course Live 并不负责实现视频会议本身而是负责管理课程是否展示Live标签、将标签与底层视频会议工具通过 LTI 集成关联起来。围绕这一目标001-course-live.rst 设计决策文档状态为 Accepted明确了几个关键设计选择背景是 Course Authoring MFE 中的 Pages and Resources 新交互将课程进度、Wiki、团队、讨论等各方面的配置集中到一处Live 是新增的课程应用之一Live 应用作为课程的一个新 Tab出现在课程体验中视频会议工具以 LTI 集成的方式接入初期仅支持 Zoom 作为视频会议 Provider但设计上允许后续扩展其他 Provider。从源码结构看该插件围绕三条主线展开CourseApp插件接口plugins.py、CourseLiveConfiguration数据模型models.py以及CourseLiveTab课程标签tab.py再辅以 REST APIviews.py与权限控制permissions.py。二、插件加载机制以 CourseApp 插件形式注册ADR 中明确该应用将作为插件加载并以命名空间openedx.course_app加入pyproject.toml。实际代码中plugins.py 定义了LiveCourseApp它继承自openedx.core.djangoapps.course_apps.plugins.CourseApp并实现了一套完整的课程应用接口接口方法实现逻辑源码位置app_idlive应用的唯一标识LiveCourseApp.app_idname/descriptionLive/Enable in-platform video conferencing by configuring live类属性is_available(course_key)恒为True对所有课程开放ADR 提到初期可放在 Waffle flag 后面LiveCourseApp.is_availableis_enabled(course_key)委托给CourseLiveConfiguration.is_enabled(course_key)由配置模型控制LiveCourseApp.is_enabledset_enabled(course_key, enabled, user)通过get_or_create创建/更新配置并在缺少 LTI 配置时自动创建一个LtiConfigurationLiveCourseApp.set_enabledget_allowed_operations(course_key, user)返回{enable: can_enable, configure: True}其中can_enable要求该课程已存在 CourseLiveConfiguration 记录即只有已配置 Live 的课程才允许启用LiveCourseApp.get_allowed_operations值得注意的设计细节是set_enabled启用 Live 时如果课程尚无 LTI 配置会自动创建一条LtiConfigurationconfig_storeCONFIG_ON_DB保证后续操作总能关联到一个 LTI 配置对象。同时apps.py 中的CourseLiveConfig通过plugin_app声明将 URL 挂载到LMS 与 CMS 两个项目下正则均为^api/course_live/也就是说管理员在 StudioCMS和学习端LMS都能访问 Course Live 的 APIplugin_app { PluginURLs.CONFIG: { ProjectType.LMS: { PluginURLs.NAMESPACE: , PluginURLs.REGEX: r^api/course_live/, PluginURLs.RELATIVE_PATH: urls, }, ProjectType.CMS: { PluginURLs.NAMESPACE: , PluginURLs.REGEX: r^api/course_live/, PluginURLs.RELATIVE_PATH: urls, }, } }三、核心数据模型CourseLiveConfigurationmodels.py 定义了唯一的模型CourseLiveConfiguration它把课程Course、LTI Provider、LTI 配置三者关联起来字段类型说明course_keyCourseKeyFielddb_indexTrue关联课程不能为空enabledBooleanField默认True若为False该课程关联的 LTI 将被禁用help_text 原文If disabled, the LTI in the associated course will be disabled.lti_configuration外键 →LtiConfiguration来自lti_consumer应用on_deleteSET_NULL可空该课程/Provider 的 LTI 配置数据provider_typeCharField(max_length50)不可为空LTI Provider 的 id如zoomfree_tierBooleanField默认False若为True表示 LTI 凭据由组织Org全局提供即使用全局共享凭据而非课程级凭据historyHistoricalRecords()通过 simple-history 记录每次变更历史模型还提供了两个关键类方法get(course_key)按课程 key 查询配置返回第一条记录无记录则返回Noneis_enabled(course_key) - bool没有配置时默认返回False有配置则返回enabled字段值。classmethod def is_enabled(cls, course_key) - bool: Default to False, if no configuration exists configuration cls.get(course_key) if not configuration: return False return configuration.enabled后台管理同样开箱即用admin.py 注册了基于SimpleHistoryAdmin的管理界面支持按course_key、enabled、provider_type搜索并按enabled、provider_type过滤同时借助 simple-history 保留配置的历史快照。数据库结构由 migrations 中的0001_initial、0002_auto_20220617_1822、0003_alter_historicalcourseliveconfiguration_options三份迁移文件维护。四、Provider 抽象层Zoom 与 BigBlueButton 的实现providers.py 是整个插件可扩展性的核心它用三层抽象封装了视频会议供应商的概念4.1 LiveProvider 基类LiveProvider(ABC)定义了每个 Provider 必须具备的能力描述id/nameProvider 标识与展示名features支持的特性列表requires_username/requires_email是否需要向 LTI 方共享用户名/邮箱PIIadditional_parameters需要的额外参数如custom_instructor_emailhas_free_tier是否支持免费档默认Falserequires_pii_sharing()requires_email or requires_username判断是否涉及 PII 共享requires_custom_email()判断是否要求自定义讲师邮箱检查additional_parameters中是否包含custom_instructor_emailis_enabledProvider 是否启用由子类实现__dict__()返回供 API 输出的 Provider 元信息结构为{ name: ..., has_free_tier: ..., features: ..., pii_sharing: {username: ..., email: ...}, additional_parameters: ... }4.2 HasGlobalCredentials 混入类HasGlobalCredentials(ABC)定义了使用组织级全局凭据的 Provider 结构要求子类提供key、secret、url三个属性并实现get_global_keys()从settings.COURSE_LIVE_GLOBAL_CREDENTIALS读取凭据has_valid_global_keys()校验key、secret、url三者均非空。4.3 Zoom 与 BigBlueButtonZoomid zoom名称Zoom LTI PRO当前默认且始终启用的 Provider声明了additional_parameters [custom_instructor_email]即配置 Zoom 时可以且可能需要提供一个自定义的讲师邮箱BigBlueButtonid big_blue_button名称Big Blue Button继承LiveProvider HasGlobalCredentialsrequires_username True其has_free_tier直接由全局凭据是否有效决定has_valid_global_keys()凭据从settings.COURSE_LIVE_GLOBAL_CREDENTIALS.get(BIG_BLUE_BUTTON, {})中读取KEY、SECRET、URL三项。4.4 ProviderManager 自动发现ProviderManager在初始化时通过LiveProvider.__subclasses__()自动发现所有 Provider 子类并实例化get_enabled_providers()进一步过滤出is_enabled为真的 Provider。这意味着新增 Provider 时只需新增一个LiveProvider子类即可被自动注册无需修改注册逻辑——这正是 ADR 中目前只支持 Zoom但其他 Provider 可后续加入的扩展性落点。五、REST API配置、查询与 iframe 渲染urls.py 在api/course_live/前缀下注册了三个端点COURSE_ID_PATTERN为平台统一的课程 id 正则端点视图方法用途course/{course_id}/CourseLiveConfigurationViewGET / POST读取或写入课程的 Live 配置providers/{course_id}/CourseLiveProvidersViewGET列出该课程可用的视频会议 Provideriframe/{course_id}/CourseLiveIframeViewGET返回嵌入 Live 工具的 iframe HTML三个端点都使用ensure_valid_course_key与verify_course_exists()双重校验课程合法性并采用JwtAuthentication、BearerAuthenticationAllowInactiveUser、SessionAuthenticationAllowInactiveUser三种认证方式。5.1 配置接口GET/POSTCourseLiveConfigurationView的权限是IsStaffOrInstructor详见第七节。GET读取CourseLiveConfiguration.get(course_id)若不存在则返回一个空配置对象序列化上下文携带pii_sharing_allowed来自lti_consumer.api.get_lti_pii_sharing_state_for_course与course_idPOST写入/更新配置。处理流程值得注意通过ProviderManager().get_enabled_providers()按provider_type找到对应 Provider若课程不允许 PII 共享而该 Provider 又需要共享 PIIprovider.requires_pii_sharing()直接返回{pii_sharing_allowed: False, message: PII sharing is not allowed on this course}拒绝若 Provider 无需额外参数且请求中携带lti_configuration则自动补入空白的additional_parameters交由CourseLiveConfigurationSerializer校验并保存。5.2 Provider 列表接口GETCourseLiveProvidersView返回形如以下结构的响应{ providers: { active: zoom, available: { zoom: { name: Zoom LTI PRO, features: [], has_free_tier: false, pii_sharing: {username: false, email: false}, additional_parameters: [custom_instructor_email] } } } }其中active为当前课程已选中的 Provider未配置时为空字符串available为所有已启用 Provider 的元信息。5.3 iframe 接口GETCourseLiveIframeView的权限为IsAuthenticated IsEnrolledOrStaff只有已选课用户或课程工作人员才能获取 iframe。它检查CourseLiveTab.is_enabled(course, user)未启用则返回{developer_message: Course live is not enabled for this course.}启用时通过course_live_tab.render_to_fragment(request, course)渲染出 iframe HTML 并返回典型输出为一个idlti-tab-embed、宽度 100%、最小高度 800px 的 LTI 嵌入 iframe见 views.py 中的示例注释。5.4 序列化层的两个关键行为serializers.py 中的LtiSerializer与CourseLiveConfigurationSerializer承担了配置数据的校验与落库lti_1p1_client_secret被标记为write_only读取配置时不会回显密钥而更新时若传入空字符串则保留原值update方法中的兼容逻辑LtiSerializer.validate_lti_config会校验custom_instructor_email的邮箱格式CourseLiveConfigurationSerializer.validate_free_tier要求free_tierTrue必须与 Provider 的has_free_tier一致否则报错Provider does not support free tier创建/更新配置时若free_tierFalse则通过内嵌LtiSerializer写入课程级 LTI 配置若free_tierTrue则置空lti_configuration改由全局凭据见 6.2 节兜底。六、Live 标签页从课程导航到 LTI 嵌入tab.py 定义了CourseLiveTab它继承自LtiCourseLaunchMixin来自openedx.features.lti_course_tab、TabFragmentViewMixin与EnrolledTab是课程导航栏中实际呈现的Live入口。class CourseLiveTab(LtiCourseLaunchMixin, TabFragmentViewMixin, EnrolledTab): type lti_live priority 42 allow_multiple False is_dynamic True title gettext_lazy(Live) ROLE_MAP { student: Student, staff: Administrator, instructor: Administrator, }几个关键实现点跳转目标link_func将标签链接指向 Learning MFE 的live页面片段get_learning_mfe_home_url(course_key..., url_fragmentlive)学习前端frontend-app-learning拿到该 fragment 后再调用iframeAPI 嵌入 LTI启用条件is_enabled在父类基础上叠加CourseLiveConfiguration.is_enabled(course.id)即标签默认不可见只有课程配置了 Live 且 enabledTrue 才显示这与 READMEenable/disable the live tab的描述一一对应test_tab.py 中用enabledTrue/False参数化验证了这一点角色映射LTI 侧角色按ROLE_MAP映射——学生为Student工作人员/讲师为Administrator若课程配置了 Zoom 且用户是全局工作人员GlobalStaff则回退为学生角色PII 增强_get_pii_lti_parameters在配置为 Zoom 且用户是课程工作人员/讲师时额外注入person_contact_email_primary request.user.email即 Zoom LTI 的custom_instructor_email场景。6.1 免费档Free Tier的 LTI 配置来源_get_lti_config是标签页渲染 LTI 的关键逻辑若课程配置了free_tierTrue则从ProviderManager找到对应 Provider并要求其是HasGlobalCredentials子类直接用全局凭据构造LtiConfigurationlaunch_url、client_key、client_secret来自全局设置否则抛出ValueError(Provider does not support global credentials)非免费档则直接使用课程自己的course_live_configurations.lti_configuration。七、权限模型谁可以配置谁可以观看permissions.py 定义了两个 DRF 权限类IsStaffOrInstructor用于配置类接口配置视图、Provider 列表视图。允许全局工作人员GlobalStaff、课程讲师CourseInstructorRole、课程工作人员CourseStaffRole访问否则返回 403IsEnrolledOrStaff用于iframe 内容接口。在前者基础上额外放行已选课学生CourseEnrollment.is_enrolled即学生只要选课即可加载 Live 标签内容但只有工作人员能修改配置。这一设计保证了学生可观看、仅授权人员可配置的职责分离。八、环境配置项Course Live 相关的全局设置在 openedx/envs/common.py 中有默认声明COURSE_LIVE_GLOBAL_CREDENTIALS {}存放各 Provider 的组织级全局凭据字典键为 Provider 标识如BIG_BLUE_BUTTON值为{KEY: ..., SECRET: ..., URL: ...}。空字典时BigBlueButton.has_valid_global_keys()返回False其免费档也不可用COURSE_LIVE_HELP_URL被 plugins.py 中LiveCourseApp.documentation_links引用作为 Course Authoring 界面中了解更多文档链接的来源。在测试环境openedx/envs/test.py中测试配置会同时为 LMS 与 CMS 注入上述凭据用于验证 BigBlueButton 全局凭据与免费档逻辑。生产部署时只需在COURSE_LIVE_GLOBAL_CREDENTIALS中填入真实凭据即可启用对应 Provider 的免费档能力。九、测试覆盖行为即规范test_tab.py 与 test_views.py 从两个层面验证了插件行为标签可见性test_user_can_access_course_live_tab用ddt参数化enabledTrue/False断言标签仅在enabledTrue时对选课用户/工作人员显示直接印证了配置模型控制标签开关的核心链路PII 共享test_course_live_lti_tab_pii对enable_sending_pii × share_username × share_email做全组合测试断言只有当课程的CourseAllowPIISharingInLTIFlag开启且对应开关为真时用户名/邮箱才会出现在 LTI 嵌入代码中验证了 PII 共享的严格受控。测试中还演示了典型的配置组装方式创建CourseLiveConfiguration如provider_typezoom并挂接一个CONFIG_ON_DB类型的LtiConfiguration含lti_1p1_launch_url、lti_1p1_client_key、lti_1p1_client_secret这与第五节 API 写入的数据结构完全一致可作为集成测试或运维排查的参考模板。十、扩展一个新视频会议 Provider综合 ADR 与源码接入一个新 Provider 的完整路径如下在 providers.py 中继承LiveProvider实现id、name、is_enabled并按需声明features、requires_username、requires_email、additional_parameters与has_free_tier若使用组织级凭据再继承HasGlobalCredentials并确保凭据以对应键写入COURSE_LIVE_GLOBAL_CREDENTIALS设置ProviderManager会通过LiveProvider.__subclasses__()自动发现该 Provider无需改动注册代码新增 Provider 即自动出现在providers/{course_id}/接口的available列表中可在配置接口中通过provider_type选中并由CourseLiveTab的 LTI 启动流程完成嵌入。整个过程对既有 API 与标签渲染逻辑零侵入充分体现了 ADR 中可扩展 Provider的设计意图。总结Course Live 插件用约十个源码文件实现了课程级 Live 标签开关 LTI Provider 抽象 全局/课程级凭据双通道 精细权限控制 自动发现的 Provider 管理的完整闭环。对平台运维者而言配置COURSE_LIVE_GLOBAL_CREDENTIALS并在 Course Authoring 的 Pages and Resources 中启用 Live 即可上线视频会议能力对二次开发者而言LiveProvider子类化与CourseApp接口是实现自定义会议工具的标准扩展点。【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表