fix(account): 删除账户时清理会话token避免残留
All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 6m0s

feat(order): 添加邀请双方赠送天数功能
refactor(invite): 移除绑定邀请码时的天数赠送逻辑
This commit is contained in:
shanshanzhong 2025-12-22 20:00:09 -08:00
parent b3edd7e2a6
commit 9bf09c4b9a
3 changed files with 44 additions and 56 deletions

View File

@ -2,7 +2,6 @@ package user
import (
"context"
"time"
"github.com/perfect-panel/server/internal/model/user"
"github.com/perfect-panel/server/internal/svc"
@ -11,7 +10,6 @@ import (
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
"gorm.io/gorm"
)
type BindInviteCodeLogic struct {
@ -45,9 +43,6 @@ func (l *BindInviteCodeLogic) BindInviteCode(req *types.BindInviteCodeRequest) e
// 查找邀请人
referrer, err := l.svcCtx.UserModel.FindOneByReferCode(l.ctx, req.InviteCode)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrapf(xerr.NewErrCode(xerr.UserNotExist), "invite code not found")
}
logger.WithContext(l.ctx).Error(err)
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query referrer failed: %v", err.Error())
}
@ -65,56 +60,5 @@ func (l *BindInviteCodeLogic) BindInviteCode(req *types.BindInviteCodeRequest) e
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update referrer id failed: %v", err.Error())
}
// 给双方赠送天数
err = l.grantGiftDaysToBothParties(currentUser, referrer)
if err != nil {
logger.WithContext(l.ctx).Error(err)
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "grant gift days failed: %v", err.Error())
}
return nil
}
// grantGiftDaysToBothParties 给双方赠送天数
func (l *BindInviteCodeLogic) grantGiftDaysToBothParties(referee *user.User, referrer *user.User) error {
giftDays := l.svcCtx.Config.Invite.GiftDays
// 给被邀请人赠送天数
err := l.grantGiftDays(referee, int(giftDays))
if err != nil {
return err
}
// 给邀请人赠送天数
err = l.grantGiftDays(referrer, int(giftDays))
if err != nil {
return err
}
return nil
}
// grantGiftDays 给用户赠送天数
func (l *BindInviteCodeLogic) grantGiftDays(user *user.User, days int) error {
// 查找用户的活跃订阅
activeSubscribe, err := l.svcCtx.UserModel.FindActiveSubscribe(l.ctx, user.Id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
// 用户没有活跃订阅,跳过赠送
logger.WithContext(l.ctx).Infof("user %d has no active subscription, skip gift days", user.Id)
return nil
}
return err
}
// 延长订阅时间
newExpiredAt := activeSubscribe.ExpireTime.Add(time.Duration(days) * 24 * time.Hour)
activeSubscribe.ExpireTime = newExpiredAt
err = l.svcCtx.UserModel.UpdateSubscribe(l.ctx, activeSubscribe)
if err != nil {
return err
}
logger.WithContext(l.ctx).Infof("granted %d days to user %d, new expired at: %v", days, user.Id, newExpiredAt)
return nil
}

View File

@ -4,7 +4,9 @@ import (
"context"
"crypto/rand"
"encoding/hex"
"fmt"
"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"
@ -94,6 +96,15 @@ func (l *DeleteAccountLogic) DeleteAccount() (resp *types.DeleteAccountResponse,
return nil, err
}
// 注销当前会话token删除Redis中的会话标记并从用户会话集合移除
if sessionId, ok := l.ctx.Value(constant.CtxKeySessionID).(string); ok && sessionId != "" {
sessionKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId)
_ = l.svcCtx.Redis.Del(l.ctx, sessionKey).Err()
// 从用户会话集合中移除当前session避免残留
sessionsKey := fmt.Sprintf("%s%v", config.UserSessionsKeyPrefix, currentUser.Id)
_ = l.svcCtx.Redis.ZRem(l.ctx, sessionsKey, sessionId).Err()
}
resp.Success = true
resp.Message = "账户注销成功"
resp.UserId = newUserId

View File

@ -5,6 +5,7 @@ package orderLogic
import (
"context"
"encoding/json"
"errors"
"fmt"
"strconv"
"time"
@ -354,6 +355,7 @@ func (l *ActivateOrderLogic) createUserSubscription(ctx context.Context, orderIn
// This runs asynchronously to avoid blocking the main order processing flow.
func (l *ActivateOrderLogic) handleCommission(ctx context.Context, userInfo *user.User, orderInfo *order.Order) {
if !l.shouldProcessCommission(userInfo, orderInfo.IsNew) {
l.grantGiftDaysToBothParties(ctx, userInfo)
return
}
@ -421,6 +423,37 @@ func (l *ActivateOrderLogic) handleCommission(ctx context.Context, userInfo *use
}
}
func (l *ActivateOrderLogic) grantGiftDaysToBothParties(ctx context.Context, referee *user.User) {
giftDays := l.svc.Config.Invite.GiftDays
if giftDays <= 0 || referee == nil || referee.Id == 0 {
return
}
_ = l.grantGiftDays(ctx, referee, int(giftDays))
if referee.RefererId == 0 {
return
}
referer, err := l.svc.UserModel.FindOne(ctx, referee.RefererId)
if err != nil || referer == nil {
return
}
_ = l.grantGiftDays(ctx, referer, int(giftDays))
}
func (l *ActivateOrderLogic) grantGiftDays(ctx context.Context, u *user.User, days int) error {
if u == nil || days <= 0 {
return nil
}
activeSubscribe, err := l.svc.UserModel.FindActiveSubscribe(ctx, u.Id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
return err
}
activeSubscribe.ExpireTime = activeSubscribe.ExpireTime.Add(time.Duration(days) * 24 * time.Hour)
return l.svc.UserModel.UpdateSubscribe(ctx, activeSubscribe)
}
// shouldProcessCommission determines if commission should be processed based on
// referrer existence, commission settings, and order type
func (l *ActivateOrderLogic) shouldProcessCommission(userInfo *user.User, isFirstPurchase bool) bool {