From d7de9e9c8902a95b06aecf24286de5f5c4fab9be Mon Sep 17 00:00:00 2001 From: liangjies <1139629972@qq.com> Date: Sun, 14 Jul 2024 23:42:00 +0800 Subject: [PATCH] =?UTF-8?q?add:=20=E7=A1=AE=E8=AE=A4=E6=8D=A2=E7=BB=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/app/api/v1/social.go | 38 ++++++++++++++++ internal/app/dao/social.go | 8 ++-- internal/app/dao/users.go | 65 +++++++++++++++++++++++++++ internal/app/model/request/social.go | 8 ++++ internal/app/model/response/social.go | 5 +++ internal/app/router/social.go | 4 +- internal/app/service/social.go | 64 +++++++++++++++----------- internal/app/service/zcloak.go | 3 +- 8 files changed, 161 insertions(+), 34 deletions(-) diff --git a/internal/app/api/v1/social.go b/internal/app/api/v1/social.go index 4fb1630..68293ac 100644 --- a/internal/app/api/v1/social.go +++ b/internal/app/api/v1/social.go @@ -156,3 +156,41 @@ func UnbindSocial(c *gin.Context) { Ok(c) } } + +// BindSocialResult 查询绑定结果 +func BindSocialResult(c *gin.Context) { + var r request.BindSocialResultRequest + if err := c.ShouldBindJSON(&r); err != nil { + FailWithMessage(GetMessage(c, "ParameterError"), c) + return + } + address := c.GetString("address") + if address == "" { + Fail(c) + return + } + if data, err := srv.BindSocialResult(address, r.Type); err != nil { + FailWithMessage(GetMessage(c, err.Error()), c) + } else { + OkWithData(data, c) + } +} + +// ConfirmBindChange 确认绑定变更 +func ConfirmBindChange(c *gin.Context) { + var r request.ConfirmBindChangeRequest + if err := c.ShouldBindJSON(&r); err != nil { + FailWithMessage(GetMessage(c, "ParameterError"), c) + return + } + address := c.GetString("address") + if address == "" { + Fail(c) + return + } + if err := srv.ConfirmBindChange(address, r.Type); err != nil { + FailWithMessage(GetMessage(c, err.Error()), c) + } else { + Ok(c) + } +} diff --git a/internal/app/dao/social.go b/internal/app/dao/social.go index 8f64b28..6ed926e 100644 --- a/internal/app/dao/social.go +++ b/internal/app/dao/social.go @@ -21,7 +21,7 @@ func (d *Dao) WechatQueryByAddress(address string) (wechatData string, err error // WechatIsBinding 判断是否已经绑定过 func (d *Dao) WechatIsBinding(fromUserName string) (string, bool, error) { var address string - err := d.db.Raw("SELECT address FROM users WHERE socials->'wechat'->>'openid' = ?", fromUserName).First(&address).Error + err := d.db.Raw("SELECT address FROM users WHERE socials->'wechat'->>'openid' = ? LIMIT 1", fromUserName).Scan(&address).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return "", false, nil @@ -106,7 +106,7 @@ func (d *Dao) DiscordQueryByAddress(address string) (discordData string, err err // DiscordIsBinding 判断Discord是否已经绑定过 func (d *Dao) DiscordIsBinding(discordID string) (string, bool, error) { var address string - err := d.db.Raw("SELECT address FROM users WHERE socials->'discord'->>'id' = ?", discordID).First(&address).Error + err := d.db.Raw("SELECT address FROM users WHERE socials->'discord'->>'id' = ? LIMIT 1", discordID).Scan(&address).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return "", false, nil @@ -119,7 +119,7 @@ func (d *Dao) DiscordIsBinding(discordID string) (string, bool, error) { // EmailIsBinding 判断邮箱是否已经绑定过 func (d *Dao) EmailIsBinding(email string) (string, bool, error) { var address string - err := d.db.Raw("SELECT address FROM users WHERE socials->>'email' = ?", email).First(&address).Error + err := d.db.Raw("SELECT address FROM users WHERE socials->>'email' = ? LIMIT 1", email).Scan(&address).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return "", false, nil @@ -195,7 +195,7 @@ func (d *Dao) GithubQueryByAddress(address string) (githubData string, err error // GithubIsBinding 判断Github是否已经绑定过 func (d *Dao) GithubIsBinding(githubID string) (string, bool, error) { var address string - err := d.db.Raw("SELECT address FROM users WHERE socials->'github'->>'id' = ?", githubID).First(&address).Error + err := d.db.Raw("SELECT address FROM users WHERE socials->'github'->>'id' = ? LIMIT 1", githubID).Scan(&address).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return "", false, nil diff --git a/internal/app/dao/users.go b/internal/app/dao/users.go index 5c5b761..b5aa1d4 100644 --- a/internal/app/dao/users.go +++ b/internal/app/dao/users.go @@ -14,6 +14,9 @@ import ( func (d *Dao) nonceKeyRedis(key string) string { return fmt.Sprintf("%snonce_%s", d.c.Redis.Prefix, key) } +func getRebindKey(bindType string, address string) string { + return fmt.Sprintf("rebind_%s_%s", bindType, address) +} func (d *Dao) HasNonce(c context.Context, nonce string) (has bool, err error) { if err = d.redis.Get(c, d.nonceKeyRedis(nonce)).Err(); err != nil { if err == redis.Nil { @@ -97,6 +100,68 @@ func (d *Dao) HasBindSocialAccount(address string) (data map[string]bool, err er return data, err } +// GetNeedRebindInfo 获取需要换绑信息 +func (d *Dao) GetNeedRebindInfo(address string, bindType string) (currentBindingAddress string, err error) { + key := getRebindKey(bindType, address) + // 从 Redis 获取 + currentBindingAddress, err = d.redis.Get(context.Background(), key).Result() + if err != nil { + if errors.Is(err, redis.Nil) { + return "", nil + } + return currentBindingAddress, err + } + return currentBindingAddress, err +} + +// SaveRebindInfo 保存换绑信息 +func (d *Dao) SaveRebindInfo(address string, bindType string, currentBindingAddress string) (err error) { + key := getRebindKey(bindType, address) + return d.redis.Set(context.Background(), key, currentBindingAddress, time.Duration(5)*time.Minute).Err() +} + +// ConfirmBindChange 确认换绑 +func (d *Dao) ConfirmBindChange(address string, bindType string) (err error) { + key := getRebindKey(bindType, address) + // 从 Redis 获取 + currentBindingAddress, err := d.redis.Get(context.Background(), key).Result() + if err != nil { + if errors.Is(err, redis.Nil) { + return errors.New("操作失败!请重新操作") + } + return err + } + tx := d.db.Begin() + selectSQL := fmt.Sprintf("SELECT COALESCE(socials->'%s', '{}') FROM users WHERE address = ? LIMIT 1", bindType) + var rawData string + err = tx.Raw(selectSQL, currentBindingAddress).Scan(&rawData).Error + if err != nil { + tx.Rollback() + return err + } + updateSQL := fmt.Sprintf("UPDATE users SET socials = jsonb_set(COALESCE(socials,'{}'), '{\"%s\"}', ?) WHERE address = ?", bindType) + err = tx.Exec( + updateSQL, + rawData, + address, + ).Error + if err != nil { + tx.Rollback() + return + } + err = tx.Exec("UPDATE users SET socials = socials - ? WHERE address = ?", bindType, currentBindingAddress).Error + if err != nil { + tx.Rollback() + return + } + err = tx.Commit().Error + if err != nil { + return + } + // 从 Redis 删除 + return d.redis.Del(context.Background(), key).Err() +} + // ParticleUpdateSocialsInfo 更新社交信息 func (d *Dao) ParticleUpdateSocialsInfo(address string, particleUserinfo datatypes.JSON) (err error) { provider := gjson.Get(particleUserinfo.String(), "thirdparty_user_info.provider").String() diff --git a/internal/app/model/request/social.go b/internal/app/model/request/social.go index f7fa4d1..673d518 100644 --- a/internal/app/model/request/social.go +++ b/internal/app/model/request/social.go @@ -13,3 +13,11 @@ type EmailBindAddressRequest struct { type UnbindRequest struct { Type string `json:"type" binding:"required"` } + +type BindSocialResultRequest struct { + Type string `json:"type" binding:"required"` +} + +type ConfirmBindChangeRequest struct { + Type string `json:"type" binding:"required"` +} diff --git a/internal/app/model/response/social.go b/internal/app/model/response/social.go index 5b6c355..06fde4b 100644 --- a/internal/app/model/response/social.go +++ b/internal/app/model/response/social.go @@ -5,3 +5,8 @@ type BindingResponse struct { Success bool `json:"success"` // 是否绑定成功 CurrentBindingAddress string `json:"current_binding_address"` // 当前绑定地址 } + +type BindingResultResponse struct { + Bound bool `json:"bound"` + CurrentBindingAddress string `json:"current_binding_address"` // 当前绑定地址 +} diff --git a/internal/app/router/social.go b/internal/app/router/social.go index 1a3dcd6..9bf166d 100644 --- a/internal/app/router/social.go +++ b/internal/app/router/social.go @@ -26,6 +26,8 @@ func InitSocialRouter(Router *gin.RouterGroup) { routerAuth.POST("/githubBindAddress", v1.GithubBindAddress) // Github 回调绑定 } { - routerAuth.POST("/unbindSocial", v1.UnbindSocial) // 解绑 + routerAuth.POST("/bindSocialResult", v1.BindSocialResult) // 查询绑定结果 + routerAuth.POST("/confirmBindChange", v1.ConfirmBindChange) // 确认绑定 + routerAuth.POST("/unbindSocial", v1.UnbindSocial) // 解绑 } } diff --git a/internal/app/service/social.go b/internal/app/service/social.go index dbdeb6a..8bdaae2 100644 --- a/internal/app/service/social.go +++ b/internal/app/service/social.go @@ -121,16 +121,12 @@ func (s *Service) DiscordCallback(address string, discordCallback interface{}, r return res, errors.New("UnexpectedError") } if Binding { - // 替换绑定 - if replace { - err = s.dao.UnbindSocial(address, "email") - if err != nil { - return res, errors.New("UnexpectedError") - } - } else { - res.CurrentBindingAddress = bindingAddress - return res, nil + err = s.dao.SaveRebindInfo(address, "discord", bindingAddress) + if err != nil { + return response.BindingResponse{}, err } + res.CurrentBindingAddress = bindingAddress + return res, nil } err = s.dao.DiscordBindAddress(discordID, username, address) if err != nil { @@ -221,16 +217,12 @@ func (s *Service) EmailBindAddress(address, emailAddress, code string, replace b return res, errors.New("UnexpectedError") } if isBinding { - // 替换绑定 - if replace { - err := s.dao.UnbindSocial(address, "email") - if err != nil { - return res, errors.New("UnexpectedError") - } - } else { - res.CurrentBindingAddress = bindingAddress - return res, nil + err = s.dao.SaveRebindInfo(address, "email", bindingAddress) + if err != nil { + return response.BindingResponse{}, err } + res.CurrentBindingAddress = bindingAddress + return res, nil } // 绑定 err = s.dao.EmailBindAddress(address, emailAddress) @@ -289,16 +281,12 @@ func (s *Service) GithubCallback(address string, githubCallback interface{}, rep return res, errors.New("UnexpectedError") } if binding { - // 替换绑定 - if replace { - err := s.dao.UnbindSocial(address, "email") - if err != nil { - return res, errors.New("UnexpectedError") - } - } else { - res.CurrentBindingAddress = bindingAddress - return res, nil + err = s.dao.SaveRebindInfo(address, "github", bindingAddress) + if err != nil { + return response.BindingResponse{}, err } + res.CurrentBindingAddress = bindingAddress + return res, nil } err = s.dao.GithubBindAddress(githubID, username, address) if err != nil { @@ -323,3 +311,25 @@ func (s *Service) UnbindSocial(address, unbindType string) (err error) { return errors.New("UnexpectedError") } } + +// BindSocialResult 查询绑定结果 +func (s *Service) BindSocialResult(address string, bindType string) (res response.BindingResultResponse, err error) { + accountBind, err := s.dao.HasBindSocialAccount(address) + if err != nil { + return response.BindingResultResponse{}, err + } + res.Bound = accountBind[bindType] + currentBindingAddress, err := s.dao.GetNeedRebindInfo(address, bindType) + if err != nil { + return response.BindingResultResponse{}, err + } + if currentBindingAddress != "" { + res.CurrentBindingAddress = fmt.Sprintf("%s...%s", currentBindingAddress[:6], currentBindingAddress[len(currentBindingAddress)-4:]) + } + return res, nil +} + +// ConfirmBindChange 确认绑定变更 +func (s *Service) ConfirmBindChange(address, bindType string) (err error) { + return s.dao.ConfirmBindChange(address, bindType) +} diff --git a/internal/app/service/zcloak.go b/internal/app/service/zcloak.go index 02cba7e..2b25de0 100644 --- a/internal/app/service/zcloak.go +++ b/internal/app/service/zcloak.go @@ -5,7 +5,6 @@ import ( "backend-go/internal/app/model/request" "backend-go/internal/app/utils" "backend-go/pkg/log" - "encoding/json" "errors" "fmt" reqV3 "github.com/imroc/req/v3" @@ -196,7 +195,7 @@ func (s *Service) SaveToNFTCollection(saveCardInfo SaveCardInfoRequest) (err err } // 发送请求 client := reqV3.C().SetCommonHeader("x-api-key", s.c.NFT.APIKey) - data, _ := json.Marshal(saveCardInfo) + //data, _ := json.Marshal(saveCardInfo) r, err := client.R().SetBodyJsonMarshal(saveCardInfo).Post(s.c.NFT.API + "/zcloak/saveCardInfo") if err != nil { log.Errorv("SaveToNFT error", zap.Error(err), zap.String("res", r.String()))