Spaces:
Runtime error
Runtime error
| package model | |
| import ( | |
| "errors" | |
| "time" | |
| "gorm.io/gorm" | |
| ) | |
| // UserOAuthBinding stores the binding relationship between users and custom OAuth providers | |
| type UserOAuthBinding struct { | |
| Id int `json:"id" gorm:"primaryKey"` | |
| UserId int `json:"user_id" gorm:"not null;uniqueIndex:ux_user_provider"` // User ID - one binding per user per provider | |
| ProviderId int `json:"provider_id" gorm:"not null;uniqueIndex:ux_user_provider;uniqueIndex:ux_provider_userid"` // Custom OAuth provider ID | |
| ProviderUserId string `json:"provider_user_id" gorm:"type:varchar(256);not null;uniqueIndex:ux_provider_userid"` // User ID from OAuth provider - one OAuth account per provider | |
| CreatedAt time.Time `json:"created_at"` | |
| } | |
| func (UserOAuthBinding) TableName() string { | |
| return "user_oauth_bindings" | |
| } | |
| // GetUserOAuthBindingsByUserId returns all OAuth bindings for a user | |
| func GetUserOAuthBindingsByUserId(userId int) ([]*UserOAuthBinding, error) { | |
| var bindings []*UserOAuthBinding | |
| err := DB.Where("user_id = ?", userId).Find(&bindings).Error | |
| return bindings, err | |
| } | |
| // GetUserOAuthBinding returns a specific binding for a user and provider | |
| func GetUserOAuthBinding(userId, providerId int) (*UserOAuthBinding, error) { | |
| var binding UserOAuthBinding | |
| err := DB.Where("user_id = ? AND provider_id = ?", userId, providerId).First(&binding).Error | |
| if err != nil { | |
| return nil, err | |
| } | |
| return &binding, nil | |
| } | |
| // GetUserByOAuthBinding finds a user by provider ID and provider user ID | |
| func GetUserByOAuthBinding(providerId int, providerUserId string) (*User, error) { | |
| var binding UserOAuthBinding | |
| err := DB.Where("provider_id = ? AND provider_user_id = ?", providerId, providerUserId).First(&binding).Error | |
| if err != nil { | |
| return nil, err | |
| } | |
| var user User | |
| err = DB.First(&user, binding.UserId).Error | |
| if err != nil { | |
| return nil, err | |
| } | |
| return &user, nil | |
| } | |
| // IsProviderUserIdTaken checks if a provider user ID is already bound to any user | |
| func IsProviderUserIdTaken(providerId int, providerUserId string) bool { | |
| var count int64 | |
| DB.Model(&UserOAuthBinding{}).Where("provider_id = ? AND provider_user_id = ?", providerId, providerUserId).Count(&count) | |
| return count > 0 | |
| } | |
| // CreateUserOAuthBinding creates a new OAuth binding | |
| func CreateUserOAuthBinding(binding *UserOAuthBinding) error { | |
| if binding.UserId == 0 { | |
| return errors.New("user ID is required") | |
| } | |
| if binding.ProviderId == 0 { | |
| return errors.New("provider ID is required") | |
| } | |
| if binding.ProviderUserId == "" { | |
| return errors.New("provider user ID is required") | |
| } | |
| // Check if this provider user ID is already taken | |
| if IsProviderUserIdTaken(binding.ProviderId, binding.ProviderUserId) { | |
| return errors.New("this OAuth account is already bound to another user") | |
| } | |
| binding.CreatedAt = time.Now() | |
| return DB.Create(binding).Error | |
| } | |
| // CreateUserOAuthBindingWithTx creates a new OAuth binding within a transaction | |
| func CreateUserOAuthBindingWithTx(tx *gorm.DB, binding *UserOAuthBinding) error { | |
| if binding.UserId == 0 { | |
| return errors.New("user ID is required") | |
| } | |
| if binding.ProviderId == 0 { | |
| return errors.New("provider ID is required") | |
| } | |
| if binding.ProviderUserId == "" { | |
| return errors.New("provider user ID is required") | |
| } | |
| // Check if this provider user ID is already taken (use tx to check within the same transaction) | |
| var count int64 | |
| tx.Model(&UserOAuthBinding{}).Where("provider_id = ? AND provider_user_id = ?", binding.ProviderId, binding.ProviderUserId).Count(&count) | |
| if count > 0 { | |
| return errors.New("this OAuth account is already bound to another user") | |
| } | |
| binding.CreatedAt = time.Now() | |
| return tx.Create(binding).Error | |
| } | |
| // UpdateUserOAuthBinding updates an existing OAuth binding (e.g., rebind to different OAuth account) | |
| func UpdateUserOAuthBinding(userId, providerId int, newProviderUserId string) error { | |
| // Check if the new provider user ID is already taken by another user | |
| var existingBinding UserOAuthBinding | |
| err := DB.Where("provider_id = ? AND provider_user_id = ?", providerId, newProviderUserId).First(&existingBinding).Error | |
| if err == nil && existingBinding.UserId != userId { | |
| return errors.New("this OAuth account is already bound to another user") | |
| } | |
| // Check if user already has a binding for this provider | |
| var binding UserOAuthBinding | |
| err = DB.Where("user_id = ? AND provider_id = ?", userId, providerId).First(&binding).Error | |
| if err != nil { | |
| // No existing binding, create new one | |
| return CreateUserOAuthBinding(&UserOAuthBinding{ | |
| UserId: userId, | |
| ProviderId: providerId, | |
| ProviderUserId: newProviderUserId, | |
| }) | |
| } | |
| // Update existing binding | |
| return DB.Model(&binding).Update("provider_user_id", newProviderUserId).Error | |
| } | |
| // DeleteUserOAuthBinding deletes an OAuth binding | |
| func DeleteUserOAuthBinding(userId, providerId int) error { | |
| return DB.Where("user_id = ? AND provider_id = ?", userId, providerId).Delete(&UserOAuthBinding{}).Error | |
| } | |
| // DeleteUserOAuthBindingsByUserId deletes all OAuth bindings for a user | |
| func DeleteUserOAuthBindingsByUserId(userId int) error { | |
| return DB.Where("user_id = ?", userId).Delete(&UserOAuthBinding{}).Error | |
| } | |
| // GetBindingCountByProviderId returns the number of bindings for a provider | |
| func GetBindingCountByProviderId(providerId int) (int64, error) { | |
| var count int64 | |
| err := DB.Model(&UserOAuthBinding{}).Where("provider_id = ?", providerId).Count(&count).Error | |
| return count, err | |
| } | |