Skip to content

Commit

Permalink
Merge branch 'feat/coupon' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
sjatsh committed Nov 6, 2023
2 parents 7fea789 + fb7aed5 commit 8b74184
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 154 deletions.
15 changes: 15 additions & 0 deletions dao/t_coupon_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,21 @@ func (d *DbDao) FindCouponCodeList(cid string, page, pageSize int) ([]*tables.Co
return res, total, nil
}

func (d *DbDao) FindCouponCode(cid string) (res []*tables.CouponInfo, err error) {
if err = d.db.Where("cid = ?", cid).Order("created_at desc").Find(&res).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
err = nil
}
}
for idx, v := range res {
res[idx].Code, err = encrypt.AesDecrypt(v.Code, config.Cfg.Das.Coupon.EncryptionKey)
if err != nil {
return
}
}
return res, nil
}

func (d *DbDao) GetCouponByCode(code string) (res tables.CouponInfo, err error) {
code, err = encrypt.AesEncrypt(code, config.Cfg.Das.Coupon.EncryptionKey)
if err != nil {
Expand Down
53 changes: 33 additions & 20 deletions http_server/handle/coupon_code_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@ package handle

import (
"das_sub_account/tables"
"fmt"
"github.com/dotbitHQ/das-lib/common"
"github.com/dotbitHQ/das-lib/core"
api_code "github.com/dotbitHQ/das-lib/http_api"
"github.com/dotbitHQ/das-lib/sign"
"github.com/gin-gonic/gin"
"net/http"
"strings"
"time"
)

type ReqCouponCodeList struct {
core.ChainTypeAddress
Cid string `json:"cid"`
Page int `json:"page" binding:"gte=1"`
PageSize int `json:"page_size" binding:"gte=1,lte=100"`
Account string `json:"account" binding:"required"`
Cid string `json:"cid" binding:"required"`
Timestamp int64 `json:"timestamp" binding:"required"`
Signature string `json:"signature" binding:"required"`
Page int `json:"page" binding:"gte=1"`
PageSize int `json:"page_size" binding:"gte=1,lte=100"`
}

type RespCouponCodeList struct {
Expand Down Expand Up @@ -57,22 +63,42 @@ func (h *HttpHandle) CouponCodeList(ctx *gin.Context) {
if err = h.doCouponCodeList(&req, &apiResp); err != nil {
log.Error("doCouponCodeList err:", err.Error(), funcName, clientIp, ctx)
}

ctx.JSON(http.StatusOK, apiResp)
}

func (h *HttpHandle) doCouponCodeList(req *ReqCouponCodeList, apiResp *api_code.ApiResp) error {
couponSetInfo, err := h.DbDao.GetCouponSetInfo(req.Cid)
if time.Now().After(time.UnixMilli(req.Timestamp).Add(time.Minute)) {
apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "timestamp expired, valid for 1 minutes")
return nil
}

res, err := req.ChainTypeAddress.FormatChainTypeAddress(h.DasCore.NetType(), false)
if err != nil {
apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid")
return nil
}
address := common.FormatAddressPayload(res.AddressPayload, res.DasAlgorithmId)

signMsg := fmt.Sprintf("%s%s%d", req.Account, req.Cid, req.Timestamp)
if ok, err := sign.VerifyPersonalSignature(common.Hex2Bytes(req.Signature), []byte(signMsg), address); err != nil {
apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, err.Error())
return nil
} else if !ok {
apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "signature invalid")
return nil
}

setInfo, err := h.DbDao.GetCouponSetInfo(req.Cid)
if err != nil {
apiResp.ApiRespErr(api_code.ApiCodeDbError, "Failed to query coupon set info")
return nil
}
if couponSetInfo.Id == 0 {
if setInfo.Id == 0 {
apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "cid no exist")
return nil
}

accInfo, err := h.DbDao.GetAccountInfoByAccountId(couponSetInfo.AccountId)
accInfo, err := h.DbDao.GetAccountInfoByAccountId(setInfo.AccountId)
if err != nil {
apiResp.ApiRespErr(api_code.ApiCodeDbError, "Failed to query parent account")
return nil
Expand All @@ -82,24 +108,11 @@ func (h *HttpHandle) doCouponCodeList(req *ReqCouponCodeList, apiResp *api_code.
return nil
}

res, err := req.ChainTypeAddress.FormatChainTypeAddress(h.DasCore.NetType(), false)
if err != nil {
apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid")
return nil
}
address := common.FormatAddressPayload(res.AddressPayload, res.DasAlgorithmId)

if !strings.EqualFold(accInfo.Manager, address) && !strings.EqualFold(accInfo.Owner, address) {
apiResp.ApiRespErr(api_code.ApiCodeNoAccountPermissions, "no account permissions")
return nil
}

setInfo, err := h.DbDao.GetCouponSetInfo(req.Cid)
if err != nil {
apiResp.ApiRespErr(api_code.ApiCodeDbError, "Failed to query coupon set info")
return nil
}

// get coupon set list
couponList, total, err := h.DbDao.FindCouponCodeList(req.Cid, req.Page, req.PageSize)
if err != nil {
Expand Down
36 changes: 0 additions & 36 deletions http_server/handle/coupon_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package handle
import (
"crypto/md5"
"das_sub_account/config"
"das_sub_account/consts"
"das_sub_account/encrypt"
"das_sub_account/internal"
"das_sub_account/tables"
Expand All @@ -14,7 +13,6 @@ import (
"github.com/dotbitHQ/das-lib/core"
api_code "github.com/dotbitHQ/das-lib/http_api"
"github.com/dotbitHQ/das-lib/smt"
"github.com/dotbitHQ/das-lib/txbuilder"
"github.com/gin-gonic/gin"
"github.com/labstack/gommon/random"
"github.com/shopspring/decimal"
Expand Down Expand Up @@ -168,40 +166,6 @@ func (h *HttpHandle) doCouponCreate(req *ReqCouponCreate, apiResp *api_code.ApiR
apiResp.ApiRespErr(api_code.ApiCodeDbError, "fail to create coupon")
return fmt.Errorf("CreateCoupon err:%s", err.Error())
}

tree := smt.NewSmtSrv(*h.SmtServerUrl, "")
smtOut, err := tree.UpdateSmt(kvs, smt.SmtOpt{GetRoot: true})
if err != nil {
apiResp.ApiRespErr(api_code.ApiCodeError500, err.Error())
return err
}
couponSetInfo.Root = smtOut.Root.String()

signMsg := fmt.Sprintf("%s%s", common.DotBitPrefix, smtOut.Root.String())

cache := &CouponCreateCache{
ReqCouponCreate: *req,
Cid: couponSetInfo.Cid,
}
signKey, reqDataStr := cache.GetSignInfo()
if err := h.RC.SetSignTxCache(signKey, reqDataStr); err != nil {
apiResp.ApiRespErr(api_code.ApiCodeCacheError, "cache err")
return fmt.Errorf("SetSignTxCache err: %s", err.Error())
}

signType := res.DasAlgorithmId
if signType == common.DasAlgorithmIdEth712 {
signType = common.DasAlgorithmIdEth
}

resp.Action = consts.ActionCouponCreate
resp.SignKey = signKey
resp.List = append(resp.List, SignInfo{
SignList: []txbuilder.SignData{{
SignType: signType,
SignMsg: signMsg,
}},
})
apiResp.ApiRespOK(resp)
return nil
}
Expand Down
119 changes: 119 additions & 0 deletions http_server/handle/coupon_download.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package handle

import (
"encoding/csv"
"fmt"
"github.com/dotbitHQ/das-lib/common"
"github.com/dotbitHQ/das-lib/core"
api_code "github.com/dotbitHQ/das-lib/http_api"
"github.com/dotbitHQ/das-lib/sign"
"github.com/gin-gonic/gin"
"net/http"
"strings"
"time"
)

type ReqCouponDownload struct {
core.ChainTypeAddress
Account string `json:"account" binding:"required"`
Cid string `json:"cid" binding:"required"`
Timestamp int64 `json:"timestamp" binding:"required"`
Signature string `json:"signature" binding:"required"`
}

func (h *HttpHandle) CouponDownload(ctx *gin.Context) {
var (
funcName = "CouponDownload"
clientIp, remoteAddrIP = GetClientIp(ctx)
req ReqCouponDownload
apiResp api_code.ApiResp
err error
)
log.Info("ApiReq:", funcName, clientIp, remoteAddrIP, ctx)

if err := ctx.ShouldBindJSON(&req); err != nil {
log.Error("ShouldBindJSON err: ", err.Error(), funcName, clientIp, remoteAddrIP, ctx)
apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid")
ctx.JSON(http.StatusOK, apiResp)
return
}

if err = h.doCouponDownload(ctx, &req, &apiResp); err != nil {
log.Error("doCouponDownload err:", err.Error(), funcName, clientIp, ctx)
}
ctx.JSON(http.StatusOK, apiResp)
}

func (h *HttpHandle) doCouponDownload(ctx *gin.Context, req *ReqCouponDownload, apiResp *api_code.ApiResp) error {
if time.Now().After(time.UnixMilli(req.Timestamp).Add(time.Minute)) {
apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "timestamp expired, valid for 1 minutes")
return nil
}

res, err := req.ChainTypeAddress.FormatChainTypeAddress(h.DasCore.NetType(), false)
if err != nil {
apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "params invalid")
return nil
}
address := common.FormatAddressPayload(res.AddressPayload, res.DasAlgorithmId)

signMsg := fmt.Sprintf("%s%s%d", req.Account, req.Cid, req.Timestamp)
if ok, err := sign.VerifyPersonalSignature(common.Hex2Bytes(req.Signature), []byte(signMsg), address); err != nil {
apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, err.Error())
return nil
} else if !ok {
apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "signature invalid")
return nil
}

setInfo, err := h.DbDao.GetCouponSetInfo(req.Cid)
if err != nil {
apiResp.ApiRespErr(api_code.ApiCodeDbError, "Failed to query coupon set info")
return nil
}
if setInfo.Id == 0 {
apiResp.ApiRespErr(api_code.ApiCodeParamsInvalid, "cid no exist")
return nil
}

accInfo, err := h.DbDao.GetAccountInfoByAccountId(setInfo.AccountId)
if err != nil {
apiResp.ApiRespErr(api_code.ApiCodeDbError, "Failed to query parent account")
return nil
}
if accInfo.Id == 0 {
apiResp.ApiRespErr(api_code.ApiCodeParentAccountNotExist, "parent account does not exist")
return nil
}
if !strings.EqualFold(accInfo.Manager, address) && !strings.EqualFold(accInfo.Owner, address) {
apiResp.ApiRespErr(api_code.ApiCodeNoAccountPermissions, "no account permissions")
return nil
}

couponList, err := h.DbDao.FindCouponCode(req.Cid)
if err != nil {
apiResp.ApiRespErr(api_code.ApiCodeDbError, "Failed to query coupon code")
return nil
}

if len(couponList) == 0 {
return nil
}

items := [][]string{
{"Code", "status"},
}
for _, v := range couponList {
items = append(items, []string{v.Code, fmt.Sprint(v.Status)})
}

ctx.Header("Content-Type", "text/csv")
ctx.Header("Content-Disposition", fmt.Sprintf("attachment;filename=%s.csv", req.Cid))
wr := csv.NewWriter(ctx.Writer)
if err := wr.WriteAll(items); err != nil {
apiResp.ApiRespErr(api_code.ApiCodeError500, err.Error())
return nil
}
wr.Flush()
return nil
}
4 changes: 3 additions & 1 deletion http_server/handle/coupon_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import (

type ReqCouponInfo struct {
core.ChainTypeAddress
Code string `json:"code"`
Code string `json:"code" binding:"required"`
remoteIp string
}

type RespCouponInfo struct {
Expand All @@ -37,6 +38,7 @@ func (h *HttpHandle) CouponInfo(ctx *gin.Context) {
ctx.JSON(http.StatusOK, apiResp)
return
}
req.remoteIp = remoteAddrIP

if err = h.doCouponInfo(&req, &apiResp); err != nil {
log.Error("doCouponInfo err:", err.Error(), funcName, clientIp, ctx)
Expand Down
Loading

0 comments on commit 8b74184

Please sign in to comment.