From c5407441765264f94cf1363e88bb2ab36f1b23fa Mon Sep 17 00:00:00 2001 From: lianghuanjie Date: Mon, 6 Jan 2025 19:45:03 +0800 Subject: [PATCH] fix: INVITE USER --- Makefile | 5 +- doc/api/admin.api | 9 +- doc/api/carv.api | 4 +- doc/swagger/{nova-task.json => nova.json} | 287 +++++++++++++++++- internal/handler/routes.go | 2 +- .../logic/admin/add_email_reward_logic.go | 21 +- .../logic/admin/send_email_reward_logic.go | 5 +- .../logic/task/verify_task_result_logic.go | 9 + .../middleware/adminsecretcheck_middleware.go | 14 +- internal/middleware/apikeycheck_middleware.go | 14 +- internal/model/nh_system_config_model.go | 2 +- internal/types/types.go | 11 +- 12 files changed, 344 insertions(+), 39 deletions(-) rename doc/swagger/{nova-task.json => nova.json} (69%) diff --git a/Makefile b/Makefile index 859b65f..4a419d6 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ pwd ?= jMDqPQM^a6hsAR table ?= cache ?= database ?= "nova_home" +tag ?= dev .PHONY: db # 链接数据库生成模型代码 @@ -37,11 +38,11 @@ build: .PHONY: img # 构建Docker镜像 img: - docker build --platform=amd64 -t harbor.phantom-u3d002.com/nova/nova-task:latest . + docker build --platform=amd64 -t harbor.phantom-u3d002.com/nova/nova-task:${tag} . .PHONY: push push: - docker push harbor.phantom-u3d002.com/nova/nova-task:latest + docker push harbor.phantom-u3d002.com/nova/nova-task:${tag} # 帮助信息 diff --git a/doc/api/admin.api b/doc/api/admin.api index 683b212..954d014 100644 --- a/doc/api/admin.api +++ b/doc/api/admin.api @@ -6,7 +6,7 @@ syntax = "v1" group: admin ) service novatask { - @doc "每日钱包签到任务" + @doc "给指定邮箱增加待发放奖励" @handler AddEmailReward post /email_reward (EmailReward) @@ -16,8 +16,9 @@ service novatask { } type EmailReward { - Email string `json:"email"` - RewardType string `json:"reward_type"` - Value float64 `json:"value"` + Email string `json:"email"` // 邮箱,多个邮箱分号隔开 + RewardType string `json:"reward_type"` // 奖励类型: points, elite_points, castile, keys + Value float64 `json:"value"` // 数量 + Remark string `json:"remark"` // 备注 } diff --git a/doc/api/carv.api b/doc/api/carv.api index a068d82..b8c9dd2 100644 --- a/doc/api/carv.api +++ b/doc/api/carv.api @@ -39,12 +39,12 @@ type CarvResult { type EmailKey { Email string `form:"email"` - ApiKey string `Header:"x-api-key"` + ApiKey string `header:"x-api-key"` } type UnlockChapterReq { Email string `form:"email"` Chapter int `form:"chapter"` - ApiKey string `Header:"x-api-key"` + ApiKey string `header:"x-api-key"` } diff --git a/doc/swagger/nova-task.json b/doc/swagger/nova.json similarity index 69% rename from doc/swagger/nova-task.json rename to doc/swagger/nova.json index a589b12..de40b27 100644 --- a/doc/swagger/nova-task.json +++ b/doc/swagger/nova.json @@ -2,6 +2,7 @@ "swagger": "2.0", "info": { "title": "", + "description": "nova api", "version": "" }, "schemes": [ @@ -15,6 +16,187 @@ "application/json" ], "paths": { + "/gapi/admin/email_reward": { + "get": { + "summary": "执行发放奖励操作", + "operationId": "SendEmailReward", + "responses": { + "200": { + "description": "A successful response.", + "schema": {} + } + }, + "tags": [ + "admin" + ] + }, + "post": { + "summary": "给指定邮箱增加待发放奖励", + "operationId": "AddEmailReward", + "responses": { + "200": { + "description": "A successful response.", + "schema": {} + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/EmailReward" + } + } + ], + "tags": [ + "admin" + ] + } + }, + "/gapi/carv/bind_role": { + "get": { + "summary": "下载并绑定Castile游戏角色", + "operationId": "DownloadAndBindRole", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/CarvResult" + } + } + }, + "parameters": [ + { + "name": "x-api-key", + "in": "header", + "required": true, + "type": "string" + }, + { + "name": "email", + "in": "query", + "required": true, + "type": "string" + } + ], + "tags": [ + "carv" + ], + "consumes": [ + "multipart/form-data" + ] + } + }, + "/gapi/carv/bind_wallet": { + "get": { + "summary": "注册绑定钱包任务", + "operationId": "BindWallet", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/CarvResult" + } + } + }, + "parameters": [ + { + "name": "x-api-key", + "in": "header", + "required": true, + "type": "string" + }, + { + "name": "email", + "in": "query", + "required": true, + "type": "string" + } + ], + "tags": [ + "carv" + ], + "consumes": [ + "multipart/form-data" + ] + } + }, + "/gapi/carv/check_in_wallet": { + "get": { + "summary": "每日钱包签到任务", + "operationId": "WalletCheckIn", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/CarvResult" + } + } + }, + "parameters": [ + { + "name": "x-api-key", + "in": "header", + "required": true, + "type": "string" + }, + { + "name": "email", + "in": "query", + "required": true, + "type": "string" + } + ], + "tags": [ + "carv" + ], + "consumes": [ + "multipart/form-data" + ] + } + }, + "/gapi/carv/unlock_chapter": { + "get": { + "summary": "游戏主线解锁第x章节", + "operationId": "UnlockChapter", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/CarvResult" + } + } + }, + "parameters": [ + { + "name": "x-api-key", + "in": "header", + "required": true, + "type": "string" + }, + { + "name": "email", + "in": "query", + "required": true, + "type": "string" + }, + { + "name": "chapter", + "in": "query", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "tags": [ + "carv" + ], + "consumes": [ + "multipart/form-data" + ] + } + }, "/gapi/task/v1/community": { "get": { "summary": "获取社区列表", @@ -253,6 +435,22 @@ } }, "definitions": { + "CarvResult": { + "type": "object", + "properties": { + "result": { + "$ref": "#/definitions/Result" + }, + "error": { + "$ref": "#/definitions/Error" + } + }, + "title": "CarvResult", + "required": [ + "result", + "error" + ] + }, "Community": { "type": "object", "properties": { @@ -294,6 +492,64 @@ "end_at" ] }, + "EmailKey": { + "type": "object", + "properties": { + "email": { + "type": "string" + } + }, + "title": "EmailKey", + "required": [ + "email" + ] + }, + "EmailReward": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": " 邮箱,多个邮箱分号隔开" + }, + "reward_type": { + "type": "string", + "description": " 奖励类型: points, elite_points, castile, keys" + }, + "value": { + "type": "number", + "format": "double", + "description": " 数量" + }, + "remark": { + "type": "string", + "description": " 备注" + } + }, + "title": "EmailReward", + "required": [ + "email", + "reward_type", + "value", + "remark" + ] + }, + "Error": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + }, + "title": "Error", + "required": [ + "code", + "message" + ] + }, "GetCommunityListResp": { "type": "object", "properties": { @@ -362,6 +618,19 @@ "points" ] }, + "Result": { + "type": "object", + "properties": { + "isValid": { + "type": "boolean", + "format": "boolean" + } + }, + "title": "Result", + "required": [ + "isValid" + ] + }, "StakeNftList": { "type": "object", "properties": { @@ -380,7 +649,6 @@ }, "title": "StakeNftList", "required": [ - "role_id", "token_ids" ] }, @@ -539,6 +807,23 @@ "token_id" ] }, + "UnlockChapterReq": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "chapter": { + "type": "integer", + "format": "int32" + } + }, + "title": "UnlockChapterReq", + "required": [ + "email", + "chapter" + ] + }, "UserNft": { "type": "object", "properties": { diff --git a/internal/handler/routes.go b/internal/handler/routes.go index 8e0f36b..68b216e 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -20,7 +20,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { []rest.Middleware{serverCtx.AdminSecretCheck}, []rest.Route{ { - // 每日钱包签到任务 + // 给指定邮箱增加待发放奖励 Method: http.MethodPost, Path: "/email_reward", Handler: admin.AddEmailRewardHandler(serverCtx), diff --git a/internal/logic/admin/add_email_reward_logic.go b/internal/logic/admin/add_email_reward_logic.go index 8b2e528..e889552 100644 --- a/internal/logic/admin/add_email_reward_logic.go +++ b/internal/logic/admin/add_email_reward_logic.go @@ -5,6 +5,7 @@ import ( "github.com/shopspring/decimal" "nova_task/internal/model" "nova_task/internal/pkg/errs" + "strings" "nova_task/internal/svc" "nova_task/internal/types" @@ -28,14 +29,18 @@ func NewAddEmailRewardLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Ad } func (l *AddEmailRewardLogic) AddEmailReward(req *types.EmailReward) error { - _, err := l.svcCtx.EmailRewardModel.Insert(l.ctx, &model.NhEmailReward{ - Email: req.Email, - RewardType: req.RewardType, - Value: decimal.NewFromFloat(req.Value), - }) - if err != nil { - l.Errorw("add email reward failed", logx.Field("err", err), logx.Field("email", req.Email)) - return errs.New(errs.ErrDatabaseOperate, err) + emails := strings.Split(req.Email, ";") + for _, email := range emails { + _, err := l.svcCtx.EmailRewardModel.Insert(l.ctx, &model.NhEmailReward{ + Email: email, + RewardType: req.RewardType, + Value: decimal.NewFromFloat(req.Value), + Remark: req.Remark, + }) + if err != nil { + l.Errorw("add email reward failed", logx.Field("err", err), logx.Field("email", req.Email)) + return errs.New(errs.ErrDatabaseOperate, err) + } } return errs.Success() diff --git a/internal/logic/admin/send_email_reward_logic.go b/internal/logic/admin/send_email_reward_logic.go index 3aba71f..e7d6cd4 100644 --- a/internal/logic/admin/send_email_reward_logic.go +++ b/internal/logic/admin/send_email_reward_logic.go @@ -35,6 +35,7 @@ func (l *SendEmailRewardLogic) SendEmailReward() error { } if len(rewards) <= 0 { + l.Infow("no email reward to send") return errs.Success() } @@ -66,6 +67,8 @@ func (l *SendEmailRewardLogic) SendEmailReward() error { } if err != nil { l.Errorw("add asset failed", logx.Field("err", err), logx.Field("uid", u.Id), logx.Field("rewardType", rw.RewardType), logx.Field("value", rw.Value)) + } else { + l.Infow("add asset success", logx.Field("uid", u.Id), logx.Field("rewardType", rw.RewardType), logx.Field("value", rw.Value)) } _, err = l.svcCtx.TaskAssetRecordModel.Insert(ctx, &model.NhTaskAssetRecord{ Uid: int(u.Id), @@ -80,5 +83,5 @@ func (l *SendEmailRewardLogic) SendEmailReward() error { } }) - return nil + return errs.Success() } diff --git a/internal/logic/task/verify_task_result_logic.go b/internal/logic/task/verify_task_result_logic.go index 20ad829..6aa9232 100644 --- a/internal/logic/task/verify_task_result_logic.go +++ b/internal/logic/task/verify_task_result_logic.go @@ -72,6 +72,15 @@ func (l *VerifyTaskResultLogic) VerifyTaskResult(req *types.VerifyTaskResultReq) if tw.TwitterId == "" { return &types.VerifyTaskResultResp{Finish: false}, nil } + case model.TASKTYPE_INVITE_USER: + count, err := l.svcCtx.PromoteBindModel.UserInviteCount(l.ctx, uint(uid)) + if err != nil { + l.Errorw("get user invite count failed", logx.Field("err", err), logx.Field("uid", uid)) + return nil, errs.New(errs.ErrDatabaseOperate, err) + } + if count < cast.ToInt64(task.Param) { + return &types.VerifyTaskResultResp{Finish: false}, nil + } case model.TASKTYPE_BIND_DISCORD: case model.TASKTYPE_DAILY_PAY: diff --git a/internal/middleware/adminsecretcheck_middleware.go b/internal/middleware/adminsecretcheck_middleware.go index 6440049..09ec695 100644 --- a/internal/middleware/adminsecretcheck_middleware.go +++ b/internal/middleware/adminsecretcheck_middleware.go @@ -16,17 +16,17 @@ func NewAdminSecretCheckMiddleware(conf model.NhSystemConfigModel) *AdminSecretC func (m *AdminSecretCheckMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - if key, err := m.conf.GetAdminSecret(r.Context()); err != nil { + key, err := m.conf.GetAdminSecret(r.Context()) + if err != nil { if !errors.Is(err, model.ErrNotFound) { http.Error(w, "system error", http.StatusInternalServerError) return } - } else { - apiKey := r.Header.Get("x-admin-secret") - if apiKey != key { - http.Error(w, "Invalid API key", http.StatusUnauthorized) - return - } + } + apiKey := r.Header.Get("x-admin-secret") + if apiKey == "" || apiKey != key { + http.Error(w, "Invalid API key", http.StatusUnauthorized) + return } next(w, r) } diff --git a/internal/middleware/apikeycheck_middleware.go b/internal/middleware/apikeycheck_middleware.go index 1563759..d3d6971 100644 --- a/internal/middleware/apikeycheck_middleware.go +++ b/internal/middleware/apikeycheck_middleware.go @@ -16,17 +16,17 @@ func NewApiKeyCheckMiddleware(conf model.NhSystemConfigModel) *ApiKeyCheckMiddle func (m *ApiKeyCheckMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - if key, err := m.conf.GetCarvApiKey(r.Context()); err != nil { + key, err := m.conf.GetCarvApiKey(r.Context()) + if err != nil { if !errors.Is(err, model.ErrNotFound) { http.Error(w, "system error", http.StatusInternalServerError) return } - } else { - apiKey := r.Header.Get("x-api-key") - if apiKey != key { - http.Error(w, "Invalid API key", http.StatusUnauthorized) - return - } + } + apiKey := r.Header.Get("x-api-key") + if apiKey == "" || apiKey != key { + http.Error(w, "Invalid API key", http.StatusUnauthorized) + return } next(w, r) diff --git a/internal/model/nh_system_config_model.go b/internal/model/nh_system_config_model.go index 5ee573b..dbc34ce 100755 --- a/internal/model/nh_system_config_model.go +++ b/internal/model/nh_system_config_model.go @@ -29,7 +29,7 @@ type ( ) func (m *customNhSystemConfigModel) GetAdminSecret(ctx context.Context) (secret string, err error) { - cf, err := m.FindOneByName(ctx, consts.CarvApiKey) + cf, err := m.FindOneByName(ctx, consts.AdminSecret) if err != nil { if !errors.Is(err, sqlx.ErrNotFound) { return "", err diff --git a/internal/types/types.go b/internal/types/types.go index 00215ec..2a1b11c 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -19,13 +19,14 @@ type Community struct { type EmailKey struct { Email string `form:"email"` - ApiKey string `Header:"x-api-key"` + ApiKey string `header:"x-api-key"` } type EmailReward struct { - Email string `json:"email"` - RewardType string `json:"reward_type"` - Value float64 `json:"value"` + Email string `json:"email"` // 邮箱,多个邮箱分号隔开 + RewardType string `json:"reward_type"` // 奖励类型: points, elite_points, castile, keys + Value float64 `json:"value"` // 数量 + Remark string `json:"remark"` // 备注 } type Error struct { @@ -101,7 +102,7 @@ type UnStakeNftReq struct { type UnlockChapterReq struct { Email string `form:"email"` Chapter int `form:"chapter"` - ApiKey string `Header:"x-api-key"` + ApiKey string `header:"x-api-key"` } type UserNft struct {