diff --git a/go.mod b/go.mod index 25f1f2a..50c3fc2 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( filippo.io/edwards25519 v1.0.0-rc.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/StackExchange/wmi v1.2.1 // indirect + github.com/allegro/bigcache/v3 v3.1.0 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect github.com/bits-and-blooms/bitset v1.5.0 // indirect github.com/blendle/zapdriver v1.3.1 // indirect diff --git a/go.sum b/go.sum index ec62c9e..b8a6383 100644 --- a/go.sum +++ b/go.sum @@ -87,6 +87,8 @@ github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGn github.com/alicebob/miniredis/v2 v2.30.0 h1:uA3uhDbCxfO9+DI/DuGeAMr9qI+noVWwGPNTFuKID5M= github.com/alicebob/miniredis/v2 v2.30.0/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk= +github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= diff --git a/internal/app/api/v1/social.go b/internal/app/api/v1/social.go index 95471ab..68293ac 100644 --- a/internal/app/api/v1/social.go +++ b/internal/app/api/v1/social.go @@ -2,7 +2,6 @@ package v1 import ( "backend-go/internal/app/model/request" - "fmt" "github.com/gin-gonic/gin" ) @@ -27,6 +26,7 @@ func WechatBindAddress(c *gin.Context) { type WechatBind struct { Address string `json:"address" form:"address" binding:"required"` Code string `json:"code" form:"code" binding:"required"` + Replace bool `json:"replace" form:"replace"` } var wechatBind WechatBind err := c.ShouldBindJSON(&wechatBind) @@ -34,7 +34,7 @@ func WechatBindAddress(c *gin.Context) { FailWithMessage(GetMessage(c, "ParameterError"), c) return } - if err := srv.WechatBindAddress(c, wechatBind.Address, wechatBind.Code); err != nil { + if err := srv.WechatBindAddress(c, wechatBind.Address, wechatBind.Code, wechatBind.Replace); err != nil { FailWithMessage(err.Error(), c) } else { Ok(c) @@ -56,14 +56,15 @@ func DiscordBindAddress(c *gin.Context) { type DiscordCallback struct { Code string `json:"code" form:"code"` Callback string `json:"callback" form:"callback"` + Replace bool `json:"replace" form:"replace"` } var discordCallback DiscordCallback _ = c.ShouldBindJSON(&discordCallback) address := c.GetString("address") - if err := srv.DiscordCallback(address, discordCallback); err != nil { + if data, err := srv.DiscordCallback(address, discordCallback, discordCallback.Replace); err != nil { OkWithMessage(GetMessage(c, err.Error()), c) } else { - OkWithMessage("", c) + OkWithData(data, c) } } @@ -91,7 +92,6 @@ func GetEmailBindCode(c *gin.Context) { func EmailBindAddress(c *gin.Context) { var r request.EmailBindAddressRequest if err := c.ShouldBindJSON(&r); err != nil { - fmt.Println(err) FailWithMessage(GetMessage(c, "ParameterError"), c) return } @@ -100,10 +100,14 @@ func EmailBindAddress(c *gin.Context) { FailWithMessage(GetMessage(c, "SignatureExpired"), c) return } - if err := srv.EmailBindAddress(address, r.Email, r.Code); err != nil { + if data, err := srv.EmailBindAddress(address, r.Email, r.Code, r.Replace); err != nil { FailWithMessage(GetMessage(c, err.Error()), c) } else { - Ok(c) + message := "操作成功" + if data.Success == false { + message = "绑定失败" + } + OkWithDetailed(data, message, c) } } @@ -122,13 +126,71 @@ func GithubBindAddress(c *gin.Context) { type GithubCallback struct { Code string `json:"code" form:"code"` Callback string `json:"callback" form:"callback"` + Replace bool `json:"replace" form:"replace"` } var githubCallback GithubCallback _ = c.ShouldBindJSON(&githubCallback) address := c.GetString("address") - if err := srv.GithubCallback(address, githubCallback); err != nil { + if data, err := srv.GithubCallback(address, githubCallback, githubCallback.Replace); err != nil { OkWithMessage(GetMessage(c, err.Error()), c) } else { - OkWithMessage("", c) + OkWithData(data, c) + } +} + +// UnbindSocial 解绑 +func UnbindSocial(c *gin.Context) { + var r request.UnbindRequest + 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.UnbindSocial(address, r.Type); err != nil { + FailWithMessage(GetMessage(c, err.Error()), c) + } else { + 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/api/v1/tutorial.go b/internal/app/api/v1/tutorial.go index d8d099c..0e94483 100644 --- a/internal/app/api/v1/tutorial.go +++ b/internal/app/api/v1/tutorial.go @@ -3,7 +3,6 @@ package v1 import ( "backend-go/internal/app/model/request" "backend-go/internal/app/model/response" - "fmt" "github.com/gin-gonic/gin" ) @@ -14,7 +13,6 @@ func GetProgressList(c *gin.Context) { return } userID := c.GetUint("userID") - fmt.Println("userID", userID) if data, err := srv.GetProgressList(userID, req); err != nil { FailWithMessage(GetMessage(c, "FetchFailed"), c) } else { diff --git a/internal/app/api/v1/user.go b/internal/app/api/v1/user.go index af62662..c307292 100644 --- a/internal/app/api/v1/user.go +++ b/internal/app/api/v1/user.go @@ -4,7 +4,6 @@ import ( "backend-go/internal/app/model/request" "backend-go/internal/app/model/response" "backend-go/internal/app/utils" - "fmt" "github.com/gin-gonic/gin" "path" "strings" @@ -156,7 +155,6 @@ func AuthLoginSign(c *gin.Context) { FailWithMessage(GetMessage(c, "ParameterError"), c) return } - fmt.Println(request) var token string var err error if utils.IsValidAddress(request.Address) { diff --git a/internal/app/assets/locale.json b/internal/app/assets/locale.json index 6e34a4e..d081707 100644 --- a/internal/app/assets/locale.json +++ b/internal/app/assets/locale.json @@ -37,7 +37,8 @@ "AddressAlreadyLinkedEmail": "The wallet address has already been linked to Email. Please do not repeat the operation.", "EmailAlreadyLinked": "The email has already been linked to another address!", "GithubAlreadyLinked": "Github has been linked to another wallet address!", - "AddressAlreadyLinkedGithub": "The wallet address has already been linked to Github. Please do not repeat the operation." + "AddressAlreadyLinkedGithub": "The wallet address has already been linked to Github. Please do not repeat the operation.", + "FailedObtainGithubInfo": "Failed to obtain Github information!" }, "zh-CN": { "OperationSuccess": "操作成功!", @@ -77,6 +78,7 @@ "AddressAlreadyLinkedEmail": "钱包地址已绑定邮箱,请勿重复操作", "EmailAlreadyLinked": "邮箱已绑定其他钱包地址", "GithubAlreadyLinked": "Github 已绑定其他钱包地址", - "AddressAlreadyLinkedGithub": "钱包地址已绑定Github,请勿重复操作" + "AddressAlreadyLinkedGithub": "钱包地址已绑定Github,请勿重复操作", + "FailedObtainGithubInfo": "绑定 Github 信息失败!" } } \ No newline at end of file diff --git a/internal/app/dao/collection.go b/internal/app/dao/collection.go index 99091dd..71e7228 100644 --- a/internal/app/dao/collection.go +++ b/internal/app/dao/collection.go @@ -5,7 +5,6 @@ import ( "backend-go/internal/app/model/request" "backend-go/internal/app/model/response" "errors" - "fmt" "github.com/spf13/cast" "gorm.io/gorm" ) @@ -356,6 +355,5 @@ func (d *Dao) GetCollectionHolderRank(address string, id int64, page, pageSize i Order("user_challenges.add_ts ASC,user_challenges.id ASC"). Limit(limit).Offset(offset). Find(&res).Error - fmt.Println(res) return res, total, err } diff --git a/internal/app/dao/quest.go b/internal/app/dao/quest.go index 9f1f4f3..1e5a263 100644 --- a/internal/app/dao/quest.go +++ b/internal/app/dao/quest.go @@ -125,10 +125,7 @@ func (d *Dao) GetQuestList(req *request.GetQuestListRequest) (questList []respon var estimateTimeTotal int64 for _, quest := range collectionQuestList { estimateTimeTotal += gjson.Get(string(quest.QuestData), "estimateTime").Int() - fmt.Println("estimateTimeTotal", estimateTimeTotal) } - - fmt.Println("estimateTimeTotal", estimateTimeTotal) if estimateTimeTotal != 0 { questList[i].EstimateTime = estimateTimeTotal } @@ -603,7 +600,6 @@ func (d *Dao) GetQuestHolderRankByTokenID(address string, tokenId string, page, Order("user_challenges.add_ts ASC,user_challenges.id ASC"). Limit(limit).Offset(offset). Find(&res).Error - fmt.Println(res) return res, total, err } diff --git a/internal/app/dao/social.go b/internal/app/dao/social.go index 63b669b..e9c83e2 100644 --- a/internal/app/dao/social.go +++ b/internal/app/dao/social.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "gorm.io/gorm" "math/rand" "time" ) @@ -18,16 +19,19 @@ func (d *Dao) WechatQueryByAddress(address string) (wechatData string, err error } // WechatIsBinding 判断是否已经绑定过 -func (d *Dao) WechatIsBinding(fromUserName string) (bool, error) { - var count int - err := d.db.Raw("SELECT count(1) FROM users WHERE socials->'wechat'->>'openid' = ?", fromUserName).Scan(&count).Error +func (d *Dao) WechatIsBinding(fromUserName string) (string, bool, error) { + var address string + err := d.db.Raw("SELECT address FROM users WHERE socials->'wechat'->>'openid' = ? LIMIT 1", fromUserName).Scan(&address).Error if err != nil { - return false, err + if errors.Is(err, gorm.ErrRecordNotFound) { + return "", false, nil + } + return "", false, err } - if count == 0 { - return false, nil + if address == "" { + return "", false, nil } - return true, nil + return address, true, nil } // WechatBindAddress 处理地址绑定 @@ -95,7 +99,7 @@ func (d *Dao) DiscordBindAddress(discordID, username, address string) (err error // DiscordQueryByAddress 查询地址绑定的discord信息 func (d *Dao) DiscordQueryByAddress(address string) (discordData string, err error) { - err = d.db.Raw("SELECT COALESCE(socials->'discord', '{}') FROM users WHERE address = ? LIMIT 1", address).Scan(&discordData).Error + err = d.db.Raw("SELECT COALESCE(socials->'discord', '{}') FROM users WHERE address = ? LIMIT 1", address).First(&discordData).Error if err != nil { return discordData, err } @@ -103,29 +107,35 @@ func (d *Dao) DiscordQueryByAddress(address string) (discordData string, err err } // DiscordIsBinding 判断Discord是否已经绑定过 -func (d *Dao) DiscordIsBinding(discordID string) (bool, error) { - var count int - err := d.db.Raw("SELECT count(1) FROM users WHERE socials->'discord'->>'id' = ?", discordID).Scan(&count).Error +func (d *Dao) DiscordIsBinding(discordID string) (string, bool, error) { + var address string + err := d.db.Raw("SELECT address FROM users WHERE socials->'discord'->>'id' = ? LIMIT 1", discordID).Scan(&address).Error if err != nil { - return false, err + if errors.Is(err, gorm.ErrRecordNotFound) { + return "", false, nil + } + return "", false, err } - if count == 0 { - return false, nil + if address == "" { + return "", false, nil } - return true, nil + return address, true, nil } // EmailIsBinding 判断邮箱是否已经绑定过 -func (d *Dao) EmailIsBinding(email string) (bool, error) { - var count int - err := d.db.Raw("SELECT count(1) FROM users WHERE socials->>'email' = ?", email).Scan(&count).Error +func (d *Dao) EmailIsBinding(email string) (string, bool, error) { + var address string + err := d.db.Raw("SELECT address FROM users WHERE socials->>'email' = ? LIMIT 1", email).Scan(&address).Error if err != nil { - return false, err + if errors.Is(err, gorm.ErrRecordNotFound) { + return "", false, nil + } + return "", false, err } - if count == 0 { - return false, nil + if address == "" { + return "", false, nil } - return true, nil + return address, true, nil } // EmailQueryByAddress 查询地址绑定的邮箱信息 @@ -192,16 +202,19 @@ func (d *Dao) GithubQueryByAddress(address string) (githubData string, err error } // GithubIsBinding 判断Github是否已经绑定过 -func (d *Dao) GithubIsBinding(githubID string) (bool, error) { - var count int - err := d.db.Raw("SELECT count(1) FROM users WHERE socials->'github'->>'id' = ?", githubID).Scan(&count).Error +func (d *Dao) GithubIsBinding(githubID string) (string, bool, error) { + var address string + err := d.db.Raw("SELECT address FROM users WHERE socials->'github'->>'id' = ? LIMIT 1", githubID).Scan(&address).Error if err != nil { - return false, err + if errors.Is(err, gorm.ErrRecordNotFound) { + return "", false, nil + } + return "", false, err } - if count == 0 { - return false, nil + if address == "" { + return "", false, nil } - return true, nil + return address, true, nil } // GithubBindAddress 处理地址绑定 @@ -234,3 +247,18 @@ func (d *Dao) GithubBindAddress(githubID, username, address string) (err error) return err } } + +// UnbindSocial 解绑 +func (d *Dao) UnbindSocial(address, social string) error { + return d.db.Exec("UPDATE users SET socials = socials - ? WHERE address = ?", social, address).Error +} + +func (d *Dao) SaveRebindingInfo(token, info interface{}) (err error) { + key := fmt.Sprintf("%s_rebinding_%s", d.c.Redis.Prefix, token) + return d.redis.Set(context.Background(), key, info, time.Minute*30).Err() +} + +func (d *Dao) GetRebindingInfo(token string) (info string, err error) { + key := fmt.Sprintf("%s_rebinding_%s", d.c.Redis.Prefix, token) + return d.redis.Get(context.Background(), key).Result() +} 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 5f06bd0..673d518 100644 --- a/internal/app/model/request/social.go +++ b/internal/app/model/request/social.go @@ -5,6 +5,19 @@ type GetEmailBindCodeRequest struct { } type EmailBindAddressRequest struct { - Email string `json:"email" binding:"required,email"` - Code string `json:"code" binding:"required"` + Email string `json:"email" binding:"required,email"` + Code string `json:"code" binding:"required"` + Replace bool `json:"replace"` // 是否替换 +} + +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 new file mode 100644 index 0000000..06fde4b --- /dev/null +++ b/internal/app/model/response/social.go @@ -0,0 +1,12 @@ +package response + +// BindingResponse 绑定提示 +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 8dffb2d..9bf166d 100644 --- a/internal/app/router/social.go +++ b/internal/app/router/social.go @@ -25,4 +25,9 @@ func InitSocialRouter(Router *gin.RouterGroup) { routerAuth.GET("/getGithubAuthorizationURL", v1.GithubAuthorizationURL) // 获取 Github 授权链接 routerAuth.POST("/githubBindAddress", v1.GithubBindAddress) // Github 回调绑定 } + { + routerAuth.POST("/bindSocialResult", v1.BindSocialResult) // 查询绑定结果 + routerAuth.POST("/confirmBindChange", v1.ConfirmBindChange) // 确认绑定 + routerAuth.POST("/unbindSocial", v1.UnbindSocial) // 解绑 + } } diff --git a/internal/app/service/answer.go b/internal/app/service/answer.go index d2ce661..ebecf8c 100644 --- a/internal/app/service/answer.go +++ b/internal/app/service/answer.go @@ -52,7 +52,6 @@ func (s *Service) AnswerCheck(key, answerUser, address string, userScore int64, return totalScore, userReturnRawScore, userReturnScore, false, errors.New("unexpect error") } } - fmt.Println("answersList", answersList) // 检查答案有效性 if len(answerU) != len(answerS) || len(scoreList) != len(answerS) { log.Error("答案数量不相等") @@ -86,9 +85,9 @@ func (s *Service) AnswerCheck(key, answerUser, address string, userScore int64, } // 单选题 if questType == "multiple_choice" { - fmt.Println("multiple_choice") - fmt.Println("questValue", questValue) - fmt.Println("answerU[i].String()", answerU[i].String()) + //fmt.Println("multiple_choice") + //fmt.Println("questValue", questValue) + //fmt.Println("answerU[i].String()", answerU[i].String()) if questValue == answerU[i].String() { score += scoreList[i].Int() } @@ -96,9 +95,9 @@ func (s *Service) AnswerCheck(key, answerUser, address string, userScore int64, } // 填空题 if questType == "fill_blank" { - fmt.Println("questValue", questValue) + //fmt.Println("questValue", questValue) for _, item := range answersList { - fmt.Println("item", item[i].String()) + //fmt.Println("item", item[i].String()) if questValue == item[i].String() { score += scoreList[i].Int() break @@ -109,8 +108,8 @@ func (s *Service) AnswerCheck(key, answerUser, address string, userScore int64, // 多选题 if questType == "multiple_response" { answerArray := gjson.Get(questValue, "@this").Array() - fmt.Println(len(answerArray)) - fmt.Println(len(answerU[i].Array())) + //fmt.Println(len(answerArray)) + //fmt.Println(len(answerU[i].Array())) // 数量 if len(answerArray) != len(answerU[i].Array()) { continue @@ -136,7 +135,7 @@ func (s *Service) AnswerCheck(key, answerUser, address string, userScore int64, } if questType == "open_quest" { if gjson.Get(v.String(), "score").Int() != 0 { - fmt.Println("score", gjson.Get(v.String(), "score").Int()) + //fmt.Println("score", gjson.Get(v.String(), "score").Int()) score += gjson.Get(v.String(), "score").Int() } else if gjson.Get(v.String(), "correct").Bool() == true { score += scoreList[i].Int() @@ -144,9 +143,9 @@ func (s *Service) AnswerCheck(key, answerUser, address string, userScore int64, } } - fmt.Println("score", score) - fmt.Println("passingScore", passingScore) - fmt.Println("userScore", userScore) + //fmt.Println("score", score) + //fmt.Println("passingScore", passingScore) + //fmt.Println("userScore", userScore) if userScore == 0 { if score >= passingScore { return totalScore, score, score * 10000 / totalScore, true, nil diff --git a/internal/app/service/badge_v2.go b/internal/app/service/badge_v2.go index cd5f1e3..d8447b5 100644 --- a/internal/app/service/badge_v2.go +++ b/internal/app/service/badge_v2.go @@ -7,7 +7,6 @@ import ( "backend-go/pkg/log" "encoding/json" "errors" - "fmt" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" solsha3 "github.com/liangjies/go-solidity-sha3" @@ -61,7 +60,6 @@ func (s *Service) SubmitClaimShareV2(address string, req request.SubmitClaimShar if err != nil { return res, errors.New("TokenIDInvalid") } - fmt.Println("quest", quest) // 校验题目 if req.Uri != "" && req.Uri != quest.Uri { return res, errors.New("QuestUpdate") diff --git a/internal/app/service/ipfs.go b/internal/app/service/ipfs.go index 0aaeb07..e27ba56 100644 --- a/internal/app/service/ipfs.go +++ b/internal/app/service/ipfs.go @@ -59,7 +59,6 @@ func (s *Service) BalanceIPFS() { indexList[i] = spent time.Sleep(time.Second * 1) } - fmt.Println(indexList) ipfsPoint.index, _ = utils.SliceMin[int64](indexList) log.Warnv("IPFS 切换: " + strconv.Itoa(ipfsPoint.index)) } diff --git a/internal/app/service/meta.go b/internal/app/service/meta.go index 629f9a1..f96793f 100644 --- a/internal/app/service/meta.go +++ b/internal/app/service/meta.go @@ -36,7 +36,6 @@ func (s *Service) HandleMetaRequest(_id, q string) []byte { } else { ipfs = q } - fmt.Println("q", q) replaceList := map[string]string{ "https://decert.me/": fmt.Sprintf("https://decert.me/quests/%s", _id), "DeCert.Me": quest.Title, diff --git a/internal/app/service/open_quest_v2.go b/internal/app/service/open_quest_v2.go index b27146e..e2933b8 100644 --- a/internal/app/service/open_quest_v2.go +++ b/internal/app/service/open_quest_v2.go @@ -85,7 +85,6 @@ func (s *Service) GetUserOpenQuestListV2(address string, r request.GetUserOpenQu if err != nil { continue } - fmt.Println("add_ts", list[i].Addts) } sort.SliceStable(list, func(i, j int) bool { return list[i].Addts > list[j].Addts diff --git a/internal/app/service/quest.go b/internal/app/service/quest.go index b5d1fc3..fd2ed65 100644 --- a/internal/app/service/quest.go +++ b/internal/app/service/quest.go @@ -6,7 +6,6 @@ import ( "backend-go/internal/app/model/response" "backend-go/internal/app/utils" "errors" - "fmt" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" @@ -57,7 +56,6 @@ func (s *Service) AddQuest(address string, add request.AddQuestRequest) (res str return } //supply, _ := new(big.Int).SetString(add.Supply, 10) - fmt.Println(add.Supply) hash := solsha3.SoliditySHA3( // types []string{"uint32", "uint32", "uint192", "string", "string", "address", "address"}, diff --git a/internal/app/service/quest_v2.go b/internal/app/service/quest_v2.go index f8b166a..607439c 100644 --- a/internal/app/service/quest_v2.go +++ b/internal/app/service/quest_v2.go @@ -3,7 +3,6 @@ package service import ( "backend-go/internal/app/model/request" "errors" - "fmt" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" solsha3 "github.com/liangjies/go-solidity-sha3" @@ -23,7 +22,6 @@ func (s *Service) AddQuestV2(address string, add request.AddQuestV2Request) (res big.NewInt(add.ChainID), add.StartTs, add.EndTs, add.Title, add.Uri, s.c.ContractV2[add.ChainID].QuestMinter, address, }, ) - fmt.Println(add.ChainID, add.StartTs, add.EndTs, add.Title, add.Uri, s.c.ContractV2[add.ChainID].QuestMinter, address) prefixedHash := solsha3.SoliditySHA3WithPrefix(hash) signature, err := crypto.Sign(prefixedHash, privateKey) signature[64] += 27 diff --git a/internal/app/service/social.go b/internal/app/service/social.go index 965435c..8bdaae2 100644 --- a/internal/app/service/social.go +++ b/internal/app/service/social.go @@ -2,6 +2,7 @@ package service import ( "backend-go/internal/app/assets" + "backend-go/internal/app/model/response" "backend-go/pkg/log" "bytes" "crypto/tls" @@ -35,7 +36,7 @@ func (s *Service) GetWechatQrcode(address string) (data string, err error) { } // WechatBindAddress 处理地址绑定 -func (s *Service) WechatBindAddress(c *gin.Context, address, fromUserName string) (err error) { +func (s *Service) WechatBindAddress(c *gin.Context, address, fromUserName string, replace bool) (err error) { // 校验key if c.GetHeader("x-api-key") != s.c.Social.Wechat.APIKey { log.Errorv("非法请求", zap.String("x-api-key", c.GetHeader("x-api-key"))) @@ -50,12 +51,23 @@ func (s *Service) WechatBindAddress(c *gin.Context, address, fromUserName string return errors.New("钱包地址已绑定,请勿重复操作") } // 判断微信是否被别的地址绑定过 - isBinding, err := s.dao.WechatIsBinding(fromUserName) + bindingAddress, isBinding, err := s.dao.WechatIsBinding(fromUserName) if err != nil { return errors.New("服务器内部错误") } if isBinding { - return errors.New("微信已经绑定过地址") + // 替换绑定 + if replace { + err = s.dao.UnbindSocial(address, "wechat") + if err != nil { + return errors.New("UnexpectedError") + } + } else { + bindingAddStr := fmt.Sprintf("%s...%s", bindingAddress[:6], bindingAddress[len(bindingAddress)-4:]) + thisAddStr := fmt.Sprintf("%s...%s", address[:6], address[len(address)-4:]) + errMsg := fmt.Sprintf("微信已经绑定到另一个用户 %s,回复 确认 解绑并绑定当前账户 %s", bindingAddStr, thisAddStr) + return errors.New(errMsg) + } } // 绑定 return s.dao.WechatBindAddress(address, fromUserName) @@ -83,37 +95,45 @@ func (s *Service) DiscordAuthorizationURL(callback string) (data string, err err } // DiscordCallback Discord 回调绑定 -func (s *Service) DiscordCallback(address string, discordCallback interface{}) (err error) { +func (s *Service) DiscordCallback(address string, discordCallback interface{}, replace bool) (res response.BindingResponse, err error) { // 跳过已绑定地址 discordData, _ := s.dao.DiscordQueryByAddress(address) if string(discordData) != "{}" { - return errors.New("AddressAlreadyLinkedDiscord") + return res, errors.New("AddressAlreadyLinkedDiscord") } // 发送请求获取 Discord 用户信息 client := req.C().SetCommonHeader("x-api-key", s.c.Social.Wechat.APIKey) r, err := client.R().SetBodyJsonMarshal(discordCallback).Post(s.c.Social.Discord.CallURL + "/v1/callback/discord") if err != nil { - return errors.New("FailedObtainDiscordInfo") + return res, errors.New("FailedObtainDiscordInfo") } - fmt.Println(r.String()) if gjson.Get(r.String(), "status").Int() != 0 { - return errors.New("FailedObtainDiscordInfo") + return res, errors.New("FailedObtainDiscordInfo") } discordID := gjson.Get(r.String(), "data.id").String() username := gjson.Get(r.String(), "data.username").String() if discordID == "" || username == "" { - return errors.New("FailedObtainDiscordInfo") + return res, errors.New("FailedObtainDiscordInfo") } // 跳过已绑定 Discord - Binding, err := s.dao.DiscordIsBinding(discordID) + bindingAddress, Binding, err := s.dao.DiscordIsBinding(discordID) if err != nil { - return errors.New("UnexpectedError") + return res, errors.New("UnexpectedError") } if Binding { - return errors.New("DiscordAlreadyLinked") + 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 { + return res, errors.New("UnexpectedError") } - - return s.dao.DiscordBindAddress(discordID, username, address) + res.Success = true + return } // GetEmailBindCode 获取邮箱绑定验证码 @@ -174,33 +194,43 @@ func (s *Service) GetEmailBindCode(address, emailAddress, language string) (err } // EmailBindAddress 处理邮箱绑定 -func (s *Service) EmailBindAddress(address, emailAddress, code string) (err error) { +func (s *Service) EmailBindAddress(address, emailAddress, code string, replace bool) (res response.BindingResponse, err error) { // 校验验证码 emailCode, err := s.dao.EmailQueryCode(address) if err != nil { - return errors.New("UnexpectedError") + return res, errors.New("UnexpectedError") } if emailCode != code { - return errors.New("EmailCaptchaError") + return res, errors.New("EmailCaptchaError") } // 判断是否已经绑定过 emailData, err := s.dao.EmailQueryByAddress(address) if err != nil { - return errors.New("EmailCaptchaError") + return res, errors.New("EmailCaptchaError") } if emailData != "{}" { - return errors.New("AddressAlreadyLinkedEmail") + return res, errors.New("AddressAlreadyLinkedEmail") } // 判断邮箱是否被别的地址绑定过 - isBinding, err := s.dao.EmailIsBinding(emailAddress) + bindingAddress, isBinding, err := s.dao.EmailIsBinding(emailAddress) if err != nil { - return errors.New("UnexpectedError") + return res, errors.New("UnexpectedError") } if isBinding { - return errors.New("EmailAlreadyLinked") + err = s.dao.SaveRebindInfo(address, "email", bindingAddress) + if err != nil { + return response.BindingResponse{}, err + } + res.CurrentBindingAddress = bindingAddress + return res, nil } // 绑定 - return s.dao.EmailBindAddress(address, emailAddress) + err = s.dao.EmailBindAddress(address, emailAddress) + if err != nil { + return res, errors.New("UnexpectedError") + } + res.Success = true + return res, nil } // GithubAuthorizationURL 获取 Github 授权链接 @@ -225,34 +255,81 @@ func (s *Service) GithubAuthorizationURL(callback string) (data string, err erro } // GithubCallback Github 回调绑定 -func (s *Service) GithubCallback(address string, githubCallback interface{}) (err error) { +func (s *Service) GithubCallback(address string, githubCallback interface{}, replace bool) (res response.BindingResponse, err error) { // 跳过已绑定地址 githubData, _ := s.dao.GithubQueryByAddress(address) if string(githubData) != "{}" { - return errors.New("AddressAlreadyLinkedGithub") + return res, errors.New("AddressAlreadyLinkedGithub") } // 发送请求获取 Github 用户信息 client := req.C().SetCommonHeader("x-api-key", s.c.Social.Wechat.APIKey) r, err := client.R().SetBodyJsonMarshal(githubCallback).Post(s.c.Social.Github.CallURL + "/v1/callback/github") if err != nil { - return errors.New("FailedObtainGithubInfo") + return res, errors.New("FailedObtainGithubInfo") } if gjson.Get(r.String(), "status").Int() != 0 { - return errors.New("FailedObtainGithubInfo") + return res, errors.New("FailedObtainGithubInfo") } githubID := gjson.Get(r.String(), "data.id").String() username := gjson.Get(r.String(), "data.username").String() if githubID == "" || username == "" { - return errors.New("FailedObtainGithubInfo") + return res, errors.New("FailedObtainGithubInfo") } // 跳过已绑定 Github - Binding, err := s.dao.GithubIsBinding(githubID) + bindingAddress, binding, err := s.dao.GithubIsBinding(githubID) if err != nil { + return res, errors.New("UnexpectedError") + } + if binding { + 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 { + return res, errors.New("UnexpectedError") + } + res.Success = true + return res, nil +} + +// UnbindSocial 解绑 +func (s *Service) UnbindSocial(address, unbindType string) (err error) { + switch unbindType { + case "wechat": + return s.dao.UnbindSocial(address, "wechat") + case "discord": + return s.dao.UnbindSocial(address, "discord") + case "email": + return s.dao.UnbindSocial(address, "email") + case "github": + return s.dao.UnbindSocial(address, "github") + default: return errors.New("UnexpectedError") } - if Binding { - return errors.New("GithubAlreadyLinked") +} + +// 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 +} - return s.dao.GithubBindAddress(githubID, username, address) +// ConfirmBindChange 确认绑定变更 +func (s *Service) ConfirmBindChange(address, bindType string) (err error) { + return s.dao.ConfirmBindChange(address, bindType) } diff --git a/internal/app/service/user.go b/internal/app/service/user.go index 84a8b8b..1c4d028 100644 --- a/internal/app/service/user.go +++ b/internal/app/service/user.go @@ -244,7 +244,6 @@ func (s *Service) AuthLoginSignRequestSolana(req request.AuthLoginSignRequest) ( if !utils.VerifySignatureSolana(req.Address, req.Signature, []byte(req.Message)) { return token, errors.New("SignatureVerificationFailed") } - fmt.Println("AuthLoginSignRequestSolana run ") // 获取Nonce indexNonce := strings.LastIndex(req.Message, "Nonce:") if indexNonce == -1 { diff --git a/internal/app/service/zcloak.go b/internal/app/service/zcloak.go index 17428eb..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,9 +195,7 @@ func (s *Service) SaveToNFTCollection(saveCardInfo SaveCardInfoRequest) (err err } // 发送请求 client := reqV3.C().SetCommonHeader("x-api-key", s.c.NFT.APIKey) - fmt.Println(s.c.NFT.API + "/zcloak/saveCardInfo") - data, _ := json.Marshal(saveCardInfo) - fmt.Println(string(data)) + //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())) @@ -249,7 +246,6 @@ func (s *Service) GenerateCard(address string, tokenID string, lang string) (err } userScore = userScore / 100 } - fmt.Println("answer", answer) s.GenerateCardInfo(address, userScore, request.GenerateCardInfoRequest{ TokenId: tokenID, Answer: answer, diff --git a/internal/auth/service/github.go b/internal/auth/service/github.go index 7078f7d..3a9a827 100644 --- a/internal/auth/service/github.go +++ b/internal/auth/service/github.go @@ -2,7 +2,6 @@ package service import ( "backend-go/pkg/log" - "fmt" "github.com/imroc/req/v3" "github.com/tidwall/gjson" "go.uber.org/zap" @@ -42,7 +41,6 @@ func (s *Service) GithubCallback(code, callback string) (id, username string, er return } id = gjson.Get(res.String(), "id").String() - username = gjson.Get(res.String(), "name").String() - fmt.Println(res.String()) + username = gjson.Get(res.String(), "login").String() return id, username, err } diff --git a/internal/auth/service/service.go b/internal/auth/service/service.go index a0894ea..a2a1733 100644 --- a/internal/auth/service/service.go +++ b/internal/auth/service/service.go @@ -3,11 +3,14 @@ package service import ( "backend-go/internal/auth/config" "context" + "github.com/allegro/bigcache/v3" + "time" ) // Service struct type Service struct { - c *config.Config + c *config.Config + cache *bigcache.BigCache } // New init. @@ -15,7 +18,7 @@ func New(c *config.Config) (s *Service) { s = &Service{ c: c, } - + s.cache, _ = bigcache.New(context.Background(), bigcache.DefaultConfig(10*time.Minute)) return } diff --git a/internal/auth/service/wechat.go b/internal/auth/service/wechat.go index 384e8d1..09c5f71 100644 --- a/internal/auth/service/wechat.go +++ b/internal/auth/service/wechat.go @@ -35,34 +35,7 @@ func (s *Service) WechatService(c *gin.Context) (err error) { officialAccount := wc.GetOfficialAccount(cfg) // 传入request和responseWriter server := officialAccount.GetServer(req, rw) - //m := officialAccount.GetMaterial().AddMaterial("image", "/Users/chenzhen/Downloads/1.jpg") - //设置接收消息的处理方法 - server.SetMessageHandler(func(msg *message.MixMessage) *message.Reply { - if msg.MsgType == message.MsgTypeEvent { - if msg.Event == message.EventSubscribe || msg.Event == message.EventScan { - if msgData, err := s.WechatBindAddress(msg.EventKey, string(msg.FromUserName)); err != nil { - if msgData != "" { - return &message.Reply{MsgType: message.MsgTypeText, MsgData: message.NewText("钱包地址绑定失败:" + msgData)} - } else { - return nil - } - } - return &message.Reply{MsgType: message.MsgTypeText, MsgData: message.NewText("钱包地址绑定成功")} - } - - if msg.Event == message.EventClick { - // 社区二维码 - image := message.NewImage("hE1FXKcBCLuXNojNQvWrBrvVQgQfoMgW2Eqv6hePAkLC4MZPj7ZjQr0wvHtuIjbB") - if msg.EventKey == "V1001_GOOD" { - return &message.Reply{MsgType: message.MsgTypeImage, MsgData: image} - } - } - } - - fmt.Println(msg.MsgType) - fmt.Println(msg) - return nil - }) + server.SetMessageHandler(s.messageHandler) //处理消息接收以及回复 err = server.Serve() if err != nil { @@ -74,6 +47,63 @@ func (s *Service) WechatService(c *gin.Context) (err error) { return } +// messageHandler 消息处理 +func (s *Service) messageHandler(msg *message.MixMessage) *message.Reply { + switch msg.MsgType { + case message.MsgTypeEvent: + return s.handleEvent(msg) + case message.MsgTypeText: + return s.handleText(msg) + } + return nil +} + +// handleText 处理文本消息 +func (s *Service) handleText(msg *message.MixMessage) *message.Reply { + if msg.Content == "确认" || msg.Content == "确定" { + return s.handleConfirmation(msg) + } + return nil +} + +// handleEvent 处理事件消息 +func (s *Service) handleEvent(msg *message.MixMessage) *message.Reply { + if msg.Event == message.EventSubscribe || msg.Event == message.EventScan { + return s.handleSubscription(msg) + } + if msg.Event == message.EventClick && msg.EventKey == "V1001_GOOD" { + return &message.Reply{MsgType: message.MsgTypeImage, MsgData: message.NewImage("hE1FXKcBCLuXNojNQvWrBrvVQgQfoMgW2Eqv6hePAkLC4MZPj7ZjQr0wvHtuIjbB")} + } + return nil +} + +// handleSubscription 处理订阅事件 +func (s *Service) handleSubscription(msg *message.MixMessage) *message.Reply { + err := s.cache.Set("wechat::"+string(msg.FromUserName), []byte(msg.EventKey)) + if err != nil { + log.Errorv("缓存失败", zap.Error(err)) + return nil + } + msgData, err := s.WechatBindAddress(msg.EventKey, string(msg.FromUserName), false) + if err != nil && msgData != "" { + return &message.Reply{MsgType: message.MsgTypeText, MsgData: message.NewText("钱包地址绑定失败:" + msgData)} + } + return &message.Reply{MsgType: message.MsgTypeText, MsgData: message.NewText("钱包地址绑定成功")} +} + +// handleConfirmation 处理确认绑定消息 +func (s *Service) handleConfirmation(msg *message.MixMessage) *message.Reply { + eventKey, err := s.cache.Get("wechat::" + string(msg.FromUserName)) + if err != nil { + return &message.Reply{MsgType: message.MsgTypeText, MsgData: message.NewText("绑定信息已过期,请重新绑定")} + } + msgData, err := s.WechatBindAddress(string(eventKey), string(msg.FromUserName), true) + if err != nil && msgData != "" { + return &message.Reply{MsgType: message.MsgTypeText, MsgData: message.NewText("钱包地址绑定失败:" + msgData)} + } + return &message.Reply{MsgType: message.MsgTypeText, MsgData: message.NewText("钱包地址绑定成功")} +} + // GetWechatQrcode 获取关注二维码 func (s *Service) GetWechatQrcode(c *gin.Context, app, address string) (data string, err error) { // 项目配置 @@ -103,7 +133,7 @@ func (s *Service) GetWechatQrcode(c *gin.Context, app, address string) (data str } // WechatBindAddress 处理地址绑定 -func (s *Service) WechatBindAddress(eventKey, fromUserName string) (msg string, err error) { +func (s *Service) WechatBindAddress(eventKey, fromUserName string, replace bool) (msg string, err error) { // 判断是否为绑定事件 if !strings.Contains(strings.Split(eventKey, "::")[1], "bind") { log.Errorv("非绑定事件", zap.String("eventKey", eventKey)) @@ -121,16 +151,18 @@ func (s *Service) WechatBindAddress(eventKey, fromUserName string) (msg string, type WechatBind struct { Address string `json:"address" form:"address" binding:"required"` Code string `json:"code" form:"code" binding:"required"` + Replace bool `json:"replace" form:"replace"` } wechatBind := WechatBind{ Address: address, Code: fromUserName, + Replace: replace, } r, err := client.R().SetBodyJsonMarshal(wechatBind).Post(wechatConfig.CallBackURL + "/v1/social/wechatBindAddress") if err != nil || r.StatusCode != 200 { return "绑定失败", errors.New("绑定失败") } - fmt.Println(r.String()) + //fmt.Println(r.String()) // 绑定失败 if gjson.Get(r.String(), "status").Int() != 0 { return gjson.Get(r.String(), "message").String(), errors.New("绑定失败")