9a6c3ba225
feat(阶段4): 后台地基 + 公告管理
...
地基:
- auth/middleware.ts 加四个角色守卫 requireAdmin / requireTeacher /
requireSuperAdmin / requireProblemPermission,对应旧 account/decorators.py 的
四个装饰器。未登录 401 login-required、角色不够 403 permission-denied,
与前端 api2 拦截器按 code 分流的两支对上。
- routes/admin/ 目录 + 总入口挂在 /api/admin。角色守卫由各子路由自己挂,
不在总入口兜一层 —— 否则「这个接口要什么角色」从注册行看不出来,
正是阶段 3 Minor M2 踩过的坑。
- packages/contract/src/admin.ts 独立放后台契约。同一张表两侧下发的字段集不同
(后台要 visible,oj 侧连键都不该出现),混在一起迟早有人在 oj 侧复用后台那个。
- utils/legacy.ts:把 toLegacy / legacyResponse 从 oj/api.ts 抽出来共用。
admin 侧组件同样读 snake_case,走同一层适配,组件不动。
公告管理(旧 /api/admin/announcement 一个路径四个动词)拆成:
GET/POST admin/announcements
GET/PUT/DELETE admin/announcements/:id
一处有意不对齐旧后端:删除不存在的公告,旧后端 filter().delete() 静默成功,
这里返回 404 —— 后台是人手点删除,静默成功会让人以为删掉了,刷新后它还在。
实测:匿名 401 / 学生 403 / 超管 200;增删改查、列表不含 content、
空标题 400、不存在 404 全部符合预期。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-07 07:06:22 -06:00
cebaa87b13
fix(Minor M-1): 站内信内嵌提交改用独立 schema,并修复题号链接
...
两件事:
1. 内嵌的 submission 之前复用 submissionDetailSchema 并把 info / ip 写死成空值,
于是键仍留在响应里。旧 SubmissionSafeModelSerializer 是 exclude,这三个键
根本不出现。改成独立的 embeddedSubmissionSchema —— 形状对上了,将来有人
把空值改成真值也不会变成泄露,因为这里压根没有这三个字段。
2. 顺带修掉一个评审没覆盖的真回归:内嵌 submission 给的是 problemId(数字主键),
而旧 serializer 的 problem 是 SlugRelatedField(slug_field="_id"),即展示用题号。
oj/user/message.vue:20 拿它拼 /problem/<题号>,迁移后拼出的是 /problem/undefined,
题号那一栏也是空的。改为下发 problem,实测返回 "1004"。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-07 07:01:13 -06:00
61f74054f9
fix(Minor M3): blog / github 加回 URL 校验
...
旧 account/serializers.py:125,127 是 serializers.URLField,迁移时降级成了
z.string().max(256)。这两个字段会被前端渲染成可点击链接,放任自由字符串等于
允许写入 javascript: 一类伪协议。
只放行 http(s)://,空串表示清空。实测 javascript:alert(1) 与 not a url 均 400,
https://example.com/x 与空串 200。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-07 07:01:13 -06:00
44f6f27841
chore(阶段3): 删除阶段 1 的临时验证物
...
GET /api/dev/problems、dev-problems.vue、对应路由项,以及只服务于它的
problemSummarySchema。阶段 1 用来验证「能从真实库读出一道题」,已完成使命。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-07 06:48:20 -06:00
836d97847e
feat(阶段3): 补齐用户侧依赖的三个 admin 端点
...
重判、提交统计、流程图统计这三条挂在旧后端的 admin 路由下,权限也确实是
teacher/super admin,但入口在用户侧页面里(提交列表页的重判按钮、两个统计面板)。
不做完,阶段 3 的出口标准「用户侧全部功能跑在新后端上」就不成立 —— 按 URL
前缀切阶段会漏掉它们。
- POST submissions/:id/rejudge ← GET admin/submission/rejudge
- GET submissions/statistics ← GET admin/submission/statistics
- GET flowcharts/statistics ← GET admin/flowchart/statistics
几处对齐旧后端的细节:
- AST_CHECK_FAILED(10) 与 ACCEPTED(0) 同算通过
- 完成度先用原始花名册人数算、再修正 person_count,顺序照搬,兜住「学生已删号
但提交记录还在」
- 有提交但零通过的学生,两个名单里都不出现(旧后端同样口径)
- 词云用 @node-rs/jieba,STOPWORDS 与 38 个自定义词逐词照搬;jieba@2 没有
insertWord,改用 loadDict 加载用户词典
- avgScore 分母是有分数的条数,对齐 Django Avg() 跳过 NULL
rejudge 的 jobId 带时间戳。队列保留最近 100 个已完成任务,沿用 submissionId
做 jobId 的话 BullMQ 会认为任务已存在,重判会静默变成空操作。
correctRate 改成数值不带 %,展示格式化交给前端。stripClassPrefix 用
startsWith+slice 而不是 replace,前缀对不上时不会从中间截出乱码;site.ts
原有的 replace 写法一并改掉。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-07 06:48:05 -06:00
8c00cdc947
feat(阶段3): oj 侧端点铺开(基线提交,未经评审)
...
由外部 agent (Codex) 在本会话额度中断期间完成。原样提交作为基线,
后续修复单独成 commit,便于区分与回退。
覆盖 oj 侧 65 个端点,新增 9 组路由(account/achievement/ai/classroom/
content/contest/flowchart/problemset/site)与对应 Zod 契约。
已核验:tsc --noEmit 退出码 0;API 可启动;/api/problems 返回真实数据;
judge 与 flowchart worker 均 ready。
未核验:权限边界与数据泄露,评审进行中。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-07 01:25:36 -06:00
ec274419c3
Build Phase 2 judge vertical slice
2026-08-06 22:42:39 -06:00
9bfe629cd7
feat(阶段1): monorepo 骨架与 @oj2/contract 契约包
2026-08-06 20:39:39 -06:00