同步历史版本代码
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/perfect-panel/server/internal/config"
|
||||
"github.com/perfect-panel/server/internal/model/user"
|
||||
"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/jwt"
|
||||
"github.com/perfect-panel/server/pkg/logger"
|
||||
"github.com/perfect-panel/server/pkg/uuidx"
|
||||
"github.com/perfect-panel/server/pkg/xerr"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type BindEmailWithVerificationLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// NewBindEmailWithVerificationLogic Bind Email With Verification
|
||||
func NewBindEmailWithVerificationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BindEmailWithVerificationLogic {
|
||||
return &BindEmailWithVerificationLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *BindEmailWithVerificationLogic) BindEmailWithVerification(req *types.BindEmailWithVerificationRequest) (*types.BindEmailWithVerificationResponse, error) {
|
||||
req.Email = strings.ToLower(strings.TrimSpace(req.Email))
|
||||
|
||||
u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User)
|
||||
if !ok {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access")
|
||||
}
|
||||
|
||||
type payload struct {
|
||||
Code string `json:"code"`
|
||||
LastAt int64 `json:"lastAt"`
|
||||
}
|
||||
var verified bool
|
||||
scenes := []string{constant.Security.String(), constant.Register.String()}
|
||||
for _, scene := range scenes {
|
||||
cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeCacheKey, scene, req.Email)
|
||||
value, getErr := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result()
|
||||
if getErr != nil || value == "" {
|
||||
continue
|
||||
}
|
||||
var p payload
|
||||
if err := json.Unmarshal([]byte(value), &p); err != nil {
|
||||
continue
|
||||
}
|
||||
if p.Code == req.Code && time.Now().Unix()-p.LastAt <= l.svcCtx.Config.VerifyCode.ExpireTime {
|
||||
_ = l.svcCtx.Redis.Del(l.ctx, cacheKey).Err()
|
||||
verified = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !verified {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error or expired")
|
||||
}
|
||||
|
||||
familyHelper := newFamilyBindingHelper(l.ctx, l.svcCtx)
|
||||
currentEmailMethod, err := familyHelper.getUserEmailMethod(u.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if currentEmailMethod != nil {
|
||||
if currentEmailMethod.AuthIdentifier == req.Email {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.FamilyAlreadyBound), "email already bound to current user")
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.FamilyCrossBindForbidden), "email already bound to another account")
|
||||
}
|
||||
|
||||
existingMethod, err := l.svcCtx.UserModel.FindUserAuthMethodByOpenID(l.ctx, "email", req.Email)
|
||||
if err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query email bind status failed")
|
||||
}
|
||||
|
||||
authInfo := &user.AuthMethods{
|
||||
UserId: u.Id,
|
||||
AuthType: "email",
|
||||
AuthIdentifier: req.Email,
|
||||
Verified: true,
|
||||
}
|
||||
if err = l.svcCtx.DB.Create(authInfo).Error; err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "bind email failed: %v", err)
|
||||
}
|
||||
token, err := l.refreshBindSessionToken(u.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &types.BindEmailWithVerificationResponse{
|
||||
Success: true,
|
||||
Message: "email bound successfully",
|
||||
Token: token,
|
||||
UserId: u.Id,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if existingMethod.UserId == u.Id {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.FamilyAlreadyBound), "email already bound to current user")
|
||||
}
|
||||
|
||||
if err = familyHelper.validateJoinFamily(existingMethod.UserId, u.Id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
joinResult, err := familyHelper.joinFamily(existingMethod.UserId, u.Id, "bind_email_with_verification")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
token, err := l.refreshBindSessionToken(u.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.BindEmailWithVerificationResponse{
|
||||
Success: true,
|
||||
Message: "joined family successfully",
|
||||
Token: token,
|
||||
UserId: u.Id,
|
||||
FamilyJoined: true,
|
||||
FamilyId: joinResult.FamilyId,
|
||||
OwnerUserId: joinResult.OwnerUserId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (l *BindEmailWithVerificationLogic) refreshBindSessionToken(userId int64) (string, error) {
|
||||
sessionId, _ := l.ctx.Value(constant.CtxKeySessionID).(string)
|
||||
if sessionId == "" {
|
||||
sessionId = uuidx.NewUUID().String()
|
||||
}
|
||||
|
||||
opts := []jwt.Option{
|
||||
jwt.WithOption("UserId", userId),
|
||||
jwt.WithOption("SessionId", sessionId),
|
||||
}
|
||||
if loginType, ok := l.ctx.Value(constant.CtxLoginType).(string); ok && loginType != "" {
|
||||
opts = append(opts, jwt.WithOption("CtxLoginType", loginType))
|
||||
}
|
||||
if identifier, ok := l.ctx.Value(constant.CtxKeyIdentifier).(string); ok && identifier != "" {
|
||||
opts = append(opts, jwt.WithOption("identifier", identifier))
|
||||
}
|
||||
|
||||
token, err := jwt.NewJwtToken(
|
||||
l.svcCtx.Config.JwtAuth.AccessSecret,
|
||||
time.Now().Unix(),
|
||||
l.svcCtx.Config.JwtAuth.AccessExpire,
|
||||
opts...,
|
||||
)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "token generate error: %v", err.Error())
|
||||
}
|
||||
|
||||
expire := time.Duration(l.svcCtx.Config.JwtAuth.AccessExpire) * time.Second
|
||||
sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId)
|
||||
if err = l.svcCtx.Redis.Set(l.ctx, sessionIdCacheKey, userId, expire).Err(); err != nil {
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "set session id error: %v", err.Error())
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
Reference in New Issue
Block a user