feat: user check update reate
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"lone-services/pkg/sms"
|
||||
"lone-services/pkg/utils"
|
||||
)
|
||||
|
||||
func NewSMS() (sms.SMS, error) {
|
||||
return sms.New(sms.Config{
|
||||
AccessKeyId: utils.GetConfigString("sms.accessKeyId"),
|
||||
AccessKeySecret: utils.GetConfigString("sms.accessKeySecret"),
|
||||
SignName: utils.GetConfigString("sms.signName"),
|
||||
Endpoint: utils.GetConfigString("sms.endpoint"),
|
||||
TemplateCode: utils.GetConfigString("sms.template.code"),
|
||||
TemplatePwd: utils.GetConfigString("sms.template.password"),
|
||||
Timeout: utils.GetConfigInt("sms.timeout"),
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package dao
|
||||
|
||||
const (
|
||||
SmsSceneLogin int32 = 1
|
||||
SmsSceneResetPassword int32 = 2
|
||||
|
||||
SmsRateLimitSeconds = 60
|
||||
SmsCodeLength = 6
|
||||
)
|
||||
@@ -22,3 +22,10 @@ func failResponse(status utils.Status) *chore.Response {
|
||||
Msg: status.Msg,
|
||||
}
|
||||
}
|
||||
|
||||
func outResponse(status utils.Status, msg string) *chore.Response {
|
||||
return &chore.Response{
|
||||
Code: status.Code,
|
||||
Msg: msg,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"lone-services/pkg/redis"
|
||||
"lone-services/pkg/sms"
|
||||
"lone-services/pkg/utils"
|
||||
"lone-services/pkg/validate"
|
||||
chore "lone-services/rpc/chore/pb"
|
||||
"lone-services/services/chore/internal/dao"
|
||||
"lone-services/services/chore/internal/svc"
|
||||
"lone-services/services/chore/validator"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type SendSmsLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewSendSmsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendSmsLogic {
|
||||
return &SendSmsLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *SendSmsLogic) SendSms(in *chore.SendSmsReq) (*chore.Response, error) {
|
||||
var req validator.SendSmsValidator
|
||||
if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty {
|
||||
return outResponse(utils.ErrorParams, msg), nil
|
||||
}
|
||||
|
||||
if l.svcCtx.SMS == nil {
|
||||
return outResponse(utils.Fail, "短信服务未配置"), nil
|
||||
}
|
||||
|
||||
kind, ok := smsSceneKind(req.Scene)
|
||||
if !ok {
|
||||
return outResponse(utils.ErrorParams, "短信场景不正确"), nil
|
||||
}
|
||||
|
||||
freqKey := smsFreqRedisKey(req.Scene, req.Mobile)
|
||||
okSet, err := redis.Client.SetNX(l.ctx, freqKey, "1", time.Duration(dao.SmsRateLimitSeconds)*time.Second).Result()
|
||||
if err != nil {
|
||||
l.Errorf("sms freq setnx: %v", err)
|
||||
return failResponse(utils.Fail), nil
|
||||
}
|
||||
if !okSet {
|
||||
return outResponse(utils.ErrorParams, "发送过于频繁,请稍后再试"), nil
|
||||
}
|
||||
|
||||
code, err := genDigitCode(dao.SmsCodeLength)
|
||||
if err != nil {
|
||||
_ = redis.Client.Del(l.ctx, freqKey).Err()
|
||||
l.Errorf("sms gen code: %v", err)
|
||||
return failResponse(utils.Fail), nil
|
||||
}
|
||||
|
||||
if err := l.svcCtx.SMS.SendByKind(req.Mobile, kind, map[string]string{"code": code}); err != nil {
|
||||
_ = redis.Client.Del(l.ctx, freqKey).Err()
|
||||
l.Errorf("sms send: %v", err)
|
||||
return outResponse(utils.Fail, "短信发送失败"), nil
|
||||
}
|
||||
|
||||
ttl := l.svcCtx.SMS.Timeout()
|
||||
if ttl <= utils.NumberZero {
|
||||
ttl = 600
|
||||
}
|
||||
codeKey := smsCodeRedisKey(req.Scene, req.Mobile)
|
||||
if err := redis.Client.Set(l.ctx, codeKey, code, time.Duration(ttl)*time.Second).Err(); err != nil {
|
||||
l.Errorf("sms cache code: %v", err)
|
||||
return failResponse(utils.Fail), nil
|
||||
}
|
||||
|
||||
return okResponse(nil), nil
|
||||
}
|
||||
|
||||
func smsSceneKind(scene int32) (sms.TemplateKind, bool) {
|
||||
switch scene {
|
||||
case dao.SmsSceneLogin:
|
||||
return sms.TemplateCode, true
|
||||
case dao.SmsSceneResetPassword:
|
||||
return sms.TemplatePassword, true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
func smsCodeRedisKey(scene int32, mobile string) string {
|
||||
return utils.CodeKey + strconv.Itoa(int(scene)) + ":" + mobile
|
||||
}
|
||||
|
||||
func smsFreqRedisKey(scene int32, mobile string) string {
|
||||
return "sms:freq:" + strconv.Itoa(int(scene)) + ":" + mobile
|
||||
}
|
||||
|
||||
func genDigitCode(length int) (string, error) {
|
||||
if length <= utils.NumberZero {
|
||||
return utils.StringEmpty, fmt.Errorf("invalid code length")
|
||||
}
|
||||
out := make([]byte, length)
|
||||
for i := range out {
|
||||
n, err := rand.Int(rand.Reader, big.NewInt(10))
|
||||
if err != nil {
|
||||
return utils.StringEmpty, err
|
||||
}
|
||||
out[i] = byte('0' + n.Int64())
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
@@ -2,11 +2,12 @@ package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"lone-services/pkg/rpcclient"
|
||||
"lone-services/pkg/utils"
|
||||
chore "lone-services/rpc/chore/pb"
|
||||
sale "lone-services/rpc/sale/pb"
|
||||
user "lone-services/rpc/user/pb"
|
||||
"lone-services/services/chore/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
@@ -32,7 +33,8 @@ func NewTestLogic(ctx context.Context, svcCtx *svc.ServiceContext) *TestLogic {
|
||||
|
||||
func (l *TestLogic) Test(in *chore.TestReq) (*chore.Response, error) {
|
||||
// cli, err := rpcclient.Get(l.svcCtx.ProductSvcName)
|
||||
cli, err := rpcclient.Get(l.svcCtx.SaleSvcName)
|
||||
// cli, err := rpcclient.Get(l.svcCtx.SaleSvcName)
|
||||
cli, err := rpcclient.Get(l.svcCtx.UserSvcName)
|
||||
|
||||
if err != nil {
|
||||
l.Errorf("get rpc: %v", err)
|
||||
@@ -103,10 +105,29 @@ func (l *TestLogic) Test(in *chore.TestReq) (*chore.Response, error) {
|
||||
// })
|
||||
|
||||
// ——————————————————————————————销售详情——————————————————————————————
|
||||
res, err := sale.NewSaleClient(cli.Conn()).InfoInternal(l.ctx, &sale.InfoReq{
|
||||
Id: int64(in.GetId()),
|
||||
})
|
||||
// res, err := sale.NewSaleClient(cli.Conn()).InfoInternal(l.ctx, &sale.InfoReq{
|
||||
// Id: int64(in.GetId()),
|
||||
// })
|
||||
|
||||
// ——————————————————————————————用户创建——————————————————————————————
|
||||
// res, err := user.NewUserClient(cli.Conn()).InternalCheckCreate(l.ctx, &user.InternalCheckCreateReq{
|
||||
// Mobile: in.GetChar(),
|
||||
// })
|
||||
|
||||
// res, err := user.NewUserClient(cli.Conn()).InternalCheckUpdate(l.ctx, &user.InternalCheckUpdateReq{
|
||||
// UserId: int64(in.GetId()),
|
||||
// Mobile: in.GetChar(),
|
||||
// })
|
||||
// fmt.Println(res.GetResult())
|
||||
|
||||
res, err := user.NewUserClient(cli.Conn()).InternalCreate(l.ctx, &user.InternalCreateReq{
|
||||
Mobile: in.GetChar(),
|
||||
ClientCode: []string{"user_skin", "user_o2"},
|
||||
CredentialType: []string{"password", "sms"},
|
||||
Identifier: in.GetChar(),
|
||||
Secret: "123123",
|
||||
})
|
||||
fmt.Println(res)
|
||||
if err != nil {
|
||||
l.Errorf("XXXXXX: %v", err)
|
||||
return failResponse(utils.ErrorInternalServer), nil
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Code generated by goctl. DO NOT EDIT.
|
||||
// goctl 1.10.2
|
||||
// goctl 1.10.1
|
||||
// Source: chore.proto
|
||||
|
||||
package server
|
||||
@@ -43,6 +43,11 @@ func (s *ChoreServer) Regions(ctx context.Context, in *chore.RegionsReq) (*chore
|
||||
return l.Regions(in)
|
||||
}
|
||||
|
||||
func (s *ChoreServer) SendSms(ctx context.Context, in *chore.SendSmsReq) (*chore.Response, error) {
|
||||
l := logic.NewSendSmsLogic(ctx, s.svcCtx)
|
||||
return l.SendSms(in)
|
||||
}
|
||||
|
||||
func (s *ChoreServer) AnswerItems(ctx context.Context, in *chore.EmptyReq) (*chore.Response, error) {
|
||||
l := logic.NewAnswerItemsLogic(ctx, s.svcCtx)
|
||||
return l.AnswerItems(in)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"lone-services/pkg/sms"
|
||||
"lone-services/pkg/utils"
|
||||
"lone-services/services/chore/internal/config"
|
||||
|
||||
@@ -13,6 +14,8 @@ type ServiceContext struct {
|
||||
DB *gorm.DB
|
||||
ProductSvcName string
|
||||
SaleSvcName string
|
||||
UserSvcName string
|
||||
SMS sms.SMS
|
||||
}
|
||||
|
||||
func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext {
|
||||
@@ -24,11 +27,22 @@ func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext {
|
||||
if saleSvc == utils.StringEmpty {
|
||||
logx.Error("config services.sale empty")
|
||||
}
|
||||
userSvc := utils.GetConfigString("services.user")
|
||||
if userSvc == utils.StringEmpty {
|
||||
logx.Error("config services.user empty")
|
||||
}
|
||||
|
||||
smsClient, err := config.NewSMS()
|
||||
if err != nil {
|
||||
logx.Errorf("sms init: %v", err)
|
||||
}
|
||||
|
||||
return &ServiceContext{
|
||||
Config: c,
|
||||
DB: db,
|
||||
ProductSvcName: productSvc,
|
||||
SaleSvcName: saleSvc,
|
||||
UserSvcName: userSvc,
|
||||
SMS: smsClient,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user