Skip to content

feat: registration code gated sign-up (email/password + OAuth) - #5

Merged
ItzArona merged 3 commits into
mainfrom
dev
Jul 23, 2026
Merged

feat: registration code gated sign-up (email/password + OAuth)#5
ItzArona merged 3 commits into
mainfrom
dev

Conversation

@ItzArona

Copy link
Copy Markdown
Collaborator

Summary

Adds an admin-managed registration code system behind a new RegistrationCodeEnabled switch (default off):

  • New registration_codes table (no quota; statuses unused(1)/used(3) only) with atomic single-use consumption (row lock + status CAS). Admin CRUD at /api/registration_code/* plus a "Registration Codes" admin page cloned from redemption codes; used rows show the consuming user's avatar + username via a LEFT JOIN (no N+1).
  • Email/password registration: when the switch is on, a valid code is required and is consumed in the same transaction as user creation (concurrent steal rolls the whole registration back).
  • Standard OAuth (GitHub/Discord/OIDC/LinuxDO): new users get a pending oauth_register auth flow (10 min TTL) and must submit a code via POST /api/oauth/complete_registration; wrong codes leave the flow retryable; existing users log in directly. WeChat/Telegram/Passkey paths untouched.
  • Invariant: the code gate stacks strictly after RegisterEnabled / PasswordRegisterEnabled (re-checked at OAuth completion time) and behavior with the switch off is unchanged.
  • Backend i18n (en/zh-CN/zh-TW) and frontend i18n (all 7 locales) included.

Testing

  • go build ./... passes; go test ./model/ ./controller/ passes, including new tests for: stacking invariants, concurrent single-use (exactly one winner), invalid/expired/used code rejection, OAuth flow retry + replay protection, RegisterEnabled re-check at completion, and switch-off regression.
  • Frontend: tsgo typecheck passes, oxlint clean for new files, i18n:sync reports 0 missing keys for all locales. (rsbuild build fails on this machine's Node 18 even on a clean tree — pre-existing environment issue, unrelated to this change.)

This PR was AI-generated (AI-assisted) — the current git user is not one of the repository's historical core developers.

Add an admin-managed registration code system behind a new
RegistrationCodeEnabled switch (default off):

- New registration_codes table (no quota, unused/used only) with atomic
  single-use consumption via row lock + status CAS
- Admin CRUD at /api/registration_code/* and a Registration Codes page
  cloned from redemption codes (used rows show avatar + username via a
  LEFT JOIN, no N+1)
- Email/password Register requires and consumes a code inside the same
  transaction as user creation
- Standard OAuth (GitHub/Discord/OIDC/LinuxDO) new users get a pending
  oauth_register auth flow and must submit a code via
  POST /api/oauth/complete_registration; existing users log in directly;
  WeChat/Telegram/Passkey untouched
- The gate stacks strictly after RegisterEnabled/PasswordRegisterEnabled
  and behavior is unchanged when the switch is off
- Backend i18n (en/zh-CN/zh-TW) and frontend i18n (7 locales)
- Tests: stacking invariants, concurrent single-use, OAuth flow retry
  and replay protection, switch-off regression
Copilot AI review requested due to automatic review settings July 23, 2026 17:34

Copilot AI 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.

Pull request overview

Adds a registration-code gate to sign-up flows (email/password and standard OAuth) behind a new RegistrationCodeEnabled switch, plus admin CRUD and UI for managing single-use registration codes.

Changes:

  • Introduces registration_codes persistence + atomic single-use consumption, and exposes admin CRUD endpoints under /api/registration_code/*.
  • Gates email/password registration and standard OAuth “new user” registration behind a registration code when enabled (with a pending oauth_register flow for OAuth).
  • Adds an admin “Registration Codes” UI (table, create/update/delete, bulk copy) and wires the feature into sidebar navigation and auth/system settings.

Reviewed changes

Copilot reviewed 56 out of 56 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
web/src/routeTree.gen.ts Adds the authenticated route entry for the registration codes page.
web/src/routes/oauth/$provider.tsx Adds client-side OAuth completion UI for registration-code-required flow.
web/src/routes/_authenticated/registration-codes/index.tsx Adds admin-only route for the Registration Codes page.
web/src/i18n/locales/zh.json Adds some new registration-code-related translations (ZH).
web/src/i18n/locales/zh-TW.json Adds some new registration-code-related translations (ZH-TW).
web/src/i18n/locales/vi.json Adds some new registration-code-related translations (VI).
web/src/i18n/locales/ru.json Adds some new registration-code-related translations (RU).
web/src/i18n/locales/ja.json Adds some new registration-code-related translations (JA).
web/src/i18n/locales/fr.json Adds some new registration-code-related translations (FR).
web/src/i18n/locales/en.json Adds some new registration-code-related translations (EN).
web/src/i18n/locales/_reports/_sync-report.json Updates i18n sync report output (notably zh-TW missingCount).
web/src/hooks/use-sidebar-data.ts Conditionally shows “Registration Codes” in the admin sidebar when enabled.
web/src/features/system-settings/types.ts Adds RegistrationCodeEnabled to auth settings types.
web/src/features/system-settings/auth/section-registry.tsx Wires RegistrationCodeEnabled into settings default values.
web/src/features/system-settings/auth/index.tsx Sets default RegistrationCodeEnabled: false.
web/src/features/system-settings/auth/basic-auth-section.tsx Adds settings toggle UI for registration code requirement.
web/src/features/registration-codes/types.ts Adds TS types/schemas for registration codes feature.
web/src/features/registration-codes/lib/utils.ts Adds client-side expiry helpers for registration codes.
web/src/features/registration-codes/lib/registration-code-form.ts Adds Zod schema + mapping helpers for create/update form payloads.
web/src/features/registration-codes/lib/index.ts Exports registration-code feature utilities.
web/src/features/registration-codes/index.tsx Adds feature entry component/layout for Registration Codes page.
web/src/features/registration-codes/constants.ts Adds status constants + error/success message keys for UI.
web/src/features/registration-codes/components/registration-codes-table.tsx Adds list/search/filter UI with pagination and empty state.
web/src/features/registration-codes/components/registration-codes-provider.tsx Adds context/provider for dialogs and table refresh triggers.
web/src/features/registration-codes/components/registration-codes-primary-buttons.tsx Adds primary actions (create, delete invalid) with confirmation.
web/src/features/registration-codes/components/registration-codes-mutate-drawer.tsx Adds create/update drawer UI (name, expiry, count).
web/src/features/registration-codes/components/registration-codes-mobile-list.tsx Adds mobile list rendering for registration codes.
web/src/features/registration-codes/components/registration-codes-dialogs.tsx Wires mutate drawer + delete dialog.
web/src/features/registration-codes/components/registration-codes-delete-dialog.tsx Adds delete confirmation dialog.
web/src/features/registration-codes/components/registration-codes-columns.tsx Adds table column definitions and filtering logic.
web/src/features/registration-codes/components/registration-code-used-cell.tsx Renders “used by” username/avatar fallback.
web/src/features/registration-codes/components/data-table-row-actions.tsx Adds per-row actions (edit/delete) with disabled rules.
web/src/features/registration-codes/components/data-table-bulk-actions.tsx Adds bulk copy action for selected codes.
web/src/features/registration-codes/api.ts Adds frontend API calls for registration code CRUD/search.
web/src/features/auth/types.ts Adds registration_code fields to payload/status types.
web/src/features/auth/sign-up/components/sign-up-form.tsx Adds registration code input field when required and includes it in payload.
web/src/features/auth/constants.ts Extends signup form schema with optional registrationCode.
web/src/features/auth/api.ts Adds completeOAuthRegistration client API call.
router/api-router.go Adds /api/oauth/complete_registration and admin /api/registration_code/* routes.
model/user.go Adds non-persisted RegistrationCode field for JSON binding.
model/registration_code.go Adds model, queries (JOIN username), and atomic consumption logic.
model/registration_code_test.go Adds model-level tests for filtering/join and single-use consumption.
model/option.go Adds RegistrationCodeEnabled to option map initialization/update.
model/main.go Includes RegistrationCode in migrations.
model/auth_flow.go Adds oauth_register auth flow purpose constant.
i18n/locales/zh-TW.yaml Adds backend i18n messages for registration codes (zh-TW).
i18n/locales/zh-CN.yaml Adds backend i18n messages for registration codes (zh-CN).
i18n/locales/en.yaml Adds backend i18n messages for registration codes (en).
i18n/keys.go Adds backend i18n key constants for registration codes.
controller/user.go Gates email/password registration behind registration codes when enabled.
controller/registration_code.go Adds admin CRUD controllers for registration codes.
controller/register_registration_code_test.go Adds controller-level tests for registration-code-gated register behavior.
controller/oauth.go Adds OAuth pending-registration flow + completion endpoint.
controller/oauth_registration_code_test.go Adds tests for OAuth gated registration flow completion and invariants.
controller/misc.go Exposes registration_code_enabled in status response.
common/constants.go Adds RegistrationCodeEnabled and registration-code status constants.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +142 to +149
if code.ExpiredTime != 0 && code.ExpiredTime < common.GetTimestamp() {
common.ApiErrorI18n(c, i18n.MsgRegistrationCodeExpireTimeInvalid)
return
}
// If you add more fields, please also update RegistrationCode.Update()
cleanCode.Name = code.Name
cleanCode.ExpiredTime = code.ExpiredTime
err = cleanCode.Update()
Comment on lines +299 to +303
<p className='text-muted-foreground text-sm'>
{i18next.t(
'This site requires a registration code to create a new account. Enter it to finish signing up.'
)}
</p>
Comment on lines +169 to +172
emptyTitle={t('No Registration Codes Found')}
emptyDescription={t(
'No registration codes available. Create your first registration code to get started.'
)}
Comment on lines +95 to +99
export const ERROR_MESSAGES = {
UNEXPECTED: 'An unexpected error occurred',
LOAD_FAILED: 'Failed to load registration codes',
SEARCH_FAILED: 'Failed to search registration codes',
CREATE_FAILED: 'Failed to create registration code',
- UpdateRegistrationCode now enforces the same 1-20 rune name rule as
  create, with a regression test
- Add the 13 registration-code UI keys that were missing from en.json
  (error/success toasts, drawer descriptions, empty state, OAuth
  completion hint) and translate them in all 7 locales

Copilot AI 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.

Pull request overview

Copilot reviewed 56 out of 56 changed files in this pull request and generated 1 comment.

Comment thread web/src/features/registration-codes/api.ts
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@ItzArona
ItzArona merged commit c6a9e3e into main Jul 23, 2026
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.

3 participants