Files
OJ2/apps/api
yuetsh 553c084579 feat(阶段4): 比赛管理 + 克隆 + ACM 赛后核查
GET/POST          admin/contests
  GET/PUT           admin/contests/:id
  POST              admin/contests/:id/clone
  GET/PUT           admin/contests/:id/acm-helper

克隆是深拷贝:新比赛从 10 分钟后开始、时长与原比赛相同、一律不可见(时间是拍脑袋定的,
直接开放会让学生看到一场没准备好的赛),比赛题目连同标签一起复制,
提交数/通过数/statistic_info 归零 —— 克隆的是题面不是历史战绩。
实测:源题 99/55 两个标签,克隆出来 0/0 两个标签俱在。

两处比旧后端更严:

- **ACM 核查的 rank 必须属于本场比赛**。旧后端只按 rank_id 取,不校验归属,
  带上任意 rank_id 就能改别的比赛的核查标记。
- 比赛详情/编辑越权时报「不存在」而不是「无权限」,不泄露「有这么个东西但你看不到」。

其余对齐:非超管只看得到自己建的比赛;空串密码归一成 null(否则 contestType 会把
「密码是空字符串」当成密码保护赛);CIDR 按 ip_network(strict=False) 的口径校验,
允许主机位非零。

核查页的 realName 是**有意下发**的:这个页面就是老师对着名单确认谁抄了,
接口已由 requireTeacher + 归属校验双重把关。

实测:学生 403;结束早于开始 400、非法 CIDR 400 且文案带具体网段;创建空串密码
→ Public、改密码后 → Password Protected 且后台能读到密码原文;克隆时长一致且不可见;
不可见比赛的核查页 404;rank 不属于本场 404。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 16:02:28 -06:00
..