ff31f7abd1e733c090dba21a26c2223635ad79a7
旧栈的 SubmissionListSerializer.get_show_link 有一条防作弊规则:学生加入含某道题的 题单后,他在加入之前留下的 AC 代码就摆在提交列表里,复制粘贴即可过关,所以要把这段 旧提交藏起来。重写时整条丢了 —— canViewSubmission 里 grep 不到一个 problemset, 自己的提交第一行就无条件 return true。 前端反而把 UI 留着了:ProblemSubmission.vue 那个锁图标的 tooltip 一直写着「这道题在 你已经加入的题单中,只有在题单中完成此题,代码才可见」,而后端永远不会给出 showLink: false,图标一次都没亮过 —— 提示语本身成了操作指引。 题单的 end_time 也因此成了孤儿字段:它不是「截止后不能提交」,是这道闸门的时间边界。 影响面不是边角:8-07 的快照里 1734 人次、188 名学生在加入题单之前就已经 AC 过题单 里的题,占全部已解题次的 22.5%。 补回来的同时改了三处旧栈的做法: - 判断放进 canViewSubmission,列表和详情一起挡。旧栈只挡列表链接, SubmissionAPI.get 光走 check_user_permission,知道 submission id 直接访问照样 拿得到代码,遮挡是虚的。 - 一题落在多个已加入题单里时取 max(join_time),「存在任一题单要求遮挡就遮挡」等价于 「早于最晚的那次加入」。旧栈用 .first() 取任意一条,行为不确定。 - 比赛提交列表不挂闸门。题单里的题必定是非比赛题(加题时卡了 contestId IS NULL), 而那条列表只出比赛提交,交集恒空,挂上去就是每页白跑一次查询 —— 而比赛进行中它是 被刷得最狠的。旧栈 ContestSubmissionListAPI 照抄了 bulk_fetch,那边同样是死代码。 闸门只挡「看代码」这一路,不挡 allowShared=false 那一路 —— 后者是分享开关的归属校验, 与作弊无关,挡了学生连自己旧提交的分享都动不了。管理员不受限,对齐旧栈的 is_regular_user() 前提。 解锁三条路实跑验证过:在题单里做出该题、题单过 end_time、题单归档。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QqqZwxtXLo2GTqMi51C94D
Description
No description provided
Languages
TypeScript
58.5%
Vue
39.6%
Shell
1.3%
Dockerfile
0.5%