auth_oauth_first_bind.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "strings"
  6. dbent "github.com/Wei-Shaw/sub2api/ent"
  7. entsql "entgo.io/ent/dialect/sql"
  8. )
  9. // ApplyProviderDefaultSettingsOnFirstBind applies provider-specific bootstrap
  10. // settings the first time a user binds a third-party identity. The grant is
  11. // idempotent per user/provider pair.
  12. func (s *AuthService) ApplyProviderDefaultSettingsOnFirstBind(
  13. ctx context.Context,
  14. userID int64,
  15. providerType string,
  16. ) error {
  17. if s == nil || s.entClient == nil || s.settingService == nil || userID <= 0 {
  18. return nil
  19. }
  20. if dbent.TxFromContext(ctx) != nil {
  21. return s.applyProviderDefaultSettingsOnFirstBind(ctx, userID, providerType)
  22. }
  23. tx, err := s.entClient.Tx(ctx)
  24. if err != nil {
  25. return fmt.Errorf("begin first bind defaults transaction: %w", err)
  26. }
  27. defer func() { _ = tx.Rollback() }()
  28. txCtx := dbent.NewTxContext(ctx, tx)
  29. if err := s.applyProviderDefaultSettingsOnFirstBind(txCtx, userID, providerType); err != nil {
  30. return err
  31. }
  32. return tx.Commit()
  33. }
  34. func (s *AuthService) applyProviderDefaultSettingsOnFirstBind(
  35. ctx context.Context,
  36. userID int64,
  37. providerType string,
  38. ) error {
  39. providerDefaults, enabled, err := s.settingService.ResolveAuthSourceGrantSettings(ctx, providerType, true)
  40. if err != nil {
  41. return fmt.Errorf("load auth source defaults: %w", err)
  42. }
  43. if !enabled {
  44. return nil
  45. }
  46. client := s.entClient
  47. if tx := dbent.TxFromContext(ctx); tx != nil {
  48. client = tx.Client()
  49. }
  50. var result entsql.Result
  51. if err := client.Driver().Exec(
  52. ctx,
  53. `INSERT INTO user_provider_default_grants (user_id, provider_type, grant_reason)
  54. VALUES ($1, $2, $3)
  55. ON CONFLICT (user_id, provider_type, grant_reason) DO NOTHING`,
  56. []any{userID, strings.TrimSpace(providerType), "first_bind"},
  57. &result,
  58. ); err != nil {
  59. return fmt.Errorf("record first bind provider grant: %w", err)
  60. }
  61. affected, err := result.RowsAffected()
  62. if err != nil {
  63. return fmt.Errorf("read first bind provider grant result: %w", err)
  64. }
  65. if affected == 0 {
  66. return nil
  67. }
  68. if providerDefaults.Balance != 0 {
  69. if err := client.User.UpdateOneID(userID).AddBalance(providerDefaults.Balance).Exec(ctx); err != nil {
  70. return fmt.Errorf("apply first bind balance default: %w", err)
  71. }
  72. }
  73. if providerDefaults.Concurrency != 0 {
  74. if err := client.User.UpdateOneID(userID).AddConcurrency(providerDefaults.Concurrency).Exec(ctx); err != nil {
  75. return fmt.Errorf("apply first bind concurrency default: %w", err)
  76. }
  77. }
  78. if s.defaultSubAssigner != nil {
  79. for _, item := range providerDefaults.Subscriptions {
  80. if _, _, err := s.defaultSubAssigner.AssignOrExtendSubscription(ctx, &AssignSubscriptionInput{
  81. UserID: userID,
  82. GroupID: item.GroupID,
  83. ValidityDays: item.ValidityDays,
  84. Notes: "auto assigned by first bind defaults",
  85. }); err != nil {
  86. return fmt.Errorf("apply first bind subscription default: %w", err)
  87. }
  88. }
  89. }
  90. return nil
  91. }