ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Open edX 证书显示设置重构深度解析:certificates_display_behavior 与 certificate_available_date 的设计与实现

Open edX 证书显示设置重构深度解析:certificates_display_behavior 与 certificate_available_date 的设计与实现 Open edX 证书显示设置重构深度解析certificates_display_behavior 与 certificate_available_date 的设计与实现【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform本篇文章基于 Open edX 平台openedx-platform的架构决策记录 005-cert-display-settings.rst系统讲解课程证书可见性相关设置的演进、三种展示行为end/end_with_date/early_no_info的语义、Mongo 数据翻译层的规则以及这些设计在xmodule、CourseDetails与证书服务中的落地实现。读完本文你将理解课程团队在 Studio 中选择证书显示选项后底层数据如何被校验、翻译与消费并掌握should_certificate_be_visible与validate_certificate_settings的核心判定逻辑。背景三个各自为政的证书可见性设置在重构之前课程中直接影响证书可见性的设置共有三个它们分别针对不同的使用场景独立开发彼此之间缺乏一致且易理解的联动关系设置项类型与含义历史问题certificate_display_date一个日期用于决定证书何时可以向学习者展示默认值为课程结束日期之后两天语义笼统未与其它设置联动certificates_display_behavior字符串决定学习者何时能看到自己证书的详情取值end、early_no_info、early_with_info没有任何取值校验字符串散落硬编码在整个平台各处certificates_show_before_end字符串布尔值决定学习者是否能在课程结束前看到证书已弃用deprecated但仍被用来判断是否应向学习者展示证书这三个设置并存导致的直接后果是课程团队难以预判学习者到底什么时候能看到证书平台侧也缺少统一的校验入口来保证数据的合法性。决策重新构想前两项设置保留弃用项直至移除ADR 的决定是重新设计前两个设置第三个设置维持弃用状态直到未来移除。具体而言certificates_display_behavior被更新为使用三个常量由枚举CertificatesDisplayBehaviors定义见 xmodule/data.pyendStudio 显示文案End date of courseend_with_dateStudio 显示文案A date after the course end dateearly_no_infoStudio 显示文案Immediately upon passing这些选项通过 Studio 中措辞更友好的下拉框dropdown供课程团队选择。这些设置仅对 instructor-paced教师主导进度课程生效self-paced自主进度课程不适用。三种行为的具体语义endEnd date of course—— 默认行为课程证书将在课程结束日期course end date到达后对学习者可见。从源码看这也是certificates_display_behavior字段的默认值见 xmodule/course_block.pycertificates_display_behavior String( display_name_(Certificates Display Behavior), help_( This field, together with certificate_available_date will determine when a user can see their certificate for the course ), scopeScope.settings, defaultCertificatesDisplayBehaviors.END.value, )early_no_infoImmediately upon passing一旦学习者在课程中达到及格成绩passing grade证书立即对学习者可见无需等待课程结束。end_with_dateA date after the course end date证书一直不展示直到certificate_available_date中设置的日期到来。这里有一条关键的联动规则如果没有选择此选项certificate_available_date在 Studio 中不会显示其值会被置为None该日期也不会对任何学习者的证书产生影响。字段定义certificate_available_date 与旧布尔字段重构后的核心日期字段certificate_available_date定义在 xmodule/course_block.pycertificate_available_date Date( help_(Date that certificates become available to learners), scopeScope.content )值得注意的是certificate_available_date的scope是Scope.content这意味着它属于课程内容本身而非课程运行设置settings这一点与certificates_display_behaviorScope.settings不同。同时旧布尔字段certificates_show_before_end保留了其定义但被标记为deprecatedTrue见 xmodule/course_block.pycertificates_show_before_end Boolean( display_name_(Certificates Downloadable Before End), help_( Enter true or false. If true, students can download certificates before the course ends, if theyve met certificate requirements. ), scopeScope.settings, defaultFalse, deprecatedTrue )而历史设置certificate_display_date的默认值 课程结束 两天行为在 CourseBlock 初始化逻辑中仍有迹可循xmodule/course_block.py 附近存在self.certificate_available_date self.end timedelta(days2)的默认逻辑印证了 ADR 中对该默认值的描述。可见性判定should_certificate_be_visible证书下载链接是否展示给学习者最终由 lms/djangoapps/certificates/utils.py 中的should_certificate_be_visible函数统一裁决def should_certificate_be_visible( certificates_display_behavior, certificates_show_before_end, has_ended, certificate_available_date, self_paced ): show_early ( certificates_display_behavior CertificatesDisplayBehaviors.EARLY_NO_INFO or certificates_show_before_end ) past_available_date ( certificates_display_behavior CertificatesDisplayBehaviors.END_WITH_DATE and certificate_available_date and certificate_available_date datetime.now(utc) ) ended_without_available_date ( certificates_display_behavior CertificatesDisplayBehaviors.END and has_ended ) return any((self_paced, show_early, past_available_date, ended_without_available_date))该函数接受 5 个参数判定逻辑可以拆解为四类可见场景满足其一即返回Trueself_paced自主进度课程证书始终可见这也是文档强调该设置仅用于教师主导课程的原因——self-paced 课程直接短路放行show_early行为为early_no_info或旧字段certificates_show_before_end为真兼容已弃用设置past_available_date行为为end_with_date且certificate_available_date已设置且早于当前时刻ended_without_available_date行为为end且课程已结束。可以清晰地看到certificates_show_before_end作为一个或条件被保留在了show_early判定中——这正是 ADR 中所说的它虽已弃用但仍被用于决定是否应向学习者展示证书。Mongo 数据翻译层把不可信的 modulestore 数据变成合法组合为什么要翻译而不是迁移由于 Mongo/modulestore 中的数据难以信任课程团队可能通过 XML 直接上传数据且平台无法像 Django/RDBMS 那样通过一次 migration 强制所有存量数据符合新范式因此决策引入了一个新的翻译层translation layer在基于 modulestore 数据构建CourseOverview模型或CourseDetails对象时对certificate_available_date与certificates_display_behavior两个字段进行校验并翻译为合法组合。需要特别强调该翻译层不会把更新后的数据写回 modulestore。它只负责把可能有问题的 modulestore 数据转换为代码库其余部分可以正常使用的功能化数据。三条翻译规则若certificates_display_behavior为early_no_info则certificate_available_date被置为None若certificate_available_date已设置且certificates_display_behavior不是early_no_info则certificates_display_behavior被改为end_with_date若以上两条都不成立则certificate_available_date置为None、certificates_display_behavior置为end。这三条规则在源码中由CourseDetails.validate_certificate_settings精确实现见 openedx/core/djangoapps/models/course_details.pyclassmethod def validate_certificate_settings(cls, certificate_available_date, certificates_display_behavior): Takes the stored values for certificate_available_date and certificates_display_behavior and verifies they work together in tandem per ADR: lms/djangoapps/certificates/docs/decisions/005-cert-display-settings.rst # early_no_info will always show regardless of settings if certificates_display_behavior CertificatesDisplayBehaviors.EARLY_NO_INFO: return (None, CertificatesDisplayBehaviors.EARLY_NO_INFO) # If the date is set and early_no_info isnt if certificate_available_date: return (certificate_available_date, CertificatesDisplayBehaviors.END_WITH_DATE) return (None, CertificatesDisplayBehaviors.END)该方法返回一个二元组(校验后的 certificate_available_date, 校验后的 certificates_display_behavior)且 docstring 中明确引用了本文所依据的 ADR 文件路径是文档 — 实现一一对应的典型样本。完整翻译表为便于速查ADR 给出了完整的翻译表简写CAD certificate_available_dateCDB certificates_display_behaviorCAD in modulestoreCDB in modulestore校验后的 CAD校验后的 CDBdateenddateend_with_datedateend_with_datedateend_with_datedateearly_no_infonullearly_no_infodate无效选项dateend_with_datenullendnullendnullend_with_datenullendnullearly_no_infonullearly_no_infonull无效选项nullend这张表揭示了一个重要事实翻译层能够容忍任何非法字符串——只要日期为空无论 CDB 存的是什么包括完全无效的选项最终都会被归一为end只要日期非空且行为不是early_no_info最终都会被归一为end_with_date。非法取值通过CertificatesDisplayBehaviors.includes_value见 xmodule/data.py可被识别但即便识别为非法翻译层也能安全兜底。翻译层在下游的消费CourseOverview 信号与 Programs 任务翻译后的字段并非只服务于证书展示还被下游多个模块消费CourseOverview 变更信号openedx/core/djangoapps/content/course_overviews/signals.py 中当certificate_available_date、certificates_display_behavior或课程结束日期发生变化时会通过transaction.on_commit发送course_cert_date_change信号通知 Credentials 服务IDA同步修正证书可见性。其中还处理了一个边界情况当展示行为为endEnd date of course且课程 end date 被修改时同样要触发信号以修正由 Credentials IDA 管理的证书可见性。Programs 进度任务openedx/core/djangoapps/programs/tasks.py 根据CourseOverview.certificates_display_behavior的值end_with_date/end/early_no_info分别计算 Program 级证书的预计可得日期说明这一设置同样影响 Program微硕士等项目的证书时间线。测试验证翻译表的单元测试翻译逻辑的正确性由专门的单元测试覆盖见 openedx/core/djangoapps/models/tests/test_course_details.py。测试用例逐行对应翻译表的 8 种组合例如(end, 有日期)→ 校验为end_with_date(end_with_date, 无日期)→ 校验为end(early_no_info, 有日期)→ 日期被清空为None且行为保持early_no_info。证书侧还有 lms/djangoapps/certificates/tests/test_utils.py 与 lms/djangoapps/certificates/tests/test_webview_views.py 等测试验证should_certificate_be_visible与 webview 渲染行为确保证书展示逻辑在视图层与工具函数层保持一致。迁移与兼容性注意事项数据不回写翻译层是读取时校验modulestore 中的原始脏数据会被原样保留不会因为翻译而被动修改。Studio 交互只有选择end_with_date时certificate_available_date输入框才会在 Studio 中显示选择其它选项时该日期被强制归一为None。弃用字段的过渡certificates_show_before_end仍以或条件参与show_early判定保证存量课程在迁移前的体验不回退但新课程应完全依赖certificates_display_behavior。适用范围三种展示行为仅对 instructor-paced 课程有意义self-paced 课程在should_certificate_be_visible中直接返回可见。小结Open edX 通过这份 ADR 将三个相互割裂的证书可见性设置收敛为一个枚举 一个可选日期的清晰模型枚举CertificatesDisplayBehaviors定义合法取值certificate_available_date仅在end_with_date场景生效validate_certificate_settings作为翻译层兜底一切历史脏数据should_certificate_be_visible统一裁决展示时机。这套文档定义语义、源码落实规则、测试锁定行为的闭环是理解 Open edX 证书系统乃至其整体架构决策流程ADR 机制的绝佳入口。【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进