This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
package recovery
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/perfect-panel/server/internal/config"
|
||||
commonLogic "github.com/perfect-panel/server/internal/logic/common"
|
||||
"github.com/perfect-panel/server/internal/svc"
|
||||
"github.com/perfect-panel/server/internal/types"
|
||||
"github.com/perfect-panel/server/pkg/constant"
|
||||
"github.com/perfect-panel/server/pkg/limit"
|
||||
"github.com/perfect-panel/server/pkg/logger"
|
||||
"github.com/perfect-panel/server/pkg/random"
|
||||
"github.com/perfect-panel/server/pkg/xerr"
|
||||
queue "github.com/perfect-panel/server/queue/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type SendCodeLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewSendCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendCodeLogic {
|
||||
return &SendCodeLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *SendCodeLogic) SendCode(req *types.RecoverySendCodeRequest) (*types.SendCodeResponse, error) {
|
||||
email := strings.ToLower(strings.TrimSpace(req.Email))
|
||||
if email == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "email is required")
|
||||
}
|
||||
|
||||
scene := constant.Security.String()
|
||||
cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeCacheKey, scene, email)
|
||||
limiter := limit.NewPeriodLimit(60, 1, l.svcCtx.Redis, fmt.Sprintf("%s:%s:%s", config.SendIntervalKeyPrefix, "email", scene))
|
||||
permit, err := limiter.Take(email)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Failed to take limit")
|
||||
}
|
||||
if !limiter.ParsePermitState(permit) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.TooManyRequests), "send email too many requests")
|
||||
}
|
||||
permit, err = l.svcCtx.AuthLimiter.Take(fmt.Sprintf("%s:%s:%s", "email", scene, email))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Failed to take limit")
|
||||
}
|
||||
if !l.svcCtx.AuthLimiter.ParsePermitState(permit) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.TodaySendCountExceedsLimit), "send email too many requests")
|
||||
}
|
||||
|
||||
code := random.Key(6, 0)
|
||||
expireTime := l.svcCtx.Config.VerifyCode.VerifyCodeExpireTime
|
||||
if expireTime == 0 {
|
||||
expireTime = 900
|
||||
}
|
||||
val, _ := json.Marshal(commonLogic.CacheKeyPayload{
|
||||
Code: code,
|
||||
LastAt: time.Now().Unix(),
|
||||
})
|
||||
if err = l.svcCtx.Redis.Set(l.ctx, cacheKey, string(val), time.Second*time.Duration(expireTime)).Err(); err != nil {
|
||||
return nil, errors.Wrap(xerr.NewErrCode(xerr.ERROR), "Failed to set verification code")
|
||||
}
|
||||
|
||||
expireMinutes := expireTime / 60
|
||||
taskPayload := queue.SendEmailPayload{
|
||||
Type: queue.EmailTypeVerify,
|
||||
Scene: scene,
|
||||
Email: email,
|
||||
Subject: "Verification code",
|
||||
Content: map[string]interface{}{
|
||||
"Type": uint8(constant.Security),
|
||||
"SiteLogo": l.svcCtx.Config.Site.SiteLogo,
|
||||
"SiteName": l.svcCtx.Config.Site.SiteName,
|
||||
"Expire": expireMinutes,
|
||||
"Code": code,
|
||||
},
|
||||
}
|
||||
payload, err := json.Marshal(taskPayload)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(xerr.NewErrCode(xerr.ERROR), "Failed to marshal task payload")
|
||||
}
|
||||
task := asynq.NewTask(queue.ForthwithSendEmail, payload, asynq.MaxRetry(3))
|
||||
if _, err = l.svcCtx.Queue.Enqueue(task); err != nil {
|
||||
return nil, errors.Wrap(xerr.NewErrCode(xerr.ERROR), "Failed to enqueue task")
|
||||
}
|
||||
|
||||
resp := &types.SendCodeResponse{Status: true}
|
||||
if l.svcCtx.Config.Model == constant.DevMode {
|
||||
resp.Code = code
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
Reference in New Issue
Block a user