Skip to content

core: contest team#1183

Open
renbaoshuo wants to merge 3 commits into
hydro-dev:masterfrom
renbaoshuo:contest-team
Open

core: contest team#1183
renbaoshuo wants to merge 3 commits into
hydro-dev:masterfrom
renbaoshuo:contest-team

Conversation

@renbaoshuo

@renbaoshuo renbaoshuo commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added end-to-end contest team participation: create/rename/leave, member invite/accept/reject, invitation management, and max team-size enforcement (default 5).
    • Added “Allow Team” toggle to contest settings and a dedicated “My Teams / Manage Teams” area with a team participation page.
    • Updated contest attendance to a dialog-based Personal vs Team mode (supports invitation code entry).
  • Bug Fixes
    • Improved teammate-aware visibility, status handling, and hidden content/code access across submissions, hacks, problems, records, clarifications, and scoreboard exports.
  • Documentation/Localization
    • Added Simplified/Traditional Chinese UI text for all team participation flows.
  • Chores
    • Added a dedicated system limit for team members and refined related error messaging.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8160810b-6aba-40c9-8614-40cd303cfba7

📥 Commits

Reviewing files that changed from the base of the PR and between d3822d0 and 0151d7c.

📒 Files selected for processing (1)
  • packages/hydrooj/src/handler/contest.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/hydrooj/src/handler/contest.ts

Walkthrough

Adds team participation to contests, including team creation, invitations, membership limits, team attendance, and contest configuration. Contest status, scoreboard rendering, submissions, judging, hacking, clarifications, file access, and record visibility now account for team members. New team-management and attendance UI flows, responsive styles, and Simplified and Traditional Chinese localization strings are included.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested reviewers: undefined-moe

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and clearly related to the main change: adding contest team support in the core code.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/hydrooj/src/handler/contest.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@renbaoshuo
renbaoshuo marked this pull request as ready for review July 10, 2026 07:10

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
packages/hydrooj/src/model/contest.ts (1)

953-964: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Parallelize per-contest status resolution.

This loop issues up to three sequential round-trips per tid (getStatus, then getTeamVid + getStatus on the non-attended path). On the contest list page with many contests this serializes into a long chain. Consider resolving all tids concurrently with Promise.all.

♻️ Suggested parallelization
-    for (const tid of tids) {
-        // eslint-disable-next-line no-await-in-loop
-        const tsdoc = await getStatus(domainId, tid, uid);
-        if (tsdoc?.attend) {
-            r[tid.toHexString()] = tsdoc;
-            continue;
-        }
-        // eslint-disable-next-line no-await-in-loop
-        const teamVid = await getTeamVid(domainId, tid, uid);
-        // eslint-disable-next-line no-await-in-loop
-        r[tid.toHexString()] = teamVid ? await getStatus(domainId, tid, teamVid) : tsdoc;
-    }
+    await Promise.all(tids.map(async (tid) => {
+        const tsdoc = await getStatus(domainId, tid, uid);
+        if (tsdoc?.attend) {
+            r[tid.toHexString()] = tsdoc;
+            return;
+        }
+        const teamVid = await getTeamVid(domainId, tid, uid);
+        r[tid.toHexString()] = teamVid ? await getStatus(domainId, tid, teamVid) : tsdoc;
+    }));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/hydrooj/src/model/contest.ts` around lines 953 - 964, Parallelize
contest status resolution by replacing the sequential loop with a Promise.all
over tids, preserving the existing attended-status and team-status fallback
behavior in each mapped task, then assign each resolved result into r using the
contest ID key.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/hydrooj/locales/zh_TW.yaml`:
- Around line 489-521: Traditional Chinese is missing the Reject translation
used by contest team UI. Add the key “Reject” to the zh_TW locale entries,
translating it as “拒絕”, alongside the related team invitation translations.

In `@packages/hydrooj/src/handler/contest.ts`:
- Line 476: Update the allowTeam assignment in the contest edit handler so an
explicit form value of false is not overridden by this.tdoc?.allowTeam. Preserve
the existing setting only when disabling teams is disallowed or existing teams
are in use; otherwise pass the submitted value through. Use the surrounding
contest update logic and tdoc team-usage checks to implement the appropriate
guard.

In `@packages/hydrooj/src/handler/judge.ts`:
- Around line 125-128: Add an index on collStatus covering the fields queried by
contest.getTeamVid, preferably { domainId, docType, docId, members }, and ensure
it is created during collection initialization or migration. Alternatively,
update getTeamVid to bypass the members lookup for non-team contests.

In `@packages/hydrooj/src/model/user.ts`:
- Around line 382-384: Update ensureVuser to normalize the username consistently
with createVuser by trimming it before lowercasing in the collV.findOne
unameLower query, ensuring whitespace-padded names match existing vusers.

---

Nitpick comments:
In `@packages/hydrooj/src/model/contest.ts`:
- Around line 953-964: Parallelize contest status resolution by replacing the
sequential loop with a Promise.all over tids, preserving the existing
attended-status and team-status fallback behavior in each mapped task, then
assign each resolved result into r using the contest ID key.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 18d2a5e0-dd96-4483-8ff7-2069819b3cd5

📥 Commits

Reviewing files that changed from the base of the PR and between f73326f and b98b93b.

📒 Files selected for processing (21)
  • packages/hydrooj/locales/zh.yaml
  • packages/hydrooj/locales/zh_TW.yaml
  • packages/hydrooj/src/error.ts
  • packages/hydrooj/src/handler/contest.ts
  • packages/hydrooj/src/handler/judge.ts
  • packages/hydrooj/src/handler/problem.ts
  • packages/hydrooj/src/handler/record.ts
  • packages/hydrooj/src/interface.ts
  • packages/hydrooj/src/model/contest.ts
  • packages/hydrooj/src/model/setting.ts
  • packages/hydrooj/src/model/user.ts
  • packages/onsite-toolkit/submit.ts
  • packages/ui-default/components/contest/contest.page.ts
  • packages/ui-default/components/contest/contest_sidebar.page.styl
  • packages/ui-default/pages/contest_team.page.styl
  • packages/ui-default/templates/contest_edit.html
  • packages/ui-default/templates/contest_main.html
  • packages/ui-default/templates/contest_team.html
  • packages/ui-default/templates/partials/contest_sidebar.html
  • packages/ui-default/templates/partials/contest_user.html
  • packages/ui-default/templates/partials/scoreboard.html

Comment thread packages/hydrooj/locales/zh_TW.yaml
Comment thread packages/hydrooj/src/handler/contest.ts
Comment thread packages/hydrooj/src/handler/judge.ts
Comment thread packages/hydrooj/src/model/user.ts Outdated
@undefined-moe

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9dee68e87c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

} else {
await this.mustMember(vuid);
}
await user.updateVuserById(vuid, { $pull: { members: target, invite: target } });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Revoke contest-status membership when removing teammates

If a teammate is removed after the team has already attended a contest, this only updates the virtual user document; existing contest status docs still keep the old members array. Since contest access is resolved through contest.getTeamVid() by searching those stored status members, the removed user will still be treated as part of the team for already-attended contests and can continue accessing team submissions/private contest state. Either update the corresponding contest status memberships or block membership changes once the team has attended contests.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@undefined-moe Should we prevent team member changes while a contest is active, or simply keep a snapshot for current contest and allow change team member for possible further contest?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my view, preserving snapshots during the contest is expected behavior. However, I hadn't fully considered whether to prohibit changes in order to reduce ambiguity.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
packages/ui-default/pages/contest_team.page.styl (2)

5-45: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate &__row / &__actions patterns between .team-invites-banner and .team-card.

The row (Lines 29-38, 99-108) and actions (Lines 39-45, 109-119) blocks are nearly identical between the two components. Consider extracting a shared mixin/class (e.g. list-row()/list-actions()) to avoid drift as one gets tweaked independently later.

Also applies to: 46-119

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui-default/pages/contest_team.page.styl` around lines 5 - 45,
Extract the duplicated row and actions styling from .team-invites-banner and
.team-card into shared Stylus mixins or reusable classes, then apply them to
both components. Preserve the existing flex, spacing, form-margin, and last-row
border behavior while ensuring future changes remain centralized.

36-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Inconsistent border color sourcing.

Lines 37 and 107 use hardcoded rgba(#000, 0.06)/rgba(#000, 0.05) for row separators, while line 115 uses the theme variable $table-border-color for the same visual purpose a few lines away. If $table-border-color is theme-aware (e.g. dark mode), the hardcoded black-alpha borders on Lines 37/107 won't adapt consistently.

♻️ Suggested fix
     &__row
       display: flex
       align-items: center
       justify-content: space-between
       gap: rem(10px)
       padding: rem(5px) 0

       &:not(:last-child)
-        border-bottom: 1px solid rgba(`#000`, 0.06)
+        border-bottom: 1px solid $table-border-color

Apply the same change at Line 107.

Also applies to: 106-108, 109-115

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui-default/pages/contest_team.page.styl` around lines 36 - 38,
Replace the hardcoded rgba(`#000`, 0.06) and rgba(`#000`, 0.05) row-separator
borders in the relevant contest team styles with the existing
$table-border-color theme variable, including the separator near the
&:not(:last-child) rule and the corresponding rule around the later row styles.
Preserve the current border placement and width.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/hydrooj/src/handler/contest.ts`:
- Around line 1000-1006: Update postRename to trim the incoming name, validate
that the trimmed value is non-empty using the same guard and error behavior as
postCreate, and only then call user.updateVuserById with the validated display
name.
- Around line 1026-1058: Update postAccept and postLeave to synchronize the
corresponding ContestStatusDoc.members snapshot whenever the vuser roster
changes. Add the necessary contest-status update after each successful
membership addition or removal, preserving existing validation and vuser
updates, so getTeamVid and contest record/clarification access immediately
reflect late joins and departures.

---

Nitpick comments:
In `@packages/ui-default/pages/contest_team.page.styl`:
- Around line 5-45: Extract the duplicated row and actions styling from
.team-invites-banner and .team-card into shared Stylus mixins or reusable
classes, then apply them to both components. Preserve the existing flex,
spacing, form-margin, and last-row border behavior while ensuring future changes
remain centralized.
- Around line 36-38: Replace the hardcoded rgba(`#000`, 0.06) and rgba(`#000`, 0.05)
row-separator borders in the relevant contest team styles with the existing
$table-border-color theme variable, including the separator near the
&:not(:last-child) rule and the corresponding rule around the later row styles.
Preserve the current border placement and width.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 890003fb-b908-423d-9174-8db99d0ad01d

📥 Commits

Reviewing files that changed from the base of the PR and between 9dee68e and dab7fb5.

📒 Files selected for processing (22)
  • packages/hydrooj/locales/zh.yaml
  • packages/hydrooj/locales/zh_TW.yaml
  • packages/hydrooj/src/error.ts
  • packages/hydrooj/src/handler/contest.ts
  • packages/hydrooj/src/handler/judge.ts
  • packages/hydrooj/src/handler/problem.ts
  • packages/hydrooj/src/handler/record.ts
  • packages/hydrooj/src/interface.ts
  • packages/hydrooj/src/model/contest.ts
  • packages/hydrooj/src/model/document.ts
  • packages/hydrooj/src/model/setting.ts
  • packages/hydrooj/src/model/user.ts
  • packages/onsite-toolkit/submit.ts
  • packages/ui-default/components/contest/contest.page.ts
  • packages/ui-default/components/contest/contest_sidebar.page.styl
  • packages/ui-default/pages/contest_team.page.styl
  • packages/ui-default/templates/contest_edit.html
  • packages/ui-default/templates/contest_main.html
  • packages/ui-default/templates/contest_team.html
  • packages/ui-default/templates/partials/contest_sidebar.html
  • packages/ui-default/templates/partials/contest_user.html
  • packages/ui-default/templates/partials/scoreboard.html
🚧 Files skipped from review as they are similar to previous changes (18)
  • packages/onsite-toolkit/submit.ts
  • packages/ui-default/components/contest/contest_sidebar.page.styl
  • packages/hydrooj/src/model/setting.ts
  • packages/ui-default/templates/partials/scoreboard.html
  • packages/ui-default/templates/contest_edit.html
  • packages/hydrooj/src/interface.ts
  • packages/hydrooj/locales/zh.yaml
  • packages/ui-default/templates/contest_main.html
  • packages/ui-default/templates/partials/contest_user.html
  • packages/hydrooj/src/model/document.ts
  • packages/hydrooj/src/error.ts
  • packages/hydrooj/src/handler/judge.ts
  • packages/hydrooj/locales/zh_TW.yaml
  • packages/ui-default/components/contest/contest.page.ts
  • packages/hydrooj/src/model/user.ts
  • packages/hydrooj/src/handler/problem.ts
  • packages/hydrooj/src/model/contest.ts
  • packages/hydrooj/src/handler/record.ts

Comment thread packages/hydrooj/src/handler/contest.ts
Comment thread packages/hydrooj/src/handler/contest.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/hydrooj/locales/zh.yaml (1)

496-496: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep the form of address consistent.

These new strings use informal “你”, while the surrounding Simplified Chinese UI consistently uses formal “您”. Please update these entries unless the team flow intentionally uses a different tone.

Proposed wording
-Choose how you want to participate in this contest.: 选择你参加本次比赛的方式。
+Choose how you want to participate in this contest.: 选择您参加本次比赛的方式。
-Leave this team? You may lose access to team contests.: 确定退出该队伍吗?退出后你可能无法访问该队伍参加的比赛。
+Leave this team? You may lose access to team contests.: 确定退出该队伍吗?退出后您可能无法访问该队伍参加的比赛。
-You are not in any team.: 你还没有加入任何队伍。
-You are not in any team yet. Create one from the panel on the right, or ask a teammate to invite you by your username.: 你还没有加入任何队伍。在右侧面板创建一个,或请队友按你的用户名邀请你。
-You have {0} pending team invite(s): 你有 {0} 个待处理的队伍邀请
+You are not in any team.: 您还没有加入任何队伍。
+You are not in any team yet. Create one from the panel on the right, or ask a teammate to invite you by your username.: 您还没有加入任何队伍。在右侧面板创建一个,或请队友按您的用户名邀请您。
+You have {0} pending team invite(s): 您有 {0} 个待处理的队伍邀请

Also applies to: 505-505, 522-524

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/hydrooj/locales/zh.yaml` at line 496, Update the newly added
Simplified Chinese contest-related entries at the referenced locale keys,
including “Choose how you want to participate in this contest.” and the entries
around the other noted locations, replacing informal “你” with formal “您” while
preserving the existing translations and meaning.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/hydrooj/locales/zh.yaml`:
- Line 496: Update the newly added Simplified Chinese contest-related entries at
the referenced locale keys, including “Choose how you want to participate in
this contest.” and the entries around the other noted locations, replacing
informal “你” with formal “您” while preserving the existing translations and
meaning.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e7562ad1-cdac-4a46-81f5-56620c111705

📥 Commits

Reviewing files that changed from the base of the PR and between dab7fb5 and d3822d0.

📒 Files selected for processing (3)
  • packages/hydrooj/locales/zh.yaml
  • packages/hydrooj/locales/zh_TW.yaml
  • packages/ui-default/templates/contest_edit.html
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/ui-default/templates/contest_edit.html
  • packages/hydrooj/locales/zh_TW.yaml

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants