This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/perfect-panel/server/internal/config"
|
||||
commonLogic "github.com/perfect-panel/server/internal/logic/common"
|
||||
"github.com/perfect-panel/server/internal/model/user"
|
||||
"github.com/perfect-panel/server/internal/svc"
|
||||
"github.com/perfect-panel/server/internal/types"
|
||||
@@ -43,6 +44,12 @@ func (l *BindEmailWithVerificationLogic) BindEmailWithVerification(req *types.Bi
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access")
|
||||
}
|
||||
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "bind_start",
|
||||
"[SubscriptionFlow] email bind with verification started",
|
||||
logger.Field("device_user_id", u.Id),
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
|
||||
type payload struct {
|
||||
Code string `json:"code"`
|
||||
LastAt int64 `json:"lastAt"`
|
||||
@@ -69,6 +76,12 @@ func (l *BindEmailWithVerificationLogic) BindEmailWithVerification(req *types.Bi
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error or expired")
|
||||
}
|
||||
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "bind_code_verified",
|
||||
"[SubscriptionFlow] email verification code accepted",
|
||||
logger.Field("device_user_id", u.Id),
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
|
||||
familyHelper := newFamilyBindingHelper(l.ctx, l.svcCtx)
|
||||
currentEmailMethod, err := familyHelper.getUserEmailMethod(u.Id)
|
||||
if err != nil {
|
||||
@@ -115,6 +128,13 @@ func (l *BindEmailWithVerificationLogic) BindEmailWithVerification(req *types.Bi
|
||||
return nil, txErr
|
||||
}
|
||||
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "email_owner_created",
|
||||
"[SubscriptionFlow] new email owner account created for bind flow",
|
||||
logger.Field("device_user_id", u.Id),
|
||||
logger.Field("owner_user_id", emailUser.Id),
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
|
||||
// Join family: email user as owner, device user as member
|
||||
if err = familyHelper.validateJoinFamily(emailUser.Id, u.Id); err != nil {
|
||||
return nil, err
|
||||
@@ -123,11 +143,32 @@ func (l *BindEmailWithVerificationLogic) BindEmailWithVerification(req *types.Bi
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "family_joined",
|
||||
"[SubscriptionFlow] device user joined email owner family",
|
||||
logger.Field("device_user_id", u.Id),
|
||||
logger.Field("owner_user_id", emailUser.Id),
|
||||
logger.Field("family_id", joinResult.FamilyId),
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
token, err := l.refreshBindSessionToken(u.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "trial_grant_requested",
|
||||
"[SubscriptionFlow] evaluating trial grant after email bind",
|
||||
logger.Field("device_user_id", u.Id),
|
||||
logger.Field("owner_user_id", emailUser.Id),
|
||||
logger.Field("family_id", joinResult.FamilyId),
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
tryGrantTrialOnEmailBind(l.ctx, l.svcCtx, l.Logger, emailUser.Id, req.Email)
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "bind_complete",
|
||||
"[SubscriptionFlow] email bind with verification completed",
|
||||
logger.Field("device_user_id", u.Id),
|
||||
logger.Field("owner_user_id", emailUser.Id),
|
||||
logger.Field("family_id", joinResult.FamilyId),
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
return &types.BindEmailWithVerificationResponse{
|
||||
Success: true,
|
||||
Message: "email user created and joined family",
|
||||
@@ -146,16 +187,44 @@ func (l *BindEmailWithVerificationLogic) BindEmailWithVerification(req *types.Bi
|
||||
if err = familyHelper.validateJoinFamily(existingMethod.UserId, u.Id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "email_owner_resolved",
|
||||
"[SubscriptionFlow] existing email owner resolved for bind flow",
|
||||
logger.Field("device_user_id", u.Id),
|
||||
logger.Field("owner_user_id", existingMethod.UserId),
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
joinResult, err := familyHelper.joinFamily(existingMethod.UserId, u.Id, "bind_email_with_verification")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "family_joined",
|
||||
"[SubscriptionFlow] device user joined existing email owner family",
|
||||
logger.Field("device_user_id", u.Id),
|
||||
logger.Field("owner_user_id", existingMethod.UserId),
|
||||
logger.Field("family_id", joinResult.FamilyId),
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
token, err := l.refreshBindSessionToken(u.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "trial_grant_requested",
|
||||
"[SubscriptionFlow] evaluating trial grant after existing email owner bind",
|
||||
logger.Field("device_user_id", u.Id),
|
||||
logger.Field("owner_user_id", existingMethod.UserId),
|
||||
logger.Field("family_id", joinResult.FamilyId),
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
tryGrantTrialOnEmailBind(l.ctx, l.svcCtx, l.Logger, existingMethod.UserId, req.Email)
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "bind_complete",
|
||||
"[SubscriptionFlow] email bind with verification completed",
|
||||
logger.Field("device_user_id", u.Id),
|
||||
logger.Field("owner_user_id", existingMethod.UserId),
|
||||
logger.Field("family_id", joinResult.FamilyId),
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
|
||||
return &types.BindEmailWithVerificationResponse{
|
||||
Success: true,
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/perfect-panel/server/internal/logic/auth"
|
||||
commonLogic "github.com/perfect-panel/server/internal/logic/common"
|
||||
"github.com/perfect-panel/server/internal/model/user"
|
||||
"github.com/perfect-panel/server/internal/svc"
|
||||
"github.com/perfect-panel/server/pkg/logger"
|
||||
@@ -14,18 +15,28 @@ import (
|
||||
|
||||
func tryGrantTrialOnEmailBind(ctx context.Context, svcCtx *svc.ServiceContext, log logger.Logger, ownerUserId int64, email string) {
|
||||
rc := svcCtx.Config.Register
|
||||
commonLogic.SubscriptionTraceInfo(log, commonLogic.SubscriptionTraceFlowEmailBind, "trial_grant_evaluating",
|
||||
"[SubscriptionFlow] evaluating email bind trial grant",
|
||||
logger.Field("owner_user_id", ownerUserId),
|
||||
logger.Field("email", email),
|
||||
logger.Field("trial_subscribe_id", rc.TrialSubscribe),
|
||||
)
|
||||
if !auth.ShouldAutoGrantTrialOnPublicEmailFlows(rc) {
|
||||
log.Infow("auto trial on email flow disabled, skip",
|
||||
commonLogic.SubscriptionTraceInfo(log, commonLogic.SubscriptionTraceFlowEmailBind, "trial_grant_skipped",
|
||||
"[SubscriptionFlow] auto trial on public email flow disabled",
|
||||
logger.Field("email", email),
|
||||
logger.Field("owner_user_id", ownerUserId),
|
||||
logger.Field("skip_reason", "public_email_trial_disabled"),
|
||||
)
|
||||
return
|
||||
}
|
||||
if !auth.ShouldGrantTrialForEmail(rc, email) {
|
||||
if rc.EnableTrial && rc.EnableTrialEmailWhitelist {
|
||||
log.Infow("email domain not in trial whitelist, skip",
|
||||
commonLogic.SubscriptionTraceInfo(log, commonLogic.SubscriptionTraceFlowEmailBind, "trial_grant_skipped",
|
||||
"[SubscriptionFlow] email domain not in trial whitelist",
|
||||
logger.Field("email", email),
|
||||
logger.Field("owner_user_id", ownerUserId),
|
||||
logger.Field("skip_reason", "trial_whitelist_rejected"),
|
||||
)
|
||||
}
|
||||
return
|
||||
@@ -36,12 +47,20 @@ func tryGrantTrialOnEmailBind(ctx context.Context, svcCtx *svc.ServiceContext, l
|
||||
Model(&user.Subscribe{}).
|
||||
Where("user_id = ? AND subscribe_id = ?", ownerUserId, rc.TrialSubscribe).
|
||||
Count(&count).Error; err != nil {
|
||||
log.Errorw("failed to check existing trial", logger.Field("error", err.Error()))
|
||||
commonLogic.SubscriptionTraceError(log, commonLogic.SubscriptionTraceFlowEmailBind, "trial_grant_error",
|
||||
"[SubscriptionFlow] failed to query existing trial subscription",
|
||||
logger.Field("owner_user_id", ownerUserId),
|
||||
logger.Field("email", email),
|
||||
logger.Field("error", err.Error()),
|
||||
)
|
||||
return
|
||||
}
|
||||
if count > 0 {
|
||||
log.Infow("trial already granted, skip",
|
||||
commonLogic.SubscriptionTraceInfo(log, commonLogic.SubscriptionTraceFlowEmailBind, "trial_grant_skipped",
|
||||
"[SubscriptionFlow] trial already exists for owner",
|
||||
logger.Field("owner_user_id", ownerUserId),
|
||||
logger.Field("email", email),
|
||||
logger.Field("skip_reason", "trial_already_exists"),
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -49,16 +68,24 @@ func tryGrantTrialOnEmailBind(ctx context.Context, svcCtx *svc.ServiceContext, l
|
||||
// Cross-user check: prevent the same real inbox (via dot trick / + alias) from
|
||||
// getting multiple trials across different accounts.
|
||||
if auth.NormalizedEmailHasTrial(ctx, svcCtx.DB, email, rc.TrialSubscribe) {
|
||||
log.Infow("normalized email already has trial via another account, skip",
|
||||
commonLogic.SubscriptionTraceInfo(log, commonLogic.SubscriptionTraceFlowEmailBind, "trial_grant_skipped",
|
||||
"[SubscriptionFlow] normalized email already received a trial elsewhere",
|
||||
logger.Field("email", email),
|
||||
logger.Field("owner_user_id", ownerUserId),
|
||||
logger.Field("skip_reason", "normalized_email_has_trial"),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
sub, err := svcCtx.SubscribeModel.FindOne(ctx, rc.TrialSubscribe)
|
||||
if err != nil {
|
||||
log.Errorw("failed to find trial subscribe template", logger.Field("error", err.Error()))
|
||||
commonLogic.SubscriptionTraceError(log, commonLogic.SubscriptionTraceFlowEmailBind, "trial_grant_error",
|
||||
"[SubscriptionFlow] failed to load trial subscription template",
|
||||
logger.Field("owner_user_id", ownerUserId),
|
||||
logger.Field("email", email),
|
||||
logger.Field("trial_subscribe_id", rc.TrialSubscribe),
|
||||
logger.Field("error", err.Error()),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -76,9 +103,13 @@ func tryGrantTrialOnEmailBind(ctx context.Context, svcCtx *svc.ServiceContext, l
|
||||
Status: 1,
|
||||
}
|
||||
if err = svcCtx.UserModel.InsertSubscribe(ctx, userSub); err != nil {
|
||||
log.Errorw("failed to insert trial subscribe",
|
||||
logger.Field("error", err.Error()),
|
||||
logger.Field("owner_user_id", ownerUserId),
|
||||
commonLogic.SubscriptionTraceError(log, commonLogic.SubscriptionTraceFlowEmailBind, "trial_grant_error",
|
||||
"[SubscriptionFlow] failed to create trial subscription for email bind",
|
||||
append(commonLogic.UserSubscribeTraceFields(userSub),
|
||||
logger.Field("error", err.Error()),
|
||||
logger.Field("owner_user_id", ownerUserId),
|
||||
logger.Field("email", email),
|
||||
)...,
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -89,9 +120,12 @@ func tryGrantTrialOnEmailBind(ctx context.Context, svcCtx *svc.ServiceContext, l
|
||||
}
|
||||
}
|
||||
|
||||
log.Infow("trial granted on email bind",
|
||||
logger.Field("owner_user_id", ownerUserId),
|
||||
logger.Field("email", email),
|
||||
logger.Field("subscribe_id", sub.Id),
|
||||
commonLogic.SubscriptionTraceInfo(log, commonLogic.SubscriptionTraceFlowEmailBind, "trial_grant_succeeded",
|
||||
"[SubscriptionFlow] trial subscription granted after email bind",
|
||||
append(commonLogic.UserSubscribeTraceFields(userSub),
|
||||
logger.Field("owner_user_id", ownerUserId),
|
||||
logger.Field("email", email),
|
||||
logger.Field("trial_subscribe_id", sub.Id),
|
||||
)...,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/perfect-panel/server/internal/config"
|
||||
commonLogic "github.com/perfect-panel/server/internal/logic/common"
|
||||
"github.com/perfect-panel/server/internal/model/user"
|
||||
"github.com/perfect-panel/server/internal/svc"
|
||||
"github.com/perfect-panel/server/internal/types"
|
||||
@@ -39,6 +40,10 @@ type CacheKeyPayload struct {
|
||||
|
||||
func (l *VerifyEmailLogic) VerifyEmail(req *types.VerifyEmailRequest) error {
|
||||
req.Email = strings.ToLower(strings.TrimSpace(req.Email))
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "verify_email_start",
|
||||
"[SubscriptionFlow] email verification started",
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeCacheKey, constant.Security, req.Email)
|
||||
value, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result()
|
||||
if err != nil {
|
||||
@@ -59,6 +64,10 @@ func (l *VerifyEmailLogic) VerifyEmail(req *types.VerifyEmailRequest) error {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code expired")
|
||||
}
|
||||
l.svcCtx.Redis.Del(l.ctx, cacheKey)
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "verify_email_code_verified",
|
||||
"[SubscriptionFlow] email verification code accepted",
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
|
||||
u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User)
|
||||
if !ok {
|
||||
@@ -77,6 +86,12 @@ func (l *VerifyEmailLogic) VerifyEmail(req *types.VerifyEmailRequest) error {
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "UpdateUserAuthMethods error")
|
||||
}
|
||||
commonLogic.SubscriptionTraceInfo(l.Logger, commonLogic.SubscriptionTraceFlowEmailBind, "verify_email_completed",
|
||||
"[SubscriptionFlow] email verification completed and trial evaluation will run",
|
||||
logger.Field("user_id", u.Id),
|
||||
logger.Field("owner_user_id", method.UserId),
|
||||
logger.Field("email", req.Email),
|
||||
)
|
||||
tryGrantTrialOnEmailBind(l.ctx, l.svcCtx, l.Logger, method.UserId, req.Email)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user