diff --git a/doc/api/admin.api b/doc/api/admin.api index e37b3b9..de16ee0 100644 --- a/doc/api/admin.api +++ b/doc/api/admin.api @@ -25,6 +25,10 @@ service novatask { @doc "修正 NFT 质押者" @handler FixNftStaker get /fix_nft_staker + + @doc "根据地址修复质押" + @handler StakeByAddress + post /stake_by_address (StakeByAddressReq) } type EmailReward { @@ -38,3 +42,7 @@ type StakeSettleReq { Date string `form:"date"` } +type StakeByAddressReq { + Address []string `json:"address"` +} + diff --git a/doc/swagger/nova.json b/doc/swagger/nova.json index 0a96b7f..bc0d49a 100644 --- a/doc/swagger/nova.json +++ b/doc/swagger/nova.json @@ -84,6 +84,31 @@ ] } }, + "/gapi/admin/stake_by_address": { + "post": { + "summary": "根据地址修复质押", + "operationId": "StakeByAddress", + "responses": { + "200": { + "description": "A successful response.", + "schema": {} + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/StakeByAddressReq" + } + } + ], + "tags": [ + "admin" + ] + } + }, "/gapi/admin/stake_settle": { "get": { "summary": "软质压手动结算", @@ -888,6 +913,21 @@ "isValid" ] }, + "StakeByAddressReq": { + "type": "object", + "properties": { + "address": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "title": "StakeByAddressReq", + "required": [ + "address" + ] + }, "StakeNftList": { "type": "object", "properties": { diff --git a/internal/handler/admin/stake_by_address_handler.go b/internal/handler/admin/stake_by_address_handler.go new file mode 100644 index 0000000..d57e9e7 --- /dev/null +++ b/internal/handler/admin/stake_by_address_handler.go @@ -0,0 +1,29 @@ +package admin + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "nova_task/internal/logic/admin" + "nova_task/internal/svc" + "nova_task/internal/types" +) + +// 根据地址修复质押 +func StakeByAddressHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.StakeByAddressReq + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := admin.NewStakeByAddressLogic(r.Context(), svcCtx) + err := l.StakeByAddress(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.Ok(w) + } + } +} diff --git a/internal/handler/routes.go b/internal/handler/routes.go index 3e9f55d..91d6c4f 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -44,6 +44,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/nft_holder_update", Handler: admin.NftHolderUpdateHandler(serverCtx), }, + { + // 根据地址修复质押 + Method: http.MethodPost, + Path: "/stake_by_address", + Handler: admin.StakeByAddressHandler(serverCtx), + }, { // 软质压手动结算 Method: http.MethodGet, diff --git a/internal/logic/admin/stake_by_address_logic.go b/internal/logic/admin/stake_by_address_logic.go new file mode 100644 index 0000000..9c0859a --- /dev/null +++ b/internal/logic/admin/stake_by_address_logic.go @@ -0,0 +1,75 @@ +package admin + +import ( + "context" + "errors" + "nova_task/internal/model" + "nova_task/internal/pkg/errs" + "nova_task/internal/pkg/utils" + "nova_task/internal/svc" + "nova_task/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type StakeByAddressLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// 根据地址修复质押 +func NewStakeByAddressLogic(ctx context.Context, svcCtx *svc.ServiceContext) *StakeByAddressLogic { + return &StakeByAddressLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *StakeByAddressLogic) StakeByAddress(req *types.StakeByAddressReq) error { + tokens, err := l.svcCtx.NftHolderModel.FindTokensByAddresses(l.ctx, req.Address) + if err != nil { + l.Errorw("find tokens by address failed", logx.Field("err", err), logx.Field("address", req.Address)) + return errs.New(errs.ErrDatabaseOperate, err) + } + for _, tk := range tokens { + uid, err := l.svcCtx.WalletModel.FindUidByAddress(l.ctx, tk.Address) + if err != nil { + l.Errorw("find uid by address failed", logx.Field("err", err), logx.Field("address", tk.Address)) + continue + } + st, err := l.svcCtx.StakeNftModel.FindOneByTokenId(l.ctx, tk.TokenId) + if err != nil { + l.Errorw("find stake nft by token id failed", logx.Field("err", err), logx.Field("tokenId", tk.TokenId)) + if errors.Is(err, model.ErrNotFound) { + var ty int8 + if utils.IsBigTarot(tk.TokenId) { + ty = 1 + } + st = &model.NhTaskNftStake{ + Uid: uid, + Type: ty, + TokenId: tk.TokenId, + State: 1, + } + _, err = l.svcCtx.StakeNftModel.Insert(l.ctx, st) + if err != nil { + l.Errorw("insert stake nft failed", logx.Field("err", err), logx.Field("stakeNft", st)) + } + } + } else { + if st.Uid != uid { + st.Uid = uid + st.State = 1 + err = l.svcCtx.StakeNftModel.Update(l.ctx, st) + if err != nil { + l.Errorw("update stake nft failed", logx.Field("err", err), logx.Field("stakeNft", st.TokenId), logx.Field("uid", uid)) + } + } + } + + } + + return errs.Success() +} diff --git a/internal/model/nh_nft_holder_model.go b/internal/model/nh_nft_holder_model.go index d3ebcb5..ebf88b0 100755 --- a/internal/model/nh_nft_holder_model.go +++ b/internal/model/nh_nft_holder_model.go @@ -7,6 +7,7 @@ import ( "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/stores/sqlc" "github.com/zeromicro/go-zero/core/stores/sqlx" + "strings" ) var _ NhNftHolderModel = (*customNhNftHolderModel)(nil) @@ -21,6 +22,7 @@ type ( DeleteOtherUpdateSeq(ctx context.Context, updateSeq int) error FindTokensByAddress(ctx context.Context, address string) ([]string, error) HoldNft(ctx context.Context, uid uint) bool + FindTokensByAddresses(ctx context.Context, addresses []string) ([]*NhNftHolder, error) } customNhNftHolderModel struct { @@ -51,6 +53,24 @@ func (m *customNhNftHolderModel) FindTokensByAddress(ctx context.Context, addres return tokens, nil } +func (m *customNhNftHolderModel) FindTokensByAddresses(ctx context.Context, addresses []string) ([]*NhNftHolder, error) { + // 生成占位符 + placeholders := make([]string, len(addresses)) + args := make([]interface{}, len(addresses)) + + for i, val := range addresses { + placeholders[i] = "?" + args[i] = val + } + query := fmt.Sprintf("select %s from %s where `address` in (%s)", nhNftHolderRows, m.table, strings.Join(placeholders, ",")) + var tokens []*NhNftHolder + err := m.conn.QueryRowsCtx(ctx, &tokens, query, args...) + if err != nil && !errors.Is(err, sqlx.ErrNotFound) { + return nil, err + } + return tokens, nil +} + func (m *customNhNftHolderModel) DeleteOtherUpdateSeq(ctx context.Context, updateSeq int) error { delSql := fmt.Sprintf("delete from %s where `update_seq` != ?", m.table) _, err := m.conn.ExecCtx(ctx, delSql, updateSeq) diff --git a/internal/types/types.go b/internal/types/types.go index 910b7d5..a70ad75 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -75,6 +75,10 @@ type Result struct { IsValid bool `json:"isValid"` } +type StakeByAddressReq struct { + Address []string `json:"address"` +} + type StakeNftList struct { RoleId uint64 `json:"role_id,optional"` // 角色id TokenIds []string `json:"token_ids"` // nft列表