fix: 比赛结束后回退提交不再被静默丢弃
What does this PR aim to accomplish?:
修复 #1017:从已结束比赛的提交页提交时,#287 / #671 实现的"自动向原题提交"回退功能失效,页面显示"提交失败!请关闭脚本后重试!",且状态里没有新的提交记录。
回退路径本身是好的——它能正确检测 没有这个比赛!、抓取 contest.php、解析出真实题号(issue 附的日志里 Real PID: 1865 就是对的)。坏的是 POST 之后的部分:
- 内层
fetch只console.log(await Response.text()),从不判断提交是否成功。 - 回退分支后面没有
return/else,控制流无条件继续执行外层的失败分支,把状态覆盖成"提交失败"——即使回退提交成功了也一样。
至于"状态里没有提交记录":日志里那次回退提交收到的其实是 XMOJ 的提交冷却页。HUSTOJ submit.php 里有 $OJ_SUBMIT_COOLDOWN_TIME(默认 5 秒)的冷却检查,上游命中时返回 302,但 XMOJ 改成了直接渲染页面,.jumbotron 里写 请勿重复提交。所以 Response.redirected 是 false,响应体被丢掉,提交也就从未发生。顺序上比赛校验在冷却检查之前,因此第一次 cid+pid 的失败提交本身不会写 solution 表。
How does this PR accomplish the above?:
把回退逻辑抽成 SubmitToEndedContestProblem(Source, O2Switch, ReportStatus),返回 {Success, Message}:
- 只把
redirected当成功信号,成功后return,外层不再覆盖状态。 - 处理提交冷却:遇到
请勿重复提交时等冷却过去再重试,3 秒一次、最多 5 次,期间在 ErrorMessage 里提示进度。这是 #1017 里"没有提交记录"的直接原因。 - 失败时显示服务端原文,从响应的
.jumbotron取,不再一律显示"提交失败!请关闭脚本后重试!"。 - 遇到
验证码错误立即RefreshCaptcha("")并停止重试——答案已经被消耗,重试没有意义。 - 补上
GetCaptchaParameter():原回退提交没带 vcode,评测队列繁忙时会因缺验证码失败。 - 题号改用
/\d+/提取:原来的substring(2, 6)会把 5 位题号截成 4 位(18650→1865),静默提交到错误的题目。 - 补齐失败路径:contest.php 取不到、
#problemset > tbody不存在、题号解析不出来时都会显示原因并恢复提交按钮。原代码在这些分支直接return,按钮会永远停在"正在提交..."。 - 顺手移除了隐式全局变量
rPID,并把重复的错误显示代码收拢成ShowSubmitStatus。
验证方式:node --check 通过;另外写了一个一次性回归脚本,从 XMOJ.user.js 里抽出 SubmitToEndedContestProblem 本体,用 mock 的 submit.php 响应跑 10 个场景(成功重定向、冷却后重试成功、冷却始终不放行、导航栏里的 status.php 不被误判成成功、带上 vcode、验证码错误、contest.php 不可达、缺 tbody、5 位题号、题号无数字),全部通过;并用 4 个 mutation 反向确认这些断言不是空跑。
By submitting this pull request, I confirm the following:
- I have read and understood the contributor's guide, as well as this entire template.
- I have commented on my proposed changes within the code.
- I have tested my changes.
- I am willing to help maintain this change if there are issues with it later.
- It is compatible with the GNU General Public License v3.0.
- I have squashed any insignificant commits.
- I have checked that another pull request for this purpose does not exist.
- I have considered and confirmed that this submission will be valuable to others.
- I accept that this submission may not be used, and the PR can be closed at the will of the maintainer.
- I give this submission freely and claim no ownership to its content.
- ⚠️ 未验证 —— 无法自行在浏览器里测试,请人工确认在新 UI 和旧/经典 UI 下均正常。
- ⚠️ 未验证 —— 未在真实的已结束比赛上做端到端提交(会产生真实提交记录),请人工复现 #1017 的步骤确认。
- I have read the above and my PR is ready for review.
关于 #7:#1018 也在修这个 issue。那个 PR 目前仍然冲突、且 XMOJ.user.js 语法不通过,所以这里另开一个。如果 #1018 先修好,这个可以关掉。
🤖 Generated with Claude Code
Summary by Sourcery
确保已结束比赛的提交能够可靠回退到原题,并在冷却或失败时提供可操作的状态反馈。
Bug Fixes:
- 修复比赛结束后回退提交被静默丢弃的问题,确保成功提交后正确跳转并保留提交记录。
- 处理提交冷却、验证码错误及网络或页面解析失败,向用户显示明确的服务端错误信息并恢复提交按钮。
- 修复五位题号解析错误,并确保回退提交携带验证码参数。
Enhancements:
- 将结束比赛回退提交流程集中封装并统一返回结果,避免失败状态被外层逻辑覆盖。
Build:
- 将项目及用户脚本版本更新至 3.6.5。
Chores:
- 新增 3.6.5 发布条目。
Summary by cubic
Fixes the fallback that resubmits to the original problem after a contest ends, so ended-contest submissions no longer fail silently with a generic "提交失败" message and the status page now records the new submission. Closes #1017.
- Extracts the fallback into
SubmitToEndedContestProblem(), returns{Success, Message}, and only treats a redirect as success so the outer failure branch no longer overwrites the status. - Retries up to 5 times with 3-second waits when the server returns the cooldown page (
请勿重复提交), which previously discarded the response and never created a submission. - Re-checks the captcha with
CaptchaIsMissing()before every retry POST, so an empty answer sent during the cooldown wait can't make the server swap the 4-digit captcha for an 8-digit one; its message and button restoration are kept intact. - Wraps both
fetchcalls in try/catch, so a network error returns an error message instead of escaping the click handler and leaving the button stuck on "正在提交...". - Shows the server's own message from
.jumbotronon failure instead of the generic error. - Refreshes the captcha immediately on
验证码错误and stops retrying, because the answer is already consumed. - Adds the missing
GetCaptchaParameter()to the fallback POST body. - Extracts real problem IDs with
/\d+/instead ofsubstring(2, 6), which truncated 5-digit IDs. - Restores the submit button when page or problem-ID parsing fails; earlier those branches returned early and left it stuck on "正在提交...".
- Bumps the script and
package.jsonversions to 3.6.5 and adds the release entry toUpdate.json.
Summary by Sourcery
确保已结束比赛的提交能够可靠回退到原题,并在冷却或失败时提供可操作的状态反馈。
Bug Fixes:
- 修复比赛结束后回退提交被静默丢弃的问题,确保成功提交后正确跳转并保留提交记录。
- 处理提交冷却、验证码错误及网络或页面解析失败,向用户显示明确的服务端错误信息并恢复提交按钮。
- 修复五位题号解析错误,并确保回退提交携带验证码参数。
Enhancements:
- 将结束比赛回退提交流程集中封装并统一返回结果,避免失败状态被外层逻辑覆盖。
Build:
- 将项目及用户脚本版本更新至 3.6.5。
Chores:
- 新增 3.6.5 发布条目。