feat: bind tribally account

This commit is contained in:
2025-03-20 17:15:54 +08:00
parent 3f09a65806
commit 937244a1a0
10 changed files with 202 additions and 0 deletions

View File

@@ -51,6 +51,10 @@ service novatask {
@doc "赛季奖励数据" @doc "赛季奖励数据"
@handler PioneerReward @handler PioneerReward
get /pioneer_reward returns (PioneerReward) get /pioneer_reward returns (PioneerReward)
@doc "绑定Tribally账号"
@handler BindTribally
get /bind_tribally returns (BindTriballyReply)
} }
type GetTaskListReq { type GetTaskListReq {
@@ -168,3 +172,7 @@ type PioneerReward {
Total float64 `json:"total"` // 总额 Total float64 `json:"total"` // 总额
} }
type BindTriballyReply {
AuthUrl string `json:"auth_url"` // 授权地址
}

View File

@@ -437,6 +437,28 @@
] ]
} }
}, },
"/gapi/task/v1/bind_tribally": {
"get": {
"summary": "绑定Tribally账号",
"operationId": "BindTribally",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/BindTriballyReply"
}
}
},
"tags": [
"task"
],
"security": [
{
"apiKey": []
}
]
}
},
"/gapi/task/v1/community": { "/gapi/task/v1/community": {
"get": { "get": {
"summary": "获取社区列表", "summary": "获取社区列表",
@@ -732,6 +754,19 @@
} }
}, },
"definitions": { "definitions": {
"BindTriballyReply": {
"type": "object",
"properties": {
"auth_url": {
"type": "string",
"description": " 授权地址"
}
},
"title": "BindTriballyReply",
"required": [
"auth_url"
]
},
"CarvResult": { "CarvResult": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@@ -13,6 +13,7 @@ const (
KgenApiKey = "kgen_api_key" KgenApiKey = "kgen_api_key"
AdminSecret = "admin_secret" AdminSecret = "admin_secret"
NftHolderApiConf = "nft_holder_api_conf" NftHolderApiConf = "nft_holder_api_conf"
TriballyApiKey = "tribally_api_key"
) )
type AssetType string type AssetType string

View File

@@ -145,6 +145,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes( server.AddRoutes(
[]rest.Route{ []rest.Route{
{
// 绑定Tribally账号
Method: http.MethodGet,
Path: "/bind_tribally",
Handler: task.BindTriballyHandler(serverCtx),
},
{ {
// 质押NFT // 质押NFT
Method: http.MethodPost, Method: http.MethodPost,

View File

@@ -0,0 +1,22 @@
package task
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"nova_task/internal/logic/task"
"nova_task/internal/svc"
)
// 绑定Tribally账号
func BindTriballyHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l := task.NewBindTriballyLogic(r.Context(), svcCtx)
resp, err := l.BindTribally()
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}

View File

@@ -0,0 +1,64 @@
package task
import (
"context"
"errors"
"nova_task/internal/model"
"nova_task/internal/pkg/errs"
"nova_task/internal/pkg/tribally"
"nova_task/internal/pkg/utils"
"nova_task/internal/svc"
"nova_task/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type BindTriballyLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 绑定Tribally账号
func NewBindTriballyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BindTriballyLogic {
return &BindTriballyLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *BindTriballyLogic) BindTribally() (resp *types.BindTriballyReply, err error) {
uid := utils.GetUidUint(l.ctx)
apiKey, err := l.svcCtx.ConfigModel.GetTriballyApiKey(l.ctx)
if err != nil {
l.Errorw("get tribally api key failed", logx.Field("err", err))
return nil, errs.New(errs.ErrDatabaseOperate, err)
}
if apiKey == "" {
return nil, errs.New(errs.ErrSystemConfig, "system config err")
}
u, err := l.svcCtx.UserModel.FindOne(l.ctx, uid)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
return nil, errs.New(errs.ErrUserNotFound, "user not found")
}
l.Errorw("get user failed", logx.Field("err", err), logx.Field("uid", uid))
return nil, errs.New(errs.ErrDatabaseOperate, err)
}
hasBind, err := l.svcCtx.RoleModel.AccountExist(l.ctx, u.Email)
if err != nil {
return nil, errs.New(errs.ErrDatabaseOperate, err)
}
if !hasBind {
return nil, errs.New(errs.ErrNotBindRole, "user not bind role")
}
authUrl, err := tribally.BindTribally(apiKey, u.Email)
if err != nil {
l.Errorw("bind tribally failed", logx.Field("err", err))
return nil, errs.New(errs.ErrInternalServer, err)
}
return &types.BindTriballyReply{AuthUrl: authUrl}, nil
}

View File

@@ -24,6 +24,7 @@ type (
GetApiKey(ctx context.Context, name string) (apiKey string, err error) GetApiKey(ctx context.Context, name string) (apiKey string, err error)
GetAdminSecret(ctx context.Context) (secret string, err error) GetAdminSecret(ctx context.Context) (secret string, err error)
GetInviterId(ctx context.Context, name string) uint GetInviterId(ctx context.Context, name string) uint
GetTriballyApiKey(ctx context.Context) (apiKey string, err error)
} }
customNhSystemConfigModel struct { customNhSystemConfigModel struct {
@@ -31,6 +32,17 @@ type (
} }
) )
func (m *customNhSystemConfigModel) GetTriballyApiKey(ctx context.Context) (apiKey string, err error) {
cf, err := m.FindOneByName(ctx, consts.TriballyApiKey)
if err != nil {
if !errors.Is(err, sqlx.ErrNotFound) {
return "", err
}
return "", nil
}
return cf.Value, nil
}
func (m *customNhSystemConfigModel) GetInviterId(ctx context.Context, name string) uint { func (m *customNhSystemConfigModel) GetInviterId(ctx context.Context, name string) uint {
cf, err := m.FindOneByName(ctx, name) cf, err := m.FindOneByName(ctx, name)
if err != nil { if err != nil {

View File

@@ -16,6 +16,7 @@ const (
ErrEncodePassword Reason = 1003 // 密码加密错误 ErrEncodePassword Reason = 1003 // 密码加密错误
ErrGenerateUUid Reason = 1004 // 生成uuid错误 ErrGenerateUUid Reason = 1004 // 生成uuid错误
ErrGenerateToken Reason = 1005 // 生成token错误 ErrGenerateToken Reason = 1005 // 生成token错误
ErrSystemConfig Reason = 1006 // 系统配置错误
// ======= 业务层错误20000~29999 ======= // ======= 业务层错误20000~29999 =======
ErrUnknownLogicError Reason = 20000 // 未知的业务错误 ErrUnknownLogicError Reason = 20000 // 未知的业务错误
@@ -30,4 +31,5 @@ const (
ErrInvalidApiKey Reason = 20009 // 无效的api key ErrInvalidApiKey Reason = 20009 // 无效的api key
ErrRoleNotFound Reason = 20010 // 角色不存在 ErrRoleNotFound Reason = 20010 // 角色不存在
ErrInvalidParam Reason = 20011 // 无效的参数 ErrInvalidParam Reason = 20011 // 无效的参数
ErrNotBindRole Reason = 20012 // 未绑定角色
) )

View File

@@ -0,0 +1,48 @@
package tribally
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
)
func BindTribally(apiKey, userId string) (string, error) {
url := "https://api.tribally.games/authenticate"
payload := strings.NewReader(fmt.Sprintf(`{"playerId": "%s"}`, userId))
req, err := http.NewRequest(http.MethodPost, url, payload)
if err != nil {
return "", err
}
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Accept", "application/json")
req.Header.Add("x-api-key", apiKey)
res, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return "", err
}
result := struct {
Error string `json:"error"`
Code string `json:"code"`
Data struct {
AuthURL string `json:"authUrl"`
} `json:"data"`
}{}
err = json.Unmarshal(body, &result)
if err != nil {
return "", err
}
if result.Error != "" {
return "", fmt.Errorf("error: %s, code: %s", result.Error, result.Code)
}
return result.Data.AuthURL, nil
}

View File

@@ -3,6 +3,10 @@
package types package types
type BindTriballyReply struct {
AuthUrl string `json:"auth_url"` // 授权地址
}
type CarvResult struct { type CarvResult struct {
Result *Result `json:"result"` Result *Result `json:"result"`
Error *Error `json:"error"` Error *Error `json:"error"`