diff --git a/auto/api/v1/alipay_priv.go b/auto/api/v1/alipay_priv.go index 2c95604c..152465a0 100644 --- a/auto/api/v1/alipay_priv.go +++ b/auto/api/v1/alipay_priv.go @@ -8,29 +8,32 @@ import ( "github.com/alimy/mir/v3" "github.com/gin-gonic/gin" "github.com/rocboss/paopao-ce/internal/model/web" + "github.com/rocboss/paopao-ce/internal/servants/base" ) type AlipayPriv interface { // Chain provide handlers chain for gin Chain() gin.HandlersChain - UserWalletBills(*web.UserWalletBillsReq) (*web.UserWalletBillsResp, mir.Error) - UserRechargeResult() mir.Error - UserRechargeLink() mir.Error + UserWalletBills(*web.UserWalletBillsReq) (*base.PageResp, mir.Error) + UserRechargeResult(*web.UserRechargeResultReq) (*web.UserRechargeResultResp, mir.Error) + UserRechargeLink(*web.UserRechargeLinkReq) (*web.UserRechargeLinkResp, mir.Error) mustEmbedUnimplementedAlipayPrivServant() } type AlipayPrivBinding interface { BindUserWalletBills(*gin.Context) (*web.UserWalletBillsReq, mir.Error) + BindUserRechargeResult(*gin.Context) (*web.UserRechargeResultReq, mir.Error) + BindUserRechargeLink(*gin.Context) (*web.UserRechargeLinkReq, mir.Error) mustEmbedUnimplementedAlipayPrivBinding() } type AlipayPrivRender interface { - RenderUserWalletBills(*gin.Context, *web.UserWalletBillsResp, mir.Error) - RenderUserRechargeResult(*gin.Context, mir.Error) - RenderUserRechargeLink(*gin.Context, mir.Error) + RenderUserWalletBills(*gin.Context, *base.PageResp, mir.Error) + RenderUserRechargeResult(*gin.Context, *web.UserRechargeResultResp, mir.Error) + RenderUserRechargeLink(*gin.Context, *web.UserRechargeLinkResp, mir.Error) mustEmbedUnimplementedAlipayPrivRender() } @@ -66,7 +69,13 @@ func RegisterAlipayPrivServant(e *gin.Engine, s AlipayPriv, b AlipayPrivBinding, default: } - r.RenderUserRechargeResult(c, s.UserRechargeResult()) + req, err := b.BindUserRechargeResult(c) + if err != nil { + r.RenderUserRechargeResult(c, nil, err) + return + } + resp, err := s.UserRechargeResult(req) + r.RenderUserRechargeResult(c, resp, err) }) router.Handle("POST", "/user/recharge", func(c *gin.Context) { @@ -76,7 +85,13 @@ func RegisterAlipayPrivServant(e *gin.Engine, s AlipayPriv, b AlipayPrivBinding, default: } - r.RenderUserRechargeLink(c, s.UserRechargeLink()) + req, err := b.BindUserRechargeLink(c) + if err != nil { + r.RenderUserRechargeLink(c, nil, err) + return + } + resp, err := s.UserRechargeLink(req) + r.RenderUserRechargeLink(c, resp, err) }) } @@ -89,16 +104,16 @@ func (UnimplementedAlipayPrivServant) Chain() gin.HandlersChain { return nil } -func (UnimplementedAlipayPrivServant) UserWalletBills(req *web.UserWalletBillsReq) (*web.UserWalletBillsResp, mir.Error) { +func (UnimplementedAlipayPrivServant) UserWalletBills(req *web.UserWalletBillsReq) (*base.PageResp, mir.Error) { return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) } -func (UnimplementedAlipayPrivServant) UserRechargeResult() mir.Error { - return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) +func (UnimplementedAlipayPrivServant) UserRechargeResult(req *web.UserRechargeResultReq) (*web.UserRechargeResultResp, mir.Error) { + return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) } -func (UnimplementedAlipayPrivServant) UserRechargeLink() mir.Error { - return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) +func (UnimplementedAlipayPrivServant) UserRechargeLink(req *web.UserRechargeLinkReq) (*web.UserRechargeLinkResp, mir.Error) { + return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) } func (UnimplementedAlipayPrivServant) mustEmbedUnimplementedAlipayPrivServant() {} @@ -108,16 +123,16 @@ type UnimplementedAlipayPrivRender struct { RenderAny func(*gin.Context, any, mir.Error) } -func (r *UnimplementedAlipayPrivRender) RenderUserWalletBills(c *gin.Context, data *web.UserWalletBillsResp, err mir.Error) { +func (r *UnimplementedAlipayPrivRender) RenderUserWalletBills(c *gin.Context, data *base.PageResp, err mir.Error) { r.RenderAny(c, data, err) } -func (r *UnimplementedAlipayPrivRender) RenderUserRechargeResult(c *gin.Context, err mir.Error) { - r.RenderAny(c, nil, err) +func (r *UnimplementedAlipayPrivRender) RenderUserRechargeResult(c *gin.Context, data *web.UserRechargeResultResp, err mir.Error) { + r.RenderAny(c, data, err) } -func (r *UnimplementedAlipayPrivRender) RenderUserRechargeLink(c *gin.Context, err mir.Error) { - r.RenderAny(c, nil, err) +func (r *UnimplementedAlipayPrivRender) RenderUserRechargeLink(c *gin.Context, data *web.UserRechargeLinkResp, err mir.Error) { + r.RenderAny(c, data, err) } func (r *UnimplementedAlipayPrivRender) mustEmbedUnimplementedAlipayPrivRender() {} @@ -133,4 +148,16 @@ func (b *UnimplementedAlipayPrivBinding) BindUserWalletBills(c *gin.Context) (*w return obj, err } +func (b *UnimplementedAlipayPrivBinding) BindUserRechargeResult(c *gin.Context) (*web.UserRechargeResultReq, mir.Error) { + obj := new(web.UserRechargeResultReq) + err := b.BindAny(c, obj) + return obj, err +} + +func (b *UnimplementedAlipayPrivBinding) BindUserRechargeLink(c *gin.Context) (*web.UserRechargeLinkReq, mir.Error) { + obj := new(web.UserRechargeLinkReq) + err := b.BindAny(c, obj) + return obj, err +} + func (b *UnimplementedAlipayPrivBinding) mustEmbedUnimplementedAlipayPrivBinding() {} diff --git a/auto/api/v1/core.go b/auto/api/v1/core.go index 50b9576a..bffc2879 100644 --- a/auto/api/v1/core.go +++ b/auto/api/v1/core.go @@ -36,7 +36,6 @@ type Core interface { type CoreBinding interface { BindChangeAvatar(*gin.Context) (*web.ChangeAvatarReq, mir.Error) - BindGetUserInfo(*gin.Context) (*web.UserInfoReq, mir.Error) mustEmbedUnimplementedCoreBinding() diff --git a/go.mod b/go.mod index 2377b980..23b5d680 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868 github.com/alimy/cfg v0.3.0 - github.com/alimy/mir/v3 v3.0.0-beta.2 + github.com/alimy/mir/v3 v3.0.0-beta.3 github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible github.com/allegro/bigcache/v3 v3.0.2 github.com/bytedance/sonic v1.5.0 diff --git a/go.sum b/go.sum index 69ac6d38..588a3b56 100644 --- a/go.sum +++ b/go.sum @@ -147,8 +147,8 @@ github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:C github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk= github.com/alimy/cfg v0.3.0 h1:9xgA0QWVCPSq9fFNRcYahVCAX22IL9ts2wrTQPfAStY= github.com/alimy/cfg v0.3.0/go.mod h1:rOxbasTH2srl6StAjNF5Vyi8bfrdkl3fLGmOYtSw81c= -github.com/alimy/mir/v3 v3.0.0-beta.2 h1:qpg0l4FEUafkpzGXlBIJtJbFjQfzbK9lDP5FJjjgOrA= -github.com/alimy/mir/v3 v3.0.0-beta.2/go.mod h1:ybhT2ijOiDn0lLwWzIY6vXdv+uzZrctS7VFfczcXBWU= +github.com/alimy/mir/v3 v3.0.0-beta.3 h1:b+2C9rvZg2ssZ0+gMUf9aYwhuJFKExO611ybXRP+/30= +github.com/alimy/mir/v3 v3.0.0-beta.3/go.mod h1:ybhT2ijOiDn0lLwWzIY6vXdv+uzZrctS7VFfczcXBWU= github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM= github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= diff --git a/internal/model/web/alipay.go b/internal/model/web/alipay.go index 2063e88c..b431f8d2 100644 --- a/internal/model/web/alipay.go +++ b/internal/model/web/alipay.go @@ -7,15 +7,37 @@ package web import ( "context" + "github.com/rocboss/paopao-ce/internal/servants/base" "github.com/smartwalle/alipay/v3" ) type UserWalletBillsReq struct { - *BaseInfo `json:"-" binding:"-"` + UserId int64 + Page int + PageSize int } -type UserWalletBillsResp struct { - // TODO +type UserWalletBillsResp = base.PageResp + +type UserRechargeLinkReq struct { + *BaseInfo `json:"-" form:"-" binding:"-"` + Host string `json:"-" form:"-" binding:"-"` + Amount int64 `json:"amount" form:"amount" binding:"required"` +} + +type UserRechargeLinkResp struct { + Id int64 `json:"id"` + Pay string `json:"pay"` +} + +type UserRechargeResultReq struct { + UserId int64 + Id int64 +} + +type UserRechargeResultResp struct { + Id int64 `json:"id"` + Status string `json:"status"` } type AlipayNotifyReq struct { diff --git a/internal/servants/base/base.go b/internal/servants/base/base.go index 301753f6..b6f244f1 100644 --- a/internal/servants/base/base.go +++ b/internal/servants/base/base.go @@ -49,6 +49,14 @@ func UserFrom(c *gin.Context) (*core.User, bool) { return nil, false } +func UserIdFrom(c *gin.Context) (int64, bool) { + if u, exists := c.Get("UID"); exists { + uid, ok := u.(int64) + return uid, ok + } + return -1, false +} + func BindAny(c *gin.Context, obj any) mir.Error { var errs xerror.ValidErrors err := c.ShouldBind(obj) @@ -57,7 +65,10 @@ func BindAny(c *gin.Context, obj any) mir.Error { } // setup *core.User if needed if setter, ok := obj.(UserSetter); ok { - user, _ := UserFrom(c) + user, exist := UserFrom(c) + if !exist { + return xerror.UnauthorizedTokenError + } setter.SetUser(user) } return nil diff --git a/internal/servants/base/page.go b/internal/servants/base/page.go new file mode 100644 index 00000000..6e3b4d05 --- /dev/null +++ b/internal/servants/base/page.go @@ -0,0 +1,27 @@ +// Copyright 2022 ROC. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package base + +type Pager struct { + Page int `json:"page"` + PageSize int `json:"page_size"` + TotalRows int64 `json:"total_rows"` +} + +type PageResp struct { + List any `json:"list"` + Pager Pager `json:"pager"` +} + +func PageRespFrom(list any, page int, pageSize int, totalRows int64) *PageResp { + return &PageResp{ + List: list, + Pager: Pager{ + Page: page, + PageSize: pageSize, + TotalRows: totalRows, + }, + } +} diff --git a/internal/servants/web/alipay.go b/internal/servants/web/alipay.go index 36fc6f60..ccbf00bc 100644 --- a/internal/servants/web/alipay.go +++ b/internal/servants/web/alipay.go @@ -5,6 +5,7 @@ package web import ( + "fmt" "time" "github.com/alimy/mir/v3" @@ -13,7 +14,9 @@ import ( "github.com/rocboss/paopao-ce/internal/model/web" "github.com/rocboss/paopao-ce/internal/servants/base" "github.com/rocboss/paopao-ce/internal/servants/chain" + "github.com/rocboss/paopao-ce/pkg/app" "github.com/rocboss/paopao-ce/pkg/convert" + "github.com/rocboss/paopao-ce/pkg/xerror" "github.com/sirupsen/logrus" "github.com/smartwalle/alipay/v3" ) @@ -44,6 +47,9 @@ type alipayPubRender struct { type alipayPrivSrv struct { api.UnimplementedAlipayPrivServant + *base.DaoServant + + alipayClient *alipay.Client } type alipayPrivBinding struct { @@ -94,10 +100,97 @@ func (s *alipayPubSrv) AlipayNotify(req *web.AlipayNotifyReq) mir.Error { return nil } +func (b *alipayPrivBinding) BindUserWalletBills(c *gin.Context) (*web.UserWalletBillsReq, mir.Error) { + uid, ok := base.UserIdFrom(c) + if !ok { + return nil, xerror.UnauthorizedTokenError + } + page, pageSize := app.GetPageOffset(c) + return &web.UserWalletBillsReq{ + UserId: uid, + Page: page, + PageSize: pageSize, + }, nil +} + +func (b *alipayPrivBinding) BindUserRechargeLink(c *gin.Context) (*web.UserRechargeLinkReq, mir.Error) { + v := &web.UserRechargeLinkReq{ + Host: c.Request.Host, + } + err := b.BindAny(c, v) + return v, err +} + +func (b *alipayPrivBinding) BindUserRechargeResult(c *gin.Context) (*web.UserRechargeResultReq, mir.Error) { + uid, exist := base.UserIdFrom(c) + if !exist { + return nil, xerror.UnauthorizedTokenError + } + return &web.UserRechargeResultReq{ + UserId: uid, + Id: convert.StrTo(c.Query("id")).MustInt64(), + }, nil +} + func (s *alipayPrivSrv) Chain() gin.HandlersChain { return gin.HandlersChain{chain.JWT()} } +func (s *alipayPrivSrv) UserWalletBills(req *web.UserWalletBillsReq) (*web.UserWalletBillsResp, mir.Error) { + bills, err := s.Ds.GetUserWalletBills(req.UserId, (req.Page-1)*req.PageSize, req.PageSize) + if err != nil { + logrus.Errorf("GetUserWalletBills err: %s", err) + return nil, _errUserWalletBillsFailed + } + totalRows, err := s.Ds.GetUserWalletBillCount(req.UserId) + if err != nil { + logrus.Errorf("GetUserWalletBillCount err: %s", err) + return nil, _errUserWalletBillsFailed + } + return base.PageRespFrom(bills, req.Page, req.PageSize, totalRows), nil +} + +func (s *alipayPrivSrv) UserRechargeLink(req *web.UserRechargeLinkReq) (*web.UserRechargeLinkResp, mir.Error) { + recharge, err := s.Ds.CreateRecharge(req.User.ID, req.Amount) + if err != nil { + logrus.Errorf("Ds.CreateRecharge err: %v", err) + return nil, _errRechargeReqFail + } + p := alipay.TradePreCreate{} + p.OutTradeNo = fmt.Sprintf("%d", recharge.ID) + p.Subject = "PaoPao用户钱包充值" + p.TotalAmount = fmt.Sprintf("%.2f", float64(recharge.Amount)/100.0) + p.NotifyURL = "https://" + req.Host + "/v1/alipay/notify" + rsp, err := s.alipayClient.TradePreCreate(p) + if err != nil { + logrus.Errorf("client.TradePreCreate err: %v\n", err) + return nil, _errRechargeReqFail + } + if rsp.Content.Code != alipay.CodeSuccess { + return nil, _errRechargeReqFail + } + return &web.UserRechargeLinkResp{ + Id: recharge.ID, + Pay: rsp.Content.QRCode, + }, nil +} + +func (s *alipayPrivSrv) UserRechargeResult(req *web.UserRechargeResultReq) (*web.UserRechargeResultResp, mir.Error) { + recharge, err := s.Ds.GetRechargeByID(req.Id) + if err != nil { + logrus.Errorf("Ds.GetRechargeByID err: %v", err) + return nil, _errGetRechargeFailed + } + if recharge.UserID != req.UserId { + logrus.Errorf("Ds.GetRechargeByID userId not equel recharge.UserID: %d req.UserId %d", recharge.UserID, req.UserId) + return nil, _errGetRechargeFailed + } + return &web.UserRechargeResultResp{ + Id: recharge.ID, + Status: recharge.TradeStatus, + }, nil +} + func newAlipayPubSrv(s *base.DaoServant) api.AlipayPub { return &alipayPubSrv{ DaoServant: s, @@ -121,8 +214,11 @@ func newAlipayPubRender() api.AlipayPubRender { } } -func newAlipayPrivSrv() api.AlipayPriv { - return &alipayPrivSrv{} +func newAlipayPrivSrv(s *base.DaoServant, client *alipay.Client) api.AlipayPriv { + return &alipayPrivSrv{ + DaoServant: s, + alipayClient: client, + } } func newAlipayPrivBinding() api.AlipayPrivBinding { diff --git a/internal/servants/web/web.go b/internal/servants/web/web.go index 22fc71a7..f9f3127b 100644 --- a/internal/servants/web/web.go +++ b/internal/servants/web/web.go @@ -34,7 +34,7 @@ func RouteWeb(e *gin.Engine) { "Alipay": func() { client := mustAlipayClient() api.RegisterAlipayPubServant(e, newAlipayPubSrv(ds), newAlipayPubBinding(client), newAlipayPubRender()) - api.RegisterAlipayPrivServant(e, newAlipayPrivSrv(), newAlipayPrivBinding(), newAlipayPrivRender()) + api.RegisterAlipayPrivServant(e, newAlipayPrivSrv(ds, client), newAlipayPrivBinding(), newAlipayPrivRender()) }, "Followship": func() { api.RegisterFollowshipServant(e, newFollowshipSrv(), newFollowshipBinding(), newFollowshipRender()) diff --git a/internal/servants/web/xerror.go b/internal/servants/web/xerror.go index bda13caf..544053b2 100644 --- a/internal/servants/web/xerror.go +++ b/internal/servants/web/xerror.go @@ -63,9 +63,10 @@ var ( _errGetCollectionsFailed = xerror.NewError(60001, "获取收藏列表失败") _errGetStarsFailed = xerror.NewError(60002, "获取点赞列表失败") - _errRechargeReqFail = xerror.NewError(70001, "充值请求失败") - _errRechargeNotifyError = xerror.NewError(70002, "充值回调失败") - _errGetRechargeFailed = xerror.NewError(70003, "充值详情获取失败") + _errRechargeReqFail = xerror.NewError(70001, "充值请求失败") + _errRechargeNotifyError = xerror.NewError(70002, "充值回调失败") + _errGetRechargeFailed = xerror.NewError(70003, "充值详情获取失败") + _errUserWalletBillsFailed = xerror.NewError(70004, "用户钱包账单获取失败") _errNoRequestingFriendToSelf = xerror.NewError(80001, "不允许添加自己为好友") _errNotExistFriendId = xerror.NewError(80002, "好友id不存在") diff --git a/mirc/web/v1/alipay.go b/mirc/web/v1/alipay.go index c4a34111..86ab6936 100644 --- a/mirc/web/v1/alipay.go +++ b/mirc/web/v1/alipay.go @@ -24,10 +24,10 @@ type AlipayPriv struct { Group Group `mir:"v1"` // UserRechargeLink 用户充值 - UserRechargeLink func(Post) `mir:"/user/recharge"` + UserRechargeLink func(Post, web.UserRechargeLinkReq) web.UserRechargeLinkResp `mir:"/user/recharge"` - // UserRechargeResult 获取钱包余额 - UserRechargeResult func(Get) `mir:"/user/recharge"` + // UserRechargeResult 获取充值结果 + UserRechargeResult func(Get, web.UserRechargeResultReq) web.UserRechargeResultResp `mir:"/user/recharge"` // UserWalletBills 获取用户账单 UserWalletBills func(Get, web.UserWalletBillsReq) web.UserWalletBillsResp `mir:"/user/wallet/bills"`