蛋蛋星球-客户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

563 lines
17 KiB

  1. package hdl
  2. import (
  3. "applet/app/db"
  4. "applet/app/e"
  5. "applet/app/es/hdl"
  6. md2 "applet/app/es/md"
  7. "applet/app/lib/auth"
  8. "applet/app/md"
  9. "applet/app/svc"
  10. "applet/app/utils"
  11. "applet/app/utils/cache"
  12. "applet/app/utils/qrcode"
  13. "code.fnuoos.com/EggPlanet/egg_models.git/src/implement"
  14. "code.fnuoos.com/EggPlanet/egg_models.git/src/model"
  15. "code.fnuoos.com/EggPlanet/egg_system_rules.git/baidu"
  16. md3 "code.fnuoos.com/EggPlanet/egg_system_rules.git/md"
  17. md4 "code.fnuoos.com/EggPlanet/egg_system_rules.git/rule/egg_energy/md"
  18. es2 "code.fnuoos.com/EggPlanet/egg_system_rules.git/utils/es"
  19. "code.fnuoos.com/go_rely_warehouse/zyos_go_es.git/es"
  20. "code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit"
  21. "context"
  22. "encoding/json"
  23. "fmt"
  24. "github.com/gin-gonic/gin"
  25. "github.com/olivere/elastic/v7"
  26. "github.com/syyongx/php2go"
  27. "github.com/tidwall/gjson"
  28. "strings"
  29. "time"
  30. )
  31. // UserInfo
  32. // @Summary 用户信息
  33. // @Tags 用户信息
  34. // @Description 用户信息
  35. // @Accept json
  36. // @Produce json
  37. // @param Authorization header string true "验证参数Bearer和token空格拼接"
  38. // @Success 200 {object} md.UserInfoResp "具体数据"
  39. // @Failure 400 {object} md.Response "具体错误"
  40. // @Router /api/v1/userInfo [get]
  41. func UserInfo(c *gin.Context) {
  42. user := svc.GetUser(c)
  43. res := md.UserInfoResp{
  44. Id: utils.Int64ToStr(user.Id),
  45. Phone: user.Phone,
  46. Nickname: user.Phone,
  47. InviteCode: user.SystemInviteCode,
  48. IsBindExtend: "0",
  49. }
  50. if user.Avatar == "" {
  51. user.Avatar = svc.GetSysCfgStr("default_avatar")
  52. }
  53. if user.Avatar != "" {
  54. res.HeadImg = svc.GetOssUrl(user.Avatar)
  55. }
  56. if user.CustomInviteCode != "" {
  57. res.InviteCode = user.CustomInviteCode
  58. }
  59. if user.ParentUid > 0 {
  60. res.IsBindExtend = "1"
  61. }
  62. e.OutSuc(c, res, nil)
  63. return
  64. }
  65. // InviteCodeUserInfo
  66. // @Summary 邀请码获取用户信息
  67. // @Tags 登录注册
  68. // @Description 邀请码获取用户信息
  69. // @Accept json
  70. // @Produce json
  71. // @Param req body md.InviteCodeUserInfoReq true "注册参数"
  72. // @Success 200 {object} md.InviteCodeUserInfoResp "具体数据"
  73. // @Failure 400 {object} md.Response "具体错误"
  74. // @Router /api/v1/inviteCode/userInfo [post]
  75. func InviteCodeUserInfo(c *gin.Context) {
  76. var req md.InviteCodeUserInfoReq
  77. err := c.ShouldBindJSON(&req)
  78. if err != nil {
  79. err = svc.HandleValidateErr(err)
  80. err1 := err.(e.E)
  81. e.OutErr(c, err1.Code, err1.Error())
  82. return
  83. }
  84. if req.InviteCode == "" {
  85. e.OutErr(c, 400, e.NewErr(400, "邀请码不能为空"))
  86. return
  87. }
  88. userDb := implement.NewUserDb(db.Db)
  89. user, err := userDb.UserGetOneByParams(map[string]interface{}{
  90. "key": "system_invite_code",
  91. "value": req.InviteCode,
  92. })
  93. if user == nil {
  94. user, _ = userDb.UserGetOneByParams(map[string]interface{}{
  95. "key": "custom_invite_code",
  96. "value": req.InviteCode,
  97. })
  98. if user == nil {
  99. e.OutErr(c, 400, e.NewErr(400, "邀请码失效,请联系上级重新获取分享"))
  100. return
  101. }
  102. }
  103. nickname := user.Nickname
  104. if nickname == "" {
  105. nickname = user.Phone
  106. }
  107. if php2go.IsNumeric(nickname) {
  108. nickname = utils.HideTrueName(user.Nickname)
  109. }
  110. user = svc.UserImg(user)
  111. res := md.InviteCodeUserInfoResp{
  112. Nickname: nickname,
  113. HeadImg: svc.GetOssUrl(user.Avatar),
  114. }
  115. e.OutSuc(c, res, nil)
  116. return
  117. }
  118. // UserBindParent
  119. // @Summary 绑定上级-要登陆的
  120. // @Tags 登录注册
  121. // @Description 绑定上级
  122. // @Accept json
  123. // @Produce json
  124. // @Param req body md.InviteCodeUserInfoReq true "注册参数"
  125. // @Success 200 {string} "具体数据"
  126. // @Failure 400 {object} md.Response "具体错误"
  127. // @Router /api/v1/memberCenter/bindParent [post]
  128. func UserBindParent(c *gin.Context) {
  129. var req md.InviteCodeUserInfoReq
  130. err := c.ShouldBindJSON(&req)
  131. if err != nil {
  132. err = svc.HandleValidateErr(err)
  133. err1 := err.(e.E)
  134. e.OutErr(c, err1.Code, err1.Error())
  135. return
  136. }
  137. if req.InviteCode == "" {
  138. e.OutErr(c, 400, e.NewErr(400, "邀请码不能为空"))
  139. return
  140. }
  141. userDb := implement.NewUserDb(db.Db)
  142. user, err := userDb.UserGetOneByParams(map[string]interface{}{
  143. "key": "system_invite_code",
  144. "value": req.InviteCode,
  145. })
  146. if user == nil {
  147. user, _ = userDb.UserGetOneByParams(map[string]interface{}{
  148. "key": "custom_invite_code",
  149. "value": req.InviteCode,
  150. })
  151. if user == nil {
  152. e.OutErr(c, 400, e.NewErr(400, "用户不存在"))
  153. return
  154. }
  155. }
  156. ownUser := svc.GetUser(c)
  157. if ownUser.ParentUid > 0 {
  158. e.OutErr(c, 400, e.NewErr(400, "已有导师"))
  159. return
  160. }
  161. if user.Id == ownUser.Id {
  162. e.OutErr(c, 400, e.NewErr(400, "不能绑定自己"))
  163. return
  164. }
  165. ownUser.ParentUid = user.Id
  166. _, err = db.Db.Where("id=?", ownUser.Id).Cols("parent_uid").Update(ownUser)
  167. if err != nil {
  168. e.OutErr(c, 400, e.NewErr(400, "绑定失败,请重试"))
  169. return
  170. }
  171. initLV := 1
  172. ur := new(model.UserRelate)
  173. ur.ParentUid = user.Id
  174. ur.Uid = ownUser.Id
  175. ur.Level = initLV
  176. ur.InviteTime = ownUser.CreateAt
  177. userRelateDb := implement.NewUserRelateDb(db.Db)
  178. _, err = userRelateDb.UserRelateInsert(ur)
  179. if err != nil {
  180. e.OutErr(c, e.ERR_DB_ORM, err)
  181. return
  182. }
  183. // 插入多级关联
  184. go svc.RoutineMultiRelate(ur.ParentUid, ur.Uid, initLV)
  185. //TODO 绑定成功后 加群之类的怎么处理
  186. if ownUser.ParentUid > 0 {
  187. //TODO::推入mq异步处理
  188. ch, err := rabbit.Cfg.Pool.GetChannel()
  189. if err != nil {
  190. e.OutErr(c, e.ERR_INIT_RABBITMQ, err.Error())
  191. return
  192. }
  193. defer ch.Release()
  194. ch.Publish(md4.EggAppExchange, md4.AddPublicPlatoonUserRelationCommissionReq{RecommendUid: utils.Int64ToStr(ownUser.ParentUid), Uid: utils.Int64ToStr(ownUser.Id)}, md4.EggRoutKeyForAddPublicPlatoonUserRelationCommission)
  195. }
  196. e.OutSuc(c, "success", nil)
  197. return
  198. }
  199. // BindUserInfo
  200. // @Summary 绑定用户信息
  201. // @Tags 会员中心
  202. // @Description 绑定用户信息
  203. // @Accept json
  204. // @Produce json
  205. // @Param req body md.WechatAccountUserInfoReq true "注册参数"
  206. // @Success 200 {string} "具体数据"
  207. // @Failure 400 {object} md.Response "具体错误"
  208. // @Router /api/v1/memberCenter/bindUserInfo [post]
  209. func BindUserInfo(c *gin.Context) {
  210. var req md.WechatAccountUserInfoReq
  211. err := c.ShouldBindJSON(&req)
  212. if err != nil {
  213. err = svc.HandleValidateErr(err)
  214. err1 := err.(e.E)
  215. e.OutErr(c, err1.Code, err1.Error())
  216. return
  217. }
  218. ownUser := svc.GetUser(c)
  219. cols := ""
  220. if req.Nickname != "" {
  221. ownUser.Nickname = req.Nickname
  222. cols += ",nickname"
  223. }
  224. if req.HeadImg != "" {
  225. ownUser.Avatar = req.HeadImg
  226. cols += ",avatar"
  227. }
  228. if req.WechatAccount != "" {
  229. ownUser.WechatAccount = req.WechatAccount
  230. cols += ",wechat_account"
  231. }
  232. if cols == "" {
  233. e.OutErr(c, 400, e.NewErr(400, "修改失败"))
  234. return
  235. }
  236. _, err = db.Db.Where("id=?", ownUser.Id).Cols(cols[1:]).Update(ownUser)
  237. if err != nil {
  238. e.OutErr(c, 400, e.NewErr(400, "修改失败"))
  239. return
  240. }
  241. e.OutSuc(c, "success", nil)
  242. return
  243. }
  244. // UpdatePassword
  245. // @Summary 修改密码-不要原密码 换成验证码
  246. // @Tags 账号与安全
  247. // @Description 修改密码
  248. // @Accept json
  249. // @Produce json
  250. // @Param req body md.UpdatePasswordReq true "注册参数"
  251. // @Success 200 string "登录成功返回"
  252. // @Failure 400 {object} md.Response "具体错误"
  253. // @Router /api/v1/memberCenter/updatePassword [post]
  254. func UpdatePassword(c *gin.Context) {
  255. var req md.UpdatePasswordReq
  256. err := c.ShouldBindJSON(&req)
  257. if err != nil {
  258. err = svc.HandleValidateErr(err)
  259. err1 := err.(e.E)
  260. e.OutErr(c, err1.Code, err1.Error())
  261. return
  262. }
  263. user := svc.GetUser(c)
  264. //校验短信
  265. err = svc.CommSmsCheck(c, user.Phone, req.Code)
  266. if err != nil {
  267. e.OutErr(c, 400, e.NewErr(400, "验证码错误,请重试"))
  268. return
  269. }
  270. user.Password = utils.Md5(req.Password)
  271. db.Db.Where("id=?", user.Id).Cols("password").Update(user)
  272. e.OutSuc(c, "success", nil)
  273. return
  274. }
  275. // UpdatePasscode
  276. // @Summary 修改支付宝密码
  277. // @Tags 账号与安全
  278. // @Description 修改支付宝密码
  279. // @Accept json
  280. // @Produce json
  281. // @Param req body md.UpdatePasscodeReq true "注册参数"
  282. // @Success 200 string "登录成功返回"
  283. // @Failure 400 {object} md.Response "具体错误"
  284. // @Router /api/v1/memberCenter/updatePasscode [post]
  285. func UpdatePasscode(c *gin.Context) {
  286. var req md.UpdatePasscodeReq
  287. err := c.ShouldBindJSON(&req)
  288. if err != nil {
  289. err = svc.HandleValidateErr(err)
  290. err1 := err.(e.E)
  291. e.OutErr(c, err1.Code, err1.Error())
  292. return
  293. }
  294. user := svc.GetUser(c)
  295. //校验短信
  296. err = svc.CommSmsCheck(c, user.Phone, req.Code)
  297. if err != nil {
  298. e.OutErr(c, 400, e.NewErr(400, "验证码错误,请重试"))
  299. return
  300. }
  301. user.Passcode = utils.Md5(req.PassCode)
  302. db.Db.Where("id=?", user.Id).Cols("passcode").Update(user)
  303. e.OutSuc(c, "success", nil)
  304. return
  305. }
  306. // InviteUrl
  307. // @Summary 邀请链接
  308. // @Tags 邀请海报
  309. // @Description 邀请链接
  310. // @Accept json
  311. // @Produce json
  312. // @Success 200 {object} md.InviteUrl "登录成功返回"
  313. // @Failure 400 {object} md.Response "具体错误"
  314. // @Router /api/v1/memberCenter/inviteUrl [get]
  315. func InviteUrl(c *gin.Context) {
  316. user := svc.GetUser(c)
  317. link := svc.GetSysCfgStr("kuaizhan_url") + "?type="
  318. res := md.InviteUrl{
  319. Link: "",
  320. InviteCode: user.SystemInviteCode,
  321. }
  322. if user.CustomInviteCode != "" {
  323. res.InviteCode = user.CustomInviteCode
  324. }
  325. _, registerViewUrl, _ := svc.DownUrl(c)
  326. if registerViewUrl != "" {
  327. link = registerViewUrl
  328. }
  329. link += "&inviteCode=" + res.InviteCode
  330. EggUserShortLink := md2.EggUserShortLink
  331. boolQueryToItem := elastic.NewBoolQuery() // 创建bool查询
  332. aggsMatch := elastic.NewMatchQuery("link", link) //设置查询条件
  333. boolQueryToItem.Must(aggsMatch)
  334. result, _ := hdl.EsSelectOne(context.Background(), EggUserShortLink, boolQueryToItem, false)
  335. isHas := 0
  336. if result != nil && len(result.Hits.Hits) > 0 {
  337. for _, hit := range result.Hits.Hits {
  338. if hit == nil {
  339. continue
  340. }
  341. jsonByte, _ := hit.Source.MarshalJSON()
  342. if gjson.Get(string(jsonByte), "short_link").String() != "" && gjson.Get(string(jsonByte), "date").Int() > time.Now().Unix() {
  343. isHas = 1
  344. link = gjson.Get(string(jsonByte), "short_link").String()
  345. }
  346. }
  347. }
  348. if isHas == 0 {
  349. url, _ := baidu.BaiduShortenUrl(svc.GetSysCfgStr("baidu_token"), link)
  350. if url != "" {
  351. var uniqueId = php2go.Md5(link)
  352. oldLink := link
  353. link = url
  354. tmp := map[string]interface{}{
  355. "uid": user.Id,
  356. "link": oldLink,
  357. "short_link": link,
  358. "date": time.Now().Unix() + 365*86400,
  359. }
  360. doc, _ := es.FirstDoc(EggUserShortLink, uniqueId)
  361. if doc == nil {
  362. es.CreateDoc(EggUserShortLink, uniqueId, tmp)
  363. } else {
  364. es.UpdateDoc(EggUserShortLink, uniqueId, tmp)
  365. }
  366. }
  367. }
  368. res.Link = link
  369. QRcode := qrcode.GetPNGBase64(link)
  370. QRcode = strings.ReplaceAll(QRcode, "\u0000", "")
  371. res.Qrcode = QRcode
  372. e.OutSuc(c, res, nil)
  373. return
  374. }
  375. // ParentInfo
  376. // @Summary 导师信息
  377. // @Tags 会员中心
  378. // @Description 导师信息
  379. // @Accept json
  380. // @Produce json
  381. // @Success 200 {object} md.ParentInfo "登录成功返回"
  382. // @Failure 400 {object} md.Response "具体错误"
  383. // @Router /api/v1/memberCenter/parentInfo [get]
  384. func ParentInfo(c *gin.Context) {
  385. ownUser := svc.GetUser(c)
  386. publicPlatoonBasicDb := implement.NewPublicPlatoonBasicSettingDb(db.Db)
  387. publicPlatoonBasic, _ := publicPlatoonBasicDb.PublicPlatoonBasicSettingGetOne()
  388. if publicPlatoonBasic != nil && int(ownUser.Id) == publicPlatoonBasic.OriginatorUid {
  389. ownUser.ParentUid = ownUser.Id
  390. }
  391. if ownUser.ParentUid == 0 {
  392. e.OutSuc(c, md.ParentInfo{}, nil)
  393. return
  394. }
  395. NewUserDb := implement.NewUserDb(db.Db)
  396. user, _ := NewUserDb.GetUser(ownUser.ParentUid)
  397. // 1. 获取会员等级名称
  398. userLevelDb := implement.NewUserLevelDb(db.Db)
  399. level, err := userLevelDb.UserLevelByID(user.Level)
  400. if err != nil {
  401. e.OutErr(c, e.ERR_DB_ORM, nil)
  402. return
  403. }
  404. code := user.SystemInviteCode
  405. if user.CustomInviteCode != "" {
  406. code = user.CustomInviteCode
  407. }
  408. res := md.ParentInfo{
  409. Nickname: user.Nickname,
  410. LevelName: level.LevelName,
  411. InviteCode: code,
  412. HeadImg: svc.GetOssUrl(user.Avatar),
  413. Id: utils.Int64ToStr(user.Id),
  414. Phone: user.Phone,
  415. WechatAccount: user.WechatAccount,
  416. }
  417. e.OutSuc(c, res, nil)
  418. return
  419. }
  420. // Delete
  421. // @Summary 注销账号操作
  422. // @Tags 账号与安全
  423. // @Description 注销账号操作
  424. // @Accept json
  425. // @Produce json
  426. // @Param req body md.DeleteUserReq true "注册参数"
  427. // @Success 200 string "登录成功返回"
  428. // @Failure 400 {object} md.Response "具体错误"
  429. // @Router /api/v1/memberCenter/delete [post]
  430. func Delete(c *gin.Context) {
  431. var req md.DeleteUserReq
  432. err := c.ShouldBindJSON(&req)
  433. if err != nil {
  434. err = svc.HandleValidateErr(err)
  435. err1 := err.(e.E)
  436. e.OutErr(c, err1.Code, err1.Error())
  437. return
  438. }
  439. user := svc.GetUser(c)
  440. //校验短信
  441. err = svc.CommSmsCheck(c, user.Phone, req.Code)
  442. if err != nil {
  443. e.OutErr(c, 400, e.NewErr(400, "验证码错误,请重试"))
  444. return
  445. }
  446. user.State = 3
  447. db.Db.Where("id=?", user.Id).Cols("state").Update(user)
  448. tmp := model.UserDeleteInfo{
  449. Uid: int(user.Id),
  450. Phone: user.Phone,
  451. CreateAt: time.Now(),
  452. }
  453. db.Db.Insert(&tmp)
  454. ch, err := rabbit.Cfg.Pool.GetChannel()
  455. if err == nil {
  456. defer ch.Release()
  457. err = ch.PublishV2(md.EggUserExchange, md.CommUserId{
  458. Uid: utils.Int64ToStr(user.Id),
  459. ParentUid: utils.Int64ToStr(user.ParentUid),
  460. }, md.EggUserDelete)
  461. if err != nil {
  462. ch.PublishV2(md.EggUserExchange, md.CommUserId{
  463. Uid: utils.Int64ToStr(user.Id),
  464. ParentUid: utils.Int64ToStr(user.ParentUid),
  465. }, md.EggUserDelete)
  466. }
  467. }
  468. // 清掉token
  469. cacheKey := fmt.Sprintf(auth.TokenKey, user.Id)
  470. _, err = cache.SetEx(cacheKey, "", 1)
  471. e.OutSuc(c, "success", nil)
  472. return
  473. }
  474. // DeleteInfo
  475. // @Summary 注销账号信息
  476. // @Tags 账号与安全
  477. // @Description 注销账号信息
  478. // @Accept json
  479. // @Produce json
  480. // @Success 200 {object} md.UserDeleteInfo "登录成功返回"
  481. // @Failure 400 {object} md.Response "具体错误"
  482. // @Router /api/v1/memberCenter/delete/info [get]
  483. func DeleteInfo(c *gin.Context) {
  484. user := svc.GetUser(c)
  485. resp := md.UserDeleteInfo{
  486. Url: fmt.Sprintf("%s%s?id=%s&is_hide=1", svc.GetSysCfgStr("wap_host"), "/#/pages/course-detail-page/course-detail-page", "115"),
  487. }
  488. extendUserCount, _ := db.Db.Where("parent_uid=?", user.Id).Count(&model.User{})
  489. NewUserWalletDb := implement.NewUserWalletDb(db.Db)
  490. walletAmount := "0"
  491. wallet, _ := NewUserWalletDb.GetUserVirtualWallet(user.Id)
  492. if wallet != nil {
  493. walletAmount = wallet.Amount
  494. }
  495. NewUserVirtualAmountDb := implement.NewUserVirtualAmountDb(db.Db)
  496. virtualWallet, _ := NewUserVirtualAmountDb.GetUserVirtualAllWallets(user.Id)
  497. virtualAmount1 := "0"
  498. virtualAmount2 := "0"
  499. virtualAmount3 := "0"
  500. settingDb := implement.NewEggEnergyBasicSettingDb(db.Db)
  501. setting, _ := settingDb.EggEnergyBasicSettingGetOne()
  502. if virtualWallet != nil {
  503. for _, v := range *virtualWallet {
  504. if v.CoinId == setting.PersonEggPointsCoinId {
  505. virtualAmount3 = utils.Float64ToStrPrec8(utils.StrToFloat64(v.Amount) + utils.StrToFloat64(virtualAmount3))
  506. }
  507. if v.CoinId == setting.TeamEggPointsCoinId {
  508. virtualAmount3 = utils.Float64ToStrPrec8(utils.StrToFloat64(v.Amount) + utils.StrToFloat64(virtualAmount3))
  509. }
  510. if v.CoinId == setting.PersonEggEnergyCoinId {
  511. virtualAmount2 = utils.Float64ToStrPrec8(utils.StrToFloat64(v.Amount) + utils.StrToFloat64(virtualAmount2))
  512. }
  513. if v.CoinId == setting.TeamEggEnergyCoinId {
  514. virtualAmount2 = utils.Float64ToStrPrec8(utils.StrToFloat64(v.Amount) + utils.StrToFloat64(virtualAmount2))
  515. }
  516. if v.CoinId == setting.ContributionCoinId {
  517. virtualAmount1 = utils.Float64ToStrPrec8(utils.StrToFloat64(v.Amount) + utils.StrToFloat64(virtualAmount1))
  518. }
  519. }
  520. }
  521. score := 60.00
  522. now := time.Now()
  523. esIndex := es2.GetLatestEffectiveIndexFromAlias(now)
  524. esIndexName := md3.EggEnergyUserEggScoreEsAlias + "_" + esIndex
  525. results, _ := es.FirstDoc(esIndexName, esIndex+"_"+utils.Int64ToStr(user.Id))
  526. if results != nil {
  527. var doc md.UserEggFlowReqRespList
  528. json.Unmarshal(results.Source, &doc)
  529. score = doc.ScoreValue
  530. }
  531. uid := user.Id
  532. sql := fmt.Sprintf("SELECT COUNT(*)AS total FROM `public_platoon_user_relation` WHERE father_uid1 = %d OR father_uid2= %d OR father_uid3= %d OR father_uid4= %d OR father_uid5= %d OR father_uid6= %d OR father_uid7= %d OR father_uid8= %d OR father_uid9= %d", uid, uid, uid, uid, uid, uid, uid, uid, uid)
  533. nativeString1, _ := db.QueryNativeString(db.Db, sql)
  534. hasUserCount := "0"
  535. if len(nativeString1) > 0 {
  536. hasUserCount = nativeString1[0]["total"]
  537. }
  538. info := []md.UserDeleteInfoList{
  539. {Title: "贡献值", Content: "贡献值 " + virtualAmount1},
  540. {Title: "能量值", Content: "能量值 " + virtualAmount2},
  541. {Title: "活跃值", Content: "活跃值 " + virtualAmount3},
  542. {Title: "蛋蛋分", Content: "蛋蛋分 " + utils.Float64ToStr(score)},
  543. {Title: "余额", Content: "余额 " + walletAmount},
  544. {Title: "直推好友", Content: "直推好友 " + utils.Int64ToStr(extendUserCount) + " 人"},
  545. {Title: "团队", Content: "团队 " + hasUserCount + " 人"},
  546. }
  547. resp.Info = info
  548. e.OutSuc(c, resp, nil)
  549. return
  550. }