From 0dfe1d8afafc59c4a5559c498342668d5a58d6ef Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Thu, 23 Jul 2026 22:41:41 +0000
Subject: [PATCH] =Still working away at the Integrations overhaul

---
 inc/managers/MagicLinkManager.php |  332 +++++++++++++++++++++++++++++++++---------------------
 1 files changed, 201 insertions(+), 131 deletions(-)

diff --git a/inc/managers/MagicLinkManager.php b/inc/managers/MagicLinkManager.php
index 6b91d7a..30c11f4 100644
--- a/inc/managers/MagicLinkManager.php
+++ b/inc/managers/MagicLinkManager.php
@@ -1,6 +1,10 @@
 <?php
 namespace JVBase\managers;
 
+use JetBrains\PhpStorm\NoReturn;
+use JVBase\base\Site;
+use JVBase\meta\Form;
+use JVBase\ui\Tabs;
 use WP_User;
 use WP_Error;
 
@@ -16,8 +20,8 @@
  */
 class MagicLinkManager
 {
-	protected CacheManager $cache;
-	protected EmailManager $email;
+	protected Cache $cache;
+	protected Cache $referral_cache;
 
 	// Token settings
 	protected int $token_expiry = 900; // 15 minutes in seconds
@@ -32,15 +36,13 @@
 
 	public function __construct()
 	{
-		$this->cache = CacheManager::for('magic_links', $this->token_expiry);
-		$this->email = new EmailManager();
+		$this->cache = Cache::for('magic_links', $this->token_expiry);
+		$this->referral_cache = Cache::for('referral_magic_links', 14 * DAY_IN_SECONDS);
 
 		// Hook into WordPress auth flow
 		add_action('template_redirect', [$this, 'handleMagicLinkClick']);
 		add_action('wp_login_failed', [$this, 'handleFailedLogin']);
-
-		// NOTE: LoginManager now handles the login form UI
-		// If magic_link integration is enabled, LoginManager will call addMagicLinkOption()
+		add_action('jvb_process_login_tokens', [$this, 'processRegistrationToken'], 10, 3);
 	}
 
 	/**
@@ -56,32 +58,25 @@
 		// Validate email
 		$email = sanitize_email($email);
 		if (!is_email($email)) {
+			error_log('Invalid email for Magic Link: '.$email);
 			return new WP_Error('invalid_email', 'Invalid email address');
 		}
 
 		// Check rate limiting
 		$rate_check = $this->checkRateLimit($email);
 		if (is_wp_error($rate_check)) {
+			error_log('Rate limit reached for Magic Link: '.$email);
 			return $rate_check;
 		}
 
 		// Handle different link types
-		switch ($type) {
-			case self::TYPE_LOGIN:
-				return $this->sendLoginLink($email, $context);
-
-			case self::TYPE_SIGNUP:
-				return $this->sendSignupLink($email, $context);
-
-			case self::TYPE_REFERRAL:
-				return $this->sendReferralLink($email, $context);
-
-			case self::TYPE_RESET:
-				return $this->sendResetLink($email, $context);
-
-			default:
-				return new WP_Error('invalid_type', 'Invalid magic link type');
-		}
+		return match ($type) {
+			self::TYPE_LOGIN => $this->sendLoginLink($email, $context),
+			self::TYPE_SIGNUP => $this->sendSignupLink($email, $context),
+			self::TYPE_REFERRAL => $this->sendReferralLink($email, $context),
+			self::TYPE_RESET => $this->sendResetLink($email, $context),
+			default => new WP_Error('invalid_type', 'Invalid magic link type'),
+		};
 	}
 
 	/**
@@ -90,6 +85,7 @@
 	protected function generateToken(string $email, string $type, array $data = []): string
 	{
 		$token = wp_generate_password(32, false);
+		error_log('Generated Token: '.$token);
 
 		$token_data = array_merge([
 			'email' => $email,
@@ -97,7 +93,15 @@
 			'created' => time()
 		], $data);
 
-		$this->cache->set($token, $token_data);
+		// Use longer expiry for referral tokens
+		if ($type === self::TYPE_REFERRAL) {
+			$this->referral_cache->set($token, $token_data);
+		} else {
+			error_log('Setting to $this->cache');
+			$this->cache->set($token, $token_data);
+		}
+
+		error_log('Generated token: '.print_r($token_data, true));
 
 		return $token;
 	}
@@ -105,11 +109,19 @@
 	/**
 	 * Verify a token
 	 */
-	protected function verifyToken(string $token, string $email): array|WP_Error
+	public function verifyToken(string $token, string $email): array|WP_Error
 	{
+		error_log('Verifying token: '.$token);
+		// Try regular cache first, then referral cache
 		$token_data = $this->cache->get($token);
+		error_log('Got token data from cache: '.print_r($token_data, true));
 
 		if (!$token_data) {
+			$token_data = $this->referral_cache->get($token);
+		}
+
+		if (!$token_data) {
+			error_log('Token not found. Checking cache stats...');
 			return new WP_Error('invalid_token', 'Invalid or expired token');
 		}
 
@@ -118,7 +130,12 @@
 		}
 
 		// Delete token after verification (single use)
-		$this->cache->delete($token);
+		// Check which cache it's in and delete from the correct one
+		if ($token_data['type'] === 'referral') {
+			$this->referral_cache->forget($token);
+		} else {
+			$this->cache->forget($token);
+		}
 
 		return $token_data;
 	}
@@ -162,7 +179,8 @@
 	{
 		$user = get_user_by('email', $email);
 		if (!$user) {
-			return new WP_Error('user_not_found', 'No account found with this email');
+			error_log('Attempted signin with no account, redirecting to signup link '.$email);
+			return $this->sendSignupLink($email, $context);
 		}
 
 		$token = $this->generateToken($email, self::TYPE_LOGIN, [
@@ -171,7 +189,7 @@
 
 		$magic_url = add_query_arg([
 			'magic_token' => $token,
-			'email' => urlencode($email),
+			'email' => rawurlencode($email),
 			'action' => 'magic_login'
 		], home_url('/'));
 
@@ -182,7 +200,7 @@
 		$subject = 'Sign in to ' . get_bloginfo('name');
 		$message = $this->getLoginEmailTemplate($user->display_name, $magic_url);
 
-		$sent = $this->email->sendEmail($email, $subject, $message, 'Log in to '. get_bloginfo('name'));
+		$sent = JVB()->email()->sendEmail($email, $subject, $message, 'Log in to '. get_bloginfo('name'));
 
 		return $sent ? true : new WP_Error('email_failed', 'Failed to send magic link');
 	}
@@ -199,7 +217,7 @@
 
 		$token_data = [
 			'name' => $context['name'] ?? '',
-			'role' => $context['role'] ?? 'subscriber',
+			'role' => $context['role'] ?? Site::getDefaultRole(),
 			'meta' => $context['meta'] ?? []
 		];
 
@@ -207,14 +225,14 @@
 
 		$magic_url = add_query_arg([
 			'magic_token' => $token,
-			'email' => urlencode($email),
+			'email' => rawurlencode($email),
 			'action' => 'magic_signup'
 		], home_url('/'));
 
 		$subject = 'Complete your ' . get_bloginfo('name') . ' registration';
 		$message = $this->getSignupEmailTemplate($context['name'] ?? '', $magic_url);
 
-		$sent = $this->email->sendEmail($email, $subject, $message, 'Complete Registration');
+		$sent = JVB()->email()->sendEmail($email, $subject, $message, 'Complete Registration');
 
 		return $sent ? true : new WP_Error('email_failed', 'Failed to send signup link');
 	}
@@ -231,24 +249,25 @@
 		$token_data = [
 			'referral_code' => $context['referral_code'],
 			'name' => $context['name'] ?? '',
-			'role' => $context['role'] ?? 'subscriber'
+			'role' => $context['role'] ?? 'subscriber',
+			'email'	=> $email
 		];
 
 		$token = $this->generateToken($email, self::TYPE_REFERRAL, $token_data);
 
 		$magic_url = add_query_arg([
 			'magic_token' => $token,
-			'email' => urlencode($email),
+			'email' => rawurlencode($email),
 			'action' => 'magic_referral'
 		], home_url('/'));
 
 		$referrer_name = $context['referrer_name'] ?? 'A friend';
 		$reward_text = $context['reward_text'] ?? '';
 
-		$subject = $referrer_name . ' invited you to join ' . get_bloginfo('name');
-		$message = $this->getReferralEmailTemplate($context['name'] ?? '', $referrer_name, $magic_url, $reward_text);
+		$subject = (array_key_exists('subject', $context) && $context['subject'] !== '') ? $context['subject'] : $referrer_name . ' invited you to join ' . get_bloginfo('name');
+		$message = $this->getReferralEmailTemplate($context['name'] ?? '', $referrer_name, $magic_url, $reward_text, $context);
 
-		$sent = $this->email->sendEmail($email, $subject, $message, 'Accept Invitation');
+		$sent = JVB()->email()->sendEmail($email, $subject, $message, 'Accept Invitation');
 
 		return $sent ? true : new WP_Error('email_failed', 'Failed to send referral link');
 	}
@@ -269,14 +288,14 @@
 
 		$magic_url = add_query_arg([
 			'magic_token' => $token,
-			'email' => urlencode($email),
+			'email' => rawurlencode($email),
 			'action' => 'magic_reset'
 		], home_url('/'));
 
 		$subject = 'Reset your password';
 		$message = $this->getResetEmailTemplate($user->display_name, $magic_url);
 
-		$sent = $this->email->sendEmail($email, $subject, $message, 'Reset Password');
+		$sent = JVB()->email()->sendEmail($email, $subject, $message, 'Reset Password');
 
 		return $sent ? true : new WP_Error('email_failed', 'Failed to send reset link');
 	}
@@ -286,13 +305,12 @@
 	 */
 	public function handleMagicLinkClick(): void
 	{
-		if (!isset($_GET['action']) || !isset($_GET['magic_token']) || !isset($_GET['email'])) {
+		if (!isset($_GET['magic_token']) || !isset($_GET['action']) || !isset($_GET['email'])) {
 			return;
 		}
-
 		$action = sanitize_text_field($_GET['action']);
 		$token = sanitize_text_field($_GET['magic_token']);
-		$email = sanitize_email($_GET['email']);
+		$email = sanitize_email(rawurldecode($_GET['email']));
 
 		if (!in_array($action, ['magic_login', 'magic_signup', 'magic_referral', 'magic_reset'])) {
 			return;
@@ -301,8 +319,7 @@
 		$token_data = $this->verifyToken($token, $email);
 
 		if (is_wp_error($token_data)) {
-			$this->handleInvalidToken($token_data);
-			return;
+			$this->cleanURL();
 		}
 
 		switch ($action) {
@@ -324,6 +341,19 @@
 		}
 	}
 
+	#[NoReturn] protected function cleanURL():void
+	{
+		global $wp;
+		$redirect = isset($_GET['redirect_to']) ? esc_url_raw($_GET['redirect_to']) : get_home_url(null, '/'.$wp->request);
+		if (isset($_GET['magic_token'])) {
+			error_log('============= Redirecting and removing magic token stuffs =============');
+			wp_safe_redirect(remove_query_arg(['magic_token', 'action', 'email'], esc_url($redirect)));
+			exit;
+		}
+		wp_safe_redirect(esc_url($redirect));
+		exit;
+	}
+
 	/**
 	 * Process login via magic link
 	 */
@@ -332,6 +362,7 @@
 		$user = get_user_by('ID', $token_data['user_id']);
 
 		if (!$user) {
+			error_log('No user found: '.print_r($user, true));
 			wp_die('Invalid user');
 		}
 
@@ -340,18 +371,18 @@
 		wp_set_auth_cookie($user->ID, true);
 
 		do_action('wp_login', $user->user_login, $user);
-
-		$redirect = isset($_GET['redirect_to']) ? esc_url_raw($_GET['redirect_to']) : home_url('/dash');
-
-		wp_safe_redirect($redirect);
-		exit;
+		$this->cleanURL();
 	}
 
 	/**
 	 * Process signup via magic link
 	 */
-	protected function processSignup(array $token_data): void
+	#[NoReturn] protected function processSignup(array $token_data): void
 	{
+		if (!array_key_exists('email', $token_data) || !array_key_exists('name', $token_data)) {
+			JVB()->error()->log('MagicLinkManager', 'Could not process Signup');
+			$this->cleanURL();
+		}
 		$user_id = wp_create_user(
 			$token_data['email'],
 			wp_generate_password(20, true, true),
@@ -359,7 +390,7 @@
 		);
 
 		if (is_wp_error($user_id)) {
-			wp_die('Failed to create account: ' . $user_id->get_error_message());
+			$this->cleanURL();
 		}
 
 		$user = get_user_by('ID', $user_id);
@@ -382,57 +413,53 @@
 		wp_set_current_user($user_id);
 		wp_set_auth_cookie($user_id, true);
 
-		do_action('user_register', $user_id);
 		do_action('wp_login', $user->user_login, $user);
 
-		wp_safe_redirect(home_url('/dash?welcome=1'));
-		exit;
+		$this->cleanURL();
 	}
 
 	/**
 	 * Process referral signup via magic link
 	 */
+	/**
+	 * Process referral signup via magic link
+	 */
 	protected function processReferralSignup(array $token_data): void
 	{
-		$user_id = wp_create_user(
-			$token_data['email'],
-			wp_generate_password(20, true, true),
-			$token_data['email']
-		);
-
-		if (is_wp_error($user_id)) {
-			wp_die('Failed to create account: ' . $user_id->get_error_message());
+		if (!array_key_exists('email', $token_data) || !array_key_exists('name', $token_data)) {
+			JVB()->error()->log('[MagicLinkManager]Could not process Referral Signup');
+			return;
 		}
 
-		if (!empty($token_data['name'])) {
-			wp_update_user([
-				'ID' => $user_id,
-				'display_name' => $token_data['name'],
-				'first_name' => $token_data['name']
-			]);
+		$email = sanitize_email($token_data['email']);
+		if (email_exists($email)) {
+			$this->processSignup($token_data);
 		}
 
-		// Store referral code for ReferralManager
-		if (session_status() === PHP_SESSION_NONE) {
-			session_start();
+		$role = JVB()->referrals()->getRole();
+		$pass = wp_generate_password(20, true, true);
+		$name = sanitize_text_field($token_data['name']);
+		$user_id = wp_insert_user([
+			'user_login' 	=> $email,
+			'user_email' 	=> $email,
+			'user_pass'		=> $pass,
+			'display_name'	=> $name,
+			'role'			=> $role
+		]);
+		if (!is_wp_error($user_id)) {
+			$response = JVB()->routes('login')->login($email, $pass, true);
+			if ($response) {
+				wp_safe_redirect(home_url('/dash?welcome=1&referral=1'));
+				exit;
+			}
+		} else {
+			JVB()->error()->log(
+				'[MagicLinkManager]',
+				$user_id->get_error_message(),
+				$token_data
+			);
+			$this->cleanURL();
 		}
-		$_SESSION[BASE . 'referral_code'] = $token_data['referral_code'];
-		setcookie(
-			BASE . 'referral_code',
-			$token_data['referral_code'],
-			time() + (86400 * 30),
-			'/'
-		);
-
-		$user = get_user_by('ID', $user_id);
-		wp_set_current_user($user_id);
-		wp_set_auth_cookie($user_id, true);
-
-		do_action('user_register', $user_id);
-		do_action('wp_login', $user->user_login, $user);
-
-		wp_safe_redirect(home_url('/dash?welcome=1&referral=1'));
-		exit;
 	}
 
 	/**
@@ -443,26 +470,22 @@
 		$user = get_user_by('ID', $token_data['user_id']);
 
 		if (!$user) {
-			wp_die('Invalid user');
+			JVB()->error()->log(
+				'MagicLinkManager',
+				'Invalid user, could not reset password',
+			);
+			$this->cleanURL();
 		}
 
 		// Log user in and redirect to password change page
 		wp_set_current_user($user->ID);
 		wp_set_auth_cookie($user->ID, true);
-
+		//TODO: hmmm
 		wp_safe_redirect(admin_url('profile.php?password_reset=1'));
 		exit;
 	}
 
 	/**
-	 * Handle invalid token
-	 */
-	protected function handleInvalidToken(WP_Error $error): void
-	{
-		wp_die($error->get_error_message());
-	}
-
-	/**
 	 * Handle failed login - offer magic link option
 	 */
 	public function handleFailedLogin(string $username): void
@@ -492,56 +515,103 @@
 
 	protected function getLoginEmailTemplate(string $name, string $magic_url): string
 	{
-		$content = '<h2>Hey ' . esc_html($name) . '!</h2>';
-		$content .= '<p>Click the button below to sign in to your account. This link expires in 15 minutes.</p>';
-		$content .= '<p style="text-align: center; margin: 30px 0;">';
-		$content .= '<a href="' . $magic_url . '" style="background: #2271b1; color: #fff; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Sign In</a>';
-		$content .= '</p>';
-		$content .= '<p style="color: #666; font-size: 14px;">If you didn\'t request this, you can safely ignore this email.</p>';
-
+		$content = JVB()->email()->h2('Hey ' . esc_html($name) . '!');
+		$content .= '<p>Click the button below to sign in to your account instantly - no password needed!</p>';
+		$content .= JVB()->email()->button($magic_url, 'Sign In Now');
+		$content .= '<p>Or copy and paste this link into your browser:</p>';
+		$content .= JVB()->email()->link($magic_url);
+		$content .= JVB()->email()->divider();
+		$content .= '<p>If you didn\'t request this, you can safely ignore this email. This link expires in 15 minutes.</p>';
 		return $content;
 	}
 
 	protected function getSignupEmailTemplate(string $name, string $magic_url): string
 	{
-		$content = '<h2>Welcome' . ($name ? ', ' . esc_html($name) : '') . '!</h2>';
-		$content .= '<p>You\'re almost there! Click the button below to complete your registration and access your account.</p>';
-		$content .= '<p style="text-align: center; margin: 30px 0;">';
-		$content .= '<a href="' . $magic_url . '" style="background: #2271b1; color: #fff; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Complete Registration</a>';
-		$content .= '</p>';
-		$content .= '<p style="color: #666; font-size: 14px;">This link expires in 15 minutes.</p>';
-
+		$content = JVB()->email()->h2('Welcome' . ($name ? ', ' . esc_html($name) : '') . '!');
+		$content .= '<p>Click the button below to complete your registration and access your account!</p>';
+		$content .= JVB()->email()->button($magic_url, 'Complete Registration');
+		$content .= '<p>Or copy and paste this link:</p>';
+		$content .= JVB()->email()->link($magic_url);
+		$content .= JVB()->email()->spacer(10);
+		$content .= '<p><small>This link expires in 24 hours.</small></p>';
 		return $content;
 	}
 
-	protected function getReferralEmailTemplate(string $name, string $referrer_name, string $magic_url, string $reward_text): string
+	protected function getReferralEmailTemplate(string $name, string $referrer_name, string $magic_url, string $reward_text, array $context): string
 	{
-		$content = '<h2>Hey' . ($name ? ' ' . esc_html($name) : '') . '!</h2>';
-		$content .= '<p><strong>' . esc_html($referrer_name) . '</strong> thinks you\'d love ' . get_bloginfo('name') . '!</p>';
+		$content = JVB()->email()->h2('Hey' . ($name ? ' ' . esc_html($name) : '') . '!');
+		$content .= sprintf(
+			'<p><strong>%s</strong> thinks you\'d love %s!</p>',
+			esc_html($referrer_name),
+			esc_html(get_bloginfo('name'))
+		);
 
-		if ($reward_text) {
-			$content .= '<p>' . esc_html($reward_text) . '</p>';
+		if (!empty($context['message'])) {
+			$content .= JVB()->email()->callout(nl2br(esc_html($context['message'])));
 		}
 
-		$content .= '<p style="text-align: center; margin: 30px 0;">';
-		$content .= '<a href="' . $magic_url . '" style="background: #2271b1; color: #fff; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Join Now</a>';
-		$content .= '</p>';
-		$content .= '<p style="color: #666; font-size: 14px;">This link expires in 15 minutes.</p>';
+		if ($reward_text) {
+			$content .= JVB()->email()->alert(
+				'<strong>Special Welcome Offer:</strong> ' . esc_html($reward_text),
+				'success'
+			);
+		}
+
+		$content .= JVB()->email()->button($magic_url, 'Join Now');
+		$content .= '<p>Or copy and paste this link:</p>';
+		$content .= JVB()->email()->link($magic_url);
+		$content .= JVB()->email()->spacer(10);
+		$content .= '<p><small>This invitation expires in 14 days.</small></p>';
 
 		return $content;
 	}
 
-	protected function getResetEmailTemplate(string $name, string $magic_url): string
+	public function renderForm():string
 	{
-		$content = '<h2>Hey ' . esc_html($name) . '!</h2>';
-		$content .= '<p>We received a request to reset your password. Click the button below to sign in and update your password.</p>';
-		$content .= '<p style="text-align: center; margin: 30px 0;">';
-		$content .= '<a href="' . $magic_url . '" style="background: #2271b1; color: #fff; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Reset Password</a>';
-		$content .= '</p>';
-		$content .= '<p style="color: #666; font-size: 14px;">If you didn\'t request this, you can safely ignore this email. This link expires in 15 minutes.</p>';
+		ob_start();
+		JVB()->connect('cloudflare')->renderTurnstile();
+		$turnstile = ob_get_clean();
+		global $wp;
 
-		return $content;
+		 $magicLink = sprintf(
+			'<form id="magic-link-form" data-save="auth/magic">
+				%s%s
+				<input type="hidden" name="redirect_to" value="%s">
+				%s
+				<button type="submit">%sLogin with Magic Link</button>
+				<p class="hint"><a href="" data-tab="login">Prefer to use a password?</a></p>
+			</form>
+			<div class="success-content" hidden>
+				<h3>Check Your Email!</h3>
+				<p>We\'ve sent you a magic link to log in - no password required! Click the link in your email to log in.</p>
+				<p class="hint">Can\'t find it? Check your spam folder.</p>
+			</div>',
+			jvbFormStatus(),
+			Form::render('user_email', null, [
+				'required'	=> true,
+				'type'		=> 'email',
+				'label'		=> 'Your Email',
+				'autocomplete'=>'email'
+			]),
+			get_home_url(null,'/'.$wp->request),
+			$turnstile,
+			jvbIcon('magic-wand'),
+//			wp_login_url()
+		);
+
+		 $login = LoginManager::getInstance()->renderLoginForm('login', get_home_url(null,'/'.$wp->request));
+
+		 $tabs = new Tabs();
+		 $tabs->addTab('magic')
+			 ->title('With Magic Link')
+			 ->icon('magic-wand')
+			 ->content($magicLink);
+
+		 $tabs->addTab('login')
+			 ->title('With Password')
+			 ->icon('password')
+			 ->content($login);
+
+		 return $tabs->render();
 	}
 }
-
-new MagicLinkManager();

--
Gitblit v1.10.0