Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 

184 lignes
6.4 KiB

  1. package model
  2. import (
  3. "errors"
  4. "time"
  5. "gorm.io/gorm"
  6. )
  7. // UserOAuthBinding stores the binding relationship between users and custom OAuth providers
  8. type UserOAuthBinding struct {
  9. Id int `json:"id" gorm:"primaryKey"`
  10. UserId int `json:"user_id" gorm:"not null;uniqueIndex:ux_user_provider"` // User ID - one binding per user per provider
  11. ProviderId int `json:"provider_id" gorm:"not null;uniqueIndex:ux_user_provider;uniqueIndex:ux_provider_userid"` // Custom OAuth provider ID
  12. 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
  13. CreatedAt time.Time `json:"created_at"`
  14. }
  15. func (UserOAuthBinding) TableName() string {
  16. return "user_oauth_bindings"
  17. }
  18. // GetUserOAuthBindingsByUserId returns all OAuth bindings for a user
  19. func GetUserOAuthBindingsByUserId(userId int) ([]*UserOAuthBinding, error) {
  20. var bindings []*UserOAuthBinding
  21. err := DB.Where("user_id = ?", userId).Find(&bindings).Error
  22. return bindings, err
  23. }
  24. // GetUserOAuthBinding returns a specific binding for a user and provider
  25. func GetUserOAuthBinding(userId, providerId int) (*UserOAuthBinding, error) {
  26. var binding UserOAuthBinding
  27. err := DB.Where("user_id = ? AND provider_id = ?", userId, providerId).First(&binding).Error
  28. if err != nil {
  29. return nil, err
  30. }
  31. return &binding, nil
  32. }
  33. // GetUserByOAuthBinding finds a user by provider ID and provider user ID
  34. func GetUserByOAuthBinding(providerId int, providerUserId string) (*User, error) {
  35. var binding UserOAuthBinding
  36. result := DB.Where("provider_id = ? AND provider_user_id = ?", providerId, providerUserId).Limit(1).Find(&binding)
  37. if result.Error != nil {
  38. return nil, result.Error
  39. }
  40. if result.RowsAffected == 0 {
  41. return nil, gorm.ErrRecordNotFound
  42. }
  43. var user User
  44. userResult := DB.Where("id = ?", binding.UserId).Limit(1).Find(&user)
  45. if userResult.Error != nil {
  46. return nil, userResult.Error
  47. }
  48. if userResult.RowsAffected == 0 {
  49. return nil, gorm.ErrRecordNotFound
  50. }
  51. return &user, nil
  52. }
  53. // IsProviderUserIdTaken checks if a provider user ID is already bound to any user
  54. func IsProviderUserIdTaken(providerId int, providerUserId string) bool {
  55. var count int64
  56. DB.Model(&UserOAuthBinding{}).Where("provider_id = ? AND provider_user_id = ?", providerId, providerUserId).Count(&count)
  57. return count > 0
  58. }
  59. // CreateUserOAuthBinding creates a new OAuth binding
  60. func CreateUserOAuthBinding(binding *UserOAuthBinding) error {
  61. if binding.UserId == 0 {
  62. return errors.New("user ID is required")
  63. }
  64. if binding.ProviderId == 0 {
  65. return errors.New("provider ID is required")
  66. }
  67. if binding.ProviderUserId == "" {
  68. return errors.New("provider user ID is required")
  69. }
  70. // Check if this provider user ID is already taken
  71. if IsProviderUserIdTaken(binding.ProviderId, binding.ProviderUserId) {
  72. return errors.New("this OAuth account is already bound to another user")
  73. }
  74. binding.CreatedAt = time.Now()
  75. return DB.Create(binding).Error
  76. }
  77. // CreateUserOAuthBindingWithTx creates a new OAuth binding within a transaction
  78. func CreateUserOAuthBindingWithTx(tx *gorm.DB, binding *UserOAuthBinding) error {
  79. if binding.UserId == 0 {
  80. return errors.New("user ID is required")
  81. }
  82. if binding.ProviderId == 0 {
  83. return errors.New("provider ID is required")
  84. }
  85. if binding.ProviderUserId == "" {
  86. return errors.New("provider user ID is required")
  87. }
  88. // Check if this provider user ID is already taken (use tx to check within the same transaction)
  89. var count int64
  90. tx.Model(&UserOAuthBinding{}).Where("provider_id = ? AND provider_user_id = ?", binding.ProviderId, binding.ProviderUserId).Count(&count)
  91. if count > 0 {
  92. return errors.New("this OAuth account is already bound to another user")
  93. }
  94. binding.CreatedAt = time.Now()
  95. return tx.Create(binding).Error
  96. }
  97. func CopyOAuthBindingsIfMissing(userId int, bindings []*UserOAuthBinding) error {
  98. return CopyOAuthBindingsIfMissingTx(DB, userId, bindings)
  99. }
  100. func CopyOAuthBindingsIfMissingTx(tx *gorm.DB, userId int, bindings []*UserOAuthBinding) error {
  101. for _, binding := range bindings {
  102. if binding == nil {
  103. continue
  104. }
  105. var existing UserOAuthBinding
  106. result := tx.Where("user_id = ? AND provider_id = ?", userId, binding.ProviderId).Limit(1).Find(&existing)
  107. if result.Error != nil {
  108. return result.Error
  109. }
  110. if result.RowsAffected > 0 {
  111. continue
  112. }
  113. newBinding := &UserOAuthBinding{
  114. UserId: userId,
  115. ProviderId: binding.ProviderId,
  116. ProviderUserId: binding.ProviderUserId,
  117. }
  118. if err := CreateUserOAuthBindingWithTx(tx, newBinding); err != nil {
  119. return err
  120. }
  121. }
  122. return nil
  123. }
  124. // UpdateUserOAuthBinding updates an existing OAuth binding (e.g., rebind to different OAuth account)
  125. func UpdateUserOAuthBinding(userId, providerId int, newProviderUserId string) error {
  126. // Check if the new provider user ID is already taken by another user
  127. var existingBinding UserOAuthBinding
  128. err := DB.Where("provider_id = ? AND provider_user_id = ?", providerId, newProviderUserId).First(&existingBinding).Error
  129. if err == nil && existingBinding.UserId != userId {
  130. return errors.New("this OAuth account is already bound to another user")
  131. }
  132. // Check if user already has a binding for this provider
  133. var binding UserOAuthBinding
  134. err = DB.Where("user_id = ? AND provider_id = ?", userId, providerId).First(&binding).Error
  135. if err != nil {
  136. // No existing binding, create new one
  137. return CreateUserOAuthBinding(&UserOAuthBinding{
  138. UserId: userId,
  139. ProviderId: providerId,
  140. ProviderUserId: newProviderUserId,
  141. })
  142. }
  143. // Update existing binding
  144. return DB.Model(&binding).Update("provider_user_id", newProviderUserId).Error
  145. }
  146. // DeleteUserOAuthBinding deletes an OAuth binding
  147. func DeleteUserOAuthBinding(userId, providerId int) error {
  148. return DB.Where("user_id = ? AND provider_id = ?", userId, providerId).Delete(&UserOAuthBinding{}).Error
  149. }
  150. // DeleteUserOAuthBindingsByUserId deletes all OAuth bindings for a user
  151. func DeleteUserOAuthBindingsByUserId(userId int) error {
  152. return DB.Where("user_id = ?", userId).Delete(&UserOAuthBinding{}).Error
  153. }
  154. // GetBindingCountByProviderId returns the number of bindings for a provider
  155. func GetBindingCountByProviderId(providerId int) (int64, error) {
  156. var count int64
  157. err := DB.Model(&UserOAuthBinding{}).Where("provider_id = ?", providerId).Count(&count).Error
  158. return count, err
  159. }