ARTICLE DETAIL

资讯详情

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

Open edX 课程证书状态机解析:downloadable / notpassing / unavailable / unverified 的设计决策与实践

Open edX 课程证书状态机解析:downloadable / notpassing / unavailable / unverified 的设计决策与实践 Open edX 课程证书状态机解析downloadable / notpassing / unavailable / unverified 的设计决策与实践【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform导读在 Open edX 平台中课程证书并非只有“有/无”两种存在形态而是由一套明确的状态status枚举驱动从生成、发放到失效、撤销每一个业务动作都会将证书记录置于特定状态。本文以 lms/djangoapps/certificates/docs/decisions/004-cert-status.rst 这份已获采纳Accepted的架构决策记录ADR为核心完整梳理当前课程证书代码实际写入的四种状态——downloadable、notpassing、unavailable、unverified并结合仓库中CertificateStatuses模型、GeneratedCertificate的状态变更方法与证书生成链路说明各状态的语义、触发条件与底层实现。读完本文你将能准确理解 Open edX 证书模块的状态机设计并能基于源码定位证书为何“拿不到”“被撤销”或“处于异常态”。一、背景证书状态为什么需要一个明确的集合课程证书在 Open edX 中存储于GeneratedCertificate模型见 lms/djangoapps/certificates/models.py。一份证书在生命周期内可能经历“已生成、已发放、已失效、未通过、未验证”等多种情形因此证书记录上有一个status字段取值来自统一的枚举类CertificateStatuses定义于 lms/djangoapps/certificates/data.py。对用户而言一份证书只有处于downloadable可下载状态时才真正“对用户可见、可获取”——学习者门户dashboard与证书展示页仅展示该状态的证书。其他状态要么表示用户尚未满足发证条件要么表示证书已被撤销用户看不到可用的证书。这一判断标准贯穿证书模块各处例如CertificateStatuses.is_passing_status()仅将downloadable与generating视为“通过”状态供成绩、退款等业务逻辑判断。1.1 历史上的全部状态值CertificateStatuses枚举完整保留了证书模块历史上出现过的所有取值data.py 中CertificateStatuses类状态值语义deletedPDF 证书已被删除deleting已发起删除 PDF 证书的请求downloadable用户已被授予证书证书就绪且可获取errorPDF 证书生成过程中发生错误generating已发起生成 PDF 证书的请求但尚未生成完成notpassing用户未达到及格成绩restricted用户被限制获取证书unavailable证书已被作废invalidatedauditing/audit_passing/audit_notpassing审计轨audit track用户的相关状态honor_passing荣誉轨honor track用户且已及格unverified用户没有获批且未过期的身份验证invalidated证书无效requesting已发起生成 PDF 证书的请求1.2 决策核心当前代码只写四种状态ADR 004 的关键决策在于尽管枚举类保留了上述全部取值但当前课程证书代码只会写入四种状态其余状态仅因历史原因与存量证书而保留downloadable—— 用户已获授证书证书就绪可获取notpassing—— 用户未达到及格成绩unavailable—— 证书已被作废unverified—— 用户没有获批且未过期的身份验证。这一点在源码枚举类的 docstring 中有明确注释data.py四种状态分别由证书生成逻辑generation.py与GeneratedCertificate的mark_notpassing()、invalidate()、mark_unverified()方法写入。二、决策四种状态各自的写入场景与代码实现2.1downloadable生成或更新一份可获取的证书当用户满足全部发证条件时证书模块会生成或更新一份downloadable证书。生成入口是 generation.py 中的generate_course_certificate()其内部通过_generate_certificate()调用GeneratedCertificate.objects.update_or_create()若该用户在此课程 run 下尚无证书记录则创建一条新记录若已存在证书记录则复用其verify_uuid保证学习者原有证书链接继续有效并更新记录。生成后若证书状态属于通过类状态PASSED_STATUSES (downloadable, generating)还会通过emit_certificate_event()发出created证书事件供埋点统计使用。2.2notpassing用户未达到及格成绩用户未通过课程时若证书记录已经存在其状态会被改写为notpassing。对应的实现是GeneratedCertificate.mark_notpassing()models.py入参包括用户当前 enrollment mode、成绩快照grade十进制小数与来源标识source内部调用统一的撤销方法_revoke_certificate()将状态置为CertificateStatuses.notpassing。ADR 同时强调了一种典型场景如果一份downloadable证书已存在而系统收到该用户未及格的成绩信号failing grade signal且该用户不在 allowlist白名单中证书状态就会被改写为notpassing。换句话说即使曾经发过证后续成绩被判定为未通过时证书仍会被降级回收。2.3unavailable证书已被作废证书一旦被作废invalidate状态即为unavailable。实现位于GeneratedCertificate.invalidate()models.py若未显式传入mode会自动查询用户在当前课程 run 的 enrollment mode记录日志后调用_revoke_certificate(statusCertificateStatuses.unavailable, ...)作废动作会触发COURSE_CERT_REVOKED信号进而启动任务检查是否需要同步撤销该学习者的项目program证书若被作废前状态为downloadable还会额外发出edx.certificate.revoked追踪事件见_revoke_certificate()注释models.py。2.4unverified身份验证未通过或已过期当用户满足除“身份验证”外的全部发证条件、但没有获批且未过期的 ID 验证时会生成一份unverified证书。实现位于GeneratedCertificate.mark_unverified()models.py同样走_revoke_certificate()将状态置为unverified。在证书生成链路中这一分支清晰可见generate_course_certificate()在证书状态非通过类时若发现状态为unverified会调用cert.mark_unverified(modeenrollment_mode, sourcecertificate_generation)generation.py。需要注意的是该判断分支使用elif即unverified的补写逻辑只针对未被判定为通过状态的证书。三、后果状态流转规则与关键边界ADR 004 明确了四种状态之间的流转后果结合源码可以归纳如下规则作废即unavailable证书一旦被作废其状态必然为unavailable。全部条件满足 →downloadable生成或更新一份可下载证书。除身份验证外全部满足 →unverified生成一份未验证状态的证书。除及格外全部满足且证书已存在 →notpassing或已有downloadable证书、收到未及格信号且用户不在 allowlist →notpassing。3.1 状态之间不存在层级关系ADR 特别强调这四种状态并不构成一个层级hierarchy。例如一份证书可以处于notpassing即使该用户同样没有通过身份验证要求。各状态由不同的业务条件独立触发不能根据某状态推断另一条件的满足情况。这提醒开发者在做证书相关判断时必须显式检查具体状态值而不是假定状态之间存在大小/先后关系。3.2 辅助状态判断方法CertificateStatuses提供了两个与退款/通过判断相关的类方法data.pyis_passing_status(status)状态是否为downloadable或generatingis_refundable_status(status)状态不在NON_REFUNDABLE_STATUSES (downloadable, generating, unavailable)中时返回 True即处于notpassing、unverified等状态的证书允许退款。此外readable_statuses字典给出了面向用户展示的友好文案例如downloadable → Received、notpassing → Not Received、unavailable → Invalidated。四、配套依据发证条件的完整要求四种状态中的downloadable对应“全部条件满足”的结果其具体条件由两份相邻 ADR 定义常规非 allowlist证书002-cert-requirements.rst要求用户在该 course run 有 enrollment 且 enrollment mode 对证书有资格无需处于 active没有已作废的证书CertificateInvalidation模型HTMLweb证书全局开启且该课程 run 开启用户已通过课程用户不是该 run 的 beta 测试者该 run 不是 CCX 课程若ENABLE_CERTIFICATES_IDV_REQUIREMENTWaffleFlag 开启还需有获批且未过期的身份验证。Allowlist 证书001-allowlist-cert-requirements.rst大体一致但将“用户已通过课程”替换为“用户在该 run 的 allowlist 中”存储于CertificateAllowlist模型早期名为白名单CertificateWhitelist且允许课程工作人员为未获证用户手动授予证书。对照可见“未验证”“未通过”正是常规发证条件中两个可独立缺失的环节——这也是unverified、notpassing两种状态存在的原因。而 allowlist 场景下notpassing的降级规则还要求“用户不在 allowlist”避免白名单用户被成绩信号误伤详见 ADR 004 Consequences。五、源码验证测试用例与状态变更链路仓库测试对上述状态变更逻辑提供了直接验证lms/djangoapps/certificates/tests/test_models.pytest_invalidate/test_invalidate_find_mode/test_invalidate_no_mode覆盖invalidate()显式传 mode、自动从 enrollment 查询 mode、无 enrollment mode 等分支test_invalidate_no_profile、test_invalidate_with_verified_name覆盖无用户 profile、启用 verified name 时的作废行为mark_notpassing与mark_unverified亦有对应测试用例如第 547 行、第 611 行附近的测试。这些测试共同确认了三点事实三种“非下载”状态都经由_revoke_certificate()统一写库invalidate()会自动补查 enrollment mode状态变更会联动事件与信号COURSE_CERT_REVOKED、edx.certificate.revoked。从源码结构可以推断状态变更的核心收敛点就是_revoke_certificate()models.py 起它记录旧状态、清除download_uuid与download_url主要影响 PDF 证书、写入新状态并触发信号与追踪事件——这保证了无论从哪个入口成绩信号、验证失效、人工作废发起状态流转行为都保持一致。六、结语Open edX 的课程证书状态设计遵循“枚举收敛 统一流转”的原则对外部保留完整历史状态值以兼容存量数据对内只使用downloadable、notpassing、unavailable、unverified四个状态表达证书当前的可获取性与资格状况。理解这份 ADR是在 Open edX 上排查证书发放问题、扩展新发证逻辑或对接证书 API 的必备基础。关键源码入口速览状态枚举与判断方法lms/djangoapps/certificates/data.py证书模型与状态变更方法lms/djangoapps/certificates/models.py证书生成链路lms/djangoapps/certificates/generation.py常规证书要求 ADRlms/djangoapps/certificates/docs/decisions/002-cert-requirements.rstAllowlist 证书要求 ADRlms/djangoapps/certificates/docs/decisions/001-allowlist-cert-requirements.rst状态变更测试lms/djangoapps/certificates/tests/test_models.py【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表