1、新接textverified
This commit is contained in:
@ -13,6 +13,7 @@ import (
|
|||||||
"go-admin/app/admin/service"
|
"go-admin/app/admin/service"
|
||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
"go-admin/common/actions"
|
"go-admin/common/actions"
|
||||||
|
"go-admin/common/middleware"
|
||||||
"go-admin/common/statuscode"
|
"go-admin/common/statuscode"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -194,7 +195,16 @@ func (e SmsPhone) Delete(c *gin.Context) {
|
|||||||
e.OK(req.GetId(), "删除成功")
|
e.OK(req.GetId(), "删除成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 租赁号码
|
// GetNumber
|
||||||
|
// @Summary 获取号码
|
||||||
|
// @Description 获取号码
|
||||||
|
// @Tags 短信手机号
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param data body dto.GetNumberReq true "data"
|
||||||
|
// @Success 200 {object} response.Response{data=decimal.Decimal} "获取号码"
|
||||||
|
// @Router /api/v1/sms-phone/get-number [post]
|
||||||
|
// @Security Bearer
|
||||||
func (e SmsPhone) GetNumber(c *gin.Context) {
|
func (e SmsPhone) GetNumber(c *gin.Context) {
|
||||||
req := dto.GetNumberReq{}
|
req := dto.GetNumberReq{}
|
||||||
s := service.SmsPhone{}
|
s := service.SmsPhone{}
|
||||||
@ -211,36 +221,38 @@ func (e SmsPhone) GetNumber(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := req.Validate(); err != nil {
|
if err1 := req.Validate(); err1 != nil {
|
||||||
e.Logger.Errorf("租赁号码失败,%s", err.Error())
|
e.Logger.Errorf("租赁号码失败,%s", err1.Error())
|
||||||
e.Error(500, err, "服务器错误请联系管理员")
|
e.Error(500, err, "服务器错误请联系管理员")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var balance decimal.Decimal
|
|
||||||
code := statuscode.Success
|
code := statuscode.Success
|
||||||
|
lang := "zh"
|
||||||
userId := user.GetUserId(c)
|
userId := user.GetUserId(c)
|
||||||
smsService, err := servicesService.GetByCode(req.ServiceCode)
|
smsService, err := servicesService.GetByCode(req.PlatformCode, req.ServiceCode)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
code = statuscode.SmsServiceUnavailable
|
code = statuscode.SmsServiceUnavailable
|
||||||
} else if smsService.Status == 2 {
|
} else if smsService.Status == 2 {
|
||||||
code = statuscode.SmsServiceUnavailable
|
code = statuscode.SmsServiceUnavailable
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
var balance decimal.Decimal
|
||||||
|
if code == statuscode.Success {
|
||||||
balance, code = s.GetNumber(&req, userId)
|
balance, code = s.GetNumber(&req, userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if code != statuscode.Success {
|
if code != statuscode.Success {
|
||||||
if code == statuscode.SmsServiceUnavailable {
|
if code == statuscode.SmsServiceUnavailable {
|
||||||
e.Error(code, nil, statuscode.GetMsg(code, "zh", smsService.Name))
|
e.Error(code, nil, statuscode.GetMsg(code, lang, smsService.Name))
|
||||||
} else {
|
} else {
|
||||||
e.Error(code, nil, statuscode.GetMsg(code, "zh"))
|
e.Error(code, nil, statuscode.GetMsg(code, lang))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
e.OK(balance, "租赁号码成功")
|
e.OK(balance, "获取号码成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取验证码
|
// 获取验证码
|
||||||
@ -327,7 +339,7 @@ func (e SmsPhone) WeakUp(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
userId := user.GetUserId(c)
|
userId := user.GetUserId(c)
|
||||||
code := s.WeakUp(&req, userId)
|
_, code := s.WeakUp(&req, userId, false)
|
||||||
|
|
||||||
if code != statuscode.Success {
|
if code != statuscode.Success {
|
||||||
e.Error(code, nil, statuscode.GetMsg(code, "zh"))
|
e.Error(code, nil, statuscode.GetMsg(code, "zh"))
|
||||||
@ -449,3 +461,289 @@ func (e SmsPhone) CleanMyPhone(c *gin.Context) {
|
|||||||
|
|
||||||
e.OK(nil, "清理成功")
|
e.OK(nil, "清理成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OpenGetNumber
|
||||||
|
// @Summary 开放接口-获取号码
|
||||||
|
// @Description 开放接口-获取号码
|
||||||
|
// @Tags 短信手机号
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param data body dto.GetNumberReq true "data"
|
||||||
|
// @Success 200 {object} response.Response{data=decimal.Decimal} "获取号码"
|
||||||
|
// @Router /api/v1/open/sms-phone/get-number [post]
|
||||||
|
func (e SmsPhone) OpenGetNumber(c *gin.Context) {
|
||||||
|
req := dto.GetNumberReq{}
|
||||||
|
s := service.SmsPhone{}
|
||||||
|
servicesService := service.SmsServices{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
MakeService(&servicesService.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err1 := req.Validate(); err1 != nil {
|
||||||
|
e.Logger.Errorf("租赁号码失败,%s", err1.Error())
|
||||||
|
e.Error(500, err, "服务器错误请联系管理员")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lang := "zh"
|
||||||
|
code := statuscode.Success
|
||||||
|
userId, err := middleware.GetUserIdByApiKey(c)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
var errCode int
|
||||||
|
|
||||||
|
switch err {
|
||||||
|
case middleware.ErrApiUnActived:
|
||||||
|
errCode = statuscode.ApiUnActived
|
||||||
|
case middleware.ErrNoAccount:
|
||||||
|
errCode = statuscode.AccountNotFound
|
||||||
|
default:
|
||||||
|
e.Logger.Errorf("获取API用户id失败 %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Error(errCode, nil, statuscode.GetMsg(errCode, lang))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
smsService, err := servicesService.GetByCode(req.PlatformCode, req.ServiceCode)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
code = statuscode.SmsServiceUnavailable
|
||||||
|
} else if smsService.Status == 2 {
|
||||||
|
code = statuscode.SmsServiceUnavailable
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp dto.OpenGetNumberResp
|
||||||
|
if code == statuscode.Success {
|
||||||
|
resp, code = s.OpenGetNumber(&req, userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
if code == statuscode.SmsServiceUnavailable {
|
||||||
|
e.Error(code, nil, statuscode.GetMsg(code, lang, smsService.Name))
|
||||||
|
} else {
|
||||||
|
e.Error(code, nil, statuscode.GetMsg(code, lang))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(resp, "获取号码成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenGetCodeByActivationId 开放api-获取验证码
|
||||||
|
// @Summary 开放接口-获取验证码
|
||||||
|
// @Description 开放接口-获取验证码
|
||||||
|
// @Tags 短信号码
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param data body dto.GetCodeReq true "body"
|
||||||
|
// @Success 200 {object} response.Response{data=dto.GetCodeResp} "成功"
|
||||||
|
// @Router /api/v1/open/sms-phone/get-code [post]
|
||||||
|
func (e SmsPhone) OpenGetCodeByActivationId(c *gin.Context) {
|
||||||
|
req := dto.GetCodeReq{}
|
||||||
|
s := service.SmsPhone{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lang := "zh"
|
||||||
|
userId, err := middleware.GetUserIdByApiKey(c)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
var errCode int
|
||||||
|
|
||||||
|
switch err {
|
||||||
|
case middleware.ErrApiUnActived:
|
||||||
|
errCode = statuscode.ApiUnActived
|
||||||
|
case middleware.ErrNoAccount:
|
||||||
|
errCode = statuscode.AccountNotFound
|
||||||
|
default:
|
||||||
|
e.Logger.Errorf("获取API用户id失败 %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Error(errCode, nil, statuscode.GetMsg(errCode, lang))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
codeData, code := s.GetCodeByActivationId(&req, userId)
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Error(code, nil, statuscode.GetMsg(code, lang))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(codeData, "获取验证码成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenCancel 开放api-取消号码
|
||||||
|
// @Summary 开放接口-取消号码
|
||||||
|
// @Description 开放接口-取消号码
|
||||||
|
// @Tags 短信号码
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param data body dto.SmsPhoneCancelNumberReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "成功"
|
||||||
|
// @Router /api/v1/open/sms-phone/cancel [post]
|
||||||
|
func (e SmsPhone) OpenCancel(c *gin.Context) {
|
||||||
|
req := dto.SmsPhoneCancelNumberReq{}
|
||||||
|
s := service.SmsPhone{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lang := "zh"
|
||||||
|
userId, err := middleware.GetUserIdByApiKey(c)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
var errCode int
|
||||||
|
|
||||||
|
switch err {
|
||||||
|
case middleware.ErrApiUnActived:
|
||||||
|
errCode = statuscode.ApiUnActived
|
||||||
|
case middleware.ErrNoAccount:
|
||||||
|
errCode = statuscode.AccountNotFound
|
||||||
|
default:
|
||||||
|
e.Logger.Errorf("获取API用户id失败 %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Error(errCode, nil, statuscode.GetMsg(errCode, lang))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
code := s.CancelNumber(&req, userId)
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Error(code, nil, statuscode.GetMsg(code, lang))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(nil, "取消号码成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenAutoRenewal 开放api-修改续费状态
|
||||||
|
// @Summary 开放接口-修改自动续费状态
|
||||||
|
// @Description 开放接口-修改自动续费状态
|
||||||
|
// @Tags 短信号码
|
||||||
|
// @Accept application/json
|
||||||
|
// @Product application/json
|
||||||
|
// @Param data body dto.SmsPhoneChangeAutoRenewReq true "body"
|
||||||
|
// @Success 200 {object} response.Response "成功"
|
||||||
|
// @Router /api/v1/open/sms-phone/auto-renewal [post]
|
||||||
|
func (e SmsPhone) OpenAutoRenewal(c *gin.Context) {
|
||||||
|
req := dto.SmsPhoneChangeAutoRenewReq{}
|
||||||
|
s := service.SmsPhone{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lang := "zh"
|
||||||
|
userId, err := middleware.GetUserIdByApiKey(c)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
var errCode int
|
||||||
|
|
||||||
|
switch err {
|
||||||
|
case middleware.ErrApiUnActived:
|
||||||
|
errCode = statuscode.ApiUnActived
|
||||||
|
case middleware.ErrNoAccount:
|
||||||
|
errCode = statuscode.AccountNotFound
|
||||||
|
default:
|
||||||
|
e.Logger.Errorf("获取API用户id失败 %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Error(errCode, nil, statuscode.GetMsg(errCode, lang))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
code := s.ChangeAutoRenew(&req, userId)
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Error(code, nil, statuscode.GetMsg(code, lang))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(nil, "修改自动续费状态成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenApi 获取服务列表
|
||||||
|
func (e SmsPhone) OpenGetServices(c *gin.Context) {
|
||||||
|
s := service.SmsServices{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := []dto.SmsServicesGetListResp{}
|
||||||
|
err = s.GetList(&resp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, statuscode.GetMsg(statuscode.ServerError, "en"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(resp, "success")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开放接口-唤醒号码
|
||||||
|
func (e SmsPhone) OpenWeakUp(c *gin.Context) {
|
||||||
|
req := dto.WeakUpReq{}
|
||||||
|
s := service.SmsPhone{}
|
||||||
|
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lang := "en"
|
||||||
|
userId, err := middleware.GetUserIdByApiKey(c)
|
||||||
|
|
||||||
|
resp, code := s.WeakUp(&req, userId, false)
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Error(code, nil, statuscode.GetMsg(code, lang))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(resp, "success")
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,14 @@
|
|||||||
package apis
|
package apis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha512"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/api"
|
"github.com/go-admin-team/go-admin-core/sdk/api"
|
||||||
@ -193,7 +200,7 @@ func (e SmsReceiveLog) Delete(c *gin.Context) {
|
|||||||
e.OK(req.GetId(), "删除成功")
|
e.OK(req.GetId(), "删除成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebHook 接收短信发送记录回调
|
// daisysms WebHook 接收短信发送记录回调
|
||||||
func (e SmsReceiveLog) WebHook(c *gin.Context) {
|
func (e SmsReceiveLog) WebHook(c *gin.Context) {
|
||||||
req := dto.SmsReceiveWebHookReq{}
|
req := dto.SmsReceiveWebHookReq{}
|
||||||
s := service.SmsReceiveLog{}
|
s := service.SmsReceiveLog{}
|
||||||
@ -217,3 +224,63 @@ func (e SmsReceiveLog) WebHook(c *gin.Context) {
|
|||||||
|
|
||||||
e.OK(nil, "接收短信发送记录回调成功")
|
e.OK(nil, "接收短信发送记录回调成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// textVerified WebHook 接收短信发送记录回调
|
||||||
|
func (e SmsReceiveLog) TextVerifiedWebHook(c *gin.Context) {
|
||||||
|
// 1. 提前读取原始 body
|
||||||
|
bodyBytes, err := io.ReadAll(c.Request.Body)
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error("Failed to read body:", err)
|
||||||
|
e.Error(500, err, "Failed to read request body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 验签
|
||||||
|
signatureHeader := c.GetHeader("X-Webhook-Signature")
|
||||||
|
if !verifyWebhookSignature(signatureHeader, bodyBytes, "whsec_UMjFrzkK4YrlOb0AyOFDZAJJ7VWChOVOhYAGKE0e5oKw") {
|
||||||
|
e.Logger.Warn("Invalid webhook signature")
|
||||||
|
e.Error(401, fmt.Errorf("invalid signature"), "Invalid signature")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 重置 body 给 Bind 用
|
||||||
|
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||||
|
|
||||||
|
req := dto.TextVerifiedWebHookReq{}
|
||||||
|
s := service.SmsTextVerified{}
|
||||||
|
|
||||||
|
err = e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
Bind(&req).
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.TextVerifiedWebHook(&req)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(500, gin.H{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Status(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验签方法
|
||||||
|
func verifyWebhookSignature(header string, body []byte, secret string) bool {
|
||||||
|
const prefix = "HMAC-SHA512="
|
||||||
|
if !strings.HasPrefix(header, prefix) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sigBase64 := strings.TrimPrefix(header, prefix)
|
||||||
|
|
||||||
|
mac := hmac.New(sha512.New, []byte(secret))
|
||||||
|
mac.Write(body)
|
||||||
|
expectedMAC := mac.Sum(nil)
|
||||||
|
expectedBase64 := base64.StdEncoding.EncodeToString(expectedMAC)
|
||||||
|
|
||||||
|
return hmac.Equal([]byte(sigBase64), []byte(expectedBase64))
|
||||||
|
}
|
||||||
|
|||||||
@ -226,6 +226,12 @@ func (e SmsServices) GetPrice(c *gin.Context) {
|
|||||||
e.Error(500, err, err.Error())
|
e.Error(500, err, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.Valid() != nil {
|
||||||
|
e.Error(500, req.Valid(), req.Valid().Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
price, err := s.GetPrice(&req)
|
price, err := s.GetPrice(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Logger.Errorf("获取价格失败,\r\n失败信息 %s", err.Error())
|
e.Logger.Errorf("获取价格失败,\r\n失败信息 %s", err.Error())
|
||||||
@ -234,3 +240,25 @@ func (e SmsServices) GetPrice(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
e.OK(price, "获取价格成功")
|
e.OK(price, "获取价格成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取翻译平台
|
||||||
|
func (e SmsServices) GetPlatform(c *gin.Context) {
|
||||||
|
s := service.SmsServices{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
list := make([]dto.SmsPlatformGetListResp, 0)
|
||||||
|
err = s.GetPlatform(&list)
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Errorf("获取翻译平台失败,\r\n失败信息 %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(list, "获取翻译平台成功")
|
||||||
|
}
|
||||||
|
|||||||
@ -492,3 +492,61 @@ func (e SysUser) GetInfo(c *gin.Context) {
|
|||||||
mp["code"] = 200
|
mp["code"] = 200
|
||||||
e.OK(mp, "")
|
e.OK(mp, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e SysUser) GetApiInfo(c *gin.Context) {
|
||||||
|
s := service.MemberApi{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userId := user.GetUserId(c)
|
||||||
|
memberData := dto.MemberApiResp{}
|
||||||
|
err = s.GetByUserId(userId, &memberData)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(memberData, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改Api状态
|
||||||
|
func (e SysUser) ChangeApiStatus(c *gin.Context) {
|
||||||
|
req := dto.MemberApiChangeStatusReq{}
|
||||||
|
s := service.MemberApi{}
|
||||||
|
err := e.MakeContext(c).
|
||||||
|
MakeOrm().
|
||||||
|
MakeService(&s.Service).
|
||||||
|
Bind(&req).
|
||||||
|
Errors
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := req.Validate(); err != nil {
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userId := user.GetUserId(c)
|
||||||
|
err = s.ChangeStatus(req.Id, userId, req.Status)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Logger.Errorf("修改api状态失败")
|
||||||
|
|
||||||
|
e.Error(500, err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.OK(nil, "")
|
||||||
|
}
|
||||||
|
|||||||
13
app/admin/models/member_api.go
Normal file
13
app/admin/models/member_api.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "go-admin/common/models"
|
||||||
|
|
||||||
|
type MemberApi struct {
|
||||||
|
models.Model
|
||||||
|
|
||||||
|
UserId int `json:"userId" gorm:"type:bigint;comment:用户id"`
|
||||||
|
ApiKey string `json:"api" gorm:"type:varchar(255);comment:api_key"`
|
||||||
|
Status int `json:"status" gorm:"type:tinyint;comment:状态 1-启用 2-禁用"`
|
||||||
|
models.ModelTime
|
||||||
|
models.ControlBy
|
||||||
|
}
|
||||||
@ -10,15 +10,16 @@ import (
|
|||||||
type SmsPhone struct {
|
type SmsPhone struct {
|
||||||
models.Model
|
models.Model
|
||||||
|
|
||||||
|
PlatformCode string `json:"platformCode" gorm:"type:varchar(20);comment:平台code"`
|
||||||
UserId int `json:"userId" gorm:"type:bigint;comment:用户Id"`
|
UserId int `json:"userId" gorm:"type:bigint;comment:用户Id"`
|
||||||
Service string `json:"service" gorm:"type:varchar(50);comment:sms 服务"`
|
Service string `json:"service" gorm:"type:varchar(50);comment:sms 服务"`
|
||||||
ServiceCode string `json:"serviceCode" gorm:"type:varchar(30);comment:服务code"`
|
ServiceCode string `json:"serviceCode" gorm:"type:varchar(30);comment:服务code"`
|
||||||
Type int `json:"type" gorm:"type:tinyint;comment:类型 0-短效 1-长效"`
|
Type int `json:"type" gorm:"type:tinyint;comment:类型 0-短效 1-长效"`
|
||||||
Period int `json:"period" gorm:"type:int;comment:时长(月)"`
|
Period int `json:"period" gorm:"type:int;comment:时长(月)"`
|
||||||
Phone string `json:"phone" gorm:"type:varchar(30);comment:号码"`
|
Phone string `json:"phone" gorm:"type:varchar(30);comment:号码"`
|
||||||
ActivationId int `json:"activationId" gorm:"type:int;comment:激活码id"`
|
ActivationId string `json:"activationId" gorm:"type:varchar(50);comment:激活码id"`
|
||||||
NewActivationId int `json:"newActivationId" gorm:"type:int;comment:新激活码id 每次获取验证码会刷新"`
|
NewActivationId string `json:"newActivationId" gorm:"type:varchar(50);comment:新激活码id 每次获取验证码会刷新"`
|
||||||
MessageId int `json:"messageId" gorm:"type:int;comment:短信模板id"`
|
MessageId string `json:"messageId" gorm:"type:varchar(50);comment:短信模板id"`
|
||||||
Code string `json:"code" gorm:"type:varchar(10);comment:验证码"`
|
Code string `json:"code" gorm:"type:varchar(10);comment:验证码"`
|
||||||
Status int `json:"status" gorm:"type:tinyint;comment:状态 1-等待验证码 2-已获取"`
|
Status int `json:"status" gorm:"type:tinyint;comment:状态 1-等待验证码 2-已获取"`
|
||||||
ExpireTime *time.Time `json:"expireTime" gorm:"type:datetime;comment:过期时间"`
|
ExpireTime *time.Time `json:"expireTime" gorm:"type:datetime;comment:过期时间"`
|
||||||
|
|||||||
@ -2,15 +2,21 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go-admin/common/models"
|
"go-admin/common/models"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SmsServices struct {
|
type SmsServices struct {
|
||||||
models.Model
|
models.Model
|
||||||
|
|
||||||
|
PlatformCode string `json:"platformCode" gorm:"type:varchar(20);comment:平台编码"`
|
||||||
Name string `json:"name" gorm:"type:varchar(255);comment:服务名称"`
|
Name string `json:"name" gorm:"type:varchar(255);comment:服务名称"`
|
||||||
Code string `json:"code" gorm:"type:varchar(50);comment:编码"`
|
Code string `json:"code" gorm:"type:varchar(50);comment:编码"`
|
||||||
ExpirationMinutes int `json:"expirationMinutes" gorm:"type:int;comment:过期时间(分钟)"`
|
ExpirationMinutes int `json:"expirationMinutes" gorm:"type:int;comment:过期时间(分钟)"`
|
||||||
Status int `json:"status" gorm:"type:tinyint;comment:状态 1-启用 2-禁用"`
|
Status int `json:"status" gorm:"type:tinyint;comment:状态 1-启用 2-禁用"`
|
||||||
|
Price decimal.Decimal `json:"price" gorm:"type:decimal(10,2);comment:价格"`
|
||||||
|
LongPrice decimal.Decimal `json:"longPrice" gorm:"type:decimal(10,2);comment:长号码价格"`
|
||||||
|
Icon string `json:"icon" gorm:"type:varchar(255);comment:图标"`
|
||||||
models.ModelTime
|
models.ModelTime
|
||||||
models.ControlBy
|
models.ControlBy
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,16 @@ func registerSmsPhoneRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddl
|
|||||||
r1.PUT("auto-renewal", api.ChangeAutoRenew) //修改自动续费状态
|
r1.PUT("auto-renewal", api.ChangeAutoRenew) //修改自动续费状态
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r2 := v1.Group("/sms").Use(middleware.FrontedAuth)
|
||||||
|
{
|
||||||
|
r2.POST("getNumber", api.OpenGetNumber) // 开放接口 租赁号码
|
||||||
|
r2.GET("getCodeByActivationId", api.OpenGetCodeByActivationId) //开放接口-获取验证码
|
||||||
|
r2.PUT("cancel", api.OpenCancel) //开放接口-取消号码
|
||||||
|
r2.PUT("auto-renewal", api.OpenAutoRenewal) //开放接口-修改自动续费
|
||||||
|
r2.GET("services", api.OpenGetServices) //开放接口-获取服务列表
|
||||||
|
r2.POST("weak-up", api.OpenWeakUp) //开放接口-唤醒号码
|
||||||
|
}
|
||||||
|
|
||||||
r := v1.Group("/sms-phone").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
|
r := v1.Group("/sms-phone").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
|
||||||
{
|
{
|
||||||
r.GET("", actions.PermissionAction(), api.GetPage)
|
r.GET("", actions.PermissionAction(), api.GetPage)
|
||||||
|
|||||||
@ -28,5 +28,6 @@ func registerSmsReceiveLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWT
|
|||||||
r1 := v1.Group("sms-receive-log")
|
r1 := v1.Group("sms-receive-log")
|
||||||
{
|
{
|
||||||
r1.POST("webhook", api.WebHook) //接收短信发送记录回调
|
r1.POST("webhook", api.WebHook) //接收短信发送记录回调
|
||||||
|
r1.POST("text-verified-webhook", api.TextVerifiedWebHook) //接收TextVerified短信发送记录回调
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,8 @@ func registerSmsServicesRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMi
|
|||||||
|
|
||||||
r1 := v1.Group("/sms-services").Use(authMiddleware.MiddlewareFunc())
|
r1 := v1.Group("/sms-services").Use(authMiddleware.MiddlewareFunc())
|
||||||
{
|
{
|
||||||
r1.GET("list", api.GetList) //获取服务列表
|
r1.GET("/platform", api.GetPlatform) //获取平台列表
|
||||||
r1.GET("price", api.GetPrice) //获取服务价格
|
r1.GET("/list", api.GetList) //获取服务列表
|
||||||
|
r1.GET("/price", api.GetPrice) //获取服务价格
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
|
|
||||||
"go-admin/app/admin/apis"
|
"go-admin/app/admin/apis"
|
||||||
"go-admin/common/actions"
|
"go-admin/common/actions"
|
||||||
"go-admin/common/middleware"
|
"go-admin/common/middleware"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -35,5 +36,7 @@ func registerSysUserRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddle
|
|||||||
v1auth := v1.Group("").Use(authMiddleware.MiddlewareFunc())
|
v1auth := v1.Group("").Use(authMiddleware.MiddlewareFunc())
|
||||||
{
|
{
|
||||||
v1auth.GET("/getinfo", api.GetInfo)
|
v1auth.GET("/getinfo", api.GetInfo)
|
||||||
|
v1auth.GET("/api-info", api.GetApiInfo)
|
||||||
|
v1auth.PUT("/api-info", api.ChangeApiStatus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,7 +44,7 @@ func (e *CliProxyService) GetTrafficInfo() ([]dto.CliProxyTraffics, error) {
|
|||||||
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.CliproxyUrl, headers)
|
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.CliproxyUrl, headers)
|
||||||
api := "/json/traffic_coutry.json"
|
api := "/json/traffic_coutry.json"
|
||||||
|
|
||||||
err := client.Get(api, nil, &resp)
|
_, err := client.Get(api, nil, &resp)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
30
app/admin/service/dto/member_api.go
Normal file
30
app/admin/service/dto/member_api.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
type MemberApiInsertReq struct {
|
||||||
|
UserId int `json:"userId" gorm:"type:bigint;comment:用户id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MemberApiResp struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
UserId int `json:"userId" gorm:"type:bigint;comment:用户id"`
|
||||||
|
ApiKey string `json:"api" gorm:"type:varchar(255);comment:apiKey"`
|
||||||
|
Status int `json:"status" gorm:"type:tinyint;comment:状态 1-启用 2-禁用"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MemberApiChangeStatusReq struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Status int `json:"status" comment:"1-启用 2-禁用"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *MemberApiChangeStatusReq) Validate() error {
|
||||||
|
if e.Id <= 0 {
|
||||||
|
return errors.New("id不能为空")
|
||||||
|
}
|
||||||
|
if e.Status != 1 && e.Status != 2 {
|
||||||
|
return errors.New("状态不正确")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -5,11 +5,15 @@ import (
|
|||||||
"go-admin/app/admin/models"
|
"go-admin/app/admin/models"
|
||||||
"go-admin/common/dto"
|
"go-admin/common/dto"
|
||||||
common "go-admin/common/models"
|
common "go-admin/common/models"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SmsPhoneGetPageReq struct {
|
type SmsPhoneGetPageReq struct {
|
||||||
dto.Pagination `search:"-"`
|
dto.Pagination `search:"-"`
|
||||||
Service string `form:"service" search:"type:exact;column:service;table:sms_phone" comment:"sms 服务"`
|
Service string `form:"service" search:"type:exact;column:service;table:sms_phone" comment:"sms 服务"`
|
||||||
|
PlatformCode string `form:"platformCode" search:"type:exact;column:platform_code;table:sms_phone" comment:"平台code"`
|
||||||
ServiceCode string `form:"serviceCode" search:"type:exact;column:service_code;table:sms_phone" comment:"服务code"`
|
ServiceCode string `form:"serviceCode" search:"type:exact;column:service_code;table:sms_phone" comment:"服务code"`
|
||||||
Type int `form:"type" search:"-" comment:"类型 0-短效 1-长效"`
|
Type int `form:"type" search:"-" comment:"类型 0-短效 1-长效"`
|
||||||
SmsPhoneOrder
|
SmsPhoneOrder
|
||||||
@ -109,6 +113,7 @@ func (s *SmsPhoneDeleteReq) GetId() interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetNumberReq struct {
|
type GetNumberReq struct {
|
||||||
|
PlatformCode string `json:"platformCode" form:"platformCode" commment:"平台code"`
|
||||||
Type int `json:"type" form:"type" comment:"类型 0-短效 1-长效"`
|
Type int `json:"type" form:"type" comment:"类型 0-短效 1-长效"`
|
||||||
ServiceCode string `json:"serviceCode" form:"serviceCode" comment:"服务code"`
|
ServiceCode string `json:"serviceCode" form:"serviceCode" comment:"服务code"`
|
||||||
Period int `json:"period" form:"period" comment:"时长(月)"`
|
Period int `json:"period" form:"period" comment:"时长(月)"`
|
||||||
@ -131,21 +136,26 @@ func (s *GetNumberReq) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetCodeReq struct {
|
type GetCodeReq struct {
|
||||||
ActivationIds []int `form:"activationIds"`
|
ActivationIds []string `form:"activationIds"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetCodeResp struct {
|
type GetCodeResp struct {
|
||||||
ActivationId int `json:"activationId" comment:"激活码id"`
|
ActivationId string `json:"activationId" comment:"激活码id"`
|
||||||
Code string `json:"code" comment:"验证码"`
|
Code string `json:"code" comment:"验证码"`
|
||||||
Status int `json:"status" comment:"状态 1-等待验证码 2-已获取"`
|
Status int `json:"status" comment:"状态 1-等待验证码 2-已获取"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WeakUpReq struct {
|
type WeakUpReq struct {
|
||||||
ActivationId int `json:"activationId" comment:"激活码id"`
|
ActivationId string `json:"activationId" comment:"激活码id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WeakUpResp struct {
|
||||||
|
ActivationId string `json:"activationId" comment:"激活id"`
|
||||||
|
MessageId string `json:"messageId" commment:"消息id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WeakUpReq) Validate() error {
|
func (s *WeakUpReq) Validate() error {
|
||||||
if s.ActivationId <= 0 {
|
if s.ActivationId == "" {
|
||||||
return errors.New("激活码id不能为空")
|
return errors.New("激活码id不能为空")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,13 +176,41 @@ func (s *DeleteMyNumberReq) Validate() error {
|
|||||||
|
|
||||||
type SmsPhoneCancelNumberReq struct {
|
type SmsPhoneCancelNumberReq struct {
|
||||||
Id int `json:"id" comment:"短信号码id"`
|
Id int `json:"id" comment:"短信号码id"`
|
||||||
|
ActivationId string `json:"activationId" comment:"短信id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SmsPhoneChangeAutoRenewReq struct {
|
type SmsPhoneChangeAutoRenewReq struct {
|
||||||
Id int `json:"id" comment:"短信号码id"`
|
Id int `json:"id" comment:"短信号码id"`
|
||||||
|
ActivationId string `json:"activationId" comment:"激活码id id或activationId "`
|
||||||
AutoRenew int `json:"autoRenew" comment:"是否自动续费 1-不自动续费 2-自动续费"`
|
AutoRenew int `json:"autoRenew" comment:"是否自动续费 1-不自动续费 2-自动续费"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SmsPhoneCleanMyPhoneReq struct {
|
type SmsPhoneCleanMyPhoneReq struct {
|
||||||
Type int `json:"type" comment:"类型 0-短效 1-长效"`
|
Type int `json:"type" comment:"类型 0-短效 1-长效"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SmsPhoneGetPhoneResp struct {
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
EndAt *time.Time `json:"endTime"`
|
||||||
|
Id string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DaisysmsPriceResp struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
Cost string `json:"cost" comment:"单价"`
|
||||||
|
Repeatable bool `json:"repeatable"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpenGetNumberResp struct {
|
||||||
|
Blance decimal.Decimal `json:"balance"`
|
||||||
|
Number string `json:"number"`
|
||||||
|
ActivationId string `json:"activationId"`
|
||||||
|
ExpireTime *time.Time `json:"expireTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpenWakeUpReq struct {
|
||||||
|
PlatformCode string `json:"platformCode" comment:"短信平台"`
|
||||||
|
ActivationId string `json:"activationId" comment:"平台id"`
|
||||||
|
}
|
||||||
|
|||||||
@ -1,13 +1,19 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"go-admin/app/admin/models"
|
"go-admin/app/admin/models"
|
||||||
"go-admin/common/dto"
|
"go-admin/common/dto"
|
||||||
common "go-admin/common/models"
|
common "go-admin/common/models"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SmsServicesGetPageReq struct {
|
type SmsServicesGetPageReq struct {
|
||||||
dto.Pagination `search:"-"`
|
dto.Pagination `search:"-"`
|
||||||
|
PlatformCode string `form:"platformCode" search:"type:exact;column:platform_code;table:sms_services" comment:"平台编码"`
|
||||||
|
Name string `form:"name" search:"type:contains;column:name;table:sms_services" comment:"服务名称"`
|
||||||
|
Status int `form:"status" search:"-"`
|
||||||
SmsServicesOrder
|
SmsServicesOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +36,11 @@ type SmsServicesInsertReq struct {
|
|||||||
Id int `json:"-" comment:""` //
|
Id int `json:"-" comment:""` //
|
||||||
Name string `json:"name" comment:"服务名称"`
|
Name string `json:"name" comment:"服务名称"`
|
||||||
Code string `json:"code" comment:"编码"`
|
Code string `json:"code" comment:"编码"`
|
||||||
|
PlatformCode string `json:"platformCode" comment:"平台编码"`
|
||||||
|
Status int `json:"status" comment:"状态 1-启用 2-禁"`
|
||||||
|
Price decimal.Decimal `json:"price" comment:"价格"`
|
||||||
|
LongPrice decimal.Decimal `json:"longPrice" comment:"长号码价格"`
|
||||||
|
ExpirationMinutes int `json:"expirationMinutes" comment:"过期时间(分钟)"`
|
||||||
common.ControlBy
|
common.ControlBy
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +50,11 @@ func (s *SmsServicesInsertReq) Generate(model *models.SmsServices) {
|
|||||||
}
|
}
|
||||||
model.Name = s.Name
|
model.Name = s.Name
|
||||||
model.Code = s.Code
|
model.Code = s.Code
|
||||||
|
model.PlatformCode = s.PlatformCode
|
||||||
|
model.Status = s.Status
|
||||||
|
model.Price = s.Price
|
||||||
|
model.LongPrice = s.LongPrice
|
||||||
|
model.ExpirationMinutes = s.ExpirationMinutes
|
||||||
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +66,11 @@ type SmsServicesUpdateReq struct {
|
|||||||
Id int `uri:"id" comment:""` //
|
Id int `uri:"id" comment:""` //
|
||||||
Name string `json:"name" comment:"服务名称"`
|
Name string `json:"name" comment:"服务名称"`
|
||||||
Code string `json:"code" comment:"编码"`
|
Code string `json:"code" comment:"编码"`
|
||||||
|
PlatformCode string `json:"platformCode" comment:"平台编码"`
|
||||||
|
Status int `json:"status" comment:"状态 1-启用 2-禁"`
|
||||||
|
Price decimal.Decimal `json:"price" comment:"价格"`
|
||||||
|
LongPrice decimal.Decimal `json:"longPrice" comment:"长号码价格"`
|
||||||
|
ExpirationMinutes int `json:"expirationMinutes" comment:"过期时间(分钟)"`
|
||||||
common.ControlBy
|
common.ControlBy
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +80,11 @@ func (s *SmsServicesUpdateReq) Generate(model *models.SmsServices) {
|
|||||||
}
|
}
|
||||||
model.Name = s.Name
|
model.Name = s.Name
|
||||||
model.Code = s.Code
|
model.Code = s.Code
|
||||||
|
model.PlatformCode = s.PlatformCode
|
||||||
|
model.Status = s.Status
|
||||||
|
model.Price = s.Price
|
||||||
|
model.LongPrice = s.LongPrice
|
||||||
|
model.ExpirationMinutes = s.ExpirationMinutes
|
||||||
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,11 +111,38 @@ func (s *SmsServicesDeleteReq) GetId() interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SmsServicesGetListResp struct {
|
type SmsServicesGetListResp struct {
|
||||||
Name string `json:"name" comment:"服务名称"`
|
PlatformCode string `json:"platformCode" comment:"平台编码"`
|
||||||
|
PlatformName string `json:"platformName" comment:"平台名称"`
|
||||||
Code string `json:"code" comment:"编码"`
|
Code string `json:"code" comment:"编码"`
|
||||||
|
Name string `json:"name" comment:"服务名称"`
|
||||||
Status int `json:"status" comment:"状态"`
|
Status int `json:"status" comment:"状态"`
|
||||||
|
Price decimal.Decimal `json:"price" comment:"价格"`
|
||||||
|
LongPrice decimal.Decimal `json:"longPrice" comment:"长号码价格"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SmsGetPriceReq struct {
|
type SmsGetPriceReq struct {
|
||||||
|
PlatformCode string `json:"platformCode" form:"platformCode" comment:"平台code"`
|
||||||
|
ServiceCode string `json:"serviceCode" form:"serviceCode" comment:"服务code"`
|
||||||
Type int `json:"type" form:"type" comment:"类型"`
|
Type int `json:"type" form:"type" comment:"类型"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *SmsGetPriceReq) Valid() error {
|
||||||
|
if e.PlatformCode == "" {
|
||||||
|
return errors.New("平台code不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.ServiceCode == "" {
|
||||||
|
return errors.New("服务code不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Type < 0 || e.Type > 1 {
|
||||||
|
return errors.New("类型错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SmsPlatformGetListResp struct {
|
||||||
|
Label string `json:"label" comment:"平台名称"`
|
||||||
|
Value string `json:"value" comment:"平台code"`
|
||||||
|
}
|
||||||
|
|||||||
214
app/admin/service/dto/text_verified.go
Normal file
214
app/admin/service/dto/text_verified.go
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 登录相应
|
||||||
|
type TextVerifiedLoginResp struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
ExpiresIn int `json:"expiresIn"`
|
||||||
|
ExpiresAt string `json:"expiresAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取区号响应
|
||||||
|
type TextVerifiedAreaResp struct {
|
||||||
|
AreaCode string `json:"areaCode"`
|
||||||
|
State string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 服务列表
|
||||||
|
type TextVerifiedServeResp struct {
|
||||||
|
ServiceName string `json:"serviceName"`
|
||||||
|
Capability string `json:"capability"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建租赁
|
||||||
|
type TextVerifiedCreateRewalReq struct {
|
||||||
|
AllowBackOrderReservations bool `json:"allowBackOrderReservations" comment:"如果设置为 true,当请求的租赁商品缺货时,将创建租赁订单"`
|
||||||
|
AlwaysOn bool `json:"alwaysOn" comment:"如果设置为 true,则有库存时将分配一条不需要唤醒的线路"`
|
||||||
|
AreaCodeSelectOption []string `json:"areaCodeSelectOption" comment:"可选的区号数组"`
|
||||||
|
Duration string `json:"duration" comment:"枚举 oneDay┃threeDay┃sevenDay┃fourteenDay┃thirtyDay┃ninetyDay┃oneYear"`
|
||||||
|
IsRenewable bool `json:"isRenewable" comment:"是否可再生"`
|
||||||
|
NumberType string `json:"numberType" comment:"枚举 mobile┃voip┃landline"`
|
||||||
|
BillingCycleIdToAssignTo string `json:"billingCycleIdToAssignTo"`
|
||||||
|
ServiceName string `json:"serviceName"`
|
||||||
|
Capability string `json:"capability" comment:"枚举 sms┃call┃smsAndCall"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回调请求
|
||||||
|
type TextVerifiedWebHookReq struct {
|
||||||
|
Attempt int `json:"attempt" comment:"尝试次数"`
|
||||||
|
OccurredAt string `json:"occurredAt" comment:"发生时间"`
|
||||||
|
Event string `json:"event" comment:"事件类型 v2.rental.billingcycle.renewed | v2.rental.billingcycle.expired | v2.sms.received | v2.rental.backorder.fulfilled | v2.reservation.created"`
|
||||||
|
Id string `json:"id" comment:"唯一标识"`
|
||||||
|
Data map[string]interface{} `json:"data" comment:"数据"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 续费成功回调请求
|
||||||
|
type TextVerifiedWebHookRenewedReq struct {
|
||||||
|
BillingCycleId string `json:"billingCycleId" comment:"续费的计费周期ID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计费周期过期回调请求 - 当您帐户的计费周期到期时触发。
|
||||||
|
type TextVerifiedWebHookBillingCycleExpiredReq struct {
|
||||||
|
BillingCycleId string `json:"billingCycleId" comment:"过期的计费周期ID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 收到短信回调请求 - 当收到短信并将其分配到您的帐户时触发。
|
||||||
|
type TextVerifiedWebHookSmsReceivedReq struct {
|
||||||
|
From string `json:"from" comment:"发送号码"`
|
||||||
|
To string `json:"to" comment:"接收号码"`
|
||||||
|
CreatedAt string `json:"createdAt" comment:"创建时间"`
|
||||||
|
SmsContent string `json:"smsContent" comment:"短信内容"`
|
||||||
|
ParsedCode string `json:"parsedCode" comment:"解析后的验证码"`
|
||||||
|
Encrypted bool `json:"encrypted" comment:"短信内容是否静态加密 "`
|
||||||
|
ReservationId string `json:"reservationId" comment:"此短信被分配到的预订的 ID。"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单预定完成时触发
|
||||||
|
type TextVerifiedWebHookFulfilledReq struct {
|
||||||
|
BackOrderId string `json:"backOrderId" comment:"订单预定ID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 预定订单创建回调
|
||||||
|
type TextVerifiedWebHookReservationCreatedReq struct {
|
||||||
|
Id string `json:"id" comment:"订单ID"`
|
||||||
|
Type string `json:"type" comment:"订单类型 verifications | rentals"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 唤醒请求
|
||||||
|
type TextVerifiedWakeUpReq struct {
|
||||||
|
RevervationId string `json:"reservationId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 唤醒响应
|
||||||
|
type TextVerifiedWakeUpResp struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
UsageWindowStart *time.Time `json:"usageWindowStart"`
|
||||||
|
UsageWindowEnd *time.Time `json:"usageWindowEnd"`
|
||||||
|
IsScheduled bool `json:"isScheduled"`
|
||||||
|
ReservationId string `json:"reservationId" comment:"预定id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求统一响应
|
||||||
|
type TextVerifiedResp struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
Href string `json:"href"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextVerifiedCreateRentalReservationDto struct {
|
||||||
|
ID string `json:"id" comment:"号码id"`
|
||||||
|
Link TextVerifiedResp `json:"link"`
|
||||||
|
ReservationType string `json:"reservationType"`
|
||||||
|
ServiceName string `json:"serviceName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 长效号码响应
|
||||||
|
type SaleResponse struct {
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
ID string `json:"id" comment:"销售id"`
|
||||||
|
BackOrderReservations []interface{} `json:"backOrderReservations"` // 由于数组为空,使用 interface{}
|
||||||
|
Reservations []TextVerifiedCreateRentalReservationDto `json:"reservations" comment:"号码信息"`
|
||||||
|
State string `json:"state"`
|
||||||
|
Total float64 `json:"total"`
|
||||||
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单次验证码创建后查询
|
||||||
|
type VerificationDTO struct {
|
||||||
|
Number string `json:"number"`
|
||||||
|
SMS TextVerifiedResp `json:"sms"`
|
||||||
|
Calls TextVerifiedResp `json:"calls"`
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
EndsAt time.Time `json:"endsAt"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
Cancel Action `json:"cancel"`
|
||||||
|
Reactivate Action `json:"reactivate"`
|
||||||
|
Report Action `json:"report"`
|
||||||
|
Reuse ReuseInfo `json:"reuse"`
|
||||||
|
Sale TextVerifiedResp `json:"sale"`
|
||||||
|
ServiceName string `json:"serviceName"`
|
||||||
|
// State 表示验证或服务的当前状态。
|
||||||
|
// 状态是以下枚举值之一,代表了从创建到完成或取消的生命周期:
|
||||||
|
// * verificationPending: 正在等待验证码。
|
||||||
|
// * verificationCompleted: 验证已成功完成。
|
||||||
|
// * verificationCanceled: 验证被取消。
|
||||||
|
// * verificationTimedOut: 验证因超时而失败。
|
||||||
|
// * verificationReported: 验证被举报。
|
||||||
|
// * verificationRefunded: 验证已退款。
|
||||||
|
// * verificationReused: 验证号码被重用。
|
||||||
|
// * verificationReactivated: 验证号码被重新激活。
|
||||||
|
//
|
||||||
|
// 对于可续订服务:
|
||||||
|
// * renewableActive: 服务活跃中。
|
||||||
|
// * renewableOverdue: 服务已逾期。
|
||||||
|
// * renewableExpired: 服务已过期。
|
||||||
|
// * renewableRefunded: 服务已退款。
|
||||||
|
//
|
||||||
|
// 对于不可续订服务:
|
||||||
|
// * nonrenewableActive: 服务活跃中。
|
||||||
|
// * nonrenewableExpired: 服务已过期。
|
||||||
|
// * nonrenewableRefunded: 服务已退款。
|
||||||
|
State string `json:"state" comment:"verificationPending┃verificationCompleted┃verificationCanceled┃verificationTimedOut┃verificationReported┃verificationRefunded┃verificationReused┃verificationReactivated┃renewableActive┃renewableOverdue┃renewableExpired┃renewableRefunded┃nonrenewableActive┃nonrenewableExpired┃nonrenewableRefunded"`
|
||||||
|
TotalCost float64 `json:"totalCost"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 长效详情
|
||||||
|
type VerificationRentalDetailResp struct {
|
||||||
|
Number string `json:"number"`
|
||||||
|
SMS TextVerifiedResp `json:"sms"`
|
||||||
|
Calls TextVerifiedResp `json:"calls"`
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
Sale TextVerifiedResp `json:"sale"`
|
||||||
|
SaleId string `json:"saleId"`
|
||||||
|
ServiceName string `json:"serviceName"`
|
||||||
|
State string `json:"state"`
|
||||||
|
AlwaysOn bool `json:"alwaysOn"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 包含可执行标志 + 链接
|
||||||
|
type Action struct {
|
||||||
|
CanCancel bool `json:"canCancel,omitempty"`
|
||||||
|
CanReactivate bool `json:"canReactivate,omitempty"`
|
||||||
|
CanReport bool `json:"canReport,omitempty"`
|
||||||
|
Link TextVerifiedResp `json:"link"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// reuse 特殊结构
|
||||||
|
type ReuseInfo struct {
|
||||||
|
Link TextVerifiedResp `json:"link"`
|
||||||
|
ReusableUntil *time.Time `json:"reusableUntil"` // null -> 指针可为空
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextVerifiedPriceReq struct {
|
||||||
|
ServiceName string `json:"serviceName" comment:"服务code"`
|
||||||
|
AreaCode bool `json:"areaCode" comment:"限制区域code"`
|
||||||
|
NumberType string `json:"numberType" comment:"mobile | voip | landline"`
|
||||||
|
Capability string `json:"capability" comment:"sms | mms | voice"`
|
||||||
|
AlwaysOn bool `json:"alwaysOn"`
|
||||||
|
IsRenewable bool `json:"isRenewable" comment:"是否可再生"`
|
||||||
|
Duration string `json:"duration" comment:"oneDay┃threeDay┃sevenDay┃fourteenDay┃thirtyDay┃ninetyDay┃oneYear"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextVerifiedPriceResp struct {
|
||||||
|
Price decimal.Decimal `json:"price"`
|
||||||
|
ServiceName string `json:"serviceName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextVerifiedSmsResp struct {
|
||||||
|
Data []TextVerifiedSmsItemResp `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextVerifiedSmsItemResp struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
From string `json:"from"`
|
||||||
|
To string `json:"to"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
SmsContent string `json:"smsContent"`
|
||||||
|
ParsedCode string `json:"parsedCode"`
|
||||||
|
Encrypted bool `json:"encrypted"`
|
||||||
|
}
|
||||||
110
app/admin/service/member_api.go
Normal file
110
app/admin/service/member_api.go
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/app/admin/service/dto"
|
||||||
|
"go-admin/common/rediskey"
|
||||||
|
"go-admin/utils/redishelper"
|
||||||
|
"go-admin/utils/utility"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MemberApi struct {
|
||||||
|
service.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e MemberApi) ChangeStatus(id, userId int, status int) error {
|
||||||
|
var api models.MemberApi
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&api).Where("id =? and user_id =?", id, userId).Update("status", status).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByUserId 通过用户ID获取用户信息
|
||||||
|
func (e *MemberApi) GetByUserId(userId int, memberData *dto.MemberApiResp) error {
|
||||||
|
var entity models.MemberApi
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&models.MemberApi{}).Where("user_id = ?", userId).First(&entity).Error; err != nil {
|
||||||
|
e.Log.Errorf("通过用户ID获取用户信息失败, %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
copier.Copy(memberData, &entity)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化用户API
|
||||||
|
func (e *MemberApi) InitApis() error {
|
||||||
|
var entitys []models.SysUser
|
||||||
|
var memberApis []models.MemberApi
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&models.SysUser{}).
|
||||||
|
Joins("LEFT JOIN member_api ON member_api.user_id = sys_user.user_id").
|
||||||
|
Where("member_api.id is null").Find(&entitys).Error; err != nil {
|
||||||
|
e.Log.Errorf("初始化 查询用户API失败, %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data models.MemberApi
|
||||||
|
for _, entity := range entitys {
|
||||||
|
e.CreateApi(entity.UserId, &data, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&models.MemberApi{}).Find(&memberApis).Error; err != nil {
|
||||||
|
e.Log.Errorf("初始化 查询用户API失败, %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range memberApis {
|
||||||
|
key := fmt.Sprintf(rediskey.MemberApiKey, item.ApiKey)
|
||||||
|
val, err := sonic.MarshalString(item)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("用户api 初始化失败")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := redishelper.DefaultRedis.SetString(key, val); err != nil {
|
||||||
|
e.Log.Errorf("用户api 初始化失败")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建api
|
||||||
|
func (e *MemberApi) CreateApi(userId int, user *models.MemberApi, retryCount int) error {
|
||||||
|
key, err := utility.GenerateBase62Key(32)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("生成API Key失败, %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
apiEntity := models.MemberApi{
|
||||||
|
UserId: userId,
|
||||||
|
ApiKey: key,
|
||||||
|
Status: 1, // 默认启用
|
||||||
|
}
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
e.Orm.Model(user).Where("api_key =?", key).Count(&count)
|
||||||
|
|
||||||
|
if count > 0 && retryCount < 1000 {
|
||||||
|
return e.CreateApi(userId, user, retryCount+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := e.Orm.Create(&apiEntity).Error; err != nil {
|
||||||
|
e.Log.Errorf("初始化用户API失败, %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
1
app/admin/service/open_common.go
Normal file
1
app/admin/service/open_common.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package service
|
||||||
355
app/admin/service/sms_daisysms.go
Normal file
355
app/admin/service/sms_daisysms.go
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/app/admin/service/dto"
|
||||||
|
"go-admin/common/global"
|
||||||
|
"go-admin/common/statuscode"
|
||||||
|
"go-admin/config"
|
||||||
|
"go-admin/utils/httphelper"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SmsDaisysms struct {
|
||||||
|
service.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步价格
|
||||||
|
func (e SmsDaisysms) SyncPrices() {
|
||||||
|
prices, err := e.GetPrices()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("GetPrices error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, price := range prices {
|
||||||
|
if err := e.Orm.Model(&models.SmsServices{}).Where("code =? and platform_code=?", price.Key, global.SmsPlatformDaisysms).Update("price", price.Cost).Error; err != nil {
|
||||||
|
e.Log.Errorf("Update price error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNumberForApi 获取短期或长期租赁号码
|
||||||
|
// getType 0-短效 1-长效
|
||||||
|
// service 服务code
|
||||||
|
// maxPrice 最大价格
|
||||||
|
// period 时长(月)
|
||||||
|
func (e *SmsDaisysms) GetNumberForApi(getType int, serviceCode string, maxPrice decimal.Decimal, period int) (int, string, int) {
|
||||||
|
acitvationId := 0
|
||||||
|
result := ""
|
||||||
|
resultCode := statuscode.Success
|
||||||
|
|
||||||
|
configResp, code := GetApiKey(e)
|
||||||
|
if code != statuscode.Success {
|
||||||
|
return acitvationId, result, code
|
||||||
|
}
|
||||||
|
url := fmt.Sprintf("?api_key=%s&action=getNumber&service=%s", configResp.ConfigValue, serviceCode)
|
||||||
|
|
||||||
|
if getType == 1 {
|
||||||
|
url = fmt.Sprintf("%s&duration=%dM", url, period)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
||||||
|
//ACCESS_NUMBER:999999:13476711222
|
||||||
|
bytes, _, err := client.GetRaw(url, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", err.Error())
|
||||||
|
|
||||||
|
if strings.Contains(err.Error(), "NO_NUMBERS") {
|
||||||
|
return acitvationId, result, statuscode.SmsOutOfStockOrUnavailable
|
||||||
|
} else {
|
||||||
|
return acitvationId, result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content := string(bytes)
|
||||||
|
|
||||||
|
if strings.Contains(content, "ACCESS_NUMBER:") {
|
||||||
|
if len(strings.Split(content, ":")) < 2 {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", content)
|
||||||
|
return acitvationId, result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
acitvationId, _ = strconv.Atoi(strings.Split(content, ":")[1])
|
||||||
|
result = strings.Split(content, ":")[2]
|
||||||
|
} else if strings.Contains(content, "MAX_PRICE_EXCEEDED:") {
|
||||||
|
e.Log.Errorf("租赁价格超过最大价格")
|
||||||
|
resultCode = statuscode.NoNumbers
|
||||||
|
} else if strings.Contains(content, "NO_NUMBERS") {
|
||||||
|
e.Log.Error("平台号码不足")
|
||||||
|
resultCode = statuscode.NoNumbers
|
||||||
|
} else if strings.Contains(content, "TOO_MANY_ACTIVE_RENTALS") {
|
||||||
|
e.Log.Error("租赁数量超过限制")
|
||||||
|
resultCode = statuscode.ServerError
|
||||||
|
} else if strings.Contains(content, "NO_MONEY") {
|
||||||
|
e.Log.Error("余额不足")
|
||||||
|
resultCode = statuscode.BalanceNotEnough
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", content)
|
||||||
|
resultCode = statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
return acitvationId, result, resultCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置租赁结束
|
||||||
|
func (e *SmsDaisysms) setStatus(id int) int {
|
||||||
|
configResp, code := GetApiKey(e)
|
||||||
|
if code != statuscode.Success {
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf("?api_key=%s&action=setStatus&id=%d&status=6", configResp.ConfigValue, id)
|
||||||
|
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
||||||
|
bytes, _, err := client.GetRaw(url, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", err.Error())
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
content := string(bytes)
|
||||||
|
|
||||||
|
if content == "ACCESS_ACTIVATION" {
|
||||||
|
return statuscode.Success
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", content)
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetApiKey(e *SmsDaisysms) (dto.GetSysConfigByKEYForServiceResp, int) {
|
||||||
|
configService := SysConfig{Service: e.Service}
|
||||||
|
configResp := dto.GetSysConfigByKEYForServiceResp{}
|
||||||
|
err := configService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: "sms_key"}, &configResp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取短信api失败, %s", err)
|
||||||
|
return dto.GetSysConfigByKEYForServiceResp{}, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
if configResp.ConfigValue == "" {
|
||||||
|
e.Log.Error("短信api不能为空")
|
||||||
|
return dto.GetSysConfigByKEYForServiceResp{}, statuscode.ServerError
|
||||||
|
}
|
||||||
|
return configResp, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCodeForApi 获取验证码
|
||||||
|
// messageId 短信id
|
||||||
|
// return 验证码, 状态码
|
||||||
|
func (e *SmsDaisysms) GetCodeForApi(messageId string) (string, int) {
|
||||||
|
result := ""
|
||||||
|
key, code := GetApiKey(e)
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
return result, code
|
||||||
|
}
|
||||||
|
url := fmt.Sprintf("?api_key=%s&action=getStatus&id=%s", key.ConfigValue, messageId)
|
||||||
|
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
||||||
|
bytes, _, err := client.GetRaw(url, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", err.Error())
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
content := string(bytes)
|
||||||
|
|
||||||
|
if strings.Contains(content, "STATUS_OK:") && content != "STATUS_OK:KEEP" {
|
||||||
|
result = strings.Split(content, ":")[1]
|
||||||
|
} else if content == "NO_ACTIVATION" {
|
||||||
|
code = statuscode.SmsNoActivation
|
||||||
|
} else if content == "STATUS_WAIT_CODE" || content == "STATUS_OK:KEEP" {
|
||||||
|
code = statuscode.SmsWaitCode
|
||||||
|
} else if content == "STATUS_CANCEL" {
|
||||||
|
code = statuscode.SmsCancel
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", content)
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, code
|
||||||
|
}
|
||||||
|
|
||||||
|
// getExtraActivation 获取额外的激活
|
||||||
|
// messageId 短信id
|
||||||
|
// return 验证码, 状态码
|
||||||
|
func (e *SmsDaisysms) getExtraActivation(activationId string) (int, int) {
|
||||||
|
result := 0
|
||||||
|
key, err := GetApiKey(e)
|
||||||
|
if err != statuscode.Success {
|
||||||
|
return 0, statuscode.ServerError
|
||||||
|
}
|
||||||
|
url := fmt.Sprintf("?api_key=%s&action=getExtraActivation&activationId=%s", key.ConfigValue, activationId)
|
||||||
|
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
||||||
|
bytes, _, err1 := client.GetRaw(url, nil)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", err1.Error())
|
||||||
|
return 0, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
content := string(bytes)
|
||||||
|
|
||||||
|
if strings.Contains(content, "ASLEEP:") {
|
||||||
|
message := strings.Split(content, ":")[1]
|
||||||
|
result, _ = strconv.Atoi(message)
|
||||||
|
|
||||||
|
if result > 0 {
|
||||||
|
return result, statuscode.Success
|
||||||
|
}
|
||||||
|
} else if strings.Contains(content, "STATUS_OK:") {
|
||||||
|
return 0, statuscode.SmsLongNumWaitCode
|
||||||
|
} else if strings.Contains(content, "ACCESS_NUMBER:") {
|
||||||
|
message := strings.Split(content, ":")[1]
|
||||||
|
result, _ = strconv.Atoi(message)
|
||||||
|
|
||||||
|
if result > 0 {
|
||||||
|
return result, statuscode.Success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Log.Errorf("激活长效号码失败,%s", content)
|
||||||
|
|
||||||
|
return 0, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeepLongTerm 长期租赁
|
||||||
|
func (e *SmsDaisysms) KeepLongTerm(activationId string) int {
|
||||||
|
key, code := GetApiKey(e)
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf("?api_key=%s&action=keep&id=%s", key.ConfigValue, activationId)
|
||||||
|
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
||||||
|
bytes, _, err := client.GetRaw(url, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", err.Error())
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
content := string(bytes)
|
||||||
|
|
||||||
|
if content == "OK" {
|
||||||
|
return statuscode.Success
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", content)
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消租赁
|
||||||
|
func (e *SmsDaisysms) CancelRental(activationId string) int {
|
||||||
|
key, code := GetApiKey(e)
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Log.Errorf("租赁api请求失败 %s")
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf("?api_key=%s&action=setStatus&id=%s&status=8", key.ConfigValue, activationId)
|
||||||
|
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
||||||
|
bytes, _, err := client.GetRaw(url, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", err.Error())
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
content := string(bytes)
|
||||||
|
|
||||||
|
if content == "ACCESS_CANCEL" {
|
||||||
|
return statuscode.Success
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", content)
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取价格
|
||||||
|
func (e *SmsDaisysms) GetPrices() ([]dto.DaisysmsPriceResp, error) {
|
||||||
|
result := make([]dto.DaisysmsPriceResp, 0)
|
||||||
|
key, code := GetApiKey(e)
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Log.Errorf("租赁api请求失败 %s")
|
||||||
|
return result, errors.New("获取租赁ApiKey失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf("?api_key=%s&action=getPrices", key.ConfigValue)
|
||||||
|
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
||||||
|
bytes, status, err := client.GetRaw(url, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", err.Error())
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mapData := make(map[string]map[string]dto.DaisysmsPriceResp)
|
||||||
|
err = sonic.Unmarshal(bytes, &mapData)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("解析失败 %s", err.Error())
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData, ok := mapData["187"]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
e.Log.Errorf("获取 187数据失败")
|
||||||
|
|
||||||
|
return result, errors.New("获取 187数据失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != http.StatusOK {
|
||||||
|
return result, fmt.Errorf("获取价格失败 %d", status)
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, v := range rawData {
|
||||||
|
v.Key = key
|
||||||
|
|
||||||
|
result = append(result, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeAutoRenew 修改自动续期
|
||||||
|
// activationId 短信id
|
||||||
|
// status 状态
|
||||||
|
func (e *SmsDaisysms) ChangeAutoRenewForApi(activationId string, status bool) int {
|
||||||
|
key, err := GetApiKey(e)
|
||||||
|
|
||||||
|
if err != statuscode.Success {
|
||||||
|
e.Log.Errorf("查询sms api请求失败 %d", activationId)
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf("?api_key=%s&action=setAutoRenew&id=%s&value=%t", key.ConfigValue, activationId, status)
|
||||||
|
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
||||||
|
bytes, _, err1 := client.GetRaw(url, nil)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
e.Log.Errorf("租赁请求失败 %s", err1.Error())
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
content := string(bytes)
|
||||||
|
|
||||||
|
if content == "OK" {
|
||||||
|
return statuscode.Success
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("修改自动续期请求失败 id:%d, status:%t, %s", activationId, status, content)
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,9 +2,8 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/service"
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
@ -17,28 +16,55 @@ import (
|
|||||||
cDto "go-admin/common/dto"
|
cDto "go-admin/common/dto"
|
||||||
"go-admin/common/global"
|
"go-admin/common/global"
|
||||||
"go-admin/common/statuscode"
|
"go-admin/common/statuscode"
|
||||||
"go-admin/config"
|
|
||||||
"go-admin/utils/httphelper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type SmsPhone struct {
|
type SmsPhone struct {
|
||||||
service.Service
|
service.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// open-API 获取电话号码
|
||||||
|
func (e SmsPhone) OpenGetNumber(req *dto.GetNumberReq, userId int) (dto.OpenGetNumberResp, int) {
|
||||||
|
resp := dto.OpenGetNumberResp{}
|
||||||
|
balanceService := MemberBalance{Service: e.Service}
|
||||||
|
balance, smsPhone, i := e.DoGetNumber(&balanceService, req, userId)
|
||||||
|
|
||||||
|
resp.Blance = balance
|
||||||
|
if i != statuscode.Success {
|
||||||
|
return resp, i
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.ActivationId = smsPhone.NewActivationId
|
||||||
|
resp.ExpireTime = smsPhone.ExpireTime
|
||||||
|
resp.Number = smsPhone.Phone
|
||||||
|
|
||||||
|
return resp, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
// 取消等待
|
// 取消等待
|
||||||
func (e *SmsPhone) CancelNumber(req *dto.SmsPhoneCancelNumberReq, userId int) int {
|
func (e *SmsPhone) CancelNumber(req *dto.SmsPhoneCancelNumberReq, userId int) int {
|
||||||
var data models.SmsPhone
|
var data models.SmsPhone
|
||||||
|
|
||||||
|
if req.Id > 0 {
|
||||||
if err := e.Orm.Model(data).Where("id =? and user_id= ?", req.Id, userId).First(&data).Error; err != nil {
|
if err := e.Orm.Model(data).Where("id =? and user_id= ?", req.Id, userId).First(&data).Error; err != nil {
|
||||||
e.Log.Errorf("获取短信号码失败, %s", err)
|
e.Log.Errorf("获取短信号码失败, %s", err)
|
||||||
return statuscode.SmsNotExisted
|
return statuscode.SmsNotExisted
|
||||||
}
|
}
|
||||||
|
} else if req.ActivationId != "" {
|
||||||
|
if err := e.Orm.Model(data).Where("new_activation_id =? and user_id= ?", req.ActivationId, userId).First(&data).Error; err != nil {
|
||||||
|
e.Log.Errorf("获取短信号码失败, %s", err)
|
||||||
|
return statuscode.SmsNotExisted
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("id和activationId 都是空")
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
if data.Actived == 1 {
|
if data.Actived == 1 {
|
||||||
code := e.CancelRental(data.NewActivationId)
|
code := e.CancelNumberManage(&data)
|
||||||
|
|
||||||
if code == statuscode.Success {
|
if code == statuscode.Success {
|
||||||
err := e.Orm.Transaction(func(tx *gorm.DB) error {
|
err := e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
if err1 := e.Orm.Model(data).Updates(map[string]interface{}{"status": 3, "code": "", "actived": "3"}).Error; err1 != nil {
|
if err1 := e.Orm.Model(data).Updates(map[string]interface{}{"status": 3, "code": "", "actived": "3", "auto_renewal": 2}).Error; err1 != nil {
|
||||||
e.Log.Errorf("更新短信号码失败, %s", err1)
|
e.Log.Errorf("更新短信号码失败, %s", err1)
|
||||||
return err1
|
return err1
|
||||||
}
|
}
|
||||||
@ -63,6 +89,23 @@ func (e *SmsPhone) CancelNumber(req *dto.SmsPhoneCancelNumberReq, userId int) in
|
|||||||
return statuscode.Success
|
return statuscode.Success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 聚合取消
|
||||||
|
func (e *SmsPhone) CancelNumberManage(data *models.SmsPhone) int {
|
||||||
|
switch data.PlatformCode {
|
||||||
|
case global.SmsPlatformDaisysms:
|
||||||
|
service := SmsDaisysms{Service: e.Service}
|
||||||
|
|
||||||
|
return service.CancelRental(data.NewActivationId)
|
||||||
|
case global.SmsPlatformTextVerified:
|
||||||
|
service := SmsTextVerified{Service: e.Service}
|
||||||
|
|
||||||
|
return service.CancelRental(data.NewActivationId, data.Type)
|
||||||
|
default:
|
||||||
|
return statuscode.SmsPlatformUnavailable
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 删除断信号码
|
// 删除断信号码
|
||||||
func (e *SmsPhone) DeleteMyNumber(req *dto.DeleteMyNumberReq, userId int) int {
|
func (e *SmsPhone) DeleteMyNumber(req *dto.DeleteMyNumberReq, userId int) int {
|
||||||
var data models.SmsPhone
|
var data models.SmsPhone
|
||||||
@ -91,35 +134,56 @@ func (e *SmsPhone) DeleteMyNumber(req *dto.DeleteMyNumberReq, userId int) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 唤醒长效号码
|
// 唤醒长效号码
|
||||||
func (e *SmsPhone) WeakUp(req *dto.WeakUpReq, userId int) int {
|
func (e *SmsPhone) WeakUp(req *dto.WeakUpReq, userId int, defult bool) (dto.WeakUpResp, int) {
|
||||||
smsPhone := models.SmsPhone{}
|
smsPhone := models.SmsPhone{}
|
||||||
|
result := dto.WeakUpResp{}
|
||||||
if err := e.Orm.Model(smsPhone).Where("activation_id =? and user_id= ?", req.ActivationId, userId).First(&smsPhone).Error; err != nil {
|
if err := e.Orm.Model(smsPhone).Where("activation_id =? and user_id= ?", req.ActivationId, userId).First(&smsPhone).Error; err != nil {
|
||||||
e.Log.Errorf("获取短信号码失败, %s", err)
|
e.Log.Errorf("获取短信号码失败, %s", err)
|
||||||
return statuscode.ServerError
|
return result, statuscode.ServerError
|
||||||
}
|
}
|
||||||
|
|
||||||
if smsPhone.Status != 1 {
|
if smsPhone.Status != 1 || defult {
|
||||||
newActivationId, code := e.getExtraActivation(smsPhone.ActivationId)
|
newActivationId, messageId, code := e.WeakUpManage(&smsPhone)
|
||||||
|
|
||||||
if code == statuscode.ServerError {
|
if code == statuscode.ServerError {
|
||||||
return code
|
return result, code
|
||||||
} else if code == statuscode.Success {
|
} else if code == statuscode.Success {
|
||||||
if err := e.Orm.Model(smsPhone).Updates(map[string]interface{}{"new_activation_id": newActivationId, "status": 1, "code": ""}).Error; err != nil {
|
if err := e.Orm.Model(smsPhone).Updates(map[string]interface{}{"new_activation_id": newActivationId, "status": 1, "code": "", "message_id": messageId}).Error; err != nil {
|
||||||
e.Log.Errorf("更新短信号码失败, %s", err)
|
e.Log.Errorf("更新短信号码失败, %s", err)
|
||||||
return statuscode.ServerError
|
return result, statuscode.ServerError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.ActivationId = newActivationId
|
||||||
|
result.MessageId = messageId
|
||||||
} else if code == statuscode.SmsLongNumWaitCode {
|
} else if code == statuscode.SmsLongNumWaitCode {
|
||||||
e.Log.Info("无须唤醒")
|
e.Log.Info("无须唤醒")
|
||||||
if err := e.Orm.Model(smsPhone).Updates(map[string]interface{}{"status": 1, "code": ""}).Error; err != nil {
|
if err := e.Orm.Model(smsPhone).Updates(map[string]interface{}{"status": 1, "code": ""}).Error; err != nil {
|
||||||
e.Log.Errorf("更新短信号码失败, %s", err)
|
e.Log.Errorf("更新短信号码失败, %s", err)
|
||||||
return statuscode.ServerError
|
return result, statuscode.ServerError
|
||||||
}
|
}
|
||||||
|
|
||||||
return statuscode.Success
|
return result, statuscode.Success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return statuscode.Success
|
return result, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// 唤醒号码
|
||||||
|
// returns newActivationId,messageId, code
|
||||||
|
func (e *SmsPhone) WeakUpManage(req *models.SmsPhone) (string, string, int) {
|
||||||
|
switch req.PlatformCode {
|
||||||
|
case global.SmsPlatformDaisysms:
|
||||||
|
service := SmsDaisysms{Service: e.Service}
|
||||||
|
id, code := service.getExtraActivation(req.ActivationId)
|
||||||
|
return strconv.Itoa(id), "", code
|
||||||
|
case global.SmsPlatformTextVerified:
|
||||||
|
service := SmsTextVerified{Service: e.Service}
|
||||||
|
|
||||||
|
return service.getExtraActivation(req.NewActivationId)
|
||||||
|
default:
|
||||||
|
return "", "", statuscode.SmsPlatformUnavailable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分页查询自己的号码列表
|
// 分页查询自己的号码列表
|
||||||
@ -142,64 +206,89 @@ func (e *SmsPhone) GetMyPage(req *dto.SmsPhoneGetPageReq, userId int, phone *[]m
|
|||||||
|
|
||||||
// 租赁号码
|
// 租赁号码
|
||||||
func (e *SmsPhone) GetNumber(req *dto.GetNumberReq, userId int) (decimal.Decimal, int) {
|
func (e *SmsPhone) GetNumber(req *dto.GetNumberReq, userId int) (decimal.Decimal, int) {
|
||||||
|
balanceService := MemberBalance{Service: e.Service}
|
||||||
|
balance, _, i := e.DoGetNumber(&balanceService, req, userId)
|
||||||
|
if i != statuscode.Success {
|
||||||
|
return balance, i
|
||||||
|
}
|
||||||
|
|
||||||
|
balance = balanceService.GetBalance(userId)
|
||||||
|
|
||||||
|
return balance, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SmsPhone) DoGetNumber(balanceService *MemberBalance, req *dto.GetNumberReq, userId int) (decimal.Decimal, models.SmsPhone, int) {
|
||||||
config := dto.GetSysConfigByKEYForServiceResp{}
|
config := dto.GetSysConfigByKEYForServiceResp{}
|
||||||
configReq := dto.SysConfigByKeyReq{}
|
configReq := dto.SysConfigByKeyReq{}
|
||||||
configService := SysConfig{Service: e.Service}
|
configService := SysConfig{Service: e.Service}
|
||||||
|
smsServices := SmsServices{Service: e.Service}
|
||||||
if strings.ToLower(req.ServiceCode) != "wa" {
|
var price decimal.Decimal
|
||||||
return decimal.Zero, statuscode.SmsServiceUnavailable
|
serviceItem, err := smsServices.GetByCode(req.PlatformCode, req.ServiceCode)
|
||||||
}
|
|
||||||
|
|
||||||
if req.Type == 0 {
|
|
||||||
configReq.ConfigKey = "number_fee_short_term"
|
|
||||||
} else {
|
|
||||||
configReq.ConfigKey = "number_fee_long_term"
|
|
||||||
}
|
|
||||||
err := configService.GetWithKey(&configReq, &config)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return decimal.Zero, statuscode.ServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.ConfigValue == "" {
|
|
||||||
e.Log.Errorf("短期或长期租赁费用不能为空")
|
|
||||||
return decimal.Zero, statuscode.ServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
price, err := decimal.NewFromString(config.ConfigValue)
|
|
||||||
if err != nil {
|
|
||||||
e.Log.Errorf("短期或长期租赁费用格式错误")
|
|
||||||
return decimal.Zero, statuscode.ServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
smsService := SmsServices{Service: e.Service}
|
|
||||||
balanceService := MemberBalance{Service: e.Service}
|
|
||||||
balance := balanceService.GetBalance(userId)
|
|
||||||
serviceItem, err := smsService.GetByCode(req.ServiceCode)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Log.Errorf("短信服务报错:%v", err)
|
e.Log.Errorf("短信服务报错:%v", err)
|
||||||
return decimal.Zero, statuscode.ServerError
|
return decimal.Decimal{}, models.SmsPhone{}, statuscode.ServerError
|
||||||
}
|
}
|
||||||
|
|
||||||
if serviceItem.Code == "" {
|
if serviceItem.Code == "" {
|
||||||
e.Log.Error("短信服务不存在")
|
e.Log.Error("短信服务不存在")
|
||||||
return decimal.Zero, statuscode.ServerError
|
return decimal.Decimal{}, models.SmsPhone{}, statuscode.ServerError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case req.Type == 0 && req.PlatformCode == global.SmsPlatformDaisysms:
|
||||||
|
price = serviceItem.Price
|
||||||
|
configReq.ConfigKey = "number_premium_daisysms"
|
||||||
|
case req.Type == 0 && req.PlatformCode == global.SmsPlatformTextVerified:
|
||||||
|
price = serviceItem.Price
|
||||||
|
configReq.ConfigKey = "number_premium_textverified"
|
||||||
|
case req.Type == 1 && req.PlatformCode == global.SmsPlatformDaisysms:
|
||||||
|
price = serviceItem.LongPrice
|
||||||
|
configReq.ConfigKey = "long_number_premium_daisysms"
|
||||||
|
case req.Type == 1 && req.PlatformCode == global.SmsPlatformTextVerified:
|
||||||
|
price = serviceItem.LongPrice
|
||||||
|
configReq.ConfigKey = "long_number_premium_textverified"
|
||||||
|
}
|
||||||
|
err = configService.GetWithKey(&configReq, &config)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return decimal.Decimal{}, models.SmsPhone{}, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.ConfigValue == "" {
|
||||||
|
e.Log.Errorf("短期长期租赁浮动百分比不能为空")
|
||||||
|
return decimal.Decimal{}, models.SmsPhone{}, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
percent, err := decimal.NewFromString(config.ConfigValue)
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("短期或长期租赁费用格式错误")
|
||||||
|
return decimal.Decimal{}, models.SmsPhone{}, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
price = price.Mul(decimal.NewFromInt(100).Add(percent)).Div(decimal.NewFromInt(100))
|
||||||
|
|
||||||
|
if price.Cmp(decimal.Zero) <= 0 {
|
||||||
|
e.Log.Errorf("短期或长期租赁费用不能小于等于0")
|
||||||
|
return decimal.Decimal{}, models.SmsPhone{}, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
balance := balanceService.GetBalance(userId)
|
||||||
|
|
||||||
if balance.LessThan(price) {
|
if balance.LessThan(price) {
|
||||||
e.Log.Error("余额不足")
|
e.Log.Error("余额不足")
|
||||||
return decimal.Zero, statuscode.BalanceNotEnough
|
return decimal.Decimal{}, models.SmsPhone{}, statuscode.BalanceNotEnough
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
activationId, phone, code := e.GetNumberForApi(req.Type, req.ServiceCode, price, req.Period)
|
activationId, phone, code, expireTime := e.GetNumberManage(req.PlatformCode, req.Type, req.ServiceCode, price, req.Period)
|
||||||
|
|
||||||
if code != statuscode.Success {
|
if code != statuscode.Success {
|
||||||
return decimal.Zero, code
|
return decimal.Decimal{}, models.SmsPhone{}, code
|
||||||
}
|
}
|
||||||
|
|
||||||
smsPhone := models.SmsPhone{}
|
smsPhone := models.SmsPhone{}
|
||||||
|
smsPhone.PlatformCode = req.PlatformCode
|
||||||
smsPhone.Phone = phone
|
smsPhone.Phone = phone
|
||||||
smsPhone.UserId = userId
|
smsPhone.UserId = userId
|
||||||
smsPhone.Service = serviceItem.Name
|
smsPhone.Service = serviceItem.Name
|
||||||
@ -213,30 +302,45 @@ func (e *SmsPhone) GetNumber(req *dto.GetNumberReq, userId int) (decimal.Decimal
|
|||||||
|
|
||||||
smsPhone.Price = price
|
smsPhone.Price = price
|
||||||
if req.Type == 1 {
|
if req.Type == 1 {
|
||||||
|
if expireTime != nil {
|
||||||
|
smsPhone.ExpireTime = expireTime
|
||||||
|
} else {
|
||||||
days := req.Period * 30
|
days := req.Period * 30
|
||||||
now = now.AddDate(0, 0, days)
|
now = now.AddDate(0, 0, days)
|
||||||
smsPhone.ExpireTime = &now
|
smsPhone.ExpireTime = &now
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if expireTime != nil {
|
||||||
|
smsPhone.ExpireTime = expireTime
|
||||||
} else {
|
} else {
|
||||||
now = now.Add(time.Minute * time.Duration(serviceItem.ExpirationMinutes))
|
now = now.Add(time.Minute * time.Duration(serviceItem.ExpirationMinutes))
|
||||||
smsPhone.ExpireTime = &now
|
smsPhone.ExpireTime = &now
|
||||||
smsPhone.AutoRenewal = 2
|
smsPhone.AutoRenewal = 2
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
smsPhone.Status = 1
|
smsPhone.Status = 1
|
||||||
|
|
||||||
if err := e.Orm.Save(&smsPhone).Error; err != nil {
|
if err := e.Orm.Save(&smsPhone).Error; err != nil {
|
||||||
e.Log.Errorf("获取手机号失败", err)
|
e.Log.Errorf("获取手机号失败", err)
|
||||||
return decimal.Zero, statuscode.ServerError
|
return decimal.Decimal{}, models.SmsPhone{}, statuscode.ServerError
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := e.Orm.Exec("UPDATE member_balance SET balance = balance -? WHERE user_id =?", price, userId).Error; err != nil {
|
if err := e.Orm.Exec("UPDATE member_balance SET balance = balance -? WHERE user_id =?", price, userId).Error; err != nil {
|
||||||
e.Log.Errorf("更新余额失败", err)
|
e.Log.Errorf("更新余额失败", err)
|
||||||
return decimal.Zero, statuscode.ServerError
|
return decimal.Decimal{}, models.SmsPhone{}, statuscode.ServerError
|
||||||
}
|
}
|
||||||
|
|
||||||
//长效号码默认开启续费
|
//长效号码默认开启续费
|
||||||
if req.Type == 1 {
|
if req.Type == 1 {
|
||||||
code := e.ChangeAutoRenewForApi(smsPhone.NewActivationId, true)
|
var code int
|
||||||
|
if req.PlatformCode == global.SmsPlatformDaisysms {
|
||||||
|
code = e.ChangeAutoRenewManage(smsPhone.PlatformCode, smsPhone.NewActivationId, true)
|
||||||
|
} else {
|
||||||
|
code = http.StatusOK
|
||||||
|
e.WeakUp(&dto.WeakUpReq{ActivationId: smsPhone.NewActivationId}, userId, true)
|
||||||
|
}
|
||||||
|
|
||||||
if code == statuscode.Success {
|
if code == statuscode.Success {
|
||||||
smsPhone.AutoRenewal = 1
|
smsPhone.AutoRenewal = 1
|
||||||
@ -247,116 +351,36 @@ func (e *SmsPhone) GetNumber(req *dto.GetNumberReq, userId int) (decimal.Decimal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
balance = balanceService.GetBalance(userId)
|
return balance, smsPhone, statuscode.Success
|
||||||
|
|
||||||
return balance, statuscode.Success
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNumberForApi 获取短期或长期租赁号码
|
// 租赁号码
|
||||||
// getType 0-短效 1-长效
|
func (e *SmsPhone) GetNumberManage(platformCode string, typ int, serviceCode string, price decimal.Decimal, period int) (string, string, int, *time.Time) {
|
||||||
// service 服务code
|
switch platformCode {
|
||||||
// maxPrice 最大价格
|
case global.SmsPlatformDaisysms:
|
||||||
// period 时长(月)
|
service := SmsDaisysms{Service: e.Service}
|
||||||
func (e *SmsPhone) GetNumberForApi(getType int, serviceCode string, maxPrice decimal.Decimal, period int) (int, string, int) {
|
activationId, phone, code := service.GetNumberForApi(typ, serviceCode, price, period)
|
||||||
acitvationId := 0
|
|
||||||
result := ""
|
return strconv.Itoa(activationId), phone, code, nil
|
||||||
resultCode := statuscode.Success
|
case global.SmsPlatformTextVerified:
|
||||||
|
service := SmsTextVerified{Service: e.Service}
|
||||||
|
resp, code := service.GetNumberForApi(typ, serviceCode, price, period)
|
||||||
|
|
||||||
configResp, code := GetApiKey(e)
|
|
||||||
if code != statuscode.Success {
|
if code != statuscode.Success {
|
||||||
return acitvationId, result, code
|
return "", "", code, nil
|
||||||
}
|
|
||||||
url := fmt.Sprintf("?api_key=%s&action=getNumber&service=%s", configResp.ConfigValue, serviceCode)
|
|
||||||
|
|
||||||
if getType == 1 {
|
|
||||||
url = fmt.Sprintf("%s&duration=%dM", url, period)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
return resp.Id, resp.Phone, code, resp.EndAt
|
||||||
//ACCESS_NUMBER:999999:13476711222
|
default:
|
||||||
bytes, err := client.GetRaw(url, nil)
|
return "", "", statuscode.SmsPlatformUnavailable, nil
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", err.Error())
|
|
||||||
return acitvationId, result, statuscode.ServerError
|
|
||||||
}
|
}
|
||||||
content := string(bytes)
|
|
||||||
|
|
||||||
if strings.Contains(content, "ACCESS_NUMBER:") {
|
|
||||||
if len(strings.Split(content, ":")) < 2 {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", content)
|
|
||||||
return acitvationId, result, statuscode.ServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
acitvationId, _ = strconv.Atoi(strings.Split(content, ":")[1])
|
|
||||||
result = strings.Split(content, ":")[2]
|
|
||||||
} else if strings.Contains(content, "MAX_PRICE_EXCEEDED:") {
|
|
||||||
e.Log.Errorf("租赁价格超过最大价格")
|
|
||||||
resultCode = statuscode.NoNumbers
|
|
||||||
} else if strings.Contains(content, "NO_NUMBERS") {
|
|
||||||
e.Log.Error("平台号码不足")
|
|
||||||
resultCode = statuscode.NoNumbers
|
|
||||||
} else if strings.Contains(content, "TOO_MANY_ACTIVE_RENTALS") {
|
|
||||||
e.Log.Error("租赁数量超过限制")
|
|
||||||
resultCode = statuscode.ServerError
|
|
||||||
} else if strings.Contains(content, "NO_MONEY") {
|
|
||||||
e.Log.Error("余额不足")
|
|
||||||
resultCode = statuscode.BalanceNotEnough
|
|
||||||
} else {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", content)
|
|
||||||
resultCode = statuscode.ServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
return acitvationId, result, resultCode
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置租赁结束
|
|
||||||
func (e *SmsPhone) setStatus(id int) int {
|
|
||||||
configResp, code := GetApiKey(e)
|
|
||||||
if code != statuscode.Success {
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
|
|
||||||
url := fmt.Sprintf("?api_key=%s&action=setStatus&id=%d&status=6", configResp.ConfigValue, id)
|
|
||||||
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
|
||||||
bytes, err := client.GetRaw(url, nil)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", err.Error())
|
|
||||||
return statuscode.ServerError
|
|
||||||
}
|
|
||||||
content := string(bytes)
|
|
||||||
|
|
||||||
if content == "ACCESS_ACTIVATION" {
|
|
||||||
return statuscode.Success
|
|
||||||
} else {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", content)
|
|
||||||
return statuscode.ServerError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetApiKey(e *SmsPhone) (dto.GetSysConfigByKEYForServiceResp, int) {
|
|
||||||
configService := SysConfig{Service: e.Service}
|
|
||||||
configResp := dto.GetSysConfigByKEYForServiceResp{}
|
|
||||||
err := configService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: "sms_key"}, &configResp)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
e.Log.Errorf("获取短信api失败, %s", err)
|
|
||||||
return dto.GetSysConfigByKEYForServiceResp{}, statuscode.ServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
if configResp.ConfigValue == "" {
|
|
||||||
e.Log.Error("短信api不能为空")
|
|
||||||
return dto.GetSysConfigByKEYForServiceResp{}, statuscode.ServerError
|
|
||||||
}
|
|
||||||
return configResp, statuscode.Success
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *SmsPhone) GetCodeByActivationId(req *dto.GetCodeReq, userId int) ([]dto.GetCodeResp, int) {
|
func (e *SmsPhone) GetCodeByActivationId(req *dto.GetCodeReq, userId int) ([]dto.GetCodeResp, int) {
|
||||||
var smsPhone []models.SmsPhone
|
var smsPhone []models.SmsPhone
|
||||||
result := []dto.GetCodeResp{}
|
result := []dto.GetCodeResp{}
|
||||||
|
|
||||||
if err := e.Orm.Model(models.SmsPhone{}).Where("user_id =? and activation_id in ?", userId, req.ActivationIds).Find(&smsPhone).Error; err != nil {
|
if err := e.Orm.Model(models.SmsPhone{}).Where("user_id =? and new_activation_id in ?", userId, req.ActivationIds).Find(&smsPhone).Error; err != nil {
|
||||||
return result, statuscode.ServerError
|
return result, statuscode.ServerError
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,7 +416,18 @@ func (e *SmsPhone) SyncCodes() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range phones {
|
for _, item := range phones {
|
||||||
code, codeStatus := e.GetCodeForApi(item.NewActivationId)
|
code, codeStatus := e.GetCodeManage(item.PlatformCode, item.NewActivationId, item.Type, item.UpdatedAt.Unix())
|
||||||
|
|
||||||
|
if code == "" {
|
||||||
|
expireTime := item.UpdatedAt.Add(time.Second * 150)
|
||||||
|
if item.PlatformCode == global.SmsPlatformTextVerified && expireTime.Before(time.Now()) {
|
||||||
|
if err := e.Orm.Model(&item).Updates(map[string]interface{}{"status": 3, "updated_at": time.Now()}).Error; err != nil {
|
||||||
|
e.Log.Errorf("手机号一睡眠 %s", item.Phone)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
mapData := make(map[string]interface{})
|
mapData := make(map[string]interface{})
|
||||||
logMapData := make(map[string]interface{})
|
logMapData := make(map[string]interface{})
|
||||||
|
|
||||||
@ -437,135 +472,18 @@ func (e *SmsPhone) SyncCodes() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCodeForApi 获取验证码
|
// 获取验证码
|
||||||
// messageId 短信id
|
func (e *SmsPhone) GetCodeManage(platformCode string, messageId string, typ int, unixTime int64) (string, int) {
|
||||||
// return 验证码, 状态码
|
switch platformCode {
|
||||||
func (e *SmsPhone) GetCodeForApi(messageId int) (string, int) {
|
case global.SmsPlatformDaisysms:
|
||||||
result := ""
|
service := SmsDaisysms{Service: e.Service}
|
||||||
key, code := GetApiKey(e)
|
|
||||||
|
|
||||||
if code != statuscode.Success {
|
return service.GetCodeForApi(messageId)
|
||||||
return result, code
|
case global.SmsPlatformTextVerified:
|
||||||
}
|
service := SmsTextVerified{Service: e.Service}
|
||||||
url := fmt.Sprintf("?api_key=%s&action=getStatus&id=%d", key.ConfigValue, messageId)
|
return service.GetCode(messageId, typ, unixTime)
|
||||||
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
default:
|
||||||
bytes, err := client.GetRaw(url, nil)
|
return "", statuscode.SmsPlatformUnavailable
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", err.Error())
|
|
||||||
return result, statuscode.ServerError
|
|
||||||
}
|
|
||||||
content := string(bytes)
|
|
||||||
|
|
||||||
if strings.Contains(content, "STATUS_OK:") && content != "STATUS_OK:KEEP" {
|
|
||||||
result = strings.Split(content, ":")[1]
|
|
||||||
} else if content == "NO_ACTIVATION" {
|
|
||||||
code = statuscode.SmsNoActivation
|
|
||||||
} else if content == "STATUS_WAIT_CODE" || content == "STATUS_OK:KEEP" {
|
|
||||||
code = statuscode.SmsWaitCode
|
|
||||||
} else if content == "STATUS_CANCEL" {
|
|
||||||
code = statuscode.SmsCancel
|
|
||||||
} else {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", content)
|
|
||||||
return result, statuscode.ServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, code
|
|
||||||
}
|
|
||||||
|
|
||||||
// getExtraActivation 获取额外的激活
|
|
||||||
// messageId 短信id
|
|
||||||
// return 验证码, 状态码
|
|
||||||
func (e *SmsPhone) getExtraActivation(activationId int) (int, int) {
|
|
||||||
result := 0
|
|
||||||
key, err := GetApiKey(e)
|
|
||||||
if err != statuscode.Success {
|
|
||||||
return 0, statuscode.ServerError
|
|
||||||
}
|
|
||||||
url := fmt.Sprintf("?api_key=%s&action=getExtraActivation&activationId=%d", key.ConfigValue, activationId)
|
|
||||||
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
|
||||||
bytes, err1 := client.GetRaw(url, nil)
|
|
||||||
|
|
||||||
if err1 != nil {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", err1.Error())
|
|
||||||
return 0, statuscode.ServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
content := string(bytes)
|
|
||||||
|
|
||||||
if strings.Contains(content, "ASLEEP:") {
|
|
||||||
message := strings.Split(content, ":")[1]
|
|
||||||
result, _ = strconv.Atoi(message)
|
|
||||||
|
|
||||||
if result > 0 {
|
|
||||||
return result, statuscode.Success
|
|
||||||
}
|
|
||||||
} else if strings.Contains(content, "STATUS_OK:") {
|
|
||||||
return 0, statuscode.SmsLongNumWaitCode
|
|
||||||
} else if strings.Contains(content, "ACCESS_NUMBER:") {
|
|
||||||
message := strings.Split(content, ":")[1]
|
|
||||||
result, _ = strconv.Atoi(message)
|
|
||||||
|
|
||||||
if result > 0 {
|
|
||||||
return result, statuscode.Success
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Log.Errorf("激活长效号码失败,%s", content)
|
|
||||||
|
|
||||||
return 0, statuscode.ServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeepLongTerm 长期租赁
|
|
||||||
func (e *SmsPhone) KeepLongTerm(activationId int) int {
|
|
||||||
key, code := GetApiKey(e)
|
|
||||||
|
|
||||||
if code != statuscode.Success {
|
|
||||||
return statuscode.ServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
url := fmt.Sprintf("?api_key=%s&action=keep&id=%d", key.ConfigValue, activationId)
|
|
||||||
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
|
||||||
bytes, err := client.GetRaw(url, nil)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", err.Error())
|
|
||||||
return statuscode.ServerError
|
|
||||||
}
|
|
||||||
content := string(bytes)
|
|
||||||
|
|
||||||
if content == "OK" {
|
|
||||||
return statuscode.Success
|
|
||||||
} else {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", content)
|
|
||||||
return statuscode.ServerError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取消租赁
|
|
||||||
func (e *SmsPhone) CancelRental(activationId int) int {
|
|
||||||
key, code := GetApiKey(e)
|
|
||||||
|
|
||||||
if code != statuscode.Success {
|
|
||||||
e.Log.Errorf("租赁api请求失败 %s")
|
|
||||||
return statuscode.ServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
url := fmt.Sprintf("?api_key=%s&action=setStatus&id=%d&status=8", key.ConfigValue, activationId)
|
|
||||||
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
|
||||||
bytes, err := client.GetRaw(url, nil)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", err.Error())
|
|
||||||
return statuscode.ServerError
|
|
||||||
}
|
|
||||||
content := string(bytes)
|
|
||||||
|
|
||||||
if content == "ACCESS_CANCEL" {
|
|
||||||
return statuscode.Success
|
|
||||||
} else {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", content)
|
|
||||||
return statuscode.ServerError
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,64 +555,74 @@ func (e SmsServices) AutoRenewal() error {
|
|||||||
func (e *SmsPhone) ChangeAutoRenew(req *dto.SmsPhoneChangeAutoRenewReq, userId int) int {
|
func (e *SmsPhone) ChangeAutoRenew(req *dto.SmsPhoneChangeAutoRenewReq, userId int) int {
|
||||||
var data models.SmsPhone
|
var data models.SmsPhone
|
||||||
|
|
||||||
|
if req.Id > 0 {
|
||||||
if err := e.Orm.Model(data).Where("id =? and user_id =?", req.Id, userId).First(&data).Error; err != nil {
|
if err := e.Orm.Model(data).Where("id =? and user_id =?", req.Id, userId).First(&data).Error; err != nil {
|
||||||
e.Log.Errorf("修改自动续期 数据不存在 id:%d err:%s", req.Id, err.Error())
|
e.Log.Errorf("修改自动续期 数据不存在 id:%d err:%s", req.Id, err.Error())
|
||||||
return statuscode.SmsNotExisted
|
return statuscode.SmsNotExisted
|
||||||
}
|
}
|
||||||
|
} else if req.ActivationId != "" {
|
||||||
|
if err := e.Orm.Model(data).Where("activation_id =? and user_id =?", req.ActivationId, userId).First(&data).Error; err != nil {
|
||||||
|
e.Log.Errorf("修改自动续期 数据不存在 id:%d err:%s", req.Id, err.Error())
|
||||||
|
return statuscode.SmsNotExisted
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return statuscode.InvalidParams
|
||||||
|
}
|
||||||
|
|
||||||
// 短期租赁不支持自动续期
|
// 短期租赁不支持自动续期
|
||||||
|
shouldReturn, i := e.DoChangeAutoRenewal(data, req.AutoRenew)
|
||||||
|
if shouldReturn {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
return statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoChangeAutoRenewal 执行修改自动续期
|
||||||
|
func (e *SmsPhone) DoChangeAutoRenewal(data models.SmsPhone, autoRenewal int) (bool, int) {
|
||||||
if data.Type == 0 {
|
if data.Type == 0 {
|
||||||
return statuscode.SmsNotAutoRenew
|
return true, statuscode.SmsNotAutoRenew
|
||||||
}
|
}
|
||||||
|
|
||||||
status := false
|
status := false
|
||||||
changeAutoRenewal := 2
|
changeAutoRenewal := 2
|
||||||
if req.AutoRenew == 1 {
|
if autoRenewal == 1 {
|
||||||
status = true
|
status = true
|
||||||
changeAutoRenewal = 1
|
changeAutoRenewal = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
data.AutoRenewal = req.AutoRenew
|
var code int
|
||||||
code := e.ChangeAutoRenewForApi(data.ActivationId, status)
|
data.AutoRenewal = autoRenewal
|
||||||
|
|
||||||
|
if data.Actived == 3 {
|
||||||
|
code = http.StatusOK
|
||||||
|
} else {
|
||||||
|
code = e.ChangeAutoRenewManage(data.PlatformCode, data.ActivationId, status)
|
||||||
|
|
||||||
if code != statuscode.Success {
|
if code != statuscode.Success {
|
||||||
return statuscode.ServerError
|
return true, statuscode.ServerError
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := e.Orm.Model(&data).Update("auto_renewal", changeAutoRenewal).Error; err != nil {
|
if err := e.Orm.Model(&data).Update("auto_renewal", changeAutoRenewal).Error; err != nil {
|
||||||
e.Log.Errorf("修改自动续期失败 id:%d, status:%t", data.ActivationId, status)
|
e.Log.Errorf("修改自动续期失败 id:%d, status:%t", data.ActivationId, status)
|
||||||
}
|
}
|
||||||
|
return false, 0
|
||||||
return statuscode.Success
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeAutoRenew 修改自动续期
|
// ChangeAutoRenewManage 修改自动续期管理
|
||||||
// activationId 短信id
|
func (e *SmsPhone) ChangeAutoRenewManage(platform string, activationId string, status bool) int {
|
||||||
// status 状态
|
switch platform {
|
||||||
func (e *SmsPhone) ChangeAutoRenewForApi(activationId int, status bool) int {
|
case global.SmsPlatformDaisysms:
|
||||||
key, err := GetApiKey(e)
|
service := SmsDaisysms{Service: e.Service}
|
||||||
|
|
||||||
if err != statuscode.Success {
|
return service.ChangeAutoRenewForApi(activationId, status)
|
||||||
e.Log.Errorf("查询sms api请求失败 %d", activationId)
|
case global.SmsPlatformTextVerified:
|
||||||
return statuscode.ServerError
|
service := SmsTextVerified{Service: e.Service}
|
||||||
}
|
|
||||||
|
|
||||||
url := fmt.Sprintf("?api_key=%s&action=setAutoRenew&id=%d&value=%t", key.ConfigValue, activationId, status)
|
return service.Renew(activationId, status)
|
||||||
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil)
|
default:
|
||||||
bytes, err1 := client.GetRaw(url, nil)
|
return statuscode.SmsPlatformUnavailable
|
||||||
|
|
||||||
if err1 != nil {
|
|
||||||
e.Log.Errorf("租赁请求失败 %s", err1.Error())
|
|
||||||
return statuscode.ServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
content := string(bytes)
|
|
||||||
|
|
||||||
if content == "OK" {
|
|
||||||
return statuscode.Success
|
|
||||||
} else {
|
|
||||||
e.Log.Errorf("修改自动续期请求失败 id:%d, status:%t, %s", activationId, status, content)
|
|
||||||
return statuscode.ServerError
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
65
app/admin/service/sms_phone_test.go
Normal file
65
app/admin/service/sms_phone_test.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-admin/app/admin/service/dto"
|
||||||
|
"go-admin/common/global"
|
||||||
|
"go-admin/common/statuscode"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVerifiedGetNumber(t *testing.T) {
|
||||||
|
db := initSetting()
|
||||||
|
|
||||||
|
service := SmsPhone{}
|
||||||
|
service.Orm = db
|
||||||
|
service.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
|
||||||
|
if _, err := service.GetNumber(&dto.GetNumberReq{
|
||||||
|
PlatformCode: global.SmsPlatformTextVerified,
|
||||||
|
Type: 1,
|
||||||
|
ServiceCode: "cocacola",
|
||||||
|
Period: 1,
|
||||||
|
}, 1); err != statuscode.Success {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifiedCancel(t *testing.T) {
|
||||||
|
db := initSetting()
|
||||||
|
|
||||||
|
service := SmsPhone{}
|
||||||
|
service.Orm = db
|
||||||
|
service.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
|
||||||
|
if err := service.CancelNumber(&dto.SmsPhoneCancelNumberReq{
|
||||||
|
Id: 129,
|
||||||
|
}, 1); err != statuscode.Success {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifiedWake(t *testing.T) {
|
||||||
|
db := initSetting()
|
||||||
|
|
||||||
|
service := SmsPhone{}
|
||||||
|
service.Orm = db
|
||||||
|
service.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
|
||||||
|
service.WeakUp(&dto.WeakUpReq{
|
||||||
|
ActivationId: "lr_01K21NVPVDEXTS1C3S8HPEC612",
|
||||||
|
}, 1, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetPrices(t *testing.T) {
|
||||||
|
db := initSetting()
|
||||||
|
|
||||||
|
service := SmsServices{}
|
||||||
|
service.Orm = db
|
||||||
|
service.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
|
||||||
|
if err := service.SyncPrices(); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -48,7 +48,7 @@ func (e SmsReceiveLog) WebHook(req *dto.SmsReceiveWebHookReq) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
phoneService := SmsPhone{Service: e.Service}
|
phoneService := SmsDaisysms{Service: e.Service}
|
||||||
if code := phoneService.setStatus(req.ActivationID); code != statuscode.Success {
|
if code := phoneService.setStatus(req.ActivationID); code != statuscode.Success {
|
||||||
e.Log.Errorf("接受验证码回调后修改状态失败 %d", code)
|
e.Log.Errorf("接受验证码回调后修改状态失败 %d", code)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,14 +12,19 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initSetting() {
|
func initSetting() *gorm.DB {
|
||||||
dsn := "root:123456@tcp(127.0.0.1:3306)/proxy_server?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
dsn := "root:123456@tcp(127.0.0.1:3306)/proxy_server?charset=utf8mb4&parseTime=True&loc=Local&timeout=1000ms"
|
||||||
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
sdk.Runtime.SetDb("default", db)
|
sdk.Runtime.SetDb("default", db)
|
||||||
config.ExtConfig.TrxGridUrl = "https://api.trongrid.io"
|
config.ExtConfig.TrxGridUrl = "https://api.trongrid.io"
|
||||||
config.ExtConfig.DaisysmsUrl = "https://daisysms.com/stubs/handler_api.php"
|
config.ExtConfig.DaisysmsUrl = "https://daisysms.com/stubs/handler_api.php"
|
||||||
|
config.ExtConfig.SmsTextVerified.ApiKey = "ZQ0swXnsaPpeGdwa3c7gT9U9I1Oh9WoDHx0amuYovvaHuqd5u6B4NBBUSUBjR"
|
||||||
|
config.ExtConfig.SmsTextVerified.UserName = "webspan@proton.me"
|
||||||
|
config.ExtConfig.SmsTextVerified.Url = "https://www.textverified.com"
|
||||||
redishelper.InitDefaultRedis("127.0.0.1:6379", "", 4)
|
redishelper.InitDefaultRedis("127.0.0.1:6379", "", 4)
|
||||||
redishelper.InitLockRedisConn("127.0.0.1:6379", "", "4")
|
redishelper.InitLockRedisConn("127.0.0.1:6379", "", "4")
|
||||||
|
|
||||||
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSmsReceiveLog(t *testing.T) {
|
func TestSmsReceiveLog(t *testing.T) {
|
||||||
|
|||||||
@ -11,21 +11,75 @@ import (
|
|||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
"go-admin/common/actions"
|
"go-admin/common/actions"
|
||||||
cDto "go-admin/common/dto"
|
cDto "go-admin/common/dto"
|
||||||
|
"go-admin/common/global"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SmsServices struct {
|
type SmsServices struct {
|
||||||
service.Service
|
service.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e SmsServices) OpenGetByCode(code string, param2 string, apiKey string) (any, error) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取平台列表
|
||||||
|
func (e SmsServices) GetPlatform(resp *[]dto.SmsPlatformGetListResp) error {
|
||||||
|
var datas []models.SysDictData
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&models.SysDictData{}).Where("dict_type = 'sms_platform'").Find(&datas).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range datas {
|
||||||
|
var respDto dto.SmsPlatformGetListResp
|
||||||
|
respDto.Label = v.DictLabel
|
||||||
|
respDto.Value = v.DictValue
|
||||||
|
|
||||||
|
*resp = append(*resp, respDto)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetPrice 获取SmsServices价格
|
// GetPrice 获取SmsServices价格
|
||||||
func (e SmsServices) GetPrice(req *dto.SmsGetPriceReq) (decimal.Decimal, error) {
|
func (e SmsServices) GetPrice(req *dto.SmsGetPriceReq) (decimal.Decimal, error) {
|
||||||
key := "number_fee_short_term"
|
var service models.SmsServices
|
||||||
|
|
||||||
if req.Type == 1 {
|
if err := e.Orm.Model(&service).Where("platform_code =? and code =?", req.PlatformCode, req.ServiceCode).First(&service).Error; err != nil {
|
||||||
key = "number_fee_long_term"
|
return decimal.Decimal{}, errors.New("获取价格失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
var price decimal.Decimal
|
var price decimal.Decimal
|
||||||
|
var key string
|
||||||
|
|
||||||
|
if req.Type == 1 {
|
||||||
|
price = service.Price
|
||||||
|
|
||||||
|
switch req.PlatformCode {
|
||||||
|
case global.SmsPlatformDaisysms:
|
||||||
|
key = "long_number_premium_daisysms"
|
||||||
|
case global.SmsPlatformTextVerified:
|
||||||
|
key = "long_number_premium_textverified"
|
||||||
|
default:
|
||||||
|
return price, errors.New("获取价格失败")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
price = service.LongPrice
|
||||||
|
|
||||||
|
switch req.PlatformCode {
|
||||||
|
case global.SmsPlatformDaisysms:
|
||||||
|
key = "number_premium_daisysms"
|
||||||
|
case global.SmsPlatformTextVerified:
|
||||||
|
key = "number_premium_textverified"
|
||||||
|
default:
|
||||||
|
return price, errors.New("获取价格失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if price.IsZero() {
|
||||||
|
return price, errors.New("获取价格失败")
|
||||||
|
}
|
||||||
|
|
||||||
configService := SysConfig{Service: e.Service}
|
configService := SysConfig{Service: e.Service}
|
||||||
configResp := dto.GetSysConfigByKEYForServiceResp{}
|
configResp := dto.GetSysConfigByKEYForServiceResp{}
|
||||||
err := configService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: key}, &configResp)
|
err := configService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: key}, &configResp)
|
||||||
@ -34,29 +88,96 @@ func (e SmsServices) GetPrice(req *dto.SmsGetPriceReq) (decimal.Decimal, error)
|
|||||||
return price, err
|
return price, err
|
||||||
}
|
}
|
||||||
|
|
||||||
price, err = decimal.NewFromString(configResp.ConfigValue)
|
percent, err := decimal.NewFromString(configResp.ConfigValue)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return price, err
|
return price, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if percent.IsZero() {
|
||||||
|
return price, nil
|
||||||
|
} else {
|
||||||
|
price = price.Mul((decimal.NewFromInt(100).Add(percent)).Div(decimal.NewFromInt(100))).Truncate(2)
|
||||||
|
}
|
||||||
|
|
||||||
return price, nil
|
return price, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetList 获取SmsServices列表
|
// GetList 获取SmsServices列表
|
||||||
func (e SmsServices) GetList(resp *[]dto.SmsServicesGetListResp) error {
|
func (e SmsServices) GetList(resp *[]dto.SmsServicesGetListResp) error {
|
||||||
var data []models.SmsServices
|
var data []models.SmsServices
|
||||||
err := e.Orm.Find(&data).Error
|
err := e.Orm.Model(&models.SmsServices{}).Where("status =1").Find(&data).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Log.Errorf("SmsServicesService GetList error:%s \r\n", err)
|
e.Log.Errorf("SmsServicesService GetList error:%s \r\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dictService := SysDictData{Service: e.Service}
|
||||||
|
dictDatas, _ := dictService.GetMapByType("sms_platform")
|
||||||
|
|
||||||
|
keys := []string{"number_premium_daisysms", "number_premium_textverified", "long_number_premium_daisysms", "long_number_premium_textverified"}
|
||||||
|
configService := SysConfig{Service: e.Service}
|
||||||
|
mapConfigs, err := configService.GetWithKeyForMap(keys)
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取配置失败,\r\n失败信息 %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for _, item := range data {
|
for _, item := range data {
|
||||||
respItem := dto.SmsServicesGetListResp{
|
respItem := dto.SmsServicesGetListResp{
|
||||||
Name: item.Name,
|
Name: item.Name,
|
||||||
Code: item.Code,
|
Code: item.Code,
|
||||||
Status: item.Status,
|
Status: item.Status,
|
||||||
|
PlatformCode: item.PlatformCode,
|
||||||
|
Price: item.Price,
|
||||||
|
LongPrice: item.LongPrice,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dict, ok := dictDatas[respItem.PlatformCode]; ok {
|
||||||
|
respItem.PlatformName = dict.DictLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
switch item.PlatformCode {
|
||||||
|
case global.SmsPlatformDaisysms:
|
||||||
|
if config, ok := mapConfigs["number_premium_daisysms"]; ok {
|
||||||
|
premium, err := decimal.NewFromString(config.ConfigValue)
|
||||||
|
|
||||||
|
if err != nil || premium.IsZero() {
|
||||||
|
e.Log.Errorf("浮动百分比为0,或者是转换错误 %s", config.ConfigValue)
|
||||||
|
} else {
|
||||||
|
respItem.Price = respItem.Price.Mul(decimal.NewFromInt(100).Add(premium).Div(decimal.NewFromInt(100))).Truncate(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if config, ok := mapConfigs["long_number_premium_daisysms"]; ok {
|
||||||
|
premium, err := decimal.NewFromString(config.ConfigValue)
|
||||||
|
|
||||||
|
if err != nil || premium.IsZero() {
|
||||||
|
e.Log.Errorf("浮动百分比为0,或者是转换错误 %s", config.ConfigValue)
|
||||||
|
} else {
|
||||||
|
respItem.LongPrice = respItem.LongPrice.Mul(decimal.NewFromInt(100).Add(premium).Div(decimal.NewFromInt(100))).Truncate(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case global.SmsPlatformTextVerified:
|
||||||
|
if config, ok := mapConfigs["number_premium_textverified"]; ok {
|
||||||
|
premium, err := decimal.NewFromString(config.ConfigValue)
|
||||||
|
|
||||||
|
if err != nil || premium.IsZero() {
|
||||||
|
e.Log.Errorf("浮动百分比为0,或者是转换错误 %s", config.ConfigValue)
|
||||||
|
} else {
|
||||||
|
respItem.Price = respItem.Price.Mul(decimal.NewFromInt(100).Add(premium).Div(decimal.NewFromInt(100))).Truncate(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if config, ok := mapConfigs["long_number_premium_textverified"]; ok {
|
||||||
|
premium, err := decimal.NewFromString(config.ConfigValue)
|
||||||
|
|
||||||
|
if err != nil || premium.IsZero() {
|
||||||
|
e.Log.Errorf("浮动百分比为0,或者是转换错误 %s", config.ConfigValue)
|
||||||
|
} else {
|
||||||
|
respItem.LongPrice = respItem.LongPrice.Mul(decimal.NewFromInt(100).Add(premium).Div(decimal.NewFromInt(100))).Truncate(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*resp = append(*resp, respItem)
|
*resp = append(*resp, respItem)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -66,13 +187,17 @@ func (e SmsServices) GetList(resp *[]dto.SmsServicesGetListResp) error {
|
|||||||
func (e *SmsServices) GetPage(c *dto.SmsServicesGetPageReq, p *actions.DataPermission, list *[]models.SmsServices, count *int64) error {
|
func (e *SmsServices) GetPage(c *dto.SmsServicesGetPageReq, p *actions.DataPermission, list *[]models.SmsServices, count *int64) error {
|
||||||
var err error
|
var err error
|
||||||
var data models.SmsServices
|
var data models.SmsServices
|
||||||
|
query := e.Orm.Model(&data).
|
||||||
err = e.Orm.Model(&data).
|
|
||||||
Scopes(
|
Scopes(
|
||||||
cDto.MakeCondition(c.GetNeedSearch()),
|
cDto.MakeCondition(c.GetNeedSearch()),
|
||||||
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
||||||
actions.Permission(data.TableName(), p),
|
actions.Permission(data.TableName(), p),
|
||||||
).
|
)
|
||||||
|
|
||||||
|
if c.Status > 0 {
|
||||||
|
query = query.Where("status = ?", c.Status)
|
||||||
|
}
|
||||||
|
err = query.
|
||||||
Find(list).Limit(-1).Offset(-1).
|
Find(list).Limit(-1).Offset(-1).
|
||||||
Count(count).Error
|
Count(count).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -154,12 +279,30 @@ func (e *SmsServices) Remove(d *dto.SmsServicesDeleteReq, p *actions.DataPermiss
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *SmsServices) GetByCode(code string) (models.SmsServices, error) {
|
func (e *SmsServices) GetByCode(platformCode, code string) (models.SmsServices, error) {
|
||||||
var data models.SmsServices
|
var data models.SmsServices
|
||||||
|
|
||||||
if err := e.Orm.Model(data).Where("code =?", code).First(&data).Error; err != nil {
|
if err := e.Orm.Model(data).Where("platform_code =? and code =?", platformCode, code).First(&data).Error; err != nil {
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 同步第三方价格
|
||||||
|
func (e *SmsServices) SyncPrices() error {
|
||||||
|
var datas []models.SmsServices
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&models.SmsServices{}).Where("platform_code =?", global.SmsPlatformTextVerified).Find(&datas).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
daisysmsService := SmsDaisysms{Service: e.Service}
|
||||||
|
textVerifiedService := SmsTextVerified{Service: e.Service}
|
||||||
|
|
||||||
|
//daisysms 同步价格
|
||||||
|
daisysmsService.SyncPrices()
|
||||||
|
//textVerified 同步价格
|
||||||
|
textVerifiedService.SyncPrices()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
855
app/admin/service/sms_text_verified.go
Normal file
855
app/admin/service/sms_text_verified.go
Normal file
@ -0,0 +1,855 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"go-admin/app/admin/models"
|
||||||
|
"go-admin/app/admin/service/dto"
|
||||||
|
"go-admin/common/global"
|
||||||
|
"go-admin/common/statuscode"
|
||||||
|
"go-admin/config"
|
||||||
|
"go-admin/utils/httphelper"
|
||||||
|
"go-admin/utils/redishelper"
|
||||||
|
"go-admin/utils/utility"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SmsTextVerified struct {
|
||||||
|
service.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取收到的验证码
|
||||||
|
// messageId 短效或长效号码的ID
|
||||||
|
// typ 0-短效 1-长效
|
||||||
|
func (e SmsTextVerified) GetCode(messageId string, typ int, unixTime int64) (string, int) {
|
||||||
|
reservationType := ""
|
||||||
|
|
||||||
|
if typ == 0 {
|
||||||
|
reservationType = "verification"
|
||||||
|
} else {
|
||||||
|
reservationType = "renewable"
|
||||||
|
}
|
||||||
|
url := fmt.Sprintf(getSmsCode, messageId, reservationType)
|
||||||
|
client, code := e.GetTextVerifiedAuthClient()
|
||||||
|
|
||||||
|
if code != http.StatusOK {
|
||||||
|
e.Log.Errorf("获取授权请求失败,status %d", code)
|
||||||
|
return "", code
|
||||||
|
}
|
||||||
|
|
||||||
|
var parsedCode string
|
||||||
|
resp := dto.TextVerifiedSmsResp{}
|
||||||
|
|
||||||
|
_, err := client.Get(url, nil, &resp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取验证码失败, error: %v", err)
|
||||||
|
return "", statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.Data) > 0 {
|
||||||
|
for _, v := range resp.Data {
|
||||||
|
// 2. 解析时间字符串
|
||||||
|
// time.RFC3339Nano 是一个预定义的格式常量,
|
||||||
|
// 它能够解析包含纳秒和时区信息的 ISO 8601 字符串。
|
||||||
|
t, err := time.Parse(time.RFC3339Nano, v.CreatedAt)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("时间解析失败:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 将解析后的 time.Time 对象转换为 Unix 时间戳
|
||||||
|
// t.Unix() 返回以秒为单位的整数时间戳
|
||||||
|
unixTimestamp := t.Unix()
|
||||||
|
|
||||||
|
if unixTimestamp >= unixTime {
|
||||||
|
parsedCode = v.ParsedCode
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedCode, http.StatusOK
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
loginUrl = "/api/pub/v2/auth"
|
||||||
|
getAreas = "/api/pub/v2/area-codes"
|
||||||
|
getServices = "/api/pub/v2/services"
|
||||||
|
createRental = "/api/pub/v2/reservations/rental" //长效收码
|
||||||
|
createVerification = "/api/pub/v2/verifications" //单次收码
|
||||||
|
cancelVerification = "/api/pub/v2/verifications/%s/cancel" //取消收码
|
||||||
|
cancelRental = "/api/pub/v2/reservations/rental/renewable/%s/refund" //取消长效号码
|
||||||
|
wakeUp = "/api/pub/v2/wake-requests" //唤醒号码
|
||||||
|
rentalPrice = "/api/pub/v2/pricing/rentals" //长效收码价格
|
||||||
|
verificationPrice = "/api/pub/v2/pricing/verifications" //单次收码价格
|
||||||
|
rentalDetail = "/api/pub/v2/reservations/rental/renewable/%s" //长效号码详情
|
||||||
|
renewRental = "/api/pub/v2/reservations/rental/renewable/%s/renew" //长效续期
|
||||||
|
updateRentalRenewStatus = "/api/pub/v2/reservations/rental/renewable/%s" // 更改续租状态
|
||||||
|
getSmsCode = "/api/pub/v2/sms?reservationId=%s&reservationType=%s" //获取短信验证码
|
||||||
|
)
|
||||||
|
|
||||||
|
var idPattern = regexp.MustCompile(`^[a-zA-Z0-9_]{28}$`)
|
||||||
|
|
||||||
|
// 获取授权失败
|
||||||
|
var ErrUnAuth = errors.New("未授权,请检查配置的账号和密码")
|
||||||
|
var ErrOutOfStockOrUnavailable = errors.New("缺货或服务不可用")
|
||||||
|
|
||||||
|
// Login 登录
|
||||||
|
func (e *SmsTextVerified) Login() (string, error) {
|
||||||
|
resp := dto.TextVerifiedLoginResp{}
|
||||||
|
var token string
|
||||||
|
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.SmsTextVerified.Url, nil)
|
||||||
|
headers := map[string]string{
|
||||||
|
"X-API-USERNAME": config.ExtConfig.SmsTextVerified.UserName,
|
||||||
|
"X-API-KEY": config.ExtConfig.SmsTextVerified.ApiKey,
|
||||||
|
}
|
||||||
|
_, err1 := client.Post(loginUrl, nil, headers, &resp)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
e.Log.Errorf("TextVerified登录失败 error: %v", err1)
|
||||||
|
return "", err1
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Token == "" {
|
||||||
|
e.Log.Errorf("TextVerified登录失败,返回的Token为空")
|
||||||
|
return "", errors.New("TextVerified登录失败,返回的Token为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
token = resp.Token
|
||||||
|
|
||||||
|
if resp.ExpiresIn >= 10 {
|
||||||
|
resp.ExpiresIn = resp.ExpiresIn - 10 // 提前10秒过期
|
||||||
|
if err := redishelper.DefaultRedis.SetStringExpire(global.TextVerifiedToken, token, time.Duration(resp.ExpiresIn)*time.Second); err != nil {
|
||||||
|
e.Log.Errorf("TextVerified登录失败,缓存Token失败 error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取token
|
||||||
|
func (e *SmsTextVerified) GetToken() (string, error) {
|
||||||
|
token, err := redishelper.DefaultRedis.GetString(global.TextVerifiedToken)
|
||||||
|
if err != nil && errors.Is(err, redis.Nil) {
|
||||||
|
// token不存在,重新登录获取
|
||||||
|
return e.Login()
|
||||||
|
}
|
||||||
|
|
||||||
|
if token == "" {
|
||||||
|
return e.Login()
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取区域
|
||||||
|
func (e *SmsTextVerified) GetAreas() ([]string, error) {
|
||||||
|
|
||||||
|
// 这里可以实现获取地区的逻辑
|
||||||
|
// 例如从数据库或配置文件中读取地区信息
|
||||||
|
areas := []string{"Area1", "Area2", "Area3"} // 示例数据
|
||||||
|
return areas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取服务列表
|
||||||
|
func (e *SmsTextVerified) GetServices() ([]dto.TextVerifiedServeResp, error) {
|
||||||
|
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.SmsTextVerified.Url, nil)
|
||||||
|
headers, err := e.GetAuthHeader()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp := []dto.TextVerifiedServeResp{}
|
||||||
|
url := fmt.Sprintf("%s?numberType=mobile&reservationType=%s", getServices, "verification")
|
||||||
|
_, err1 := client.Get(url, headers, &resp)
|
||||||
|
if err1 != nil {
|
||||||
|
e.Log.Errorf("TextVerified获取服务列表失败 error: %v", err1)
|
||||||
|
return nil, err1
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步服务列表
|
||||||
|
func (e *SmsTextVerified) SyncServices() error {
|
||||||
|
services, err := e.GetServices()
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取服务列表失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取所有服务的 Capability 作为查询条件
|
||||||
|
capabilities := make([]string, 0, len(services))
|
||||||
|
for _, service := range services {
|
||||||
|
if strings.ToLower(service.Capability) != "sms" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if utility.ContainsString(capabilities, service.ServiceName) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
capabilities = append(capabilities, service.ServiceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量查询已存在的服务
|
||||||
|
var existingServices []models.SmsServices
|
||||||
|
err = e.Orm.Model(&models.SmsServices{}).
|
||||||
|
Where("platform_code = ? AND code IN ?", global.SmsPlatformTextVerified, capabilities).
|
||||||
|
Find(&existingServices).Error
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("批量查询服务失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建现有服务的 Code 集合,便于快速查找
|
||||||
|
existingServiceCodes := make(map[string]struct{}, len(existingServices))
|
||||||
|
for _, svc := range existingServices {
|
||||||
|
existingServiceCodes[svc.Code] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选出需要新增的服务
|
||||||
|
entitys := make([]models.SmsServices, 0)
|
||||||
|
for _, service := range services {
|
||||||
|
if _, exists := existingServiceCodes[service.ServiceName]; !exists && strings.ToLower(service.Capability) == "sms" {
|
||||||
|
entity := models.SmsServices{
|
||||||
|
Name: service.ServiceName,
|
||||||
|
Code: service.ServiceName,
|
||||||
|
PlatformCode: global.SmsPlatformTextVerified,
|
||||||
|
ExpirationMinutes: 3,
|
||||||
|
Status: 2,
|
||||||
|
}
|
||||||
|
entitys = append(entitys, entity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量创建新服务
|
||||||
|
if len(entitys) > 0 {
|
||||||
|
err = e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
|
if err := tx.CreateInBatches(&entitys, 500).Error; err != nil {
|
||||||
|
e.Log.Errorf("同步服务列表失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步价格
|
||||||
|
func (e *SmsTextVerified) SyncPrices() error {
|
||||||
|
var services []models.SmsServices
|
||||||
|
var entity models.SmsServices
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&entity).Where("platform_code = ? and status =1", global.SmsPlatformTextVerified).Find(&services).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range services {
|
||||||
|
params := map[string]interface{}{}
|
||||||
|
|
||||||
|
price, code := e.GetPrice(0, v.Code)
|
||||||
|
|
||||||
|
if code == http.StatusOK {
|
||||||
|
params["price"] = price
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Microsecond * 500) // 避免请求过快被限制
|
||||||
|
longPrice, code := e.GetPrice(1, v.Code)
|
||||||
|
if code == http.StatusOK {
|
||||||
|
params["long_price"] = longPrice
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(params) > 0 {
|
||||||
|
if err := e.Orm.Model(&entity).Where("platform_code = ? and code = ?", global.SmsPlatformTextVerified, v.Code).Updates(params).Error; err != nil {
|
||||||
|
e.Log.Errorf("同步服务价格失败: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 号码租赁
|
||||||
|
// getType 0-短效 1-长效
|
||||||
|
// service 服务code
|
||||||
|
// maxPrice 最大价格
|
||||||
|
// period 时长(月=30天)
|
||||||
|
func (e SmsTextVerified) GetNumberForApi(typ int, serviceCode string, price decimal.Decimal, period int) (dto.SmsPhoneGetPhoneResp, int) {
|
||||||
|
//这个平台的所有号码都是美国号码 默认国家代码都是 +1
|
||||||
|
var err error
|
||||||
|
var createResp dto.TextVerifiedResp
|
||||||
|
var result dto.SmsPhoneGetPhoneResp
|
||||||
|
switch typ {
|
||||||
|
case 0:
|
||||||
|
var code int
|
||||||
|
createResp, code = e.CreateVerification(serviceCode)
|
||||||
|
|
||||||
|
if code == statuscode.Success && createResp.Href != "" {
|
||||||
|
bytes, err := e.doRequest(&createResp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("短效号码 获取号码失败:%v", e)
|
||||||
|
return result, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := dto.VerificationDTO{}
|
||||||
|
|
||||||
|
if err := sonic.Unmarshal(bytes, &resp); err != nil {
|
||||||
|
e.Log.Errorf("短效号码 获取号码失败:%v", e)
|
||||||
|
return result, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Id = resp.ID
|
||||||
|
result.Phone = "1" + resp.Number
|
||||||
|
result.EndAt = &resp.EndsAt
|
||||||
|
|
||||||
|
return result, statuscode.Success
|
||||||
|
} else if code == statuscode.Success && createResp.Href == "" {
|
||||||
|
e.Log.Errorf("获取号码没有 返回值")
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("获取号码失败:%v", err)
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
createResp, err = e.CreateRental(serviceCode)
|
||||||
|
|
||||||
|
if err == nil && createResp.Href != "" {
|
||||||
|
saleId := getIdByUrl(createResp.Href)
|
||||||
|
bytes, err := e.doRequest(&createResp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("通过销售id [%s] 获取号码失败:%v", saleId, err)
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := dto.SaleResponse{}
|
||||||
|
if err := sonic.Unmarshal(bytes, &resp); err != nil {
|
||||||
|
e.Log.Errorf("反序列化失败:%v", err)
|
||||||
|
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.Reservations) > 0 {
|
||||||
|
for _, v := range resp.Reservations {
|
||||||
|
if v.ID != "" {
|
||||||
|
result.Id = v.ID
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Id == "" {
|
||||||
|
e.Log.Errorf("获取长效号码失败,没有返回值")
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
detail, code := e.GetRentalDetail(result.Id)
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
return result, code
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Phone = "1" + detail.Number
|
||||||
|
endTime := resp.UpdatedAt.AddDate(0, 0, 30)
|
||||||
|
result.EndAt = &(endTime) // 30天后过期
|
||||||
|
|
||||||
|
return result, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if err == nil && createResp.Href == "" {
|
||||||
|
e.Log.Errorf("获取长效号码失败,没有返回值")
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
} else {
|
||||||
|
if err == ErrOutOfStockOrUnavailable {
|
||||||
|
return result, statuscode.SmsOutOfStockOrUnavailable
|
||||||
|
}
|
||||||
|
e.Log.Errorf("获取长效号码失败:%v", err)
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return result, statuscode.SmsPlatformUnavailable
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行查询请求
|
||||||
|
func (e *SmsTextVerified) doRequest(resp *dto.TextVerifiedResp) ([]byte, error) {
|
||||||
|
bytes := []byte{}
|
||||||
|
if resp.Href == "" {
|
||||||
|
return bytes, errors.New("成功请求没有返回url")
|
||||||
|
}
|
||||||
|
|
||||||
|
header, err := e.GetAuthHeader()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return bytes, fmt.Errorf("获取授权失败:%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := httphelper.NewHTTPClient(10*time.Second, "", header)
|
||||||
|
|
||||||
|
_, err = client.DoRequest(resp.Method, resp.Href, nil, nil, nil, &bytes)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return bytes, fmt.Errorf("请求失败:%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 长号码租赁
|
||||||
|
func (e *SmsTextVerified) CreateRental(serviceCode string) (dto.TextVerifiedResp, error) {
|
||||||
|
req := dto.TextVerifiedCreateRewalReq{
|
||||||
|
ServiceName: serviceCode,
|
||||||
|
Capability: "sms",
|
||||||
|
NumberType: "mobile",
|
||||||
|
IsRenewable: true,
|
||||||
|
AlwaysOn: false,
|
||||||
|
Duration: "thirtyDay",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := dto.TextVerifiedResp{}
|
||||||
|
|
||||||
|
client, code := e.GetTextVerifiedAuthClient()
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Log.Errorf("获取头信息失败 error: %d", code)
|
||||||
|
return resp, ErrUnAuth
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
status, err := client.Post(createRental, req, headers, &resp)
|
||||||
|
|
||||||
|
// 201 成功
|
||||||
|
if status == http.StatusCreated || resp.Href != "" {
|
||||||
|
return resp, nil
|
||||||
|
} else if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "Out of stock or unavailable") {
|
||||||
|
e.Log.Errorf("缺货或服务不可用 %v", err)
|
||||||
|
return resp, ErrOutOfStockOrUnavailable
|
||||||
|
}
|
||||||
|
e.Log.Errorf("短信平台不可用 error: %v", err)
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, fmt.Errorf("短信平台不可用 status: %v, error: %v", status, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取长效号码详情
|
||||||
|
func (e *SmsTextVerified) GetRentalDetail(id string) (dto.VerificationRentalDetailResp, int) {
|
||||||
|
result := dto.VerificationRentalDetailResp{}
|
||||||
|
|
||||||
|
client, code := e.GetTextVerifiedAuthClient()
|
||||||
|
if code != statuscode.Success {
|
||||||
|
return result, code
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := client.Get(fmt.Sprintf(rentalDetail, id), nil, &result)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("查询长效详情失败 id:%s error: %v", id, err)
|
||||||
|
return result, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// 唤醒号码
|
||||||
|
// returns activationId,messageId, code
|
||||||
|
func (e SmsTextVerified) getExtraActivation(id string) (string, string, int) {
|
||||||
|
client, code := e.GetTextVerifiedAuthClient()
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
return "", "", code
|
||||||
|
}
|
||||||
|
|
||||||
|
req := dto.TextVerifiedWakeUpReq{
|
||||||
|
RevervationId: id,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := dto.TextVerifiedResp{}
|
||||||
|
headers := map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
status, err := client.Post(wakeUp, req, headers, &resp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("唤醒号码失败 id:%s error: %v", id, err)
|
||||||
|
return "", "", statuscode.ServerError
|
||||||
|
} else if status == http.StatusCreated || status == http.StatusOK {
|
||||||
|
if resp.Method != "" && resp.Href != "" {
|
||||||
|
bytes, err := e.doRequest(&resp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("唤醒号码失败 id:%s error: %v", id, err)
|
||||||
|
return "", "", statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
detailResp := dto.TextVerifiedWakeUpResp{}
|
||||||
|
|
||||||
|
if err := sonic.Unmarshal(bytes, &detailResp); err != nil {
|
||||||
|
e.Log.Errorf("唤醒号码反序列化失败 id:%s error: %v", id, err)
|
||||||
|
return "", "", statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
return detailResp.ReservationId, detailResp.Id, statuscode.Success
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("唤醒号码失败 id:%s error: %v", id, err)
|
||||||
|
return "", "", statuscode.ServerError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", "", statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取价格
|
||||||
|
// getType 0-短效 1-长效
|
||||||
|
// returns decimal.Decimal(单价), int(状态code)
|
||||||
|
func (e *SmsTextVerified) GetPrice(typ int, serviceName string) (decimal.Decimal, int) {
|
||||||
|
switch typ {
|
||||||
|
case 1:
|
||||||
|
return e.GetRentalPrice(serviceName)
|
||||||
|
case 0:
|
||||||
|
return e.GetVerificationPrice(serviceName)
|
||||||
|
default:
|
||||||
|
return decimal.Zero, statuscode.SmsInvalidType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取长租价格
|
||||||
|
func (e *SmsTextVerified) GetRentalPrice(serviceName string) (decimal.Decimal, int) {
|
||||||
|
req := dto.TextVerifiedPriceReq{
|
||||||
|
ServiceName: serviceName,
|
||||||
|
Capability: "sms",
|
||||||
|
NumberType: "mobile",
|
||||||
|
AreaCode: false,
|
||||||
|
Duration: "thirtyDay",
|
||||||
|
}
|
||||||
|
|
||||||
|
client, code := e.GetTextVerifiedAuthClient()
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Log.Errorf("获取授权请求失败,status %d", code)
|
||||||
|
return decimal.Zero, code
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := dto.TextVerifiedPriceResp{}
|
||||||
|
headers := map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := client.Post(rentalPrice, req, headers, &resp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取价格失败, error: %v", err)
|
||||||
|
return decimal.Zero, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.Price, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取单次验证码价格
|
||||||
|
func (e *SmsTextVerified) GetVerificationPrice(sericeName string) (decimal.Decimal, int) {
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"serviceName": sericeName,
|
||||||
|
"areaCode": false,
|
||||||
|
"carrier": false,
|
||||||
|
"capability": "sms",
|
||||||
|
"numberType": "mobile",
|
||||||
|
}
|
||||||
|
|
||||||
|
client, code := e.GetTextVerifiedAuthClient()
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Log.Errorf("获取授权请求失败,status %d", code)
|
||||||
|
return decimal.Zero, code
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := dto.TextVerifiedPriceResp{}
|
||||||
|
headers := map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
_, err := client.Post(verificationPrice, params, headers, &resp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("获取价格失败, error: %v", err)
|
||||||
|
return decimal.Zero, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.Price, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单次接收
|
||||||
|
func (e *SmsTextVerified) CreateVerification(serviceCode string) (dto.TextVerifiedResp, int) {
|
||||||
|
req := dto.TextVerifiedCreateRewalReq{
|
||||||
|
ServiceName: serviceCode,
|
||||||
|
Capability: "sms",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := dto.TextVerifiedResp{}
|
||||||
|
client, code := e.GetTextVerifiedAuthClient()
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
return resp, code
|
||||||
|
}
|
||||||
|
headers := map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
status, err := client.Post(createVerification, req, headers, &resp)
|
||||||
|
|
||||||
|
// 201 成功
|
||||||
|
if status == http.StatusCreated {
|
||||||
|
return resp, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("TextVerified创建单次收码失败 error: %v", err)
|
||||||
|
return resp, statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消验证码
|
||||||
|
// typ 0-短效 1-长效
|
||||||
|
func (e SmsTextVerified) CancelRental(id string, typ int) int {
|
||||||
|
client, code := e.GetTextVerifiedAuthClient()
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
var url string
|
||||||
|
|
||||||
|
if typ == 0 {
|
||||||
|
url = fmt.Sprintf(cancelVerification, id)
|
||||||
|
} else {
|
||||||
|
url = fmt.Sprintf(cancelRental, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
_, code, err := client.PostRaw(url, headers)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "Self service refund not permitted for this rental") {
|
||||||
|
return statuscode.SmsRentalRefundNotPermitted
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Log.Errorf("TextVerified取消验证码失败 error: %v", err)
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
if code != http.StatusOK {
|
||||||
|
e.Log.Errorf("TextVerified取消验证码失败,返回状态码 %d", code)
|
||||||
|
}
|
||||||
|
|
||||||
|
return statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SmsTextVerified) GetTextVerifiedAuthClient() (*httphelper.HTTPClient, int) {
|
||||||
|
header, err := e.GetAuthHeader()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("取消验证码获取token失败 error: %v", err)
|
||||||
|
return nil, statuscode.ServerError
|
||||||
|
}
|
||||||
|
client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.SmsTextVerified.Url, header)
|
||||||
|
|
||||||
|
return client, statuscode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
// TextVerifiedWebHook TextVerified短信发送记录回调
|
||||||
|
func (e *SmsTextVerified) TextVerifiedWebHook(req *dto.TextVerifiedWebHookReq) error {
|
||||||
|
entity := &models.SmsPhone{}
|
||||||
|
|
||||||
|
switch req.Event {
|
||||||
|
//续订回调
|
||||||
|
case "v2.rental.billingcycle.renewed":
|
||||||
|
e.Log.Infof("续订回调 %v", req)
|
||||||
|
data := dto.TextVerifiedWebHookRenewedReq{}
|
||||||
|
val, err := sonic.MarshalString(req.Data)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("数据类型错误 %v", req)
|
||||||
|
return fmt.Errorf("数据类型错误 %s", req.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sonic.UnmarshalString(val, &data)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("数据类型错误 %v", req)
|
||||||
|
return fmt.Errorf("数据类型错误 %s", req.Data)
|
||||||
|
}
|
||||||
|
//过期回调
|
||||||
|
case "v2.rental.billingcycle.expired":
|
||||||
|
e.Log.Infof("过期 %v", req)
|
||||||
|
// data := dto.TextVerifiedWebHookBillingCycleExpiredReq{}
|
||||||
|
// val, err := sonic.MarshalString(req.Data)
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// e.Log.Errorf("数据类型错误 %v", req)
|
||||||
|
// return fmt.Errorf("数据类型错误 %s", req.Data)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// err = sonic.UnmarshalString(val, &data)
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// e.Log.Errorf("数据类型错误 %v", req)
|
||||||
|
// return fmt.Errorf("数据类型错误 %s", req.Data)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := e.Orm.Model(&entity).Where("new_activation_id =? and status ='1'", data.RevervationId).Updates(map[string]interface{}{"status": 3}).Error; err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//收到短信回调
|
||||||
|
case "v2.sms.received":
|
||||||
|
e.Log.Infof("收到短信回调 %v", req)
|
||||||
|
data := dto.TextVerifiedWebHookSmsReceivedReq{}
|
||||||
|
|
||||||
|
val, err := sonic.MarshalString(req.Data)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("数据类型错误 %v", req)
|
||||||
|
return fmt.Errorf("数据类型错误 %s", req.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sonic.UnmarshalString(val, &data)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("数据类型错误 %v", req)
|
||||||
|
return fmt.Errorf("数据类型错误 %s", req.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&entity).Where("new_activation_id =? and status =1", data.ReservationId).Updates(map[string]interface{}{"status": "2", "actived": 2, "code": data.ParsedCode}).Error; err != nil {
|
||||||
|
e.Log.Errorf("数据类型错误 %v", req)
|
||||||
|
return fmt.Errorf("数据类型错误 %s", req.Data)
|
||||||
|
}
|
||||||
|
//预定订单完成回调
|
||||||
|
case "v2.rental.backorder.fulfilled":
|
||||||
|
e.Log.Infof("预定订单完成回调 %v", req)
|
||||||
|
data := dto.TextVerifiedWebHookFulfilledReq{}
|
||||||
|
val, err := sonic.MarshalString(req.Data)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("数据类型错误 %v", req)
|
||||||
|
return fmt.Errorf("数据类型错误 %s", req.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sonic.UnmarshalString(val, &data)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("数据类型错误 %v", req)
|
||||||
|
return fmt.Errorf("数据类型错误 %s", req.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if err:=e.Orm.Model(&entity).Where("new_activation_id =? ",data.)
|
||||||
|
// 预定订单创建
|
||||||
|
case "v2.reservation.created":
|
||||||
|
// e.Log.Infof("预定订单创建 %v", req)
|
||||||
|
// data := dto.TextVerifiedWebHookReservationCreatedReq{}
|
||||||
|
// val, err := sonic.MarshalString(req.Data)
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// e.Log.Errorf("数据类型错误 %v", req)
|
||||||
|
// return fmt.Errorf("数据类型错误 %s", req.Data)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// err = sonic.UnmarshalString(val, &data)
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// e.Log.Errorf("数据类型错误 %v", req)
|
||||||
|
// return fmt.Errorf("数据类型错误 %s", req.Data)
|
||||||
|
// }
|
||||||
|
default:
|
||||||
|
e.Log.Errorf("未知的事件类型 %s", req.Event)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 续期
|
||||||
|
// typ 0-短效 1-长效
|
||||||
|
func (e *SmsTextVerified) Renew(activationId string, status bool) int {
|
||||||
|
url := fmt.Sprintf(updateRentalRenewStatus, activationId)
|
||||||
|
|
||||||
|
client, code := e.GetTextVerifiedAuthClient()
|
||||||
|
|
||||||
|
if code != statuscode.Success {
|
||||||
|
e.Log.Errorf("获取长效续期失败 %d", code)
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"includeForRenewal": status,
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
mapData := map[string]interface{}{}
|
||||||
|
statuCode, err := client.Post(url, params, headers, &mapData)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e.Log.Errorf("修改长效续期状态失败 %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if statuCode == http.StatusOK {
|
||||||
|
return statuscode.Success
|
||||||
|
} else {
|
||||||
|
e.Log.Errorf("修改长效续期状态失败 %d", statuCode)
|
||||||
|
return statuscode.ServerError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取授权header头
|
||||||
|
func (e *SmsTextVerified) GetAuthHeader() (map[string]string, error) {
|
||||||
|
token, err := e.GetToken()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
headers := map[string]string{
|
||||||
|
"Authorization": "Bearer " + token,
|
||||||
|
}
|
||||||
|
return headers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取id 根据url (https://www.textverified.com/api/pub/v2/sales/{id}}")
|
||||||
|
func getIdByUrl(URLString string) string {
|
||||||
|
parsedNewURL, _ := url.Parse(URLString)
|
||||||
|
newID := path.Base(parsedNewURL.Path)
|
||||||
|
|
||||||
|
if isValidID(newID) {
|
||||||
|
return newID
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidID(s string) bool {
|
||||||
|
return idPattern.MatchString(s)
|
||||||
|
}
|
||||||
53
app/admin/service/sms_text_verified_test.go
Normal file
53
app/admin/service/sms_text_verified_test.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSmsTextVerifiedLogin(t *testing.T) {
|
||||||
|
db := initSetting()
|
||||||
|
|
||||||
|
s := SmsTextVerified{}
|
||||||
|
s.Orm = db
|
||||||
|
s.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
|
||||||
|
token, err := s.Login()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Login failed: %v", err)
|
||||||
|
} else {
|
||||||
|
t.Logf("Login succeeded, token: %s", token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSmsTextVerifiedGetServices(t *testing.T) {
|
||||||
|
db := initSetting()
|
||||||
|
|
||||||
|
s := SmsTextVerified{}
|
||||||
|
s.Orm = db
|
||||||
|
s.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
|
||||||
|
// Now, test GetServices with the valid token
|
||||||
|
servicesResp, err := s.GetServices()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("GetServices failed: %v", err)
|
||||||
|
} else {
|
||||||
|
t.Logf("GetServices succeeded, services: %+v", servicesResp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSyncTextVerifiedServices(t *testing.T) {
|
||||||
|
db := initSetting()
|
||||||
|
|
||||||
|
s := SmsTextVerified{}
|
||||||
|
s.Orm = db
|
||||||
|
s.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
|
||||||
|
err := s.SyncServices()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("SyncTextVerifiedServices failed: %v", err)
|
||||||
|
} else {
|
||||||
|
t.Log("SyncTextVerifiedServices succeeded")
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -175,6 +175,31 @@ func (e *SysConfig) GetWithKey(c *dto.SysConfigByKeyReq, resp *dto.GetSysConfigB
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *SysConfig) GetWithKeyForList(keys []string, list *[]dto.GetSysConfigByKEYForServiceResp) error {
|
||||||
|
if err := e.Orm.Model(&models.SysConfig{}).Where("config_key in ?", keys).
|
||||||
|
Find(list).Error; err != nil {
|
||||||
|
e.Log.Errorf("Service GetSysConfigByKey error:%s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SysConfig) GetWithKeyForMap(keys []string) (map[string]dto.GetSysConfigByKEYForServiceResp, error) {
|
||||||
|
listData := make([]dto.GetSysConfigByKEYForServiceResp, 0)
|
||||||
|
err := e.GetWithKeyForList(keys, &listData)
|
||||||
|
result := make(map[string]dto.GetSysConfigByKEYForServiceResp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range listData {
|
||||||
|
result[v.ConfigKey] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *SysConfig) GetWithKeyList(c *dto.SysConfigGetToSysAppReq, list *[]models.SysConfig) error {
|
func (e *SysConfig) GetWithKeyList(c *dto.SysConfigGetToSysAppReq, list *[]models.SysConfig) error {
|
||||||
var err error
|
var err error
|
||||||
err = e.Orm.
|
err = e.Orm.
|
||||||
|
|||||||
@ -15,6 +15,33 @@ type SysDictData struct {
|
|||||||
service.Service
|
service.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *SysDictData) GetMapByType(typ string) (map[string]models.SysDictData, error) {
|
||||||
|
datas, err := e.GetByType(typ)
|
||||||
|
result := make(map[string]models.SysDictData)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, data := range datas {
|
||||||
|
result[data.DictValue] = data
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据 type获取字典数据
|
||||||
|
func (e SysDictData) GetByType(typ string) ([]models.SysDictData, error) {
|
||||||
|
var datas []models.SysDictData
|
||||||
|
|
||||||
|
if err := e.Orm.Model(&models.SysDictData{}).Where("dict_type = ?", typ).Find(&datas).Error; err != nil {
|
||||||
|
e.Log.Errorf("根据type获取字典数据失败,\r\n失败信息 %s", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return datas, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetPage 获取列表
|
// GetPage 获取列表
|
||||||
func (e *SysDictData) GetPage(c *dto.SysDictDataGetPageReq, list *[]models.SysDictData, count *int64) error {
|
func (e *SysDictData) GetPage(c *dto.SysDictDataGetPageReq, list *[]models.SysDictData, count *int64) error {
|
||||||
var err error
|
var err error
|
||||||
|
|||||||
@ -50,6 +50,9 @@ func (e SysUser) Register(req *dto.RegisterReq) (dto.SysUserRegisterResp, int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data.RoleId = role.RoleId
|
data.RoleId = role.RoleId
|
||||||
|
memberApiService := MemberApi{}
|
||||||
|
memberApiService.Log = e.Log
|
||||||
|
var memberApi models.MemberApi
|
||||||
|
|
||||||
err := e.Orm.Transaction(func(tx *gorm.DB) error {
|
err := e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
if err1 := tx.Create(&data).Error; err1 != nil {
|
if err1 := tx.Create(&data).Error; err1 != nil {
|
||||||
@ -67,6 +70,13 @@ func (e SysUser) Register(req *dto.RegisterReq) (dto.SysUserRegisterResp, int) {
|
|||||||
result.Token = token
|
result.Token = token
|
||||||
result.Expire = int(expire.Unix())
|
result.Expire = int(expire.Unix())
|
||||||
|
|
||||||
|
memberApiService.Orm = tx
|
||||||
|
|
||||||
|
if err1 := memberApiService.CreateApi(data.UserId, &memberApi, 0); err1 != nil {
|
||||||
|
e.Log.Errorf("创建用户失败 %v", err1)
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -170,11 +180,27 @@ func (e *SysUser) Insert(c *dto.SysUserInsertReq) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.Generate(&data)
|
c.Generate(&data)
|
||||||
err = e.Orm.Create(&data).Error
|
|
||||||
|
memberApiService := MemberApi{}
|
||||||
|
memberApiService.Log = e.Log
|
||||||
|
|
||||||
|
err = e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||||
|
err = tx.Create(&data).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Log.Errorf("db error: %s", err)
|
e.Log.Errorf("db error: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memberApiService.Orm = tx
|
||||||
|
|
||||||
|
if err1 := memberApiService.CreateApi(data.UserId, &models.MemberApi{}, 0); err1 != nil {
|
||||||
|
e.Log.Errorf("创建用户API失败, %s", err1)
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@ func InitJob() {
|
|||||||
"SmsJob": SmsJob{}, //短信定时查询验证码
|
"SmsJob": SmsJob{}, //短信定时查询验证码
|
||||||
"SmsRenewalJob": SmsRenewalJob{}, //短信定时自动续期
|
"SmsRenewalJob": SmsRenewalJob{}, //短信定时自动续期
|
||||||
"AutoDeleteJob": AutoDeleteJob{}, //定时删除任务
|
"AutoDeleteJob": AutoDeleteJob{}, //定时删除任务
|
||||||
|
"SmsPriceJob": SmsPriceJob{}, // 短信价格定时同步
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type SmsJob struct{}
|
type SmsJob struct{}
|
||||||
|
type SmsPriceJob struct{}
|
||||||
|
|
||||||
// 定时查询结果
|
// 定时查询结果
|
||||||
func (j SmsJob) Exec(args interface{}) error {
|
func (j SmsJob) Exec(args interface{}) error {
|
||||||
@ -16,3 +17,17 @@ func (j SmsJob) Exec(args interface{}) error {
|
|||||||
|
|
||||||
return phoneService.SyncCodes()
|
return phoneService.SyncCodes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 定时同步价格
|
||||||
|
func (j SmsPriceJob) Exec(args interface{}) error {
|
||||||
|
smsService := service.SmsServices{}
|
||||||
|
smsService.Orm = GetDb()
|
||||||
|
smsService.Log = logger.NewHelper(logger.DefaultLogger)
|
||||||
|
|
||||||
|
// 同步价格
|
||||||
|
if err := smsService.SyncPrices(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@ -25,3 +25,13 @@ func TestSmsRenew(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSmsPriceJob(t *testing.T) {
|
||||||
|
initSetting()
|
||||||
|
config.ExtConfig.DaisysmsUrl = "https://daisysms.com/stubs/handler_api.php"
|
||||||
|
job := SmsPriceJob{}
|
||||||
|
|
||||||
|
if err := job.Exec(nil); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -5,8 +5,9 @@ import (
|
|||||||
"go-admin/app/admin/service"
|
"go-admin/app/admin/service"
|
||||||
"go-admin/app/admin/service/dto"
|
"go-admin/app/admin/service/dto"
|
||||||
"go-admin/config"
|
"go-admin/config"
|
||||||
|
"go-admin/utils/redishelper"
|
||||||
"go-admin/utils/utility"
|
"go-admin/utils/utility"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -26,6 +27,19 @@ const (
|
|||||||
|
|
||||||
// trx 链上支付定时查询
|
// trx 链上支付定时查询
|
||||||
func (j TrxPaymentJob) Exec(arg interface{}) error {
|
func (j TrxPaymentJob) Exec(arg interface{}) error {
|
||||||
|
key := fmt.Sprintf("pre_order:%s", "*")
|
||||||
|
keys, err := redishelper.DefaultRedis.ScanKeys(key)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("查询redis key失败", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(keys) == 0 {
|
||||||
|
logger.Info("没有待处理订单")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
configService := service.SysConfig{}
|
configService := service.SysConfig{}
|
||||||
configService.Orm = GetDb()
|
configService.Orm = GetDb()
|
||||||
req := dto.SysConfigByKeyReq{}
|
req := dto.SysConfigByKeyReq{}
|
||||||
@ -82,19 +96,31 @@ func (j TrxPaymentJob) Exec(arg interface{}) error {
|
|||||||
// GetTRC20Transfers 获取指定 TRC20 代币的交易记录
|
// GetTRC20Transfers 获取指定 TRC20 代币的交易记录
|
||||||
func GetTRC20Transfers(contractAddress, accountAddress string, minTimestamp, maxTimestamp int64) ([]dto.TRC20Transfer, error) {
|
func GetTRC20Transfers(contractAddress, accountAddress string, minTimestamp, maxTimestamp int64) ([]dto.TRC20Transfer, error) {
|
||||||
url := fmt.Sprintf("%s/v1/accounts/%s/transactions/trc20?contract_address=%s", config.ExtConfig.TrxGridUrl, accountAddress, contractAddress)
|
url := fmt.Sprintf("%s/v1/accounts/%s/transactions/trc20?contract_address=%s", config.ExtConfig.TrxGridUrl, accountAddress, contractAddress)
|
||||||
|
|
||||||
if minTimestamp > 0 {
|
if minTimestamp > 0 {
|
||||||
url += fmt.Sprintf("&min_timestamp=%d", minTimestamp)
|
url += fmt.Sprintf("&min_timestamp=%d", minTimestamp)
|
||||||
}
|
}
|
||||||
if maxTimestamp > 0 {
|
if maxTimestamp > 0 {
|
||||||
url += fmt.Sprintf("&max_timestamp=%d", maxTimestamp)
|
url += fmt.Sprintf("&max_timestamp=%d", maxTimestamp)
|
||||||
}
|
}
|
||||||
resp, err := http.Get(url)
|
// logger.Info("查询地址:", url)
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置请求头(包含 TronGrid API Key)
|
||||||
|
req.Header.Set("Accept", "*/*")
|
||||||
|
req.Header.Set("TRON-PRO-API-KEY", config.ExtConfig.TronApiKey) // 从配置读取 API Key
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to send request: %v", err)
|
return nil, fmt.Errorf("failed to send request: %v", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read response body: %v", err)
|
return nil, fmt.Errorf("failed to read response body: %v", err)
|
||||||
}
|
}
|
||||||
@ -102,6 +128,7 @@ func GetTRC20Transfers(contractAddress, accountAddress string, minTimestamp, max
|
|||||||
var result struct {
|
var result struct {
|
||||||
Data []dto.TRC20Transfer `json:"data"`
|
Data []dto.TRC20Transfer `json:"data"`
|
||||||
}
|
}
|
||||||
|
// logger.Info("查询结果:", string(body))
|
||||||
if err := sonic.Unmarshal(body, &result); err != nil {
|
if err := sonic.Unmarshal(body, &result); err != nil {
|
||||||
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
|
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,10 @@ func initSetting() {
|
|||||||
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
sdk.Runtime.SetDb("default", db)
|
sdk.Runtime.SetDb("default", db)
|
||||||
config.ExtConfig.TrxGridUrl = "https://api.trongrid.io"
|
config.ExtConfig.TrxGridUrl = "https://api.trongrid.io"
|
||||||
|
config.ExtConfig.DaisysmsUrl = "https://daisysms.com/stubs/handler_api.php"
|
||||||
|
config.ExtConfig.SmsTextVerified.ApiKey = "ZQ0swXnsaPpeGdwa3c7gT9U9I1Oh9WoDHx0amuYovvaHuqd5u6B4NBBUSUBjR"
|
||||||
|
config.ExtConfig.SmsTextVerified.UserName = "webspan@proton.me"
|
||||||
|
config.ExtConfig.SmsTextVerified.Url = "https://www.textverified.com"
|
||||||
redishelper.InitDefaultRedis("127.0.0.1:6379", "", 4)
|
redishelper.InitDefaultRedis("127.0.0.1:6379", "", 4)
|
||||||
redishelper.InitLockRedisConn("127.0.0.1:6379", "", "4")
|
redishelper.InitLockRedisConn("127.0.0.1:6379", "", "4")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -186,9 +186,8 @@ func initRouter() {
|
|||||||
if config.SslConfig.Enable {
|
if config.SslConfig.Enable {
|
||||||
r.Use(handler.TlsHandler())
|
r.Use(handler.TlsHandler())
|
||||||
}
|
}
|
||||||
//r.Use(middleware.Metrics())
|
//r.Use(middleware.Metrics()).Use(common.Sentinel()).
|
||||||
r.Use(common.Sentinel()).
|
r.Use(common.RequestId(pkg.TrafficKey)).
|
||||||
Use(common.RequestId(pkg.TrafficKey)).
|
|
||||||
Use(api.SetRequestLogger)
|
Use(api.SetRequestLogger)
|
||||||
|
|
||||||
common.InitMiddleware(r)
|
common.InitMiddleware(r)
|
||||||
@ -218,4 +217,10 @@ func initBusinesses() {
|
|||||||
if _, err := cliProxyService.GetTrafficInfo(); err != nil {
|
if _, err := cliProxyService.GetTrafficInfo(); err != nil {
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memberApiService := service.MemberApi{}
|
||||||
|
memberApiService.Orm = cliProxyService.Orm
|
||||||
|
memberApiService.Log = cliProxyService.Log
|
||||||
|
|
||||||
|
memberApiService.InitApis()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,16 @@ package global
|
|||||||
|
|
||||||
//ConfigKey
|
//ConfigKey
|
||||||
const (
|
const (
|
||||||
TrafficProxyEffectiveDay = "traffic_proxy_effective_day" //流量代理有效天数
|
//流量代理有效天数
|
||||||
LongNumberRenewDeductionStandard = "long_number_renew_deduction_standard" //长效号码续费标准
|
TrafficProxyEffectiveDay = "traffic_proxy_effective_day"
|
||||||
IPRenewDeductionStandard = "ip_renew_deduction_standard" //长效IP续费kk扣除标准
|
//短期号码扣除标准
|
||||||
|
ShortNumberDeductionStandard = "number_fee_short_term"
|
||||||
|
//长效号码扣除标准
|
||||||
|
LongNumberDeductionStandard = "number_fee_long_term"
|
||||||
|
//长效号码续费标准
|
||||||
|
LongNumberRenewDeductionStandard = "long_number_renew_deduction_standard"
|
||||||
|
//长效IP续费kk扣除标准
|
||||||
|
IPRenewDeductionStandard = "ip_renew_deduction_standard"
|
||||||
|
|
||||||
ProxyExpiryTime = "proxy_expiry_time" //代理过期记录保留时长
|
ProxyExpiryTime = "proxy_expiry_time" //代理过期记录保留时长
|
||||||
SmsExpiryTime = "sms_expiry_time" //接码过期记录保留时长
|
SmsExpiryTime = "sms_expiry_time" //接码过期记录保留时长
|
||||||
|
|||||||
7
common/global/sms_services.go
Normal file
7
common/global/sms_services.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package global
|
||||||
|
|
||||||
|
//短效平台code 字典【sms_platform】
|
||||||
|
const (
|
||||||
|
SmsPlatformDaisysms = "daisysms"
|
||||||
|
SmsPlatformTextVerified = "textverified"
|
||||||
|
)
|
||||||
6
common/global/text_verified.go
Normal file
6
common/global/text_verified.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package global
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TextVerified Token
|
||||||
|
TextVerifiedToken = "TextVerifiedToken"
|
||||||
|
)
|
||||||
@ -1,13 +1,28 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-admin-team/go-admin-core/sdk/config"
|
"go-admin/app/admin/models"
|
||||||
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
|
|
||||||
"go-admin/common/middleware/handler"
|
"go-admin/common/middleware/handler"
|
||||||
|
"go-admin/common/rediskey"
|
||||||
|
"go-admin/common/statuscode"
|
||||||
|
"go-admin/utils/redishelper"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/config"
|
||||||
|
"github.com/go-admin-team/go-admin-core/sdk/pkg"
|
||||||
|
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrQueryUserId = errors.New("查询用户失败")
|
||||||
|
var ErrNoAccount = errors.New("没有API用户")
|
||||||
|
var ErrApiUnActived = errors.New("API未激活")
|
||||||
|
|
||||||
// AuthInit jwt验证new
|
// AuthInit jwt验证new
|
||||||
func AuthInit() (*jwt.GinJWTMiddleware, error) {
|
func AuthInit() (*jwt.GinJWTMiddleware, error) {
|
||||||
timeout := time.Hour
|
timeout := time.Hour
|
||||||
@ -34,3 +49,107 @@ func AuthInit() (*jwt.GinJWTMiddleware, error) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apikey授权认证
|
||||||
|
func FrontedAuth(c *gin.Context) {
|
||||||
|
// 从请求头中获取 token 和 os
|
||||||
|
apikey := c.GetHeader("x-api-key")
|
||||||
|
// 如果 token 不存在,返回未登录的状态
|
||||||
|
if len(apikey) == 0 {
|
||||||
|
err := ResponseWithStatus(c, statuscode.Unauthorized)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Abort() // 停止后续中间件的执行
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 验证 token 并获取结果
|
||||||
|
key := fmt.Sprintf(rediskey.MemberApiKey, apikey)
|
||||||
|
val, err := redishelper.DefaultRedis.GetString(key)
|
||||||
|
|
||||||
|
if err != nil || val == "" {
|
||||||
|
ResponseWithStatus(c, statuscode.Unauthorized)
|
||||||
|
c.Abort() // 停止后续中间件的执行
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将解析后的 token 设置到请求头中
|
||||||
|
c.Set("apiKey", apikey)
|
||||||
|
// 继续处理请求
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponseWithStatus 带状态的响应
|
||||||
|
func ResponseWithStatus(ctx *gin.Context, code int, data ...interface{}) error {
|
||||||
|
resp := statuscode.Response{
|
||||||
|
Code: code,
|
||||||
|
Msg: "un authorized",
|
||||||
|
}
|
||||||
|
|
||||||
|
// resp.RequestID = pkg.GenerateMsgIDFromContext(ctx)
|
||||||
|
if len(data) > 0 {
|
||||||
|
resp.Data = data[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
switch code {
|
||||||
|
case 401, 500, 405, 404:
|
||||||
|
ctx.JSON(code, resp)
|
||||||
|
default:
|
||||||
|
ctx.JSON(200, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取ApiKey用户id
|
||||||
|
func GetUserIdWithApiKey(ctx *gin.Context) (int, error) {
|
||||||
|
apikey, ok := ctx.Get("apiKey")
|
||||||
|
if !ok {
|
||||||
|
return 0, errors.New("apiKey not found")
|
||||||
|
}
|
||||||
|
return strconv.Atoi(apikey.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户id 根据ApiKey
|
||||||
|
func GetUserIdByApiKey(c *gin.Context) (int, error) {
|
||||||
|
apiKey, ok := c.Get("apiKey")
|
||||||
|
if !ok {
|
||||||
|
return 0, errors.New("apiKey not found")
|
||||||
|
}
|
||||||
|
db, err := pkg.GetOrm(c)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var userId int
|
||||||
|
val, err := redishelper.DefaultRedis.GetString(fmt.Sprintf(rediskey.MemberApiKey, apiKey))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return userId, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if val == "" {
|
||||||
|
var user models.MemberApi
|
||||||
|
|
||||||
|
if dbErr := db.Model(&user).Where("api_key = ?", apiKey).First(&user).Error; dbErr != nil {
|
||||||
|
return userId, ErrNoAccount
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.Status != 1 {
|
||||||
|
return userId, ErrApiUnActived
|
||||||
|
}
|
||||||
|
|
||||||
|
userId = user.UserId
|
||||||
|
} else {
|
||||||
|
data := models.MemberApi{}
|
||||||
|
err = sonic.UnmarshalString(val, &data)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return userId, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userId = data.UserId
|
||||||
|
}
|
||||||
|
|
||||||
|
return userId, nil
|
||||||
|
}
|
||||||
|
|||||||
6
common/rediskey/member_api.go
Normal file
6
common/rediskey/member_api.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package rediskey
|
||||||
|
|
||||||
|
const (
|
||||||
|
//用户api
|
||||||
|
MemberApiKey = "member_api:%s"
|
||||||
|
)
|
||||||
@ -2,6 +2,14 @@ package statuscode
|
|||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Status int `json:"status"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
RequestID string `json:"RequestId"`
|
||||||
|
}
|
||||||
|
|
||||||
var StatusCodeZh = map[int]string{
|
var StatusCodeZh = map[int]string{
|
||||||
Success: "成功",
|
Success: "成功",
|
||||||
AccountExisted: "账号已存在",
|
AccountExisted: "账号已存在",
|
||||||
@ -17,6 +25,9 @@ var StatusCodeZh = map[int]string{
|
|||||||
MaxPriceExceeded: "超过最大接受单价",
|
MaxPriceExceeded: "超过最大接受单价",
|
||||||
NoNumbers: "号码不足",
|
NoNumbers: "号码不足",
|
||||||
RentalsNotFinished: "需要先完成部分租赁才能继续租赁",
|
RentalsNotFinished: "需要先完成部分租赁才能继续租赁",
|
||||||
|
Unauthorized: "未授权",
|
||||||
|
ApiUnActived: "API未激活",
|
||||||
|
InvalidParams: "参数错误",
|
||||||
|
|
||||||
SmsCancel: "短信验证码_手机号过期",
|
SmsCancel: "短信验证码_手机号过期",
|
||||||
SmsNoActivation: "短信验证码_手机号不存在",
|
SmsNoActivation: "短信验证码_手机号不存在",
|
||||||
@ -26,6 +37,10 @@ var StatusCodeZh = map[int]string{
|
|||||||
SmsNotExpired: "号码未过期无法删除",
|
SmsNotExpired: "号码未过期无法删除",
|
||||||
SmsNotAutoRenew: "短效号码无法自动续期",
|
SmsNotAutoRenew: "短效号码无法自动续期",
|
||||||
SmsServiceUnavailable: "%s服务暂不可用",
|
SmsServiceUnavailable: "%s服务暂不可用",
|
||||||
|
SmsPlatformUnavailable: "通道不可用",
|
||||||
|
SmsInvalidType: "短信验证码_无效类型",
|
||||||
|
SmsOutOfStockOrUnavailable: "短信验证码_缺货或服务不可用",
|
||||||
|
SmsRentalRefundNotPermitted: "短信验证码_租赁退款不允许",
|
||||||
}
|
}
|
||||||
|
|
||||||
var StatusCodeEn = map[int]string{
|
var StatusCodeEn = map[int]string{
|
||||||
@ -43,6 +58,9 @@ var StatusCodeEn = map[int]string{
|
|||||||
MaxPriceExceeded: "max price exceeded",
|
MaxPriceExceeded: "max price exceeded",
|
||||||
NoNumbers: "no numbers",
|
NoNumbers: "no numbers",
|
||||||
RentalsNotFinished: "need to finish some rentals before renting more",
|
RentalsNotFinished: "need to finish some rentals before renting more",
|
||||||
|
Unauthorized: "un authorized",
|
||||||
|
ApiUnActived: "API un actived.",
|
||||||
|
InvalidParams: "invalid params",
|
||||||
|
|
||||||
SmsCancel: "sms code expired",
|
SmsCancel: "sms code expired",
|
||||||
SmsNoActivation: "sms code not exist",
|
SmsNoActivation: "sms code not exist",
|
||||||
@ -52,6 +70,10 @@ var StatusCodeEn = map[int]string{
|
|||||||
SmsNotExpired: "number not expired, can not delete",
|
SmsNotExpired: "number not expired, can not delete",
|
||||||
SmsNotAutoRenew: "num can not auto renew",
|
SmsNotAutoRenew: "num can not auto renew",
|
||||||
SmsServiceUnavailable: "%s service unavailable",
|
SmsServiceUnavailable: "%s service unavailable",
|
||||||
|
SmsPlatformUnavailable: "channel unavailable",
|
||||||
|
SmsInvalidType: "sms type invalid",
|
||||||
|
SmsOutOfStockOrUnavailable: "sms out of stock or unavailable",
|
||||||
|
SmsRentalRefundNotPermitted: "sms rental refund not permitted",
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMsg 获取状态码对应的消息
|
// GetMsg 获取状态码对应的消息
|
||||||
@ -108,6 +130,12 @@ const (
|
|||||||
NoNumbers = 10012
|
NoNumbers = 10012
|
||||||
// Need to finish some rentals before renting more
|
// Need to finish some rentals before renting more
|
||||||
RentalsNotFinished = 10013
|
RentalsNotFinished = 10013
|
||||||
|
// 未授权
|
||||||
|
Unauthorized = 10014
|
||||||
|
// Api未激活
|
||||||
|
ApiUnActived = 10015
|
||||||
|
//参数错误
|
||||||
|
InvalidParams = 10016
|
||||||
|
|
||||||
//短信验证码_手机号过期
|
//短信验证码_手机号过期
|
||||||
SmsCancel = 20014
|
SmsCancel = 20014
|
||||||
@ -125,4 +153,12 @@ const (
|
|||||||
SmsNotAutoRenew = 20020
|
SmsNotAutoRenew = 20020
|
||||||
//短信验证码_服务暂不可用
|
//短信验证码_服务暂不可用
|
||||||
SmsServiceUnavailable = 20021
|
SmsServiceUnavailable = 20021
|
||||||
|
//短信-通道不可用
|
||||||
|
SmsPlatformUnavailable = 20022
|
||||||
|
//短信-未知类型
|
||||||
|
SmsInvalidType = 20023
|
||||||
|
// 短信-缺货或服务不可用
|
||||||
|
SmsOutOfStockOrUnavailable = 20024
|
||||||
|
// 短信-租赁退款不允许
|
||||||
|
SmsRentalRefundNotPermitted = 20025
|
||||||
)
|
)
|
||||||
|
|||||||
@ -12,9 +12,17 @@ var ExtConfig Extend
|
|||||||
type Extend struct {
|
type Extend struct {
|
||||||
AMap AMap // 这里配置对应配置文件的结构即可
|
AMap AMap // 这里配置对应配置文件的结构即可
|
||||||
TrxGridUrl string
|
TrxGridUrl string
|
||||||
|
TronApiKey string `yaml:"tronApiKey"`
|
||||||
CliproxyUrl string //cliproxy服务地址
|
CliproxyUrl string //cliproxy服务地址
|
||||||
CliproxyApiUrl string //cliproxy api地址
|
CliproxyApiUrl string //cliproxy api地址
|
||||||
DaisysmsUrl string //daisysms服务地址
|
DaisysmsUrl string //daisysms服务地址
|
||||||
|
SmsTextVerified SmsTextVerified `yaml:"smsTextVerified"` //短信验证服务配置
|
||||||
|
}
|
||||||
|
|
||||||
|
type SmsTextVerified struct {
|
||||||
|
Url string `yaml:"url"`
|
||||||
|
UserName string `yaml:"userName"`
|
||||||
|
ApiKey string `yaml:"apiKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AMap struct {
|
type AMap struct {
|
||||||
|
|||||||
@ -51,12 +51,19 @@ settings:
|
|||||||
|
|
||||||
#trx api
|
#trx api
|
||||||
trxGridUrl: "https://api.trongrid.io"
|
trxGridUrl: "https://api.trongrid.io"
|
||||||
|
tronApiKey: "223c129e-73f5-470f-9464-f9969846c134"
|
||||||
#cliproxy url
|
#cliproxy url
|
||||||
cliproxyUrl: "https://f.cliproxy.com"
|
cliproxyUrl: "https://f.cliproxy.com"
|
||||||
#cliproxy api url
|
#cliproxy api url
|
||||||
cliproxyApiUrl: "https://api.cliproxy.com"
|
cliproxyApiUrl: "https://api.cliproxy.com"
|
||||||
#daisysms api url
|
#daisysms api url
|
||||||
daisysmsUrl: "https://daisysms.com/stubs/handler_api.php"
|
daisysmsUrl: "https://daisysms.com/stubs/handler_api.php"
|
||||||
|
#sms text_verified
|
||||||
|
smsTextVerified:
|
||||||
|
url: "https://www.textverified.com"
|
||||||
|
userName: "webspan@proton.me"
|
||||||
|
apiKey: "ZQ0swXnsaPpeGdwa3c7gT9U9I1Oh9WoDHx0amuYovvaHuqd5u6B4NBBUSUBjR"
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
redis:
|
redis:
|
||||||
addr: 127.0.0.1:6379
|
addr: 127.0.0.1:6379
|
||||||
|
|||||||
6
go.mod
6
go.mod
@ -1,6 +1,6 @@
|
|||||||
module go-admin
|
module go-admin
|
||||||
|
|
||||||
go 1.18
|
go 1.24
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alibaba/sentinel-golang v1.0.4
|
github.com/alibaba/sentinel-golang v1.0.4
|
||||||
@ -14,8 +14,10 @@ require (
|
|||||||
github.com/go-admin-team/go-admin-core v1.4.1-0.20220809101213-21187928f7d9
|
github.com/go-admin-team/go-admin-core v1.4.1-0.20220809101213-21187928f7d9
|
||||||
github.com/go-admin-team/go-admin-core/sdk v1.4.1-0.20220809101213-21187928f7d9
|
github.com/go-admin-team/go-admin-core/sdk v1.4.1-0.20220809101213-21187928f7d9
|
||||||
github.com/go-redis/redis/v8 v8.11.5
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.12+incompatible
|
github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.12+incompatible
|
||||||
|
github.com/jinzhu/copier v0.4.0
|
||||||
github.com/mssola/user_agent v0.5.2
|
github.com/mssola/user_agent v0.5.2
|
||||||
github.com/opentracing/opentracing-go v1.1.0
|
github.com/opentracing/opentracing-go v1.1.0
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
@ -77,7 +79,6 @@ require (
|
|||||||
github.com/go-redis/redis/v7 v7.4.0 // indirect
|
github.com/go-redis/redis/v7 v7.4.0 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
|
||||||
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||||
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 // indirect
|
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 // indirect
|
||||||
@ -97,7 +98,6 @@ require (
|
|||||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
||||||
github.com/jackc/pgtype v1.11.0 // indirect
|
github.com/jackc/pgtype v1.11.0 // indirect
|
||||||
github.com/jackc/pgx/v4 v4.16.1 // indirect
|
github.com/jackc/pgx/v4 v4.16.1 // indirect
|
||||||
github.com/jinzhu/copier v0.4.0 // indirect
|
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
|
|||||||
@ -50,13 +50,13 @@ func (c *HTTPClient) applyHeaders(req *http.Request, customHeaders map[string]st
|
|||||||
// customHeaders: 自定义请求头,将覆盖默认请求头
|
// customHeaders: 自定义请求头,将覆盖默认请求头
|
||||||
// responseData: 用于存储响应数据的目标结构体(指针类型),如果为 nil 则表示不需要 JSON 解码
|
// responseData: 用于存储响应数据的目标结构体(指针类型),如果为 nil 则表示不需要 JSON 解码
|
||||||
// rawResponse: 用于存储原始响应体字节切片(*[]byte),如果为 nil 则表示不需要原始响应
|
// rawResponse: 用于存储原始响应体字节切片(*[]byte),如果为 nil 则表示不需要原始响应
|
||||||
func (c *HTTPClient) doRequest(
|
func (c *HTTPClient) DoRequest(
|
||||||
method, path string,
|
method, path string,
|
||||||
requestBody interface{},
|
requestBody interface{},
|
||||||
customHeaders map[string]string,
|
customHeaders map[string]string,
|
||||||
responseData interface{},
|
responseData interface{},
|
||||||
rawResponse *[]byte, // 新增参数:指向字节切片的指针,用于存储原始响应
|
rawResponse *[]byte, // 新增参数:指向字节切片的指针,用于存储原始响应
|
||||||
) error {
|
) (int, error) {
|
||||||
// 拼接完整的 URL
|
// 拼接完整的 URL
|
||||||
url := c.BaseURL + path
|
url := c.BaseURL + path
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ func (c *HTTPClient) doRequest(
|
|||||||
// 将请求体编码为 JSON
|
// 将请求体编码为 JSON
|
||||||
jsonBody, err := json.Marshal(requestBody)
|
jsonBody, err := json.Marshal(requestBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("json marshal request body failed: %w", err)
|
return -1, fmt.Errorf("json marshal request body failed: %w", err)
|
||||||
}
|
}
|
||||||
reqBodyReader = bytes.NewBuffer(jsonBody)
|
reqBodyReader = bytes.NewBuffer(jsonBody)
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ func (c *HTTPClient) doRequest(
|
|||||||
// 创建新的 HTTP 请求
|
// 创建新的 HTTP 请求
|
||||||
req, err := http.NewRequest(method, url, reqBodyReader)
|
req, err := http.NewRequest(method, url, reqBodyReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("create http request failed: %w", err)
|
return -1, fmt.Errorf("create http request failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 应用请求头
|
// 应用请求头
|
||||||
@ -85,14 +85,14 @@ func (c *HTTPClient) doRequest(
|
|||||||
// 发送请求
|
// 发送请求
|
||||||
resp, err := c.Client.Do(req)
|
resp, err := c.Client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("send http request failed: %w", err)
|
return -1, fmt.Errorf("send http request failed: %w", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
// 检查 HTTP 状态码
|
// 检查 HTTP 状态码
|
||||||
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest {
|
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest {
|
||||||
bodyBytes, _ := io.ReadAll(resp.Body) // 读取错误响应体
|
bodyBytes, _ := io.ReadAll(resp.Body) // 读取错误响应体
|
||||||
return fmt.Errorf("http request failed with status: %d, body: %s", resp.StatusCode, string(bodyBytes))
|
return resp.StatusCode, fmt.Errorf("http request failed with status: %d, body: %s", resp.StatusCode, string(bodyBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解码响应(支持 gzip)
|
// 解码响应(支持 gzip)
|
||||||
@ -100,7 +100,7 @@ func (c *HTTPClient) doRequest(
|
|||||||
if resp.Header.Get("Content-Encoding") == "gzip" {
|
if resp.Header.Get("Content-Encoding") == "gzip" {
|
||||||
gzipReader, err := gzip.NewReader(resp.Body)
|
gzipReader, err := gzip.NewReader(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("create gzip reader failed: %w", err)
|
return http.StatusOK, fmt.Errorf("create gzip reader failed: %w", err)
|
||||||
}
|
}
|
||||||
defer gzipReader.Close()
|
defer gzipReader.Close()
|
||||||
reader = gzipReader
|
reader = gzipReader
|
||||||
@ -109,7 +109,7 @@ func (c *HTTPClient) doRequest(
|
|||||||
// 首先读取整个响应体,然后决定如何处理
|
// 首先读取整个响应体,然后决定如何处理
|
||||||
bodyBytes, err := io.ReadAll(reader)
|
bodyBytes, err := io.ReadAll(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("read response body failed: %w", err)
|
return http.StatusOK, fmt.Errorf("read response body failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果提供了原始响应目标,则填充它
|
// 如果提供了原始响应目标,则填充它
|
||||||
@ -121,19 +121,19 @@ func (c *HTTPClient) doRequest(
|
|||||||
if responseData != nil {
|
if responseData != nil {
|
||||||
err = json.Unmarshal(bodyBytes, responseData) // 直接对字节切片使用 Unmarshal
|
err = json.Unmarshal(bodyBytes, responseData) // 直接对字节切片使用 Unmarshal
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("json decode response body failed: %w", err)
|
return http.StatusOK, fmt.Errorf("json decode response body failed: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return http.StatusOK, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 发送 GET 请求
|
// Get 发送 GET 请求
|
||||||
// path: 请求路径
|
// path: 请求路径
|
||||||
// customHeaders: 自定义请求头
|
// customHeaders: 自定义请求头
|
||||||
// responseData: 用于存储响应数据的目标结构体(指针类型)
|
// responseData: 用于存储响应数据的目标结构体(指针类型)
|
||||||
func (c *HTTPClient) Get(path string, customHeaders map[string]string, responseData interface{}) error {
|
func (c *HTTPClient) Get(path string, customHeaders map[string]string, responseData interface{}) (int, error) {
|
||||||
return c.doRequest(http.MethodGet, path, nil, customHeaders, responseData, nil) // rawResponse 传递 nil
|
return c.DoRequest(http.MethodGet, path, nil, customHeaders, responseData, nil) // rawResponse 传递 nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post 发送 POST 请求
|
// Post 发送 POST 请求
|
||||||
@ -141,8 +141,8 @@ func (c *HTTPClient) Get(path string, customHeaders map[string]string, responseD
|
|||||||
// requestBody: 请求体数据
|
// requestBody: 请求体数据
|
||||||
// customHeaders: 自定义请求头
|
// customHeaders: 自定义请求头
|
||||||
// responseData: 用于存储响应数据的目标结构体(指针类型)
|
// responseData: 用于存储响应数据的目标结构体(指针类型)
|
||||||
func (c *HTTPClient) Post(path string, requestBody interface{}, customHeaders map[string]string, responseData interface{}) error {
|
func (c *HTTPClient) Post(path string, requestBody interface{}, customHeaders map[string]string, responseData interface{}) (int, error) {
|
||||||
return c.doRequest(http.MethodPost, path, requestBody, customHeaders, responseData, nil) // rawResponse 传递 nil
|
return c.DoRequest(http.MethodPost, path, requestBody, customHeaders, responseData, nil) // rawResponse 传递 nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostWithContentType 发送 POST 请求,支持自定义 Content-Type(如 application/json 或 multipart/form-data)
|
// PostWithContentType 发送 POST 请求,支持自定义 Content-Type(如 application/json 或 multipart/form-data)
|
||||||
@ -232,17 +232,19 @@ func (c *HTTPClient) PostWithContentType(path string, requestBody interface{}, c
|
|||||||
// requestBody: 请求体数据
|
// requestBody: 请求体数据
|
||||||
// customHeaders: 自定义请求头
|
// customHeaders: 自定义请求头
|
||||||
// responseData: 用于存储响应数据的目标结构体(指针类型)
|
// responseData: 用于存储响应数据的目标结构体(指针类型)
|
||||||
func (c *HTTPClient) Put(path string, requestBody interface{}, customHeaders map[string]string, responseData interface{}) error {
|
// returns 状态码 和 错误信息
|
||||||
return c.doRequest(http.MethodPut, path, requestBody, customHeaders, responseData, nil) // rawResponse 传递 nil
|
func (c *HTTPClient) Put(path string, requestBody interface{}, customHeaders map[string]string, responseData interface{}) (int, error) {
|
||||||
|
return c.DoRequest(http.MethodPut, path, requestBody, customHeaders, responseData, nil) // rawResponse 传递 nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 发送 DELETE 请求
|
// Delete 发送 DELETE 请求
|
||||||
// path: 请求路径
|
// path: 请求路径
|
||||||
// customHeaders: 自定义请求头
|
// customHeaders: 自定义请求头
|
||||||
// responseData: 用于存储响应数据的目标结构体(指针类型)
|
// responseData: 用于存储响应数据的目标结构体(指针类型)
|
||||||
func (c *HTTPClient) Delete(path string, customHeaders map[string]string, responseData interface{}) error {
|
// returns 状态码 和 错误信息
|
||||||
|
func (c *HTTPClient) Delete(path string, customHeaders map[string]string, responseData interface{}) (int, error) {
|
||||||
// DELETE 请求通常没有请求体,但某些 RESTful API 可能支持
|
// DELETE 请求通常没有请求体,但某些 RESTful API 可能支持
|
||||||
return c.doRequest(http.MethodDelete, path, nil, customHeaders, responseData, nil) // rawResponse 传递 nil
|
return c.DoRequest(http.MethodDelete, path, nil, customHeaders, responseData, nil) // rawResponse 传递 nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch 发送 PATCH 请求
|
// Patch 发送 PATCH 请求
|
||||||
@ -250,20 +252,39 @@ func (c *HTTPClient) Delete(path string, customHeaders map[string]string, respon
|
|||||||
// requestBody: 请求体数据
|
// requestBody: 请求体数据
|
||||||
// customHeaders: 自定义请求头
|
// customHeaders: 自定义请求头
|
||||||
// responseData: 用于存储响应数据的目标结构体(指针类型)
|
// responseData: 用于存储响应数据的目标结构体(指针类型)
|
||||||
func (c *HTTPClient) Patch(path string, requestBody interface{}, customHeaders map[string]string, responseData interface{}) error {
|
// returns 状态码 和 错误信息
|
||||||
return c.doRequest(http.MethodPatch, path, requestBody, customHeaders, responseData, nil) // rawResponse 传递 nil
|
func (c *HTTPClient) Patch(path string, requestBody interface{}, customHeaders map[string]string, responseData interface{}) (int, error) {
|
||||||
|
return c.DoRequest(http.MethodPatch, path, requestBody, customHeaders, responseData, nil) // rawResponse 传递 nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRaw 发送 GET 请求并返回原始响应体
|
// GetRaw 发送 GET 请求并返回原始响应体
|
||||||
// path: 请求路径
|
// path: 请求路径
|
||||||
// customHeaders: 自定义请求头
|
// customHeaders: 自定义请求头
|
||||||
// 返回值: 原始响应体字节切片或错误
|
// 返回值: 原始响应体字节切片或错误
|
||||||
func (c *HTTPClient) GetRaw(path string, customHeaders map[string]string) ([]byte, error) {
|
// 状态码
|
||||||
|
// 错误信息
|
||||||
|
func (c *HTTPClient) GetRaw(path string, customHeaders map[string]string) ([]byte, int, error) {
|
||||||
var raw []byte
|
var raw []byte
|
||||||
// responseData 传递 nil,rawResponse 传递 &raw
|
// responseData 传递 nil,rawResponse 传递 &raw
|
||||||
err := c.doRequest(http.MethodGet, path, nil, customHeaders, nil, &raw)
|
statusCode, err := c.DoRequest(http.MethodGet, path, nil, customHeaders, nil, &raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, statusCode, err
|
||||||
}
|
}
|
||||||
return raw, nil
|
return raw, statusCode, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostRaw 发送 POST 请求并返回原始响应体
|
||||||
|
// path: 请求路径
|
||||||
|
// customHeaders: 自定义请求头
|
||||||
|
// 返回值: 原始响应体字节切片或错误
|
||||||
|
// 状态码
|
||||||
|
// 错误信息
|
||||||
|
func (c *HTTPClient) PostRaw(path string, customHeaders map[string]string) ([]byte, int, error) {
|
||||||
|
var raw []byte
|
||||||
|
// responseData 传递 nil,rawResponse 传递 &raw
|
||||||
|
statusCode, err := c.DoRequest(http.MethodPost, path, nil, customHeaders, nil, &raw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, statusCode, err
|
||||||
|
}
|
||||||
|
return raw, statusCode, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user