From 957537efc4f0540b864fa269aa93f6a16c5c7e19 Mon Sep 17 00:00:00 2001 From: lianghuanjie Date: Fri, 10 Jan 2025 16:20:58 +0800 Subject: [PATCH] game7 api --- doc/api/game7.api | 33 +++++ doc/api/nova.api | 1 + doc/swagger/nova.json | 114 ++++++++++++++++++ internal/consts/consts.go | 2 + .../handler/game7/game7_task_check_handler.go | 29 +++++ internal/handler/routes.go | 16 +++ internal/logic/carv/bind_wallet_logic.go | 3 +- .../carv/download_and_bind_role_logic.go | 3 +- internal/logic/carv/unlock_chapter_logic.go | 3 +- internal/logic/carv/wallet_check_in_logic.go | 3 +- .../logic/game7/game7_task_check_logic.go | 81 +++++++++++++ internal/middleware/apikeycheck_middleware.go | 23 ++-- .../middleware/game7apikeycheck_middleware.go | 36 ++++++ internal/model/nh_system_config_model.go | 14 +-- internal/svc/service_context.go | 2 + internal/types/types.go | 20 +++ 16 files changed, 359 insertions(+), 24 deletions(-) create mode 100644 doc/api/game7.api create mode 100644 internal/handler/game7/game7_task_check_handler.go create mode 100644 internal/logic/game7/game7_task_check_logic.go create mode 100644 internal/middleware/game7apikeycheck_middleware.go diff --git a/doc/api/game7.api b/doc/api/game7.api new file mode 100644 index 0000000..a3aa71c --- /dev/null +++ b/doc/api/game7.api @@ -0,0 +1,33 @@ +syntax = "v1" + +@server ( + prefix: /gapi/game7 + middleware: Game7ApiKeyCheck + group: game7 +) +service novatask { + @doc "Game7任务完成检查" + @handler Game7TaskCheck + get /task (Game7TaskCheckReq) returns (Game7Result) +} + +type Game7TaskCheckReq { + ApiKey string `header:"x-api-key"` // api key + Email string `form:"email"` // 邮箱 + Type int8 `form:"type"` // 1.是否在官网注册并链接钱包(是/否) 2.是否有超过两个以上的英雄(是/否) 3.是否消耗召唤券召唤了新英雄(是/否) 4. 是否在游戏内绑定了官网账号(是/否) 5. 是否有一个31级以上的英雄(是/否) 6. 是否完成了主线第一章(是/否) +} + +type Status { + Code int `json:"code"` // 状态码 + Msg string `json:"msg"` // 状态信息 +} + +type Game7ResultData { + IsValid bool `json:"isValid"` // true:是,false:否 +} + +type Game7Result { + Status Status `json:"status"` // 状态 + Data Game7ResultData `json:"data"` // 数据 +} + diff --git a/doc/api/nova.api b/doc/api/nova.api index ee80d7d..5024910 100644 --- a/doc/api/nova.api +++ b/doc/api/nova.api @@ -3,6 +3,7 @@ syntax = "v1" import "task.api" import "carv.api" import "admin.api" +import "game7.api" info ( desc: "nova api" diff --git a/doc/swagger/nova.json b/doc/swagger/nova.json index 861b15e..4edad85 100644 --- a/doc/swagger/nova.json +++ b/doc/swagger/nova.json @@ -298,6 +298,50 @@ ] } }, + "/gapi/game7/task": { + "get": { + "summary": "Game7任务完成检查", + "operationId": "Game7TaskCheck", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/Game7Result" + } + } + }, + "parameters": [ + { + "name": "x-api-key", + "description": " api key", + "in": "header", + "required": true, + "type": "string" + }, + { + "name": "email", + "description": " 邮箱", + "in": "query", + "required": true, + "type": "string" + }, + { + "name": "type", + "description": " 1.是否在官网注册并链接钱包(是/否) 2.是否有超过两个以上的英雄(是/否) 3.是否消耗召唤券召唤了新英雄(是/否) 4. 是否在游戏内绑定了官网账号(是/否) 5. 是否有一个31级以上的英雄(是/否) 6. 是否完成了主线第一章(是/否)", + "in": "query", + "required": true, + "type": "integer", + "format": "int8" + } + ], + "tags": [ + "game7" + ], + "consumes": [ + "multipart/form-data" + ] + } + }, "/gapi/task/v1/community": { "get": { "summary": "获取社区列表", @@ -686,6 +730,57 @@ "message" ] }, + "Game7Result": { + "type": "object", + "properties": { + "status": { + "$ref": "#/definitions/Status", + "description": " 状态" + }, + "data": { + "$ref": "#/definitions/Game7ResultData", + "description": " 数据" + } + }, + "title": "Game7Result", + "required": [ + "status", + "data" + ] + }, + "Game7ResultData": { + "type": "object", + "properties": { + "isValid": { + "type": "boolean", + "format": "boolean", + "description": " true:是,false:否" + } + }, + "title": "Game7ResultData", + "required": [ + "isValid" + ] + }, + "Game7TaskCheckReq": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": " 邮箱" + }, + "type": { + "type": "integer", + "format": "int8", + "description": " 1.是否在官网注册并链接钱包(是/否) 2.是否有超过两个以上的英雄(是/否) 3.是否消耗召唤券召唤了新英雄(是/否) 4. 是否在游戏内绑定了官网账号(是/否) 5. 是否有一个31级以上的英雄(是/否) 6. 是否完成了主线第一章(是/否)" + } + }, + "title": "Game7TaskCheckReq", + "required": [ + "email", + "type" + ] + }, "GetCommunityListResp": { "type": "object", "properties": { @@ -870,6 +965,25 @@ "total_income_tokens" ] }, + "Status": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "description": " 状态码" + }, + "msg": { + "type": "string", + "description": " 状态信息" + } + }, + "title": "Status", + "required": [ + "code", + "msg" + ] + }, "Task": { "type": "object", "properties": { diff --git a/internal/consts/consts.go b/internal/consts/consts.go index 1af6f7b..480170f 100644 --- a/internal/consts/consts.go +++ b/internal/consts/consts.go @@ -9,6 +9,8 @@ const ( NftStakeTaskDate = "nft_stake_task_date" NftStakeTaskConf = "nft_stake_task_conf" CarvApiKey = "carv_api_key" + Game7ApiKey = "game7_api_key" + KgenApiKey = "kgen_api_key" AdminSecret = "admin_secret" NftHolderApiConf = "nft_holder_api_conf" ) diff --git a/internal/handler/game7/game7_task_check_handler.go b/internal/handler/game7/game7_task_check_handler.go new file mode 100644 index 0000000..cced134 --- /dev/null +++ b/internal/handler/game7/game7_task_check_handler.go @@ -0,0 +1,29 @@ +package game7 + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "nova_task/internal/logic/game7" + "nova_task/internal/svc" + "nova_task/internal/types" +) + +// Game7任务完成检查 +func Game7TaskCheckHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.Game7TaskCheckReq + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := game7.NewGame7TaskCheckLogic(r.Context(), svcCtx) + resp, err := l.Game7TaskCheck(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/routes.go b/internal/handler/routes.go index 9b2dda1..29d1c30 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -8,6 +8,7 @@ import ( admin "nova_task/internal/handler/admin" carv "nova_task/internal/handler/carv" + game7 "nova_task/internal/handler/game7" task "nova_task/internal/handler/task" "nova_task/internal/svc" @@ -81,6 +82,21 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { rest.WithPrefix("/gapi/carv"), ) + server.AddRoutes( + rest.WithMiddlewares( + []rest.Middleware{serverCtx.Game7ApiKeyCheck}, + []rest.Route{ + { + // Game7任务完成检查 + Method: http.MethodGet, + Path: "/task", + Handler: game7.Game7TaskCheckHandler(serverCtx), + }, + }..., + ), + rest.WithPrefix("/gapi/game7"), + ) + server.AddRoutes( []rest.Route{ { diff --git a/internal/logic/carv/bind_wallet_logic.go b/internal/logic/carv/bind_wallet_logic.go index b0d9298..05808f7 100644 --- a/internal/logic/carv/bind_wallet_logic.go +++ b/internal/logic/carv/bind_wallet_logic.go @@ -3,6 +3,7 @@ package carv import ( "context" "errors" + "nova_task/internal/consts" "nova_task/internal/model" "nova_task/internal/pkg/errs" @@ -48,7 +49,7 @@ func (l *BindWalletLogic) BindWallet(req *types.EmailKey) *types.CarvResult { } } - shareId := l.svcCtx.ConfigModel.GetCarvIoInviterId(l.ctx) + shareId := l.svcCtx.ConfigModel.GetInviterId(l.ctx, consts.CarvIoInviterId) if pb.ShareUid != shareId || pb.IsBindWallet == 0 { return &types.CarvResult{ diff --git a/internal/logic/carv/download_and_bind_role_logic.go b/internal/logic/carv/download_and_bind_role_logic.go index b70681d..7c74c48 100644 --- a/internal/logic/carv/download_and_bind_role_logic.go +++ b/internal/logic/carv/download_and_bind_role_logic.go @@ -3,6 +3,7 @@ package carv import ( "context" "errors" + "nova_task/internal/consts" "nova_task/internal/model" "nova_task/internal/pkg/errs" "nova_task/internal/svc" @@ -45,7 +46,7 @@ func (l *DownloadAndBindRoleLogic) DownloadAndBindRole(req *types.EmailKey) *typ }} } - shareId := l.svcCtx.ConfigModel.GetCarvIoInviterId(l.ctx) + shareId := l.svcCtx.ConfigModel.GetInviterId(l.ctx, consts.CarvIoInviterId) if pb.ShareUid != shareId || pb.IsCreateRole == 0 { return &types.CarvResult{ Result: &types.Result{IsValid: false}, diff --git a/internal/logic/carv/unlock_chapter_logic.go b/internal/logic/carv/unlock_chapter_logic.go index e6a1db2..492c6be 100644 --- a/internal/logic/carv/unlock_chapter_logic.go +++ b/internal/logic/carv/unlock_chapter_logic.go @@ -3,6 +3,7 @@ package carv import ( "context" "errors" + "nova_task/internal/consts" "nova_task/internal/model" "nova_task/internal/pkg/errs" @@ -48,7 +49,7 @@ func (l *UnlockChapterLogic) UnlockChapter(req *types.UnlockChapterReq) *types.C } } - shareId := l.svcCtx.ConfigModel.GetCarvIoInviterId(l.ctx) + shareId := l.svcCtx.ConfigModel.GetInviterId(l.ctx, consts.CarvIoInviterId) if pb.ShareUid != shareId { return &types.CarvResult{ diff --git a/internal/logic/carv/wallet_check_in_logic.go b/internal/logic/carv/wallet_check_in_logic.go index b2a4552..ee3db2f 100644 --- a/internal/logic/carv/wallet_check_in_logic.go +++ b/internal/logic/carv/wallet_check_in_logic.go @@ -4,6 +4,7 @@ import ( "context" "errors" "github.com/spf13/cast" + "nova_task/internal/consts" "nova_task/internal/model" "nova_task/internal/pkg/errs" "time" @@ -50,7 +51,7 @@ func (l *WalletCheckInLogic) WalletCheckIn(req *types.EmailKey) *types.CarvResul } } - shareId := l.svcCtx.ConfigModel.GetCarvIoInviterId(l.ctx) + shareId := l.svcCtx.ConfigModel.GetInviterId(l.ctx, consts.CarvIoInviterId) if pb.ShareUid != shareId { return &types.CarvResult{ diff --git a/internal/logic/game7/game7_task_check_logic.go b/internal/logic/game7/game7_task_check_logic.go new file mode 100644 index 0000000..7f85fab --- /dev/null +++ b/internal/logic/game7/game7_task_check_logic.go @@ -0,0 +1,81 @@ +package game7 + +import ( + "context" + "errors" + "nova_task/internal/consts" + "nova_task/internal/model" + "nova_task/internal/pkg/errs" + + "nova_task/internal/svc" + "nova_task/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type Game7TaskCheckLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewGame7TaskCheckLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Game7TaskCheckLogic { + return &Game7TaskCheckLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *Game7TaskCheckLogic) Game7TaskCheck(req *types.Game7TaskCheckReq) (*types.Game7ResultData, error) { + uid, resultErr := l.svcCtx.GetUidByEmail(l.ctx, req.Email) + if resultErr != nil { + return nil, errs.New(errs.Reason(resultErr.Error.Code), resultErr.Error.Message) + } + + pb, err := l.svcCtx.PromoteBindModel.FindOneByInvitedUid(l.ctx, uid) + if err != nil { + if !errors.Is(err, model.ErrNotFound) { + return nil, errs.New(errs.ErrDatabaseOperate, err) + } + return &types.Game7ResultData{ + IsValid: false, + }, nil + } + + shareId := l.svcCtx.ConfigModel.GetInviterId(l.ctx, consts.Game7IoInviterId) + + if pb.ShareUid != shareId { + return nil, errs.New(errs.ErrUserNotFound, "user not found") + } + + var isValid bool + // 1.是否在官网注册并链接钱包(是/否) 2.是否有超过两个以上的英雄(是/否) 3.是否消耗召唤券召唤了新英雄(是/否) 4. 是否在游戏内绑定了官网账号(是/否) 5. 是否有一个31级以上的英雄(是/否) 6. 是否完成了主线第一章(是/否) + switch req.Type { + case 1: + isValid = pb.IsBindWallet == 1 + case 4: + isValid = pb.IsCreateRole == 1 + case 2, 3, 5, 6: + gp, err := l.svcCtx.GameReportModel.FindOneByUid(l.ctx, uid) + if err != nil { + if !errors.Is(err, model.ErrNotFound) { + return nil, errs.New(errs.ErrDatabaseOperate, err) + } + isValid = false + } else { + switch req.Type { + case 2: + isValid = gp.IsHaveTwoHero == 1 + case 3: + isValid = gp.IsUsedSummon == 1 + case 5: + isValid = gp.IsHaveHero31 == 1 + case 6: + isValid = gp.Chapter >= 1 + } + } + } + + return &types.Game7ResultData{IsValid: isValid}, nil +} diff --git a/internal/middleware/apikeycheck_middleware.go b/internal/middleware/apikeycheck_middleware.go index c95601a..8d4cc9f 100644 --- a/internal/middleware/apikeycheck_middleware.go +++ b/internal/middleware/apikeycheck_middleware.go @@ -1,8 +1,8 @@ package middleware import ( - "errors" "net/http" + "nova_task/internal/consts" "nova_task/internal/model" "nova_task/internal/pkg/errs" "nova_task/internal/types" @@ -10,7 +10,6 @@ import ( type ApiKeyCheckMiddleware struct { conf model.NhSystemConfigModel - user model.NhUserModel } func NewApiKeyCheckMiddleware(conf model.NhSystemConfigModel) *ApiKeyCheckMiddleware { @@ -20,24 +19,22 @@ func NewApiKeyCheckMiddleware(conf model.NhSystemConfigModel) *ApiKeyCheckMiddle func (m *ApiKeyCheckMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - key, err := m.conf.GetCarvApiKey(ctx) + key, err := m.conf.GetApiKey(ctx, consts.CarvApiKey) if err != nil { - if !errors.Is(err, model.ErrNotFound) { - result := types.CarvResult{ - Error: &types.Error{ - Code: int(errs.ErrDatabaseOperate), - Message: "api key config not exist", - }, - } - errs.WriteHttpResponse(ctx, w, result) - return + result := types.CarvResult{ + Error: &types.Error{ + Code: int(errs.ErrDatabaseOperate), + Message: "api key config not exist", + }, } + errs.WriteHttpResponse(ctx, w, result) + return } apiKey := r.Header.Get("x-api-key") if apiKey == "" || apiKey != key { result := types.CarvResult{ Error: &types.Error{ - Code: int(errs.ErrInvalidApiKey), + Code: int(errs.ErrUnauthorized), Message: "invalid api key", }, } diff --git a/internal/middleware/game7apikeycheck_middleware.go b/internal/middleware/game7apikeycheck_middleware.go new file mode 100644 index 0000000..cd20666 --- /dev/null +++ b/internal/middleware/game7apikeycheck_middleware.go @@ -0,0 +1,36 @@ +package middleware + +import ( + "net/http" + "nova_task/internal/consts" + "nova_task/internal/model" + "nova_task/internal/pkg/errs" +) + +type Game7ApiKeyCheckMiddleware struct { + conf model.NhSystemConfigModel +} + +func NewGame7ApiKeyCheckMiddleware(conf model.NhSystemConfigModel) *Game7ApiKeyCheckMiddleware { + return &Game7ApiKeyCheckMiddleware{conf: conf} +} + +func (m *Game7ApiKeyCheckMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + key, err := m.conf.GetApiKey(ctx, consts.Game7ApiKey) + if err != nil { + _, result := errs.ErrorHandle(errs.New(errs.ErrDatabaseOperate, "api key config not exist")) + errs.WriteHttpResponse(ctx, w, result) + return + } + apiKey := r.Header.Get("x-api-key") + if apiKey == "" || apiKey != key { + _, result := errs.ErrorHandle(errs.New(errs.ErrUnauthorized, "invalid api key")) + errs.WriteHttpResponse(ctx, w, result) + return + } + + next(w, r) + } +} diff --git a/internal/model/nh_system_config_model.go b/internal/model/nh_system_config_model.go index 369540e..6ba2774 100755 --- a/internal/model/nh_system_config_model.go +++ b/internal/model/nh_system_config_model.go @@ -21,9 +21,9 @@ type ( nhSystemConfigModel GetNftStakeTaskOpenDate(ctx context.Context) (start, end time.Time, err error) GetNftStakeTaskConf(ctx context.Context) (conf NftStakeTaskConf, err error) - GetCarvApiKey(ctx context.Context) (apiKey string, err error) + GetApiKey(ctx context.Context, name string) (apiKey string, err error) GetAdminSecret(ctx context.Context) (secret string, err error) - GetCarvIoInviterId(ctx context.Context) uint + GetInviterId(ctx context.Context, name string) uint } customNhSystemConfigModel struct { @@ -31,11 +31,11 @@ type ( } ) -func (m *customNhSystemConfigModel) GetCarvIoInviterId(ctx context.Context) uint { - cf, err := m.FindOneByName(ctx, consts.AdminSecret) +func (m *customNhSystemConfigModel) GetInviterId(ctx context.Context, name string) uint { + cf, err := m.FindOneByName(ctx, name) if err != nil { if !errors.Is(err, sqlx.ErrNotFound) { - logx.Errorw("GetCarvIoInviterId error", logx.Field("err", err)) + logx.Errorw("GetInviterId error", logx.Field("err", err)) } return 0 } @@ -53,8 +53,8 @@ func (m *customNhSystemConfigModel) GetAdminSecret(ctx context.Context) (secret return cf.Value, nil } -func (m *customNhSystemConfigModel) GetCarvApiKey(ctx context.Context) (string, error) { - cf, err := m.FindOneByName(ctx, consts.CarvApiKey) +func (m *customNhSystemConfigModel) GetApiKey(ctx context.Context, name string) (string, error) { + cf, err := m.FindOneByName(ctx, name) if err != nil { if !errors.Is(err, sqlx.ErrNotFound) { return "", err diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go index d8a07fe..d472e86 100644 --- a/internal/svc/service_context.go +++ b/internal/svc/service_context.go @@ -43,6 +43,7 @@ type ServiceContext struct { ApiKeyCheck rest.Middleware AdminSecretCheck rest.Middleware + Game7ApiKeyCheck rest.Middleware Earn *ea.Client DBConn sqlx.SqlConn @@ -79,6 +80,7 @@ func NewServiceContext(c config.Config) *ServiceContext { ApiKeyCheck: middleware.NewApiKeyCheckMiddleware(configModel).Handle, AdminSecretCheck: middleware.NewAdminSecretCheckMiddleware(configModel).Handle, + Game7ApiKeyCheck: middleware.NewGame7ApiKeyCheckMiddleware(configModel).Handle, Earn: c.Earn.BuildEarnClient(), DBConn: dbConn, diff --git a/internal/types/types.go b/internal/types/types.go index 39ce6a2..aef2330 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -36,6 +36,21 @@ type Error struct { Message string `json:"message"` } +type Game7Result struct { + Status Status `json:"status"` // 状态 + Data Game7ResultData `json:"data"` // 数据 +} + +type Game7ResultData struct { + IsValid bool `json:"isValid"` // true:是,false:否 +} + +type Game7TaskCheckReq struct { + ApiKey string `header:"x-api-key"` // api key + Email string `form:"email"` // 邮箱 + Type int8 `form:"type"` // 1.是否在官网注册并链接钱包(是/否) 2.是否有超过两个以上的英雄(是/否) 3.是否消耗召唤券召唤了新英雄(是/否) 4. 是否在游戏内绑定了官网账号(是/否) 5. 是否有一个31级以上的英雄(是/否) 6. 是否完成了主线第一章(是/否) +} + type GetCommunityListResp struct { CommunityList []Community `json:"community_list"` // 社区列表 } @@ -84,6 +99,11 @@ type StakeTaskDetail struct { TotalIncomeTokens float64 `json:"total_income_tokens"` // 累计收益 } +type Status struct { + Code int `json:"code"` // 状态码 + Msg string `json:"msg"` // 状态信息 +} + type Task struct { Id uint `json:"id"` // 任务ID CommunityId uint `json:"community_id"` // 所属社区ID