-
Notifications
You must be signed in to change notification settings - Fork 11.2k
feat: Support dynamic updating of users' groupings based on Oauth inf… #4088
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a65baeb
cceb63b
5c900ea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ import ( | |
| "github.com/QuantumNous/new-api/i18n" | ||
| "github.com/QuantumNous/new-api/model" | ||
| "github.com/QuantumNous/new-api/oauth" | ||
| "github.com/QuantumNous/new-api/setting/ratio_setting" | ||
| "github.com/gin-contrib/sessions" | ||
| "github.com/gin-gonic/gin" | ||
| "gorm.io/gorm" | ||
|
|
@@ -209,6 +210,29 @@ func findOrCreateOAuthUser(c *gin.Context, provider oauth.Provider, oauthUser *o | |
| if user.Id == 0 { | ||
| return nil, &OAuthUserDeletedError{} | ||
| } | ||
|
|
||
| // Update user's group if OAuth provides a different group and it's in available groups | ||
| if oauthUser.Group != "" && oauthUser.Group != user.Group { | ||
| common.SysLog(fmt.Sprintf("[OAuth] User %d current group: '%s', OAuth group: '%s'", user.Id, user.Group, oauthUser.Group)) | ||
| // Check if group exists in group ratio settings | ||
| if ratio_setting.ContainsGroupRatio(oauthUser.Group) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check how groups are typically validated elsewhere in the codebase
rg -n --type go -C3 'ContainsGroupRatio|groupRatioMap' --glob '!*_test.go'Repository: QuantumNous/new-api Length of output: 4535 🏁 Script executed: #!/bin/bash
# Find group configuration files and what groups are defined
find . -type f -name "*.go" | xargs grep -l "defaultGroup" | head -10Repository: QuantumNous/new-api Length of output: 101 🏁 Script executed: #!/bin/bash
# Check what groups are defined in the ratio setting
rg -n "defaultGroupRatio|defaultGroupSpecialUsableGroup" --type go -A 10 | head -80Repository: QuantumNous/new-api Length of output: 3317 🏁 Script executed: #!/bin/bash
# Check if there's any OAuth-specific group configuration
rg -n "oauth.*group|OAuth.*[Gg]roup" --type go | grep -i configRepository: QuantumNous/new-api Length of output: 45 🏁 Script executed: #!/bin/bash
# Look for other group validation patterns in the codebase
rg -n "user\.Group\s*=|Group.*=" --type go controller/ | head -20Repository: QuantumNous/new-api Length of output: 1408 🏁 Script executed: #!/bin/bash
# Check the oauth.go file context around lines 215-295 to understand the group assignment flow
sed -n '210,300p' controller/oauth.goRepository: QuantumNous/new-api Length of output: 3629 🏁 Script executed: #!/bin/bash
# Check if there's OAuth provider configuration for allowed groups
rg -n "oauth.*config|oauthUser|GetUserInfoFromOAuth" --type go -B 2 -A 5 | head -100Repository: QuantumNous/new-api Length of output: 6025 🏁 Script executed: #!/bin/bash
# Look for OAuthUser struct definition to understand what Group field represents
rg -n "type.*OAuthUser|oauthUser.*Group" --type go -B 2 -A 8 | head -80Repository: QuantumNous/new-api Length of output: 4314 🏁 Script executed: #!/bin/bash
# Check the full OAuthUser struct definition to see if there's any group-related field
rg -n "type OAuthUser" --type go -A 15 oauth/Repository: QuantumNous/new-api Length of output: 944 🏁 Script executed: #!/bin/bash
# Look for where OAuthUser.Group is populated from OAuth provider
rg -n "\.Group\s*=" --type go oauth/ | head -20Repository: QuantumNous/new-api Length of output: 45 🏁 Script executed: #!/bin/bash
# Check if there's any OAuth provider configuration related to allowed groups
rg -n "config.*[Gg]roup|allowedGroup|groupMapping" --type go -i | head -30Repository: QuantumNous/new-api Length of output: 537 🏁 Script executed: #!/bin/bash
# Check the GenericOAuthProvider config to understand GroupField better
rg -n "type.*Provider|GroupField" --type go oauth/ -B 2 -A 2 | head -50Repository: QuantumNous/new-api Length of output: 1828 🏁 Script executed: #!/bin/bash
# Look for GenericOAuthProvider struct and its config
rg -n "type GenericOAuthProvider|type.*Config" --type go oauth/generic.go -A 20 | head -80Repository: QuantumNous/new-api Length of output: 582 🏁 Script executed: #!/bin/bash
# Check what GroupField is used for in the generic provider
sed -n '240,280p' oauth/generic.goRepository: QuantumNous/new-api Length of output: 1670 Replace Using
Introduce a dedicated "OAuth allowed groups" configuration (separate from 🤖 Prompt for AI Agents |
||
| user.Group = oauthUser.Group | ||
| if err := user.Update(false); err != nil { | ||
| common.SysError(fmt.Sprintf("[OAuth] Failed to update user %d group to '%s': %s", user.Id, oauthUser.Group, err.Error())) | ||
| } else { | ||
| common.SysLog(fmt.Sprintf("[OAuth] Updated user %d group to '%s' from OAuth provider", user.Id, oauthUser.Group)) | ||
| } | ||
| } else { | ||
| common.SysLog(fmt.Sprintf("[OAuth] OAuth group '%s' not in group ratio settings for user %d, keeping current group '%s'", oauthUser.Group, user.Id, user.Group)) | ||
| } | ||
| } else { | ||
| if oauthUser.Group == "" { | ||
| common.SysLog(fmt.Sprintf("[OAuth] User %d OAuth group is empty, skipping group update", user.Id)) | ||
| } else if oauthUser.Group == user.Group { | ||
| common.SysLog(fmt.Sprintf("[OAuth] User %d group '%s' already matches OAuth group, no update needed", user.Id, user.Group)) | ||
| } | ||
| } | ||
|
Comment on lines
+213
to
+234
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Race condition: The Consider using a targeted column update instead: 🔧 Proposed fix using targeted update if ratio_setting.ContainsGroupRatio(oauthUser.Group) {
- user.Group = oauthUser.Group
- if err := user.Update(false); err != nil {
+ if err := model.DB.Model(user).Update("group", oauthUser.Group).Error; err != nil {
common.SysError(fmt.Sprintf("[OAuth] Failed to update user %d group to '%s': %s", user.Id, oauthUser.Group, err.Error()))
} else {
+ user.Group = oauthUser.Group // Update local copy after successful DB write
common.SysLog(fmt.Sprintf("[OAuth] Updated user %d group to '%s' from OAuth provider", user.Id, oauthUser.Group))
}🤖 Prompt for AI Agents |
||
|
|
||
| return user, nil | ||
| } | ||
|
|
||
|
|
@@ -262,6 +286,17 @@ func findOrCreateOAuthUser(c *gin.Context, provider oauth.Provider, oauthUser *o | |
| user.Role = common.RoleCommonUser | ||
| user.Status = common.UserStatusEnabled | ||
|
|
||
| // Auto-assign group from OAuth provider if configured | ||
| if oauthUser.Group != "" { | ||
| // Check if the group from OAuth is in the platform's group ratio settings | ||
| if ratio_setting.ContainsGroupRatio(oauthUser.Group) { | ||
| user.Group = oauthUser.Group | ||
| common.SysLog(fmt.Sprintf("[OAuth] Auto-assigned group '%s' to new user from OAuth provider (matched group ratio settings)", oauthUser.Group)) | ||
| } else { | ||
| common.SysLog(fmt.Sprintf("[OAuth] Group '%s' from OAuth provider not found in group ratio settings, using default 'default'", oauthUser.Group)) | ||
| } | ||
| } | ||
|
|
||
| // Handle affiliate code | ||
| affCode := session.Get("aff") | ||
| inviterId := 0 | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GroupFieldcannot be cleared once set due to non-pointer type.Unlike other optional fields (
WellKnown,AccessPolicy, etc.) which use*stringto distinguish "not provided" from "set to empty",GroupFieldis a plainstring. The conditionif req.GroupField != ""prevents clearing an existing value.🔧 Proposed fix to allow clearing GroupField
type UpdateCustomOAuthProviderRequest struct { ... - GroupField string `json:"group_field"` + GroupField *string `json:"group_field"` ... }And update the handler:
Also applies to: 376-378
🤖 Prompt for AI Agents