Skip to content

feat: 关联 discord 账号 - #1706

Merged
seefs001 merged 3 commits into
QuantumNous:mainfrom
StageDog:feat/discord_oauth
Nov 23, 2025
Merged

feat: 关联 discord 账号#1706
seefs001 merged 3 commits into
QuantumNous:mainfrom
StageDog:feat/discord_oauth

Conversation

@StageDog

@StageDog StageDog commented Aug 31, 2025

Copy link
Copy Markdown
Contributor

PR 类型

  • 新功能

PR 是否包含破坏性更新?

PR 描述

为 discord 添加 oauth 关联

Summary by CodeRabbit

  • New Features

    • Added Discord OAuth login and registration.
    • Added Discord account binding for existing users and discord_id in user profiles.
    • Added admin Discord OAuth settings with validation to prevent enabling without credentials.
    • Integrated Discord buttons/routes across login, registration, account management and admin UI.
  • Documentation

    • Updated README, API docs and Chinese locale entries to include Discord OAuth.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Aug 31, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds Discord OAuth: backend handlers for login and binding, Discord settings, user model DiscordId, frontend OAuth flows/buttons/routes, system settings UI, and API/docs updates to expose /api/oauth/discord and related status flags.

Changes

Cohort / File(s) Change Summary
Docs & API reference
README.en.md, README.md, docs/api/web_api.md
Added Discord OAuth to docs and API table (GET /api/oauth/discord).
Backend — OAuth handlers & settings
controller/discord.go, setting/system_setting/discord.go
New Discord OAuth handlers (DiscordOAuth, DiscordBind) with code→token exchange, user info fetch, user creation/reuse and binding logic; added DiscordSettings (Enabled, ClientId, ClientSecret) and accessor.
Backend — Integration points
controller/misc.go, controller/option.go, controller/user.go, router/api-router.go
Exposed discord_oauth and discord_client_id in status; validation added when enabling discord.enabled; added discord_id to GetSelf response; registered GET /api/oauth/discord route.
Data model
model/user.go
Added DiscordId string (DB index), FillUserByDiscordId() method, and IsDiscordIdAlreadyTaken() helper.
Frontend — OAuth helpers & i18n
web/src/helpers/api.js, web/src/i18n/locales/zh.json
Added onDiscordOAuthClicked(client_id) to initiate Discord OAuth; added Chinese translation for Discord login label.
Frontend — Routes & callbacks
web/src/App.jsx
Added '/oauth/discord' route rendering OAuth2Callback for Discord.
Frontend — Login & Registration UI
web/src/components/auth/LoginForm.jsx, web/src/components/auth/RegisterForm.jsx
Added Discord OAuth button, loading state, click handlers that call onDiscordOAuthClicked and enforce agreement checks.
Frontend — Settings & Account binding UI
web/src/components/settings/SystemSetting.jsx, web/src/components/settings/personal/cards/AccountManagement.jsx, web/src/components/table/users/modals/EditUserModal.jsx
Added Discord config inputs (client id/secret) and checkbox, submit flow for Discord credentials, account-binding card/button in personal settings, and discord_id field in EditUserModal.

Sequence Diagram(s)

sequenceDiagram
    participant U as User (Browser)
    participant FE as Frontend
    participant BE as Backend (Gin)
    participant D as Discord OAuth
    participant DB as Database

    rect rgb(220,240,255)
    note over U,BE: Discord OAuth Login / Registration

    U->>FE: Click "Continue with Discord"
    FE->>FE: getOAuthState()
    FE->>D: Redirect to Discord OAuth (client_id, redirect_uri, state)
    D->>U: Authorize & redirect back (/oauth/discord?code&state)

    U->>FE: Browser hits /oauth/discord
    FE->>BE: GET /api/oauth/discord?code=...
    BE->>D: Exchange code -> token
    D-->>BE: access_token
    BE->>D: Fetch user info (identify, openid)
    D-->>BE: discord user (id, username)
    alt DiscordId exists
        BE->>DB: Lookup user by discord_id
        DB-->>BE: user
        BE->>BE: validate status -> login
    else New user
        BE->>DB: ensure discord_id not taken
        BE->>DB: create user with discord_id
    end
    BE-->>FE: JSON success / user info
    FE->>U: Complete login / redirect
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

  • Review Discord token exchange & HTTP error handling in controller/discord.go.
  • Verify uniqueness checks and DB updates around DiscordId in model/user.go.
  • Confirm settings validation in controller/option.go and UI submit flow in web/src/components/settings/SystemSetting.jsx.
  • Check frontend state/UX paths in Login/Register components.

Possibly related PRs

Suggested reviewers

  • seefs001

Poem

🐰 I hopped to add a Discord key,
Tokens scurried back to me,
Buttons sparkle, users bind,
Settings tucked and code aligned,
A tiny rabbit cheers with glee! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.56% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat: 关联 discord 账号' directly matches the main objective of adding Discord OAuth account association functionality across the codebase.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2bc9916 and 5f27edc.

📒 Files selected for processing (1)
  • model/user.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • model/user.go

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 and usage tips.

@seefs001
seefs001 changed the base branch from alpha to main November 22, 2025 10:30
@seefs001

Copy link
Copy Markdown
Collaborator

代码看着没什么问题,但是还有最后一个地方需要处理,新的设置项的读取和写入需要模仿 @settings 下的内容来操作,这个弄完就应当可以合并了

@StageDog

StageDog commented Nov 22, 2025

Copy link
Copy Markdown
Contributor Author

新的设置项的读取和写入需要模仿 @settings 下的内容来操作

这个具体在哪里,我在仓库里搜索 @settings 没能找到

是指这个吗

package system_setting
import "github.com/QuantumNous/new-api/setting/config"
type OIDCSettings struct {
Enabled bool `json:"enabled"`
ClientId string `json:"client_id"`
ClientSecret string `json:"client_secret"`
WellKnown string `json:"well_known"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
UserInfoEndpoint string `json:"user_info_endpoint"`
}
// 默认配置
var defaultOIDCSettings = OIDCSettings{}
func init() {
// 注册到全局配置管理器
config.GlobalConfig.Register("oidc", &defaultOIDCSettings)
}
func GetOIDCSettings() *OIDCSettings {
return &defaultOIDCSettings
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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)
web/src/components/auth/RegisterForm.jsx (1)

31-32: Discord OAuth handler and loading state are wired correctly; optional alignment with terms gating

The new onDiscordOAuthClicked import, discordLoading state, and handleDiscordClick implementation are consistent with existing OAuth handlers (GitHub, LinuxDO, OIDC) and the helper signature. Given that LoginForm.jsx’s handleDiscordClick enforces the 用户协议/隐私政策 checkbox before redirect, consider reusing the same (hasUserAgreement || hasPrivacyPolicy) && !agreedToTerms guard here if you want Discord-based registration to obey the same terms requirement.

Also applies to: 55-79, 270-277

controller/discord.go (1)

36-100: Discord token & userinfo fetch helper is sound; optional logging enhancement

The code correctly validates code, uses client credentials, applies a 5s timeout, checks for a missing access_token, and then fetches /users/@me with proper authorization and status checks. For easier debugging of misconfigurations, you might additionally log the token endpoint’s non-200 status and (sanitized) body before returning the generic “获取 Token 失败/用户信息失败” errors, but this is not required for correctness.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between efb8f1f and 87811a0.

📒 Files selected for processing (19)
  • README.en.md (1 hunks)
  • README.md (1 hunks)
  • common/constants.go (2 hunks)
  • controller/discord.go (1 hunks)
  • controller/misc.go (1 hunks)
  • controller/option.go (1 hunks)
  • controller/user.go (1 hunks)
  • docs/api/web_api.md (1 hunks)
  • model/option.go (4 hunks)
  • model/user.go (3 hunks)
  • router/api-router.go (1 hunks)
  • web/src/App.jsx (1 hunks)
  • web/src/components/auth/LoginForm.jsx (7 hunks)
  • web/src/components/auth/RegisterForm.jsx (7 hunks)
  • web/src/components/settings/SystemSetting.jsx (5 hunks)
  • web/src/components/settings/personal/cards/AccountManagement.jsx (2 hunks)
  • web/src/components/table/users/modals/EditUserModal.jsx (2 hunks)
  • web/src/helpers/api.js (1 hunks)
  • web/src/i18n/locales/zh.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (10)
router/api-router.go (2)
middleware/rate-limit.go (1)
  • CriticalRateLimit (104-109)
controller/discord.go (1)
  • DiscordOAuth (102-179)
controller/option.go (1)
common/constants.go (1)
  • DiscordClientId (86-86)
model/user.go (1)
model/main.go (1)
  • DB (64-64)
model/option.go (1)
common/constants.go (4)
  • OptionMap (37-37)
  • DiscordOAuthEnabled (47-47)
  • DiscordClientId (86-86)
  • DiscordClientSecret (87-87)
web/src/components/settings/personal/cards/AccountManagement.jsx (2)
web/src/components/settings/PersonalSetting.jsx (1)
  • status (61-61)
web/src/helpers/api.js (1)
  • onDiscordOAuthClicked (234-243)
web/src/components/auth/RegisterForm.jsx (2)
web/src/components/auth/LoginForm.jsx (3)
  • discordLoading (78-78)
  • handleDiscordClick (305-317)
  • status (105-108)
web/src/helpers/api.js (1)
  • onDiscordOAuthClicked (234-243)
controller/misc.go (1)
common/constants.go (2)
  • DiscordOAuthEnabled (47-47)
  • DiscordClientId (86-86)
web/src/components/auth/LoginForm.jsx (3)
web/src/components/auth/RegisterForm.jsx (6)
  • discordLoading (77-77)
  • handleDiscordClick (270-277)
  • hasUserAgreement (89-89)
  • hasPrivacyPolicy (90-90)
  • agreedToTerms (88-88)
  • status (103-106)
web/src/helpers/utils.jsx (1)
  • showInfo (161-163)
web/src/helpers/api.js (1)
  • onDiscordOAuthClicked (234-243)
controller/discord.go (5)
common/constants.go (5)
  • DiscordClientId (86-86)
  • DiscordClientSecret (87-87)
  • DiscordOAuthEnabled (47-47)
  • RegisterEnabled (52-52)
  • UserStatusEnabled (179-179)
setting/system_setting/system_setting_old.go (1)
  • ServerAddress (3-3)
common/sys_log.go (2)
  • SysLog (11-14)
  • SysError (16-19)
common/gin.go (1)
  • ApiError (104-109)
model/user.go (3)
  • User (20-50)
  • IsDiscordIdAlreadyTaken (590-592)
  • GetMaxUserId (182-186)
web/src/App.jsx (2)
web/src/components/common/ui/Loading.jsx (1)
  • Loading (23-29)
web/src/components/auth/OAuth2Callback.jsx (1)
  • OAuth2Callback (33-93)
🔇 Additional comments (29)
controller/user.go (1)

456-456: LGTM: Discord ID field properly exposed in user self-information.

The addition of discord_id to the GetSelf response is consistent with the existing OAuth provider fields (github_id, oidc_id, wechat_id, telegram_id) and correctly exposes the Discord account binding information to the frontend.

web/src/components/table/users/modals/EditUserModal.jsx (1)

75-75: LGTM: Discord ID field properly integrated into user edit modal.

The discord_id field has been correctly added to:

  • Initial form values (line 75) for proper form initialization
  • Binding information display list (line 336) following the established pattern for third-party OAuth accounts

The placement and implementation are consistent with other OAuth provider integrations.

Also applies to: 336-336

model/user.go (1)

30-30: LGTM: Discord ID field and lookup method properly implemented.

The DiscordId field definition (line 30) and FillUserByDiscordId method (lines 543-549) follow the established patterns for other OAuth providers, with proper:

  • JSON and GORM tags with indexing
  • Error handling for empty IDs
  • Database query implementation

Also applies to: 543-549

docs/api/web_api.md (1)

45-45: LGTM: API documentation properly updated.

The Discord OAuth endpoint documentation has been correctly added to the OAuth / Third-party login section, following the same format as existing OAuth endpoints (GitHub, OIDC, LinuxDO, etc.).

web/src/i18n/locales/zh.json (1)

260-260: LGTM: Chinese translation properly added.

The Discord login translation entry follows the established pattern for other OAuth providers (GitHub, LinuxDO, OIDC) and is correctly placed in the localization file.

controller/misc.go (1)

55-56: LGTM: Discord OAuth status fields properly exposed.

The discord_oauth and discord_client_id fields have been correctly added to the GetStatus endpoint response, following the same pattern as the GitHub OAuth integration (lines 53-54). This enables the frontend to check Discord OAuth availability and configuration.

Note: Based on the PR review comment from seefs001, there may be additional work needed to handle Discord settings through the @settings system. Please verify that common.DiscordOAuthEnabled and common.DiscordClientId are properly synchronized with the settings/options persistence layer, similar to how other OAuth providers handle their configuration.

Based on learnings

router/api-router.go (1)

33-33: LGTM: Discord OAuth route properly registered.

The Discord OAuth endpoint has been correctly added with:

  • Appropriate CriticalRateLimit middleware (consistent with other OAuth routes)
  • Proper route placement in the OAuth section
  • Standard RESTful pattern matching existing OAuth implementations
README.md (1)

196-196: LGTM: Documentation properly updated with Discord OAuth feature.

The Discord authorization login feature has been correctly added to the "授权与安全" (Authorization and Security) section of the README, maintaining consistency with other OAuth provider listings.

README.en.md (1)

196-196: LGTM - Documentation update for Discord OAuth

The Discord authorization login entry is properly added to the Authorization and Security section, consistent with other OAuth provider entries.

web/src/App.jsx (1)

195-202: LGTM - Discord OAuth route follows established pattern

The new Discord OAuth callback route is correctly implemented, matching the structure of existing OAuth providers (GitHub, OIDC, LinuxDO) with proper Suspense wrapping and error handling.

common/constants.go (2)

47-47: LGTM - Discord OAuth constants properly defined

The Discord OAuth configuration constants follow the established pattern of other OAuth providers (GitHub, LinuxDO) with appropriate default values.


86-87: LGTM - Discord credentials constants

Client ID and Secret constants are properly declared, consistent with the GitHub OAuth implementation pattern.

web/src/components/settings/personal/cards/AccountManagement.jsx (1)

251-290: LGTM - Discord account binding UI properly implemented

The Discord binding card follows the exact pattern of existing OAuth provider bindings (GitHub, LinuxDO), with proper state management, conditional rendering, and consistent UI layout.

model/option.go (4)

41-41: LGTM - Discord OAuth enabled flag initialization

The DiscordOAuthEnabled option is properly initialized in the option map, following the same pattern as GitHubOAuthEnabled.


99-100: LGTM - Discord credentials initialization

Discord client ID and secret are properly initialized with empty defaults in the option map, consistent with GitHub OAuth credentials.


230-231: LGTM - Discord enabled flag update logic

The update logic for DiscordOAuthEnabled properly converts the string value to boolean and assigns it to the global variable, following the established pattern.


368-371: LGTM - Discord credentials update logic

The update cases for DiscordClientId and DiscordClientSecret properly assign values to the corresponding global variables, consistent with GitHub OAuth handling.

controller/option.go (1)

74-81: LGTM - Discord OAuth validation follows established pattern

The validation check for Discord OAuth credentials mirrors the GitHub OAuth validation, preventing enablement without proper configuration. The Chinese error message is consistent with other validation messages in this file.

web/src/components/auth/LoginForm.jsx (4)

304-317: LGTM - Discord login handler properly implemented

The handleDiscordClick function correctly implements user agreement validation and loading state management, following the same pattern as GitHub OAuth.


493-504: LGTM - Discord login button consistent with other OAuth providers

The Discord OAuth button is properly rendered with:

  • Conditional display based on status.discord_oauth
  • Consistent styling with other OAuth buttons
  • Proper icon integration
  • Loading state handling
  • Localized button text

748-748: LGTM - Discord included in OAuth options check

Discord is properly included in the conditional logic that determines whether to show the "other login options" button.


884-884: LGTM - Discord included in form display logic

Discord is correctly included in the conditional that decides whether to show OAuth options or the email login form.

web/src/helpers/api.js (1)

234-243: Original review comment is incorrect

Discord DOES support openid as a valid OAuth 2.0 scope. The claim that "Discord doesn't implement OpenID Connect" is inaccurate. The current implementation using scope = 'identify+openid' is valid and no changes are needed.

Likely an incorrect or invalid review comment.

web/src/components/auth/RegisterForm.jsx (2)

392-403: Discord OAuth button integration looks correct

The new Discord button is properly gated on status.discord_oauth, uses SiDiscord with appropriate sizing, binds to handleDiscordClick, and reflects discordLoading for UX consistency with other providers.


618-623: Gating conditions correctly include Discord as an OAuth option

Adding status.discord_oauth into both the “其他注册选项” condition and the top-level decision between email form vs. OAuth options ensures that Discord-only setups behave correctly (i.e., the alternate options button shows and the OAuth panel is used when Discord is the sole provider).

Also applies to: 713-719

controller/discord.go (1)

102-179: DiscordOAuth flow correctly handles state, toggle flags, and auto-registration

DiscordOAuth properly validates the state against the session, branches to binding when a session user exists, respects DiscordOAuthEnabled and RegisterEnabled, reuses IsDiscordIdAlreadyTaken/FillUserByDiscordId for existing accounts, and only auto-creates a user when allowed, with sensible fallbacks for Username and DisplayName. The post-login status check against UserStatusEnabled before setupLogin is also consistent with the rest of the system.

web/src/components/settings/SystemSetting.jsx (3)

49-58: Discord settings are correctly added to inputs and option normalization

The additions of DiscordOAuthEnabled, DiscordClientId, and DiscordClientSecret to inputs and originInputs, plus inclusion of DiscordOAuthEnabled in the boolean toBoolean switch, mirror how other auth toggles are handled. This satisfies the requirement that new settings follow the existing @settings read/normalize pattern.

Also applies to: 173-191


480-499: submitDiscordOAuth mirrors existing provider submit patterns

submitDiscordOAuth follows the same approach as submitGitHubOAuth/submitLinuxDOOAuth: only pushes DiscordClientId when changed, and only sends DiscordClientSecret when it has changed and is non-empty, avoiding accidental secret clearing and unnecessary writes. Using the shared updateOptions helper keeps behavior consistent with other providers.


1042-1050: Discord OAuth toggle and configuration UI are consistent with other providers

The new DiscordOAuthEnabled checkbox in the 登录/注册 section and the dedicated “配置 Discord OAuth” card align with the existing GitHub/Linux DO patterns. The banner text correctly guides admins to use ${ServerAddress} and ${ServerAddress}/oauth/discord for Homepage and callback URLs, matching the backend’s redirect_uri construction. This should make the new provider straightforward to operate.

Also applies to: 1447-1477

Comment thread controller/discord.go
Comment on lines +181 to +224
func DiscordBind(c *gin.Context) {
if !common.DiscordOAuthEnabled {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "管理员未开启通过 Discord 登录以及注册",
})
return
}
code := c.Query("code")
discordUser, err := getDiscordUserInfoByCode(code)
if err != nil {
common.ApiError(c, err)
return
}
user := model.User{
DiscordId: discordUser.UID,
}
if model.IsDiscordIdAlreadyTaken(user.DiscordId) {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "该 Discord 账户已被绑定",
})
return
}
session := sessions.Default(c)
id := session.Get("id")
// id := c.GetInt("id") // critical bug!
user.Id = id.(int)
err = user.FillUserById()
if err != nil {
common.ApiError(c, err)
return
}
user.DiscordId = discordUser.UID
err = user.Update(false)
if err != nil {
common.ApiError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "bind",
})
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Guard against panics when reading user id from session in DiscordBind

DiscordBind assumes session.Get("id") is always a non-nil int and immediately does id.(int). If the route is ever hit without a fully populated session (e.g., expired session, misconfigured middleware, or different type stored), this will panic and 500 the request. The commented // id := c.GetInt("id") // critical bug! line is also stale and confusing.

Safely handle missing/invalid session ids and remove the dead comment, for example:

-    session := sessions.Default(c)
-    id := session.Get("id")
-    // id := c.GetInt("id")  // critical bug!
-    user.Id = id.(int)
+    session := sessions.Default(c)
+    idVal := session.Get("id")
+    id, ok := idVal.(int)
+    if !ok {
+        c.JSON(http.StatusOK, gin.H{
+            "success": false,
+            "message": "用户未登录或会话无效",
+        })
+        return
+    }
+    user.Id = id

This avoids a runtime panic and returns a controlled JSON error instead.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func DiscordBind(c *gin.Context) {
if !common.DiscordOAuthEnabled {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "管理员未开启通过 Discord 登录以及注册",
})
return
}
code := c.Query("code")
discordUser, err := getDiscordUserInfoByCode(code)
if err != nil {
common.ApiError(c, err)
return
}
user := model.User{
DiscordId: discordUser.UID,
}
if model.IsDiscordIdAlreadyTaken(user.DiscordId) {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "该 Discord 账户已被绑定",
})
return
}
session := sessions.Default(c)
id := session.Get("id")
// id := c.GetInt("id") // critical bug!
user.Id = id.(int)
err = user.FillUserById()
if err != nil {
common.ApiError(c, err)
return
}
user.DiscordId = discordUser.UID
err = user.Update(false)
if err != nil {
common.ApiError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "bind",
})
}
func DiscordBind(c *gin.Context) {
if !common.DiscordOAuthEnabled {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "管理员未开启通过 Discord 登录以及注册",
})
return
}
code := c.Query("code")
discordUser, err := getDiscordUserInfoByCode(code)
if err != nil {
common.ApiError(c, err)
return
}
user := model.User{
DiscordId: discordUser.UID,
}
if model.IsDiscordIdAlreadyTaken(user.DiscordId) {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "该 Discord 账户已被绑定",
})
return
}
session := sessions.Default(c)
idVal := session.Get("id")
id, ok := idVal.(int)
if !ok {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "用户未登录或会话无效",
})
return
}
user.Id = id
err = user.FillUserById()
if err != nil {
common.ApiError(c, err)
return
}
user.DiscordId = discordUser.UID
err = user.Update(false)
if err != nil {
common.ApiError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "bind",
})
}
🤖 Prompt for AI Agents
In controller/discord.go around lines 181-224, DiscordBind currently does an
unchecked id.(int) on session.Get("id") and has a stale commented line; change
it to safely read and validate the session id (remove the dead comment):
retrieve session.Get("id"), check for nil, perform a safe type assertion (or use
a type switch) to extract an int, and if missing/invalid return a controlled
JSON error (or common.ApiError) instead of panicking; only proceed to
FillUserById/Update when you have a valid int user id.

Comment thread model/user.go
@seefs001

Copy link
Copy Markdown
Collaborator

新的设置项的读取和写入需要模仿 @settings 下的内容来操作

这个具体在哪里,我在仓库里搜索 @settings 没能找到

是指这个吗

package system_setting
import "github.com/QuantumNous/new-api/setting/config"
type OIDCSettings struct {
Enabled bool `json:"enabled"`
ClientId string `json:"client_id"`
ClientSecret string `json:"client_secret"`
WellKnown string `json:"well_known"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
UserInfoEndpoint string `json:"user_info_endpoint"`
}
// 默认配置
var defaultOIDCSettings = OIDCSettings{}
func init() {
// 注册到全局配置管理器
config.GlobalConfig.Register("oidc", &defaultOIDCSettings)
}
func GetOIDCSettings() *OIDCSettings {
return &defaultOIDCSettings
}

对的,需要按照这个加一个

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
setting/system_setting/discord.go (1)

5-9: Consider following Go naming conventions for acronyms.

The field name ClientId should be ClientID to follow Go's naming convention where acronyms are capitalized (e.g., ID, URL, HTTP). Same applies to the JSON tag which should remain client_id.

 type DiscordSettings struct {
 	Enabled               bool   `json:"enabled"`
-	ClientId              string `json:"client_id"`
+	ClientID              string `json:"client_id"`
 	ClientSecret          string `json:"client_secret"`
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 87811a0 and 2bc9916.

📒 Files selected for processing (5)
  • controller/discord.go (1 hunks)
  • controller/misc.go (1 hunks)
  • controller/option.go (1 hunks)
  • setting/system_setting/discord.go (1 hunks)
  • web/src/components/settings/SystemSetting.jsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • controller/option.go
  • controller/discord.go
  • controller/misc.go
🧰 Additional context used
🧬 Code graph analysis (2)
setting/system_setting/discord.go (1)
setting/config/config.go (1)
  • GlobalConfig (19-19)
web/src/components/settings/SystemSetting.jsx (1)
web/src/components/table/channels/modals/EditChannelModal.jsx (2)
  • originInputs (130-166)
  • inputs (171-171)
🔇 Additional comments (7)
setting/system_setting/discord.go (2)

19-21: Verify thread safety of returning pointer to package-level variable.

Returning a direct pointer to the package-level defaultDiscordSettings allows callers to mutate the shared state, which could lead to race conditions if accessed concurrently. Consider whether the config manager provides synchronization, or if a copy should be returned instead.

If thread safety is a concern, you might consider returning a copy:

func GetDiscordSettings() DiscordSettings {
	return defaultDiscordSettings
}

Or ensuring all access is synchronized through the config manager.


14-17: Implementation follows the requested pattern correctly.

The Discord settings registration follows the same pattern as other OAuth providers (like OIDC) in the codebase, which addresses the reviewer's feedback about following the @settings implementation pattern.

web/src/components/settings/SystemSetting.jsx (5)

55-57: State initialization follows consistent naming pattern.

The Discord state fields use dot notation (discord.enabled, discord.client_id, discord.client_secret), which is consistent with the OIDC implementation and appropriate for namespaced settings.


185-185: Boolean option handling is correct.

The discord.enabled field is properly added to the boolean normalization switch case, ensuring the value from the API is correctly converted to a boolean. This matches the pattern used for other OAuth providers.


480-499: Submit function implementation looks good.

The submitDiscordOAuth function correctly follows the established pattern used by submitGitHubOAuth and other OAuth providers:

  • Only submits changed fields
  • Protects the secret field by only updating when non-empty
  • Uses the existing updateOptions helper

1042-1050: Discord login checkbox is properly implemented.

The Discord enable checkbox is correctly integrated into the login/registration configuration section, following the same pattern as other OAuth providers (GitHub, OIDC, etc.).


1447-1477: Discord OAuth configuration UI is well-implemented.

The Discord OAuth configuration card follows the established pattern:

  • Provides helpful setup instructions in the Banner
  • Uses proper field notation for the Form inputs
  • Correctly marks the secret field as password type
  • Wired to the appropriate submit handler

The implementation is consistent with other OAuth provider configurations (GitHub, OIDC).

@seefs001
seefs001 merged commit 07aff1f into QuantumNous:main Nov 23, 2025
1 check passed
@StageDog
StageDog deleted the feat/discord_oauth branch December 2, 2025 11:15
ennnnny pushed a commit to ennnnny/new-api that referenced this pull request Mar 17, 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.

2 participants