backend/internal/logic/auth/request_password_reset_logi...

140 lines
4.2 KiB
Go
Raw Normal View History

package auth
import (
2025-10-22 13:40:31 +00:00
"backend/internal/domain"
"backend/internal/utils"
2025-11-04 09:47:36 +00:00
errs "backend/pkg/library/errors"
2025-10-22 13:40:31 +00:00
"backend/pkg/member/domain/member"
"backend/pkg/member/domain/usecase"
"context"
2025-10-22 13:40:31 +00:00
"fmt"
"backend/internal/svc"
"backend/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type RequestPasswordResetLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewRequestPasswordResetLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RequestPasswordResetLogic {
return &RequestPasswordResetLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
2025-10-06 13:14:58 +00:00
// RequestPasswordReset 請求發送密碼重設驗證碼 aka 忘記密碼
func (l *RequestPasswordResetLogic) RequestPasswordReset(req *types.RequestPasswordResetReq) (resp *types.RespOK, err error) {
2025-10-22 13:40:31 +00:00
// 驗證並標準化帳號
acc, err := l.validateAndNormalizeAccount(req.AccountType, req.Identifier)
if err != nil {
return nil, err
}
// 檢查發送冷卻時間
rk := domain.GenerateVerifyCodeRedisKey.With(fmt.Sprintf("%s:%d", acc, member.GenerateCodeTypeForgetPassword)).ToString()
if err := l.checkVerifyCodeCooldown(rk); err != nil {
return nil, err
}
// 確認帳號是否註冊並檢查平台限制
if err := l.checkAccountAndPlatform(acc); err != nil {
return nil, err
}
// 生成驗證碼
vcode, err := l.svcCtx.AccountUC.GenerateRefreshCode(l.ctx, usecase.GenerateRefreshCodeRequest{
LoginID: acc,
CodeType: member.GenerateCodeTypeForgetPassword,
})
if err != nil {
return nil, err
}
// 獲取用戶資訊並確認綁定帳號
account, err := l.svcCtx.AccountUC.GetUIDByAccount(l.ctx, usecase.GetUIDByAccountRequest{Account: acc})
if err != nil {
2025-11-04 09:47:36 +00:00
return nil, errs.ResNotFoundError(fmt.Sprintf("account not found:%s", acc))
2025-10-22 13:40:31 +00:00
}
info, err := l.svcCtx.AccountUC.GetUserInfo(l.ctx, usecase.GetUserInfoRequest{UID: account.UID})
if err != nil {
return nil, err
}
// 發送驗證碼
fmt.Println("======= send", vcode.Data.VerifyCode, &info)
//nickname := getEmailShowName(&info)
//if err := l.sendVerificationCode(req.AccountType, acc, &info, vcode.Data.VerifyCode, nickname); err != nil {
// return nil, err
//}
// 設置 Redis 鍵
l.setRedisKeyWithExpiry(rk, vcode.Data.VerifyCode, 60)
return &types.RespOK{}, nil
}
// validateAndNormalizeAccount 驗證並標準化帳號
func (l *RequestPasswordResetLogic) validateAndNormalizeAccount(accountType, account string) (string, error) {
switch member.GetAccountTypeByCode(accountType) {
case member.AccountTypePhone:
phone, isPhone := utils.NormalizeTaiwanMobile(account)
if !isPhone {
2025-11-04 09:47:36 +00:00
return "", errs.InputInvalidFormatError("phone number is invalid")
2025-10-22 13:40:31 +00:00
}
2025-10-22 13:40:31 +00:00
return phone, nil
case member.AccountTypeMail:
if !utils.IsValidEmail(account) {
2025-11-04 09:47:36 +00:00
return "", errs.InputInvalidFormatError("email is invalid")
2025-10-22 13:40:31 +00:00
}
return account, nil
case member.AccountTypeNone, member.AccountTypeDefine:
default:
}
2025-11-04 09:47:36 +00:00
return "", errs.InputInvalidFormatError("unsupported account type")
2025-10-22 13:40:31 +00:00
}
// checkVerifyCodeCooldown 檢查是否已在限制時間內發送過驗證碼
func (l *RequestPasswordResetLogic) checkVerifyCodeCooldown(rk string) error {
if cachedCode, err := l.svcCtx.Redis.GetCtx(l.ctx, rk); err != nil || cachedCode != "" {
2025-11-04 09:47:36 +00:00
return errs.SysTooManyRequestError("verification code already sent, please wait 3min for system to send again")
2025-10-22 13:40:31 +00:00
}
return nil
}
// checkAccountAndPlatform 檢查帳號是否註冊及平台限制
func (l *RequestPasswordResetLogic) checkAccountAndPlatform(acc string) error {
accountInfo, err := l.svcCtx.AccountUC.GetUserAccountInfo(l.ctx, usecase.GetUIDByAccountRequest{Account: acc})
if err != nil {
return err
}
if accountInfo.Data.Platform != member.Digimon {
2025-11-04 09:47:36 +00:00
return errs.InputInvalidFormatError(
2025-10-22 13:40:31 +00:00
"failed to send verify code since platform not correct")
}
return nil
}
// setRedisKeyWithExpiry 設置 Redis 鍵
func (l *RequestPasswordResetLogic) setRedisKeyWithExpiry(rk, verifyCode string, expiry int) {
if status, err := l.svcCtx.Redis.SetnxExCtx(l.ctx, rk, verifyCode, expiry); err != nil || !status {
2025-11-04 09:47:36 +00:00
_ = errs.DBErrorErrorL(l.svcCtx.Logger, []errs.LogField{
{Key: "redisKey", Val: rk},
{Key: "error", Val: err.Error()},
2025-10-22 13:40:31 +00:00
}, "failed to set redis expire").Wrap(err)
}
}