PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.5
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.5
1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 All 49 releases
fluent-cart / app / Services / CustomerIdentity / EmailClaimPortal.php

EmailClaimPortal.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.5, at app/Services/CustomerIdentity/EmailClaimPortal.php

137 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Services\CustomerIdentity;
4
5 use FluentCart\Api\StoreSettings;
6 use FluentCart\App\App;
7 use FluentCart\Framework\Support\Arr;
8
9 /**
10 * The customer-portal face of EmailClaimService: a notice offering to confirm
11 * the account's address, the landing form a mailed link opens, and the
12 * post-redirect-get handling of both submissions.
13 *
14 * The matching signed-in browser submits valid links automatically with a nonce.
15 * A plain GET or a signed-out mail scanner cannot apply the claim.
16 */
17 class EmailClaimPortal
18 {
19 const ACTION_FIELD = 'fct_email_claim_action';
20
21 const NONCE_ACTION = 'fct_email_claim';
22
23 /**
24 * Handle a submitted send/confirm form. Returns where to redirect, or null
25 * when the request is not ours.
26 *
27 * @return string|null
28 */
29 public static function handleSubmission(): ?string
30 {
31 $action = Arr::get($_POST, static::ACTION_FIELD, '');
32 if (!is_string($action) || !in_array($action, ['send', 'confirm'], true)) {
33 return null;
34 }
35
36 $portal = (new StoreSettings())->getCustomerProfilePage();
37 if (!$portal) {
38 return null;
39 }
40
41 $nonce = Arr::get($_POST, '_wpnonce', '');
42 if (!is_user_logged_in() || !is_string($nonce) || !wp_verify_nonce(wp_unslash($nonce), static::NONCE_ACTION)) {
43 $status = 'invalid';
44 } elseif ($action === 'send') {
45 $status = EmailClaimService::issue();
46 } else {
47 $token = Arr::get($_POST, EmailClaimService::QUERY_TOKEN, '');
48 $status = is_string($token) ? EmailClaimService::confirm(sanitize_text_field(wp_unslash($token))) : 'invalid';
49 }
50
51 return add_query_arg(EmailClaimService::QUERY_STATUS, $status, $portal);
52 }
53
54 /**
55 * The notice/form HTML for the current request, or '' when there is nothing to show.
56 */
57 public static function render(): string
58 {
59 if (!is_user_logged_in()) {
60 return '';
61 }
62
63 $status = Arr::get($_GET, EmailClaimService::QUERY_STATUS, '');
64 $status = is_string($status) ? sanitize_key($status) : '';
65
66 $token = Arr::get($_GET, EmailClaimService::QUERY_TOKEN, '');
67 $token = is_string($token) ? sanitize_text_field(wp_unslash($token)) : '';
68
69 $confirmEmail = '';
70 if ($token) {
71 $claim = EmailClaimService::resolveClaim($token);
72 if ($claim['status'] === 'ok') {
73 $confirmEmail = $claim['email'];
74 } else {
75 $status = $claim['status'];
76 $token = '';
77 }
78 }
79
80 $offer = $token ? null : EmailClaimService::getOffer();
81 $progress = CustomerRecoveryService::progress(get_current_user_id());
82 if (!$token && !EmailVerificationService::isRequired(get_current_user_id())) {
83 if (!$offer && in_array($status, ['sent', 'confirmed'], true)) {
84 $status = ''; // A previously opened send-link URL is no longer current.
85 }
86 if (($progress['status'] ?? '') === 'blocked_storage') {
87 $status = 'storage_unsupported';
88 } elseif (($progress['status'] ?? '') === 'pending') {
89 $status = 'recovering';
90 } elseif ($status === 'recovering' && ($progress['status'] ?? '') === 'completed') {
91 $status = $offer ? 'confirmed' : '';
92 } elseif (in_array($status, ['', 'recovering'], true) && in_array($progress['status'] ?? '', ['failed', 'incomplete', 'cancelled'], true)) {
93 $status = 'recovery_failed';
94 }
95 }
96
97
98 if (!$status && !$offer && !$token) {
99 if (!EmailVerificationService::isRequired(get_current_user_id())) {
100 return '';
101 }
102 $status = EmailClaimService::isEnabled() ? 'conflict' : 'disabled';
103 }
104
105 $messages = [
106 'storage_unsupported' => __('Email confirmation and purchase recovery are unavailable. Please contact the store.', 'fluent-cart'),
107 'recovering' => __('Your email is confirmed. Past purchases are being recovered in the background. You can use your dashboard while recovery finishes.', 'fluent-cart'),
108 'recovery_failed' => __('Some past purchases could not be recovered. Request a new confirmation link to retry, or contact the store.', 'fluent-cart'),
109 'sent' => __('Confirmation email sent. Please check your inbox and follow the link to confirm your email address. If you cannot find it, check your spam folder.', 'fluent-cart'),
110 'confirmed' => __('Your email address is confirmed and your purchases are now in this account.', 'fluent-cart'),
111 'incomplete' => __('Your email address is confirmed, but some purchases could not be moved. Please contact the store.', 'fluent-cart'),
112 'throttled' => __('Too many confirmation requests. Please try again in an hour.', 'fluent-cart'),
113 'failed' => __('Your email could not be confirmed. Please try again or contact the store.', 'fluent-cart'),
114 'send_failed' => __('The confirmation email could not be sent. Please try again.', 'fluent-cart'),
115 'expired' => __('This confirmation link has expired. Request a new one below.', 'fluent-cart'),
116 'wrong_account' => __('Sign in to the account that requested this confirmation link.', 'fluent-cart'),
117 'stale' => __('Your account has changed since this link was sent. Request a new one below.', 'fluent-cart'),
118 'conflict' => __('This address belongs to another customer account. Please contact the store.', 'fluent-cart'),
119 'invalid' => __('This confirmation link is not valid.', 'fluent-cart'),
120 'disabled' => __('Email confirmation is not available.', 'fluent-cart'),
121 'unavailable' => __('There is nothing to confirm for this account.', 'fluent-cart'),
122 'no_portal' => __('The customer portal is not configured. Please contact the store.', 'fluent-cart'),
123 ];
124
125 return (string) App::make('view')->make('frontend.customer.email_claim', [
126 'message' => Arr::get($messages, $status, ''),
127 'is_sent' => $status === 'sent',
128 'is_error' => $status && !in_array($status, ['sent', 'confirmed', 'recovering'], true),
129 'offer_email' => $offer ? $offer['to'] : '',
130 'offer_reason' => $offer ? $offer['reason'] : '',
131 'confirm_email' => $confirmEmail,
132 'token' => $token,
133 'action_url' => (new StoreSettings())->getCustomerProfilePage(),
134 ]);
135 }
136 }
137