gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package user
  4. import (
  5. "context"
  6. "errors"
  7. "fmt"
  8. "strings"
  9. "code.gitea.io/gitea/models/db"
  10. "code.gitea.io/gitea/modules/cache"
  11. setting_module "code.gitea.io/gitea/modules/setting"
  12. "code.gitea.io/gitea/modules/util"
  13. "xorm.io/builder"
  14. )
  15. // Setting is a key value store of user settings
  16. type Setting struct {
  17. ID int64 `xorm:"pk autoincr"`
  18. UserID int64 `xorm:"index unique(key_userid)"` // to load all of someone's settings
  19. SettingKey string `xorm:"varchar(255) index unique(key_userid)"` // ensure key is always lowercase
  20. SettingValue string `xorm:"text"`
  21. }
  22. // TableName sets the table name for the settings struct
  23. func (s *Setting) TableName() string {
  24. return "user_setting"
  25. }
  26. func init() {
  27. db.RegisterModel(new(Setting))
  28. }
  29. // ErrUserSettingIsNotExist represents an error that a setting is not exist with special key
  30. type ErrUserSettingIsNotExist struct {
  31. Key string
  32. }
  33. // Error implements error
  34. func (err ErrUserSettingIsNotExist) Error() string {
  35. return fmt.Sprintf("Setting[%s] is not exist", err.Key)
  36. }
  37. func (err ErrUserSettingIsNotExist) Unwrap() error {
  38. return util.ErrNotExist
  39. }
  40. // IsErrUserSettingIsNotExist return true if err is ErrSettingIsNotExist
  41. func IsErrUserSettingIsNotExist(err error) bool {
  42. _, ok := err.(ErrUserSettingIsNotExist)
  43. return ok
  44. }
  45. // genSettingCacheKey returns the cache key for some configuration
  46. func genSettingCacheKey(userID int64, key string) string {
  47. return fmt.Sprintf("user_%d.setting.%s", userID, key)
  48. }
  49. // GetSetting returns the setting value via the key
  50. func GetSetting(ctx context.Context, uid int64, key string) (string, error) {
  51. return cache.GetString(genSettingCacheKey(uid, key), func() (string, error) {
  52. res, err := GetSettingNoCache(ctx, uid, key)
  53. if err != nil {
  54. return "", err
  55. }
  56. return res.SettingValue, nil
  57. })
  58. }
  59. // GetSettingNoCache returns specific setting without using the cache
  60. func GetSettingNoCache(ctx context.Context, uid int64, key string) (*Setting, error) {
  61. v, err := GetSettings(ctx, uid, []string{key})
  62. if err != nil {
  63. return nil, err
  64. }
  65. if len(v) == 0 {
  66. return nil, ErrUserSettingIsNotExist{key}
  67. }
  68. return v[key], nil
  69. }
  70. // GetSettings returns specific settings from user
  71. func GetSettings(ctx context.Context, uid int64, keys []string) (map[string]*Setting, error) {
  72. settings := make([]*Setting, 0, len(keys))
  73. if err := db.GetEngine(ctx).
  74. Where("user_id=?", uid).
  75. And(builder.In("setting_key", keys)).
  76. Find(&settings); err != nil {
  77. return nil, err
  78. }
  79. settingsMap := make(map[string]*Setting)
  80. for _, s := range settings {
  81. settingsMap[s.SettingKey] = s
  82. }
  83. return settingsMap, nil
  84. }
  85. // GetUserAllSettings returns all settings from user
  86. func GetUserAllSettings(ctx context.Context, uid int64) (map[string]*Setting, error) {
  87. settings := make([]*Setting, 0, 5)
  88. if err := db.GetEngine(ctx).
  89. Where("user_id=?", uid).
  90. Find(&settings); err != nil {
  91. return nil, err
  92. }
  93. settingsMap := make(map[string]*Setting)
  94. for _, s := range settings {
  95. settingsMap[s.SettingKey] = s
  96. }
  97. return settingsMap, nil
  98. }
  99. func validateUserSettingKey(key string) error {
  100. if len(key) == 0 {
  101. return errors.New("setting key must be set")
  102. }
  103. if strings.ToLower(key) != key {
  104. return errors.New("setting key should be lowercase")
  105. }
  106. return nil
  107. }
  108. // GetUserSetting gets a specific setting for a user
  109. func GetUserSetting(ctx context.Context, userID int64, key string, def ...string) (string, error) {
  110. if err := validateUserSettingKey(key); err != nil {
  111. return "", err
  112. }
  113. setting := &Setting{UserID: userID, SettingKey: key}
  114. has, err := db.GetEngine(ctx).Get(setting)
  115. if err != nil {
  116. return "", err
  117. }
  118. if !has {
  119. if len(def) == 1 {
  120. return def[0], nil
  121. }
  122. return "", nil
  123. }
  124. return setting.SettingValue, nil
  125. }
  126. // DeleteUserSetting deletes a specific setting for a user
  127. func DeleteUserSetting(ctx context.Context, userID int64, key string) error {
  128. if err := validateUserSettingKey(key); err != nil {
  129. return err
  130. }
  131. cache.Remove(genSettingCacheKey(userID, key))
  132. _, err := db.GetEngine(ctx).Delete(&Setting{UserID: userID, SettingKey: key})
  133. return err
  134. }
  135. // SetUserSetting updates a users' setting for a specific key
  136. func SetUserSetting(ctx context.Context, userID int64, key, value string) error {
  137. if err := validateUserSettingKey(key); err != nil {
  138. return err
  139. }
  140. if err := upsertUserSettingValue(ctx, userID, key, value); err != nil {
  141. return err
  142. }
  143. cc := cache.GetCache()
  144. if cc != nil {
  145. return cc.Put(genSettingCacheKey(userID, key), value, setting_module.CacheService.TTLSeconds())
  146. }
  147. return nil
  148. }
  149. func upsertUserSettingValue(ctx context.Context, userID int64, key, value string) error {
  150. return db.WithTx(ctx, func(ctx context.Context) error {
  151. e := db.GetEngine(ctx)
  152. // here we use a general method to do a safe upsert for different databases (and most transaction levels)
  153. // 1. try to UPDATE the record and acquire the transaction write lock
  154. // if UPDATE returns non-zero rows are changed, OK, the setting is saved correctly
  155. // if UPDATE returns "0 rows changed", two possibilities: (a) record doesn't exist (b) value is not changed
  156. // 2. do a SELECT to check if the row exists or not (we already have the transaction lock)
  157. // 3. if the row doesn't exist, do an INSERT (we are still protected by the transaction lock, so it's safe)
  158. //
  159. // to optimize the SELECT in step 2, we can use an extra column like `revision=revision+1`
  160. // to make sure the UPDATE always returns a non-zero value for existing (unchanged) records.
  161. res, err := e.Exec("UPDATE user_setting SET setting_value=? WHERE setting_key=? AND user_id=?", value, key, userID)
  162. if err != nil {
  163. return err
  164. }
  165. rows, _ := res.RowsAffected()
  166. if rows > 0 {
  167. // the existing row is updated, so we can return
  168. return nil
  169. }
  170. // in case the value isn't changed, update would return 0 rows changed, so we need this check
  171. has, err := e.Exist(&Setting{UserID: userID, SettingKey: key})
  172. if err != nil {
  173. return err
  174. }
  175. if has {
  176. return nil
  177. }
  178. // if no existing row, insert a new row
  179. _, err = e.Insert(&Setting{UserID: userID, SettingKey: key, SettingValue: value})
  180. return err
  181. })
  182. }