PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.4.5
Fluent Support – Helpdesk & Customer Support Ticket System v2.4.5
2.4.5 2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 All 69 releases
fluent-support / app / Hooks / Handlers / EmailNotificationHandler.php

EmailNotificationHandler.php in Fluent Support – Helpdesk & Customer Support Ticket System 2.4.5, at app/Hooks/Handlers/EmailNotificationHandler.php

564 lines 21.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentSupport\App\Hooks\Handlers;
4
5 use FluentSupport\App\App;
6 use FluentSupport\App\Models\Agent;
7 use FluentSupport\App\Models\Meta;
8 use FluentSupport\App\Models\Ticket;
9 use FluentSupport\App\Services\EmailNotification\Settings;
10 use FluentSupport\App\Services\Emogrifier;
11 use FluentSupport\App\Services\Helper;
12 use FluentSupport\App\Services\Mailer;
13 use FluentSupport\App\Services\Tickets\AgentTicketAccess;
14 use FluentSupport\Framework\Support\Arr;
15
16 class EmailNotificationHandler
17 {
18 public function ticketCreated($ticket, $customer)
19 {
20 $mailbox = $ticket->mailbox;
21
22 if (!$mailbox) {
23 return;
24 }
25
26 // Let's send welcome email to customer if enabled
27 $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_created_email_to_customer');
28
29 // Blocked customers get no email; the admin copy below still goes out.
30 if ($customer && $customer->canReceiveNotifications()
31 && $this->shouldSendEmail($emailSettings, 'ticket_created_email_to_customer', $ticket, $customer)) {
32 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
33 'customer' => $customer,
34 'business' => $mailbox,
35 'ticket' => $ticket
36 ]);
37
38 $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_created_email_to_customer');
39
40 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
41 'customer' => $customer,
42 'business' => $mailbox,
43 'ticket' => $ticket,
44 'email_type' => 'ticket_created_email_to_customer'
45 ]);
46
47 $headers = self::automatedHeaders($mailbox->getMailerHeader());
48
49 $headers = apply_filters('fluent_support/mail_to_customer_header', $headers, [
50 'cc_email' => $ticket->getSettingsValue('cc_email', []),
51 'hook_type' => 'ticket_created_email_to_customer',
52 'ticket' => $ticket
53 ]);
54
55 $attachments = [];
56
57 if ($emailSettings['send_attachments'] == 'yes' && ($files = $ticket->attachments)) {
58 foreach ($files as $file) {
59 if ($file->driver == 'local') {
60 $filePath = $file->file_path;
61 } else {
62 $filePath = Arr::get($file->settings, 'local_temp_path');
63 }
64 if (file_exists($filePath)) {
65 $attachments[] = $filePath;
66 }
67 }
68 }
69
70 Mailer::send($customer->email, $subject, $emailBody, $headers, $attachments);
71 }
72
73 // let's send email to admin if enabled
74 $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_created_email_to_admin');
75 if ($this->shouldSendEmail($emailSettings, 'ticket_created_email_to_admin', $ticket, $customer)
76 && is_email($mailbox->settings['admin_email_address'])
77 ) {
78
79 $mailTo = Arr::get($mailbox->settings, 'admin_email_address');
80
81 if (!$mailTo || !is_email($mailTo)) {
82 return;
83 }
84
85 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
86 'customer' => $customer,
87 'business' => $mailbox,
88 'ticket' => $ticket
89 ]);
90
91 $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_created_email_to_admin');
92
93 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
94 'customer' => $customer,
95 'business' => $mailbox,
96 'ticket' => $ticket,
97 'email_type' => 'ticket_created_email_to_admin'
98 ]);
99
100 $headers = self::automatedHeaders($mailbox->getMailerHeader());
101
102 $attachments = [];
103
104 if ($emailSettings['send_attachments'] == 'yes' && ($files = $ticket->attachments)) {
105 foreach ($files as $file) {
106
107 if ($file->driver == 'local') {
108 $filePath = $file->file_path;
109 } else {
110 $filePath = Arr::get($file->settings, 'local_temp_path');
111 }
112 if (file_exists($filePath)) {
113 $attachments[] = $filePath;
114 }
115
116 }
117 }
118
119 Mailer::send($mailTo, $subject, $emailBody, $headers, $attachments);
120 }
121 }
122
123 public function agentReplied($response, $ticket, $agent)
124 {
125 $mailbox = $ticket->mailbox;
126
127
128 if (!$mailbox) {
129 return false;
130 }
131
132 // Let's send welcome email to customer if enabled
133 $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_replied_by_agent_email_to_customer');
134
135
136 if ($emailSettings && $emailSettings['status'] == 'yes') {
137
138 $ticket->load('customer');
139 $customer = $ticket->customer;
140
141 if (!$customer->canReceiveNotifications()) {
142 return false;
143 }
144
145 if (!$this->shouldSendEmail($emailSettings, 'ticket_replied_by_agent_email_to_customer', $ticket, $customer)) {
146 return false;
147 }
148
149 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
150 'customer' => $customer,
151 'business' => $mailbox,
152 'ticket' => $ticket,
153 'response' => $response,
154 'agent' => $agent
155 ]);
156
157 $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_replied_by_agent_email_to_customer');
158
159 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
160 'customer' => $customer,
161 'business' => $mailbox,
162 'ticket' => $ticket,
163 'response' => $response,
164 'agent' => $agent,
165 'email_type' => 'ticket_replied_by_agent_email_to_customer'
166 ]);
167
168
169 // Written by the agent, so the From name follows the inbox's From name setting.
170 $headers = $mailbox->getMailerHeader($agent);
171 $headers = apply_filters('fluent_support/mail_to_customer_header', $headers, [
172 'cc_email' => $response->getSettingsValue('cc_email', []),
173 'hook_type' => 'ticket_replied_by_agent_email_to_customer',
174 'ticket' => $ticket
175 ]);
176 $attachments = [];
177
178 if ($emailSettings['send_attachments'] == 'yes' && ($files = $response->attachments)) {
179 foreach ($files as $file) {
180 if ($file->driver == 'local') {
181 $filePath = $file->file_path;
182 } else {
183 $filePath = Arr::get($file->settings, 'local_temp_path');
184 }
185 if (file_exists($filePath)) {
186 $attachments[] = $filePath;
187 }
188 }
189 }
190
191 Mailer::send($customer->email, $subject, $emailBody, $headers, $attachments);
192 }
193 }
194
195 public function closedByAgent($ticket, $agent)
196 {
197 $mailbox = $ticket->mailbox;
198 if (!$mailbox) {
199 return;
200 }
201
202 // Let's send welcome email to customer if enabled
203 $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_closed_by_agent_email_to_customer');
204 if ($emailSettings && $emailSettings['status'] == 'yes') {
205
206 $ticket->load('customer');
207 $customer = $ticket->customer;
208
209 if (!$customer->canReceiveNotifications()) {
210 return false;
211 }
212
213 if (!$this->shouldSendEmail($emailSettings, 'ticket_closed_by_agent_email_to_customer', $ticket, $customer)) {
214 return false;
215 }
216
217 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
218 'customer' => $customer,
219 'business' => $mailbox,
220 'ticket' => $ticket,
221 'agent' => $agent,
222 ]);
223
224 $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_closed_by_agent_email_to_customer');
225
226 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
227 'customer' => $customer,
228 'business' => $mailbox,
229 'ticket' => $ticket,
230 'agent' => $agent,
231 'email_type' => 'ticket_closed_by_agent_email_to_customer'
232 ]);
233
234 $headers = self::automatedHeaders($mailbox->getMailerHeader());
235 $headers = apply_filters('fluent_support/mail_to_customer_header', $headers, [
236 'cc_email' => $ticket->getSettingsValue('cc_email', []),
237 'hook_type' => 'ticket_closed_by_agent_email_to_customer',
238 'ticket' => $ticket
239 ]);
240 Mailer::send($customer->email, $subject, $emailBody, $headers);
241 }
242 }
243
244 public function customerReplied($response, $ticket, $customer)
245 {
246 $mailbox = $ticket->mailbox;
247 if (!$mailbox) {
248 return;
249 }
250
251 // Let's send welcome email to customer if enabled
252 $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_replied_by_customer_email_to_admin');
253 if ($this->shouldSendEmail($emailSettings, 'ticket_replied_by_customer_email_to_admin', $ticket, $customer)) {
254
255 $ticket->load('agent');
256 $agent = $ticket->agent;
257
258 $emailTo = $mailbox->settings['admin_email_address'];
259 if ($agent) {
260 $emailTo = $agent->email;
261 }
262
263 if (!$emailTo || !is_email($emailTo)) {
264 return;
265 }
266
267 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
268 'customer' => $customer,
269 'business' => $mailbox,
270 'ticket' => $ticket,
271 'response' => $response,
272 'agent' => $agent
273 ]);
274
275 $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_replied_by_customer_email_to_admin');
276
277 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
278 'customer' => $customer,
279 'business' => $mailbox,
280 'ticket' => $ticket,
281 'response' => $response,
282 'agent' => $agent,
283 'email_type' => 'ticket_replied_by_customer_email_to_admin'
284 ]);
285
286 $headers = self::automatedHeaders($mailbox->getMailerHeader());
287 $attachments = [];
288
289 if ($emailSettings['send_attachments'] == 'yes' && ($files = $response->attachments)) {
290 foreach ($files as $file) {
291 if ($file->driver == 'local') {
292 $filePath = $file->file_path;
293 } else {
294 $filePath = Arr::get($file->settings, 'local_temp_path');
295 }
296 if (file_exists($filePath)) {
297 $attachments[] = $filePath;
298 }
299 }
300 }
301
302 Mailer::send($emailTo, $subject, $emailBody, $headers, $attachments);
303 }
304 }
305
306 public function onAgentAssign(Agent $agent, Ticket $ticket, ?Agent $assigner = null)
307 {
308 if ($agent->status !== 'active' || (int) $ticket->agent_id !== (int) $agent->id) {
309 return;
310 }
311
312 if (!(new AgentTicketAccess())->canAccess($agent, $ticket)) {
313 return;
314 }
315
316 $currentUser = Helper::getAgentByUserId();
317
318 if ($currentUser && $currentUser->user_id == $agent->user_id) {
319 return;
320 }
321
322 $mailbox = $ticket->mailbox;
323
324 if (!$mailbox) {
325 return;
326 }
327
328 // Let's send notification email to agent if enabled
329 $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_agent_on_change');
330
331 if ($this->shouldSendEmail($emailSettings, 'ticket_agent_on_change', $ticket, $agent)) {
332
333 if ($agent) {
334 $emailTo = $agent->email;
335 }
336
337 if (!$emailTo || !is_email($emailTo)) {
338 return;
339 }
340
341 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
342 'business' => $mailbox,
343 'ticket' => $ticket,
344 'agent' => $agent,
345 'assigner' => $assigner
346 ]);
347
348 $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_agent_on_change');
349
350 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
351 'business' => $mailbox,
352 'ticket' => $ticket,
353 'agent' => $agent,
354 'assigner' => $assigner,
355 'email_type' => 'ticket_agent_on_change'
356 ]);
357
358 $headers = self::automatedHeaders($mailbox->getMailerHeader());
359
360 Mailer::send($emailTo, $subject, $emailBody, $headers);
361 }
362 }
363
364 public function ticketCreatedByAgent($ticket, $customer, $agent)
365 {
366 $mailbox = $ticket->mailbox;
367
368 if (!$mailbox || !$customer || !$customer->canReceiveNotifications()) {
369 return;
370 }
371
372 // Let's send welcome email to customer if enabled
373 $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_created_by_agent_email_to_customer');
374 if ($this->shouldSendEmail($emailSettings, 'ticket_created_by_agent_email_to_customer', $ticket, $customer)) {
375 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
376 'customer' => $customer,
377 'agent' => $agent,
378 'business' => $mailbox,
379 'ticket' => $ticket
380 ]);
381
382 $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_created_by_agent_email_to_customer');
383
384 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
385 'customer' => $customer,
386 'business' => $mailbox,
387 'agent' => $agent,
388 'ticket' => $ticket,
389 'email_type' => 'ticket_created_by_agent_email_to_customer'
390 ]);
391
392 $headers = apply_filters('fluent_support/mail_to_customer_header', self::automatedHeaders($mailbox->getMailerHeader()), [
393 'hook_type' => 'ticket_created_by_agent_email_to_customer',
394 'cc_email' => [],
395 'ticket' => $ticket
396 ]);
397
398 $attachments = [];
399
400 if ($emailSettings['send_attachments'] == 'yes' && ($files = $ticket->attachments)) {
401 foreach ($files as $file) {
402 if ($file->driver == 'local') {
403 $filePath = $file->file_path;
404 } else {
405 $filePath = Arr::get($file->settings, 'local_temp_path');
406 }
407 if (file_exists($filePath)) {
408 $attachments[] = $filePath;
409 }
410 }
411 }
412
413 Mailer::send($customer->email, $subject, $emailBody, $headers, $attachments);
414 }
415 }
416
417 public function ticketCreatedByAgentOnBehalf($response, $ticket, $agent)
418 {
419 $mailbox = $ticket->mailbox;
420
421 if (!$mailbox) {
422 return;
423 }
424
425 $emailSettings = (new Settings())->getBoxEmailSettings($mailbox, 'ticket_created_by_agent_on_behalf_email_to_customer');
426 if ($this->shouldSendEmail($emailSettings, 'ticket_created_by_agent_on_behalf_email_to_customer', $ticket)) {
427
428 $ticket->load('customer');
429 $customer = $ticket->customer;
430
431 if (!$customer->canReceiveNotifications()) {
432 return false;
433 }
434
435 $subject = apply_filters('fluent_support/parse_smartcode_data', $emailSettings['email_subject'], [
436 'customer' => $customer,
437 'agent' => $agent,
438 'business' => $mailbox,
439 'ticket' => $ticket,
440 'response' => $response
441 ]);
442
443 $subject = apply_filters('fluent_support/ticket_email_subject', $subject, $ticket, 'ticket_created_by_agent_on_behalf_email_to_customer');
444
445 $emailBody = $this->parseEmailBody($emailSettings['email_body'], [
446 'customer' => $customer,
447 'business' => $mailbox,
448 'agent' => $agent,
449 'ticket' => $ticket,
450 'response' => $response,
451 'email_type' => 'ticket_created_by_agent_on_behalf_email_to_customer'
452 ]);
453
454 $headers = apply_filters('fluent_support/mail_to_customer_header', $mailbox->getMailerHeader($agent), [
455 'hook_type' => 'ticket_created_by_agent_on_behalf_email_to_customer',
456 'cc_email' => [],
457 'ticket' => $ticket
458 ]);
459
460 $attachments = [];
461
462 if ($emailSettings['send_attachments'] == 'yes') {
463 $files = $response->attachments;
464
465 // Agent-initiated ticket uploads are stored on the ticket, while this email
466 // is rendered from the synthetic first response created during ticket creation.
467 if ((!$files || $files->isEmpty()) && $ticket->attachments) {
468 $files = $ticket->attachments;
469 }
470
471 foreach ($files as $file) {
472 if ($file->driver == 'local') {
473 $filePath = $file->file_path;
474 } else {
475 $filePath = Arr::get($file->settings, 'local_temp_path');
476 }
477 if (file_exists($filePath)) {
478 $attachments[] = $filePath;
479 }
480 }
481 }
482
483 Mailer::send($customer->email, $subject, $emailBody, $headers, $attachments);
484 }
485 }
486
487 private function emailTemplateCss()
488 {
489 $app = App::getInstance();
490 return $app->view->make('emails.styles');
491 }
492
493 protected function parseEmailBody($emailBody, $data)
494 {
495 $data['email_body'] = apply_filters('fluent_support/parse_smartcode_data', $emailBody, $data);
496
497 $app = App::getInstance();
498
499 if (isset($data['business'])) {
500 $businessName = $data['business']->name;
501 } else {
502 $businessName = get_bloginfo('name');
503 }
504
505 $footerCreditUrl = Helper::getUpgradeUrl('mail_footer', ['base_url' => 'https://fluentsupport.com/']);
506 $footerText = apply_filters('fluent_support/email_footer_credit', 'This email is a service from ' . $businessName . '. Support Plugin is Powered by <a href="' . esc_url($footerCreditUrl) . '" style="color:#9e9e9e;" target="_new">FluentSupport</a>.');
507
508 $data['email_footer'] = $footerText;
509
510 $emailTypeForCustomerFooter = ['ticket_created_email_to_customer', 'ticket_replied_by_agent_email_to_customer', 'ticket_closed_by_agent_email_to_customer', 'ticket_created_by_agent_on_behalf_email_to_customer'];
511
512 if (defined('FLUENTSUPPORTPRO') && in_array($data['email_type'], $emailTypeForCustomerFooter)
513 && !is_null($data['business']->email_footer)) {
514 $data['email_footer'] = apply_filters('fluent_support/parse_smartcode_data', $data['business']->email_footer, $data);
515 }
516
517 $emailBody = $app->view->make('emails.ticket_template', $data);
518 $emogrifier = new Emogrifier($emailBody, $this->emailTemplateCss());
519 $emogrifier->disableInvisibleNodeRemoval();
520 return $emogrifier->emogrify();
521 }
522
523 protected function shouldSendEmail($emailSettings, $emailType, $ticket, $person = null)
524 {
525 if (!$emailSettings || $emailSettings['status'] != 'yes') {
526 return false;
527 }
528
529 return apply_filters('fluent_support/should_send_notification', true, 'email', $emailType, $ticket, $person);
530 }
531
532 /**
533 * Mark a system-generated email (confirmations, closed notices, agent alerts) so
534 * autoresponders don't answer it (RFC 3834 Auto-Submitted, and Outlook's
535 * X-Auto-Response-Suppress). An answer would come back through email piping and
536 * could start a mail loop. Replies an agent writes are not marked.
537 *
538 * @param array $headers
539 * @return array
540 */
541 public static function automatedHeaders($headers)
542 {
543 if (!apply_filters('fluent_support/mark_automated_emails', true)) {
544 return $headers;
545 }
546
547 $headers[] = 'Auto-Submitted: auto-generated';
548 $headers[] = 'X-Auto-Response-Suppress: All';
549
550 return $headers;
551 }
552
553 public function getMailerHeaderWithCc($headers, $info)
554 {
555 if (isset($info['cc_email'])) {
556 $CcHeaders = !empty($info['cc_email']) && is_array($info['cc_email']) ? implode(', ', $info['cc_email']) : '';
557 $headers[] = $CcHeaders ? "Cc: $CcHeaders" : '';
558 }
559
560 return $headers;
561 }
562
563 }
564