user_base.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. package dao
  2. import (
  3. "context"
  4. xsql "database/sql"
  5. "encoding/json"
  6. "fmt"
  7. "go-common/app/service/bbq/user/api"
  8. "go-common/app/service/bbq/user/internal/conf"
  9. "go-common/app/service/bbq/user/internal/model"
  10. "go-common/library/cache/redis"
  11. "go-common/library/database/sql"
  12. "go-common/library/ecode"
  13. "go-common/library/log"
  14. "strconv"
  15. "strings"
  16. )
  17. const (
  18. _incrUserBase = "insert into user_base (`mid`,`uname`,`face`,`birthday`,`exp`,`level`,`user_type`,`complete_degree`,`sex`) values(?,?,?,?,?,?,?,?,?)"
  19. //_incrUserUname = "insert into user_base (`mid`,`uname`) values(?,?)"
  20. // TODO: 用户签名数据暂时隐藏
  21. // _userBase = "select `mid`,`uname`,`face`,`birthday`,`exp`,`level`,`ctime`,`mtime`,`signature`,`region`,`sex`, `user_type`,`complete_degree`from user_base where `mid` in (%s)"
  22. _userBase = "select `mid`,`uname`,`face`,`birthday`,`exp`,`level`,`ctime`,`mtime`,'',`region`,`sex`, `user_type`,`complete_degree`from user_base where `mid` in (%s)"
  23. _updateUserUname = "update user_base set `uname` = ? where `mid` = ?"
  24. _selectUname = "select `mid` from user_base where `uname` = ? and `mid` != ?"
  25. _selectBZhanUpUname = "select `mid` from user_statistics_hive where `uname` = ? and `mid` != ? and `fan_total` > 10000"
  26. _updateUser = "update user_base set uname=?, face=?, birthday=?, sex=?, region=?, signature=?, complete_degree=? where mid=?"
  27. _updateUserField = "update user_base set `%s` = ? where mid = ?"
  28. )
  29. // keyUserBase 用户基础信息缓存key
  30. func keyUserBase(mid int64) string {
  31. return fmt.Sprintf(model.CacheKeyUserBase, mid)
  32. }
  33. // RawUserBase 从数据库获取用户基础信息
  34. func (d *Dao) RawUserBase(c context.Context, mids []int64) (res map[int64]*api.UserBase, err error) {
  35. if len(mids) == 0 {
  36. return
  37. }
  38. var midStr string
  39. for _, mid := range mids {
  40. if len(midStr) != 0 {
  41. midStr += ","
  42. }
  43. midStr += strconv.FormatInt(mid, 10)
  44. }
  45. querySQL := fmt.Sprintf(_userBase, midStr)
  46. rows, err := d.db.Query(c, querySQL)
  47. if err != nil {
  48. log.Errorv(c, log.KV("event", "mysql_query"), log.KV("error", err), log.KV("sql", querySQL))
  49. return
  50. }
  51. defer rows.Close()
  52. for rows.Next() {
  53. userBase := new(api.UserBase)
  54. if err = rows.Scan(&userBase.Mid,
  55. &userBase.Uname,
  56. &userBase.Face,
  57. &userBase.Birthday,
  58. &userBase.Exp,
  59. &userBase.Level,
  60. &userBase.Ctime,
  61. &userBase.Mtime,
  62. &userBase.Signature,
  63. &userBase.Region,
  64. &userBase.Sex,
  65. &userBase.UserType,
  66. &userBase.CompleteDegree); err != nil {
  67. log.Errorv(c, log.KV("event", "mysql_scan"), log.KV("error", err), log.KV("sql", querySQL))
  68. return
  69. }
  70. if res == nil {
  71. res = make(map[int64]*api.UserBase)
  72. }
  73. res[userBase.Mid] = userBase
  74. }
  75. log.Infov(c, log.KV("event", "mysql_query"), log.KV("row_num", len(res)), log.KV("sql", querySQL))
  76. return
  77. }
  78. // CacheUserBase multi get user base from cache.
  79. func (d *Dao) CacheUserBase(c context.Context, mids []int64) (res map[int64]*api.UserBase, err error) {
  80. if res == nil {
  81. res = make(map[int64]*api.UserBase)
  82. }
  83. keys := make([]string, 0, len(mids))
  84. keyMidMap := make(map[int64]bool, len(mids))
  85. for _, mid := range mids {
  86. key := keyUserBase(mid)
  87. if _, exist := keyMidMap[mid]; !exist {
  88. // duplicate mid
  89. keyMidMap[mid] = true
  90. keys = append(keys, key)
  91. }
  92. }
  93. conn := d.redis.Get(c)
  94. defer conn.Close()
  95. for _, key := range keys {
  96. conn.Send("GET", key)
  97. }
  98. conn.Flush()
  99. var data []byte
  100. for i := 0; i < len(keys); i++ {
  101. if data, err = redis.Bytes(conn.Receive()); err != nil {
  102. if err == redis.ErrNil {
  103. err = nil
  104. } else {
  105. log.Errorv(c, log.KV("event", "redis_get"), log.KV("key", keys[i]))
  106. }
  107. continue
  108. }
  109. baseItem := new(api.UserBase)
  110. json.Unmarshal(data, baseItem)
  111. res[baseItem.Mid] = baseItem
  112. }
  113. log.Infov(c, log.KV("event", "redis_get"), log.KV("row_num", len(res)))
  114. return
  115. }
  116. // AddCacheUserBase 添加用户缓存
  117. func (d *Dao) AddCacheUserBase(c context.Context, userBases map[int64]*api.UserBase) (err error) {
  118. keyValueMap := make(map[string][]byte, len(userBases))
  119. for mid, userBase := range userBases {
  120. key := keyUserBase(mid)
  121. if _, exist := keyValueMap[key]; !exist {
  122. data, _ := json.Marshal(userBase)
  123. keyValueMap[key] = data
  124. }
  125. }
  126. conn := d.redis.Get(c)
  127. defer conn.Close()
  128. for key, value := range keyValueMap {
  129. conn.Send("SET", key, value, "EX", model.CacheExpireUserBase)
  130. }
  131. conn.Flush()
  132. for i := 0; i < len(keyValueMap); i++ {
  133. conn.Receive()
  134. }
  135. log.Infov(c, log.KV("event", "redis_set"), log.KV("row_num", len(userBases)))
  136. return
  137. }
  138. //DelCacheUserBase 删除用户缓存
  139. func (d *Dao) DelCacheUserBase(c context.Context, mid int64) {
  140. var key = keyUserBase(mid)
  141. conn := d.redis.Get(c)
  142. defer conn.Close()
  143. conn.Do("DEL", key)
  144. }
  145. ////TxAddUserBase .
  146. //func (d *Dao) TxAddUserBase(c context.Context, tx *sql.Tx, userBase *api.UserBase) (num int64, err error) {
  147. // var res xsql.Result
  148. // if res, err = tx.Exec(_incrUserBase, userBase.Mid, userBase.Uname, userBase.Face, userBase.Birthday, userBase.Exp, userBase.Level, userBase.UserType, userBase.CompleteDegree); err != nil {
  149. // log.Error("incr user base err(%v)", err)
  150. // return
  151. // }
  152. // d.DelCacheUserBase(c, userBase.Mid)
  153. // return res.LastInsertId()
  154. //}
  155. //
  156. // UpdateUserField .
  157. func (d *Dao) UpdateUserField(c context.Context, tx *sql.Tx, mid int64, field string, f interface{}) (num int64, err error) {
  158. var res xsql.Result
  159. querySQL := fmt.Sprintf(_updateUserField, field)
  160. if res, err = tx.Exec(querySQL, f, mid); err != nil {
  161. log.Errorv(c, log.KV("log", fmt.Sprintf("update user mid(%d) field(%s) value(%v) err(%v)", mid, field, f, err)))
  162. return
  163. }
  164. log.V(1).Infow(c, "log", "update user field", "mid", mid, "field", field, "value", f)
  165. d.DelCacheUserBase(c, mid)
  166. return res.RowsAffected()
  167. }
  168. //AddUserBase .
  169. func (d *Dao) AddUserBase(c context.Context, userBase *api.UserBase) (num int64, err error) {
  170. var res xsql.Result
  171. if res, err = d.db.Exec(c, _incrUserBase, userBase.Mid, userBase.Uname, userBase.Face, userBase.Birthday, userBase.Exp, userBase.Level, userBase.UserType, userBase.CompleteDegree, userBase.Sex); err != nil {
  172. log.Error("incr user base err(%v)", err)
  173. return
  174. }
  175. d.DelCacheUserBase(c, userBase.Mid)
  176. return res.LastInsertId()
  177. }
  178. //UpdateUserBaseUname .
  179. func (d *Dao) UpdateUserBaseUname(c context.Context, mid int64, uname string) (num int64, err error) {
  180. var res xsql.Result
  181. if res, err = d.db.Exec(c, _updateUserUname, uname, mid); err != nil {
  182. log.Error("update user base uname err(%v)", err)
  183. return
  184. }
  185. d.DelCacheUserBase(c, mid)
  186. return res.RowsAffected()
  187. }
  188. // UpdateUserBase 更新用户基础信息
  189. func (d *Dao) UpdateUserBase(c context.Context, mid int64, userBase *api.UserBase) (num int64, err error) {
  190. var res xsql.Result
  191. if res, err = d.db.Exec(c, _updateUser, userBase.Uname, userBase.Face, userBase.Birthday, userBase.Sex,
  192. userBase.Region, userBase.Signature, userBase.CompleteDegree, mid); err != nil {
  193. log.Errorv(c, log.KV("event", "mysql_update"), log.KV("mid", mid), log.KV("error", err))
  194. return
  195. }
  196. d.DelCacheUserBase(c, mid)
  197. return res.RowsAffected()
  198. }
  199. // CheckUname 检测昵称
  200. func (d *Dao) CheckUname(c context.Context, mid int64, uname string) (err error) {
  201. // 前缀不能为Qing_
  202. if strings.HasPrefix(uname, "Qing_") {
  203. err = ecode.UserUnamePrefixErr
  204. return
  205. }
  206. //特殊字符
  207. if !model.CheckUnameSpecial(uname) {
  208. err = ecode.UserUnameSpecial
  209. return
  210. }
  211. //字符长度
  212. if !model.CheckUnameLength(uname) {
  213. err = ecode.UserUnameLength
  214. return
  215. }
  216. //bbq是否存在
  217. tmp := int64(0)
  218. row := d.db.QueryRow(c, _selectUname, uname, mid)
  219. if err = row.Scan(&tmp); err != nil && err != sql.ErrNoRows {
  220. err = ecode.EditUserBaseErr
  221. return
  222. }
  223. if tmp != 0 {
  224. err = ecode.UserUnameExisted
  225. log.Infow(c, "log", "uname已存在", "uname", uname, "mid", mid)
  226. return
  227. }
  228. //自己b站的昵称
  229. var userCard *model.UserCard
  230. if userCard, err = d.RawUserCard(c, mid); err != nil {
  231. err = ecode.EditUserBaseErr
  232. return
  233. }
  234. if userCard.Name == uname {
  235. return nil
  236. }
  237. //是否是万粉的昵称
  238. row2 := d.db.QueryRow(c, _selectBZhanUpUname, uname, mid)
  239. if tmpErr := row2.Scan(&tmp); tmpErr != nil && tmpErr != sql.ErrNoRows {
  240. err = ecode.EditUserBaseErr
  241. log.V(1).Infow(c, "log", "获取B站万粉资料为空", "uname", uname)
  242. return
  243. }
  244. if tmp != 0 {
  245. err = ecode.UserUnameExisted
  246. log.Infow(c, "log", "uname命中B站万粉up主", "uname", uname, "mid", mid)
  247. return
  248. }
  249. // 昵称是否包含敏感词
  250. level, filterErr := d.Filter(c, uname, "BBQ_account")
  251. if filterErr != nil {
  252. log.Errorv(c, log.KV("log", "filter fail"))
  253. } else if level >= 20 {
  254. err = ecode.UserUnameFilterErr
  255. log.Warnv(c, log.KV("log", fmt.Sprintf("uname filter fail: uname=%s, level=%d", uname, level)))
  256. return
  257. }
  258. // 运营不允许使用的uname列表中
  259. if conf.UnameConf.UnameForbidden(uname) {
  260. log.Infow(c, "log", "hit fobidden uname", "uname", uname)
  261. err = ecode.UserUnameExisted
  262. return
  263. }
  264. return nil
  265. }