← All changes
|
app/Services/FormBuilder/Notifications/EmailNotificationActions.php
+201
-16
3.6.31
→
6.2.15
View file →
| @@ -1,8 +1,12 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | 3 | namespace FluentForm\App\Services\FormBuilder\Notifications; |
| 4 | 4 | |
| 5 | +defined('ABSPATH') or die; | |
| 6 | + | |
| 7 | +use FluentForm\App\Helpers\Helper; | |
| 8 | +use FluentForm\App\Services\FormBuilder\ShortCodeParser; | |
| 5 | 9 | use FluentForm\Framework\Foundation\Application; |
| 6 | 10 | use FluentForm\Framework\Helpers\ArrayHelper; |
| 7 | 11 | |
| 8 | 12 | class EmailNotificationActions |
| @@ -15,39 +19,134 @@ | ||
| 15 | 19 | } |
| 16 | 20 | |
| 17 | 21 | public function register() |
| 18 | 22 | { |
| 19 | - add_filter('fluentform_notifying_async_email_notifications', '__return_false', 9); | |
| 23 | + add_filter('fluentform/notifying_async_email_notifications', '__return_false', 9); | |
| 24 | + add_filter('fluentform/notifying_async_notifications', '__return_false', 9); | |
| 20 | 25 | |
| 21 | - add_filter('fluentform_global_notification_active_types', function ($types) { | |
| 26 | + add_filter('fluentform/global_notification_active_types', function ($types) { | |
| 22 | 27 | $types['notifications'] = 'email_notifications'; |
| 23 | 28 | return $types; |
| 24 | 29 | }); |
| 25 | 30 | |
| 26 | - add_action('fluentform_integration_notify_notifications', array($this, 'notify'), 10, 4); | |
| 31 | + add_action('fluentform/integration_notify_notifications', [$this, 'notify'], 10, 4); | |
| 32 | + | |
| 33 | + add_action('fluentform/notify_on_form_submit', [$this, 'notifyOnSubmitPaymentForm'], 10, 3); | |
| 27 | 34 | } |
| 28 | 35 | |
| 36 | + public function notifyOnSubmitPaymentForm($submissionId, $submissionData, $form) | |
| 37 | + { | |
| 38 | + $emailFeeds = wpFluent()->table('fluentform_form_meta') | |
| 39 | + ->where('form_id', $form->id) | |
| 40 | + ->where('meta_key', 'notifications') | |
| 41 | + ->get(); | |
| 42 | + | |
| 43 | + if (count($emailFeeds) === 0) { | |
| 44 | + return; | |
| 45 | + } | |
| 46 | + | |
| 47 | + $formData = $this->getFormData($submissionId); | |
| 48 | + $notificationManager = new \FluentForm\App\Services\Integrations\GlobalNotificationManager(wpFluentForm()); | |
| 49 | + | |
| 50 | + $activeEmailFeeds = $notificationManager->getEnabledFeeds($emailFeeds, $formData, $submissionId); | |
| 51 | + if (! $activeEmailFeeds) { | |
| 52 | + return; | |
| 53 | + } | |
| 54 | + | |
| 55 | + $onSubmitEmailFeeds = array_filter($activeEmailFeeds, function ($feed) { | |
| 56 | + return 'payment_form_submit' == ArrayHelper::get($feed, 'settings.feed_trigger_event'); | |
| 57 | + }); | |
| 58 | + | |
| 59 | + if (! $onSubmitEmailFeeds || 'yes' === Helper::getSubmissionMeta($submissionId, '_ff_on_submit_email_sent')) { | |
| 60 | + return; | |
| 61 | + } | |
| 62 | + | |
| 63 | + $entry = $this->getEntry($submissionId); | |
| 64 | + | |
| 65 | + foreach ($onSubmitEmailFeeds as $feed) { | |
| 66 | + $processedValues = $feed['settings']; | |
| 67 | + unset($processedValues['conditionals']); | |
| 68 | + | |
| 69 | + $processedValues = ShortCodeParser::parse( | |
| 70 | + $processedValues, | |
| 71 | + $submissionId, | |
| 72 | + $formData, | |
| 73 | + $form, | |
| 74 | + false, | |
| 75 | + $feed['meta_key'] | |
| 76 | + ); | |
| 77 | + $feed['processedValues'] = $processedValues; | |
| 78 | + | |
| 79 | + $this->notify($feed, $formData, $entry, $form); | |
| 80 | + } | |
| 81 | + | |
| 82 | + Helper::setSubmissionMeta($submissionId, '_ff_on_submit_email_sent', 'yes', $form->id); | |
| 83 | + } | |
| 84 | + | |
| 29 | 85 | public function notify($feed, $formData, $entry, $form) |
| 30 | 86 | { |
| 87 | + // A payment_success email asserts a settled charge, so gate it on the payment status | |
| 88 | + // for every payment form -- not only those with a Payment Method field. | |
| 89 | + $isTriggerOnPaymentSuccess = ArrayHelper::get($feed, 'processedValues.feed_trigger_event') === 'payment_success'; | |
| 90 | + if (!empty($form->has_payment) && $isTriggerOnPaymentSuccess && !$this->paymentSucceeded($entry, $form)) { | |
| 91 | + return; | |
| 92 | + } | |
| 93 | + | |
| 31 | 94 | $notifier = $this->app->make( |
| 32 | 95 | 'FluentForm\App\Services\FormBuilder\Notifications\EmailNotification' |
| 33 | 96 | ); |
| 34 | 97 | |
| 35 | 98 | $emailData = $feed['processedValues']; |
| 99 | + $emailAttachments = $this->getAttachments($emailData, $formData, $entry, $form); | |
| 100 | + if ($emailAttachments) { | |
| 101 | + $emailData['attachments'] = $emailAttachments; | |
| 102 | + } | |
| 36 | 103 | |
| 104 | + $notifier->notify($emailData, $formData, $form, $entry->id); | |
| 105 | + } | |
| 106 | + | |
| 107 | + // Whether a payment_success trigger may fire for this entry. | |
| 108 | + protected function paymentSucceeded($entry, $form) | |
| 109 | + { | |
| 110 | + $paymentStatus = is_null($entry->payment_status ?? null) ? '' : (string) $entry->payment_status; | |
| 111 | + | |
| 112 | + // Settled → a custom/settled status a gateway registered still fires; it is only the | |
| 113 | + // known-unsettled ones that defer. | |
| 114 | + if ('' !== $paymentStatus) { | |
| 115 | + $unsettledStatuses = apply_filters('fluentform/unsettled_payment_statuses', [ | |
| 116 | + 'pending', 'failed', 'requires_review', 'cancelled', 'refunded', 'partially-refunded', | |
| 117 | + ]); | |
| 118 | + return !in_array($paymentStatus, $unsettledStatuses, true); | |
| 119 | + } | |
| 120 | + | |
| 121 | + // Empty status is a $0 order: fulfil a coupon-zeroed purchase, not an omitted or zeroed input. | |
| 122 | + $isFreeOrder = 'yes' === Helper::getSubmissionMeta($entry->id, '_ff_zero_total_free_order'); | |
| 123 | + | |
| 124 | + return (bool) apply_filters('fluentform/send_payment_success_on_zero_total', $isFreeOrder, $entry, $form); | |
| 125 | + } | |
| 126 | + | |
| 127 | + /** | |
| 128 | + * @param $emailData | |
| 129 | + * @param $formData | |
| 130 | + * @param $entry | |
| 131 | + * @param $form | |
| 132 | + * | |
| 133 | + * @return array | |
| 134 | + */ | |
| 135 | + private function getAttachments($emailData, $formData, $entry, $form) | |
| 136 | + { | |
| 37 | 137 | $emailAttachments = []; |
| 38 | - if(!empty($emailData['attachments']) && is_array($emailData['attachments'])) { | |
| 138 | + | |
| 139 | + $uploadDir = wp_upload_dir(); | |
| 140 | + | |
| 141 | + if (!empty($emailData['attachments']) && is_array($emailData['attachments'])) { | |
| 39 | 142 | $attachments = []; |
| 40 | 143 | foreach ($emailData['attachments'] as $name) { |
| 41 | 144 | $fileUrls = ArrayHelper::get($formData, $name); |
| 42 | - if($fileUrls && is_array($fileUrls)) { | |
| 145 | + if ($fileUrls && is_array($fileUrls)) { | |
| 43 | 146 | foreach ($fileUrls as $url) { |
| 44 | - $filePath = str_replace( | |
| 45 | - site_url(''), | |
| 46 | - wp_normalize_path( untrailingslashit( ABSPATH ) ), | |
| 47 | - $url | |
| 48 | - ); | |
| 49 | - if(file_exists($filePath)) { | |
| 147 | + $filePath = $this->resolveUploadAttachmentPath($url, $uploadDir); | |
| 148 | + if ($filePath) { | |
| 50 | 149 | $attachments[] = $filePath; |
| 51 | 150 | } |
| 52 | 151 | } |
| 53 | 152 | } |
| @@ -53,14 +152,100 @@ | ||
| 53 | 152 | } |
| 54 | 153 | } |
| 55 | 154 | $emailAttachments = $attachments; |
| 56 | 155 | } |
| 156 | + $mediaAttachments = ArrayHelper::get($emailData, 'media_attachments'); | |
| 157 | + if (!empty($mediaAttachments) && is_array($mediaAttachments)) { | |
| 158 | + $attachments = []; | |
| 159 | + foreach ($mediaAttachments as $file) { | |
| 160 | + $fileUrl = ArrayHelper::get($file, 'url'); | |
| 161 | + $filePath = $this->resolveUploadAttachmentPath($fileUrl, $uploadDir); | |
| 162 | + if ($filePath) { | |
| 163 | + $attachments[] = $filePath; | |
| 164 | + } | |
| 165 | + } | |
| 166 | + $emailAttachments = array_merge($emailAttachments, $attachments); | |
| 167 | + } | |
| 168 | + | |
| 169 | + $emailAttachments = apply_filters_deprecated( | |
| 170 | + 'fluentform_email_attachments', | |
| 171 | + [ | |
| 172 | + $emailAttachments, | |
| 173 | + $emailData, | |
| 174 | + $formData, | |
| 175 | + $entry, | |
| 176 | + $form | |
| 177 | + ], | |
| 178 | + FLUENTFORM_FRAMEWORK_UPGRADE, | |
| 179 | + 'fluentform/email_attachments', | |
| 180 | + 'Use fluentform/email_attachments instead of fluentform_email_attachments.' | |
| 181 | + ); | |
| 182 | + // let others to apply attachments | |
| 183 | + $emailAttachments = apply_filters( | |
| 184 | + 'fluentform/email_attachments', | |
| 185 | + $emailAttachments, | |
| 186 | + $emailData, | |
| 187 | + $formData, | |
| 188 | + $entry, | |
| 189 | + $form | |
| 190 | + ); | |
| 191 | + return $emailAttachments; | |
| 192 | + } | |
| 57 | 193 | |
| 58 | - // let others to apply attachments | |
| 59 | - $emailAttachments = apply_filters('fluentform_email_attachments', $emailAttachments, $emailData, $formData, $entry, $form); | |
| 60 | - if($emailAttachments) { | |
| 61 | - $emailData['attachments'] = $emailAttachments; | |
| 194 | + private function resolveUploadAttachmentPath($fileUrl, $uploadDir) | |
| 195 | + { | |
| 196 | + if (!$fileUrl || empty($uploadDir['baseurl']) || empty($uploadDir['basedir'])) { | |
| 197 | + return null; | |
| 62 | 198 | } |
| 63 | 199 | |
| 64 | - $notifier->notify($emailData, $formData, $form, $entry->id); | |
| 200 | + $normalizedUrl = strtok($fileUrl, '?#'); | |
| 201 | + if (strpos($normalizedUrl, $uploadDir['baseurl']) !== 0) { | |
| 202 | + return null; | |
| 203 | + } | |
| 204 | + | |
| 205 | + $relativePath = rawurldecode(str_replace($uploadDir['baseurl'], '', $normalizedUrl)); | |
| 206 | + $relativePath = ltrim(wp_normalize_path($relativePath), '/'); | |
| 207 | + | |
| 208 | + if (!$relativePath || strpos($relativePath, '../') !== false) { | |
| 209 | + return null; | |
| 210 | + } | |
| 211 | + | |
| 212 | + $uploadsBaseDir = realpath($uploadDir['basedir']); | |
| 213 | + if (!$uploadsBaseDir) { | |
| 214 | + return null; | |
| 215 | + } | |
| 216 | + | |
| 217 | + $uploadsBaseDir = trailingslashit(wp_normalize_path($uploadsBaseDir)); | |
| 218 | + $resolvedPath = realpath($uploadsBaseDir . $relativePath); | |
| 219 | + | |
| 220 | + if (!$resolvedPath) { | |
| 221 | + return null; | |
| 222 | + } | |
| 223 | + | |
| 224 | + $resolvedPath = wp_normalize_path($resolvedPath); | |
| 225 | + if (strpos($resolvedPath, $uploadsBaseDir) !== 0 || !is_file($resolvedPath)) { | |
| 226 | + return null; | |
| 227 | + } | |
| 228 | + | |
| 229 | + return $resolvedPath; | |
| 230 | + } | |
| 231 | + | |
| 232 | + public function getFormData($submissionId) | |
| 233 | + { | |
| 234 | + $submission = wpFluent()->table('fluentform_submissions') | |
| 235 | + ->where('id', $submissionId) | |
| 236 | + ->first(); | |
| 237 | + | |
| 238 | + if (! $submission) { | |
| 239 | + return false; | |
| 240 | + } | |
| 241 | + | |
| 242 | + return json_decode($submission->response, true); | |
| 243 | + } | |
| 244 | + | |
| 245 | + public function getEntry($submissionId) | |
| 246 | + { | |
| 247 | + return wpFluent()->table('fluentform_submissions') | |
| 248 | + ->where('id', $submissionId) | |
| 249 | + ->first(); | |
| 65 | 250 | } |
| 66 | 251 | } |