feat: unify invite flow with referral ref
This commit is contained in:
1 parent
f1d6809109
commit
b501cf4611
47 files changed
+1083
-2548
No files matched your search
@@ -30,7 +30,7 @@ class EmailVerification {
|
||||
update_user_meta($user_id, Service::EMAIL_VERIFIED_META, 1);
|
||||
self::clear_email_verification($user_id);
|
||||
// 仅在状态由"未验证 → 已验证"跳变时触发,避免历史 backfill / 重复调用造成奖励重发。
|
||||
// 监听方负责自己幂等(aksrt_invite 表的 status 检查已经做到这一点)。
|
||||
// 监听方负责自己幂等(Ref 关系使用原子奖励状态处理重复事件)。
|
||||
if (!$was_verified) {
|
||||
do_action('aksrt_email_verified', $user_id);
|
||||
}
|
||||
@@ -447,7 +447,7 @@ class EmailVerification {
|
||||
update_user_meta($user_id, Service::EMAIL_VERIFIED_META, 1);
|
||||
self::clear_email_verification($user_id);
|
||||
Service::log_event('verify.success', ['uid' => $user_id]);
|
||||
// 状态跳变时触发 hook,邀请系统等模块据此发奖
|
||||
// 状态跳变时触发 hook,Ref 推广奖励等模块据此发奖
|
||||
if (!$was_verified) {
|
||||
do_action('aksrt_email_verified', $user_id);
|
||||
}
|
||||
|
||||
@@ -41,35 +41,6 @@ final class Service {
|
||||
private const RESEND_IP_MAX = 6;
|
||||
private const RESEND_IP_WINDOW = 600;
|
||||
|
||||
/**
|
||||
* 注册流程内的"待消费"邀请码上下文。
|
||||
*
|
||||
* 由 register_user() 在 wp_create_user 之前写入,由 \AKSRT\Credits\Invite::on_user_register
|
||||
* 通过 take_pending_invite_context() 一次性消费。
|
||||
*
|
||||
* 设计为请求级静态:避免污染 transient 表,也避免依赖 cookie 在跨标签场景下的不确定性。
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $pending_invite_inviter_id = 0;
|
||||
/** @var string */
|
||||
private static $pending_invite_code = '';
|
||||
|
||||
/**
|
||||
* 取出并清空当前注册请求的"表单 invite_code 解析结果"。
|
||||
*
|
||||
* @return array{inviter_id:int, code:string}
|
||||
*/
|
||||
public static function take_pending_invite_context(): array {
|
||||
$ctx = [
|
||||
'inviter_id' => (int) self::$pending_invite_inviter_id,
|
||||
'code' => (string) self::$pending_invite_code,
|
||||
];
|
||||
self::$pending_invite_inviter_id = 0;
|
||||
self::$pending_invite_code = '';
|
||||
return $ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动钩子:注册全局 authenticate 拦截器(阶段 4)
|
||||
* 调用方:bootstrap.php 在所有类加载完成后调用一次。
|
||||
|
||||
+36
-44
@@ -11,10 +11,6 @@ trait ServicePart1a {
|
||||
|
||||
|
||||
public static function register_user(array $post, array $context = []): array {
|
||||
// 先 reset pending invite context,避免同一进程内残留污染
|
||||
self::$pending_invite_inviter_id = 0;
|
||||
self::$pending_invite_code = '';
|
||||
|
||||
$user_login = sanitize_user(wp_unslash($post['user_login'] ?? ''), true);
|
||||
$user_email = sanitize_email(wp_unslash($post['user_email'] ?? ''));
|
||||
$password = (string) ($post['user_pass'] ?? '');
|
||||
@@ -60,53 +56,47 @@ trait ServicePart1a {
|
||||
}
|
||||
}
|
||||
|
||||
// ====== 解析邀请码 ======
|
||||
// 优先级:表单 invite_code(用户显式填写) > cookie aksrt_invite
|
||||
$invite_registration_enabled = class_exists('\AKSRT\Settings\Settings') && \AKSRT\Settings\Settings::invite_registration_enabled();
|
||||
$invite_mode = $invite_registration_enabled && class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::invite_register_field_mode()
|
||||
: 'hidden';
|
||||
$invite_code = isset($post['invite_code']) ? sanitize_key((string) wp_unslash($post['invite_code'])) : '';
|
||||
$resolved_inviter_id = 0;
|
||||
$invite_is_valid = false;
|
||||
|
||||
if (!$invite_registration_enabled) {
|
||||
// 邀请功能关闭,忽略所有邀请码
|
||||
$invite_code = '';
|
||||
} elseif ($invite_code !== '') {
|
||||
if (class_exists('\AKSRT\Credits\Invite')) {
|
||||
$invite_service = \AKSRT\Credits\Invite::get_instance();
|
||||
$resolved_inviter_id = $invite_service->resolve_code($invite_code);
|
||||
$invite_is_valid = $invite_service->validate_code($invite_code);
|
||||
}
|
||||
// 必填模式下,邀请码无效时根据后台开关决定是否拒绝
|
||||
$reject_invalid = class_exists('\AKSRT\Settings\Settings') && \AKSRT\Settings\Settings::invite_reject_invalid();
|
||||
if ($invite_mode === 'required' && $reject_invalid && !$invite_is_valid) {
|
||||
return ['success' => false, 'error' => __('邀请码无效,请检查后重试', 'aksrt')];
|
||||
}
|
||||
} elseif ($invite_mode === 'required') {
|
||||
return ['success' => false, 'error' => __('请填写邀请码', 'aksrt')];
|
||||
$ref_service = class_exists('\AKSRT\Payment\ReferralAttribution')
|
||||
? \AKSRT\Payment\ReferralAttribution::get_instance()
|
||||
: null;
|
||||
if ($ref_service) {
|
||||
$ref_service->clear_registration_context();
|
||||
}
|
||||
$registration = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_referral_registration_settings()
|
||||
: ['enabled' => false, 'register_field' => 'hidden', 'reject_invalid' => true];
|
||||
$submitted_ref = isset($post['ref']) ? sanitize_key((string) wp_unslash($post['ref'])) : '';
|
||||
$field_mode = !empty($registration['enabled'])
|
||||
? (string) ($registration['register_field'] ?? 'hidden')
|
||||
: 'hidden';
|
||||
$accept_submitted = !empty($registration['enabled']) && $field_mode !== 'hidden';
|
||||
$ref_context = $ref_service
|
||||
? $ref_service->prepare_registration($accept_submitted ? $submitted_ref : '')
|
||||
: ['ref' => '', 'valid' => false, 'submitted_valid' => false, 'conflict' => false, 'source' => 'none'];
|
||||
|
||||
// 把解析到的 inviter_id 暂存到静态字段,user_register hook 内部读取(优先于 cookie)
|
||||
self::$pending_invite_inviter_id = $resolved_inviter_id;
|
||||
self::$pending_invite_code = $invite_code;
|
||||
if ($field_mode === 'required' && empty($ref_context['valid'])) {
|
||||
if ($submitted_ref === '') {
|
||||
if ($ref_service) {
|
||||
$ref_service->clear_registration_context();
|
||||
}
|
||||
return ['success' => false, 'error' => __('请填写推广码', 'aksrt')];
|
||||
}
|
||||
if (!empty($registration['reject_invalid'])) {
|
||||
if ($ref_service) {
|
||||
$ref_service->clear_registration_context();
|
||||
}
|
||||
return ['success' => false, 'error' => __('推广码无效,请检查后重试', 'aksrt')];
|
||||
}
|
||||
}
|
||||
|
||||
$user_id = wp_create_user($user_login, $password, $user_email);
|
||||
if (is_wp_error($user_id)) {
|
||||
self::$pending_invite_inviter_id = 0;
|
||||
self::$pending_invite_code = '';
|
||||
if ($ref_service) {
|
||||
$ref_service->clear_registration_context();
|
||||
}
|
||||
return ['success' => false, 'error' => $user_id->get_error_message()];
|
||||
}
|
||||
|
||||
if ($invite_code !== '' && $resolved_inviter_id <= 0 && class_exists('\AKSRT\Credits\Invite')) {
|
||||
\AKSRT\Credits\Invite::get_instance()->handle_registration_invite((int) $user_id, $invite_code);
|
||||
}
|
||||
|
||||
// wp_create_user 内部已触发 user_register hook,\AKSRT\Credits\Invite::on_user_register 已读取 pending 字段。
|
||||
// 这里清空,避免污染后续请求。
|
||||
self::$pending_invite_inviter_id = 0;
|
||||
self::$pending_invite_code = '';
|
||||
$ref_notice = $ref_service ? $ref_service->take_registration_notice() : '';
|
||||
|
||||
$user = get_userdata($user_id);
|
||||
if (!$user || is_wp_error($user)) {
|
||||
@@ -124,6 +114,7 @@ trait ServicePart1a {
|
||||
'user_id' => (int) $user_id,
|
||||
'user' => $user,
|
||||
'user_login' => $user_login,
|
||||
'notice' => $ref_notice,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -150,6 +141,7 @@ trait ServicePart1a {
|
||||
'verification_method' => $method,
|
||||
'verify_url' => self::get_email_verification_url((int) $user_id, ['mode' => $method]),
|
||||
'message' => $begin['message'] ?? '',
|
||||
'notice' => $ref_notice,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ trait ServicePart1b {
|
||||
/**
|
||||
* 手机号注册
|
||||
*
|
||||
* @param array $post POST 数据 (phone, code, password, invite_code)
|
||||
* @param array $post POST 数据 (phone, code, password, ref)
|
||||
* @return array{success: bool, user_id?: int, error?: string, redirect?: string}
|
||||
*/
|
||||
public static function register_by_phone(array $post): array {
|
||||
@@ -283,9 +283,44 @@ trait ServicePart1b {
|
||||
$suffix++;
|
||||
}
|
||||
|
||||
$ref_service = class_exists('\AKSRT\Payment\ReferralAttribution')
|
||||
? \AKSRT\Payment\ReferralAttribution::get_instance()
|
||||
: null;
|
||||
if ($ref_service) {
|
||||
$ref_service->clear_registration_context();
|
||||
}
|
||||
$registration = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_referral_registration_settings()
|
||||
: ['enabled' => false, 'register_field' => 'hidden', 'reject_invalid' => true];
|
||||
$submitted_ref = sanitize_key((string) ($post['ref'] ?? ''));
|
||||
$field_mode = !empty($registration['enabled'])
|
||||
? (string) ($registration['register_field'] ?? 'hidden')
|
||||
: 'hidden';
|
||||
$accept_submitted = !empty($registration['enabled']) && $field_mode !== 'hidden';
|
||||
$ref_context = $ref_service
|
||||
? $ref_service->prepare_registration($accept_submitted ? $submitted_ref : '')
|
||||
: ['valid' => false, 'submitted_valid' => false, 'conflict' => false, 'source' => 'none'];
|
||||
if ($field_mode === 'required' && empty($ref_context['valid'])) {
|
||||
if ($submitted_ref === '') {
|
||||
if ($ref_service) {
|
||||
$ref_service->clear_registration_context();
|
||||
}
|
||||
return ['success' => false, 'error' => __('请填写推广码', 'aksrt')];
|
||||
}
|
||||
if (!empty($registration['reject_invalid'])) {
|
||||
if ($ref_service) {
|
||||
$ref_service->clear_registration_context();
|
||||
}
|
||||
return ['success' => false, 'error' => __('推广码无效,请检查后重试', 'aksrt')];
|
||||
}
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
$user_id = wp_create_user($username, $pass, $phone . '@sms.aksrt.local');
|
||||
if (is_wp_error($user_id)) {
|
||||
if ($ref_service) {
|
||||
$ref_service->clear_registration_context();
|
||||
}
|
||||
return ['success' => false, 'error' => $user_id->get_error_message()];
|
||||
}
|
||||
|
||||
@@ -296,10 +331,8 @@ trait ServicePart1b {
|
||||
// 邮箱标记为已验证(手机注册等同于已验证)
|
||||
update_user_meta($user_id, 'aksrt_email_verified', '1');
|
||||
|
||||
// 处理邀请码
|
||||
$invite_code = sanitize_key((string) ($post['invite_code'] ?? ''));
|
||||
if ($invite_code !== '' && class_exists('\AKSRT\Credits\Invite')) {
|
||||
\AKSRT\Credits\Invite::get_instance()->handle_registration_invite($user_id, $invite_code);
|
||||
if ($ref_service) {
|
||||
$ref_service->reward_registered_user((int) $user_id);
|
||||
}
|
||||
|
||||
// 自动登录
|
||||
@@ -315,6 +348,7 @@ trait ServicePart1b {
|
||||
'user_id' => $user_id,
|
||||
'redirect' => $redirect,
|
||||
'message' => __('注册成功', 'aksrt'),
|
||||
'notice' => $ref_service ? $ref_service->take_registration_notice() : '',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user