PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 1.5.5
Fluent Support – Helpdesk & Customer Support Ticket System v1.5.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 1.5.5 All 68 releases
fluent-support / app / Http / Controllers / CustomerPortalController.php

CustomerPortalController.php in Fluent Support – Helpdesk & Customer Support Ticket System 1.5.5, at app/Http/Controllers/CustomerPortalController.php

518 lines 16.1 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\Http\Controllers;
4
5 use FluentSupport\App\Models\Attachment;
6 use FluentSupport\App\Models\Customer;
7 use FluentSupport\App\Models\MailBox;
8 use FluentSupport\App\Models\Product;
9 use FluentSupport\App\Models\Conversation;
10 use FluentSupport\App\Models\Ticket;
11 use FluentSupport\App\Services\Helper;
12 use FluentSupport\App\Services\Includes\FileSystem;
13 use FluentSupport\App\Services\Tickets\ResponseService;
14 use FluentSupport\App\Services\Tickets\TicketService;
15 use FluentSupport\Framework\Request\Request;
16 use FluentSupport\Framework\Support\Arr;
17
18 /**
19 * CustomerPortalController class for REST API
20 * This class is responsible for getting data for all request related to customer and customer portal
21 * @package FluentSupport\App\Http\Controllers
22 *
23 * @version 1.0.0
24 */
25
26 class CustomerPortalController extends Controller
27 {
28 /**
29 * getTickets will generate ticket information with customer and agents by customer
30 * @param Request $request
31 * @return array
32 */
33 public function getTickets(Request $request)
34 {
35 //Get customer information
36 $customer = $this->resolveCustomer($request);
37
38 if (!$customer) {
39 return $this->sendError([
40 'message' => __('No Customer Found', 'fluent-support'),
41 'error_type' => 'no_customer'
42 ]);
43 }
44
45 if($customer->status == 'inactive') {
46 return $this->sendError([
47 'message' => __('Sorry, You do not have access to customer portal', 'fluent-support'),
48 'error_type' => 'inactive_customer'
49 ]);
50 }
51
52 $statuses = Arr::get([
53 'open' => ['new', 'active', 'on-hold'],
54 'all' => [],
55 'closed' => ['closed']
56 ], $request->get('filter_type', ''));
57
58 //get tickets with customer and agent
59 $ticketsQuery = Ticket::with([
60 'customer' => function ($query) {
61 $query->select(['first_name', 'last_name', 'id']);
62 }, 'agent' => function ($query) {
63 $query->select(['first_name', 'last_name', 'id']);
64 }
65 ])
66 ->where('customer_id', $customer->id)
67 ->orderBy('id', 'DESC');
68
69 $ticketsQuery->where('customer_id', $customer->id);
70
71 if ($statuses) {
72 $ticketsQuery->whereIn('status', $statuses);
73 }
74
75 $tickets = $ticketsQuery->paginate();
76
77 foreach ($tickets as $ticket) {
78 $ticket->human_date = sprintf(__('%s ago', 'fluent-support'), human_time_diff(strtotime($ticket->created_at), current_time('timestamp')));
79 $ticket->preview_response = $ticket->getLastResponse();
80 }
81
82 return [
83 'tickets' => $tickets
84 ];
85 }
86
87 /**
88 * createTicket method will create ticket submitted by customers
89 * @param Request $request
90 * @return array
91 * @throws \FluentSupport\Framework\Validator\ValidationException
92 */
93 public function createTicket(Request $request)
94 {
95 $data = $request->all();
96
97 $this->validate($data, [
98 'title' => 'required',
99 'content' => 'required'
100 ]);
101
102 $data['title'] = sanitize_text_field(wp_unslash($data['title']));
103
104 $data['content'] = wp_unslash(wp_kses_post($data['content']));
105
106 $customer = $this->resolveCustomer($request, true);
107
108 if($customer->status == 'inactive') {
109 return $this->sendError([
110 'message' => __('Sorry, You do not have access to customer portal', 'fluent-support'),
111 'error_type' => 'inactive_customer'
112 ]);
113 }
114
115 if (!$customer) {
116 return $this->sendError([
117 'message' => __('No Customer Found', 'fluent-support'),
118 'error_type' => 'no_customer'
119 ]);
120 }
121
122 $data['customer_id'] = $customer->id;
123 $data['product_source'] = 'local';
124 $data['mailbox_id'] = $this->resolveMailboxId($request);
125
126 $disabledFields = apply_filters('fluent_support/disabled_ticket_fields', []);
127
128 if(!in_array('priority', $disabledFields)) {
129 $data['priority'] = sanitize_text_field($data['client_priority']);
130 $data['client_priority'] = sanitize_text_field($data['client_priority']);
131 }
132
133 if(in_array('product_services', $disabledFields)) {
134 unset($data['product_id']);
135 }
136
137 $data['source'] = 'web';
138
139 /*
140 * Filter ticket data
141 *
142 * @since v1.0.0
143 * @param array $data
144 * @param object $customer
145 */
146 $data = apply_filters('fluent_support/create_ticket_data', $data, $customer);
147
148 /*
149 * Action before ticket create
150 *
151 * @since v1.0.0
152 * @param array $data
153 * @param object $customer
154 */
155 do_action('fluent_support/before_ticket_create', $data, $customer);
156 $ticket = Ticket::create($data);
157
158 if (($attachments = Arr::get($data, 'attachments')) && !in_array('file_upload', $disabledFields)) {
159
160 Attachment::whereNull('ticket_id')
161 ->whereIn('file_hash', $attachments)
162 ->whereNull('ticket_id')
163 ->update([
164 'ticket_id' => $ticket->id,
165 'person_id' => $customer->id,
166 'status' => 'active'
167 ]);
168
169 $ticket->load('attachments');
170 }
171
172
173 if(defined('FLUENTSUPPORTPRO')) {
174 $customData = Arr::get($data, 'custom_data');
175 if($customData) {
176 $customData = wp_unslash($customData);
177 $ticket->syncCustomFields($customData);
178 }
179 }
180
181 /*
182 * Action on ticket create
183 *
184 * @since v1.0.0
185 * @param object $ticket
186 * @param object $customer
187 */
188 do_action('fluent_support/ticket_created', $ticket, $customer);
189
190 return [
191 'message' => __('Ticket has been created successfully', 'fluent-support'),
192 'ticket' => $ticket
193 ];
194 }
195
196 /**
197 * getTicket method will get the ticket information with customer and agent as well as response in a ticket by ticket id
198 * @param Request $request
199 * @param $ticketId
200 * @return array
201 */
202 public function getTicket(Request $request, $ticketId)
203 {
204 //Get ticket by id with customer, agent, product and attachments
205 $ticket = Ticket::where('id', $ticketId)
206 ->with([
207 'customer' => function ($query) {
208 $query->select(['first_name', 'email', 'person_type', 'last_name', 'id']);
209 }, 'agent' => function ($query) {
210 $query->select(['first_name', 'email', 'person_type', 'last_name', 'id', 'title']);
211 },
212 'product',
213 'attachments'
214 ])
215 ->first();
216
217 if ($request->get('intended_ticket_hash') && Helper::isPublicSignedTicketEnabled()) {
218 $customer = $ticket->customer;
219 } else {
220 $customer = $this->resolveCustomer($request);
221 }
222
223 if (!$customer) {
224 return $this->sendError([
225 'message' => __('Sorry, You do not have permission to this support ticket', 'fluent-support'),
226 'error_type' => 'no_customer'
227 ]);
228 }
229
230 if($customer->status == 'inactive') {
231 return $this->sendError([
232 'message' => __('Sorry, You do not have access to customer portal', 'fluent-support'),
233 'error_type' => 'inactive_customer'
234 ]);
235 }
236
237
238 if ($ticket->privacy == 'private' && $customer->id != $ticket->customer_id) {
239 return $this->sendError([
240 'message' => __('You do not have permission to view this support ticket', 'fluent-support'),
241 'error_type' => 'permission_error'
242 ]);
243 }
244
245 //Get responses in a ticket by
246 $responses = Conversation::where('ticket_id', $ticketId)
247 ->with([
248 'person' => function ($query) {
249 $query->select(['first_name', 'email', 'person_type', 'last_name', 'id', 'title']);
250 },
251 'attachments'
252 ])
253 ->filterByType('response')
254 ->orderBy('id', 'DESC')
255 ->get();
256
257 foreach ($responses as $response) {
258 $response->content = make_clickable($response->content);
259 if ($response->person) {
260 $response->person->setHidden(['email']);
261 }
262 }
263
264 $ticket->content = make_clickable($ticket->content);
265
266 if ($ticket->customer) {
267 $ticket->customer->setHidden(['email']);
268 }
269
270 if ($ticket->agent) {
271 $ticket->agent->setHidden(['email']);
272 }
273
274 if ($ticket->status == 'closed') {
275 $ticket->load('closed_by_person');
276 if ($ticket->closed_by_person) {
277 $ticket->closed_by_person->setVisible(['first_name', 'last_name', 'id', 'full_name', 'photo']);
278 }
279 }
280
281 if(defined('FLUENTSUPPORTPRO')) {
282 $ticket->custom_fields = $ticket->customData('public', true);
283 }
284
285 return [
286 'ticket' => $ticket,
287 'responses' => $responses,
288 'sign_on_id' => $ticket->customer_id
289 ];
290 }
291
292 /**
293 * createResponse method will create response by customer in a ticket by ticket id
294 * @param Request $request
295 * @param $ticketId
296 * @return array
297 * @throws \FluentSupport\Framework\Validator\ValidationException
298 */
299 public function createResponse(Request $request, $ticketId)
300 {
301 $data = $request->all();
302 $this->validate($data, [
303 'content' => 'required'
304 ]);
305
306 $data['content'] = wp_unslash(wp_kses_post($data['content']));
307
308
309 $ticket = Ticket::with(['customer'])->findOrFail($ticketId);
310
311 if ($request->get('intended_ticket_hash') && Helper::isPublicSignedTicketEnabled()) {
312 $customer = $ticket->customer;
313 } else {
314 $customer = $this->resolveCustomer($request);
315 }
316
317 if (!$customer) {
318 return $this->sendError([
319 'message' => __('Sorry! No customer found', 'fluent-support')
320 ]);
321 }
322
323 if($customer->status == 'inactive') {
324 return $this->sendError([
325 'message' => __('Sorry, You do not have access to customer portal', 'fluent-support'),
326 'error_type' => 'inactive_customer'
327 ]);
328 }
329
330
331 if ($ticket->privacy == 'private' && $customer->id != $ticket->customer_id) {
332 return $this->sendError([
333 'message' => __('Sorry! You can not reply to this ticket', 'fluent-support')
334 ]);
335 }
336
337 $data['conversation_type'] = 'response';
338 $responseData = (new ResponseService())->createResponse($data, $customer, $ticket);
339
340 return [
341 'message' => __('Reply has been added', 'fluent-support'),
342 'response' => $responseData['response'],
343 'ticket' => $responseData['ticket']
344 ];
345 }
346
347 /**
348 * closeTicket method will close a ticket by customer using ticket id
349 * @param Request $request
350 * @param $ticketId
351 * @return array
352 */
353 public function closeTicket(Request $request, $ticketId)
354 {
355 $ticket = Ticket::with(['customer'])->findOrFail($ticketId);
356
357 if ($request->get('intended_ticket_hash') && Helper::isPublicSignedTicketEnabled()) {
358 $customer = $ticket->customer;
359 } else {
360 $customer = $this->resolveCustomer($request);
361 }
362
363 if (!$customer) {
364 return $this->sendError([
365 'message' => __('Sorry! No customer found', 'fluent-support')
366 ]);
367 }
368
369 if($customer->status == 'inactive') {
370 return $this->sendError([
371 'message' => __('Sorry, You do not have access to customer portal', 'fluent-support'),
372 'error_type' => 'inactive_customer'
373 ]);
374 }
375
376
377 if ($customer->id != $ticket->customer_id) {
378 return $this->sendError([
379 'message' => __('Sorry! You can not close this ticket', 'fluent-support')
380 ]);
381 }
382
383 return [
384 'message' => __('Ticket has been closed', 'fluent_support'),
385 'ticket' => (new TicketService())->close($ticket, $customer)
386 ];
387 }
388
389 /**
390 * closeTicket method will re-open a ticket by customer using ticket id
391 * @param Request $request
392 * @param $ticketId
393 * @return array
394 */
395 public function reOpenTicket(Request $request, $ticketId)
396 {
397 $ticket = Ticket::with(['customer'])->findOrFail($ticketId);
398
399 if ($request->get('intended_ticket_hash') && Helper::isPublicSignedTicketEnabled()) {
400 $customer = $ticket->customer;
401 } else {
402 $customer = $this->resolveCustomer($request);
403 }
404
405 if($customer->status == 'inactive') {
406 return $this->sendError([
407 'message' => __('Sorry, You do not have access to customer portal', 'fluent-support'),
408 'error_type' => 'inactive_customer'
409 ]);
410 }
411
412
413 if (!$customer) {
414 return $this->sendError([
415 'message' => __('Sorry! No customer found', 'fluent-support')
416 ]);
417 }
418
419 if ($customer->id != $ticket->customer_id) {
420 return $this->sendError([
421 'message' => __('Sorry! You can not close this ticket', 'fluent-support')
422 ]);
423 }
424
425
426 return [
427 'message' => __('Ticket has been opened again', 'fluent_support'),
428 'ticket' => (new TicketService())->reopen($ticket, $customer)
429 ];
430
431
432 }
433
434 /**
435 * resolveCustomer method will create and return or only return existing customer
436 * This method will het customer id or customer info or option to force create as parameter.
437 * @param $request
438 * @param false $forceCreate
439 * @return false|Customer
440 */
441 private function resolveCustomer($request, $forceCreate = false)
442 {
443 $onBehalf = $request->get('on_behalf');
444
445 if (!$onBehalf) {
446 $user = get_user_by('ID', get_current_user_id());
447 if (!$user) {
448 return false;
449 }
450 $onBehalf = [
451 'user_id' => $user->ID,
452 'email' => $user->user_email,
453 'last_ip_address' => $request->getIp()
454 ];
455 }
456
457 if ($forceCreate) {
458 return Customer::maybeCreateCustomer($onBehalf);
459 }
460
461 return Customer::getCustomerFromData($onBehalf);
462 }
463
464 /**
465 * getPublicOptions method will return the list of product and customer priorities
466 * @return array
467 */
468 public function getPublicOptions()
469 {
470 $products = Product::select(['id', 'title'])->get();
471
472 return [
473 'support_products' => $products,
474 'customer_ticket_priorities' => Helper::customerTicketPriorities()
475 ];
476 }
477
478 /**
479 * getCustomFieldsRender method will return the list of custom fields
480 * @return array|array[]
481 */
482 public function getCustomFieldsRender()
483 {
484 if(!defined('FLUENTSUPPORTPRO')) {
485 return [
486 'custom_fields_rendered' => []
487 ];
488 }
489
490 return [
491 'custom_fields_rendered' => \FluentSupportPro\App\Services\CustomFieldsService::getRenderedPublicFields()
492 ];
493
494 }
495
496 /**
497 * resolveMailboxId method will either get information of the mailbox added by user or default and return the id
498 * @param $request
499 * @return null
500 */
501 private function resolveMailboxId($request)
502 {
503 if ($mailboxId = $request->get('mailbox_id')) {
504 $mailbox = MailBox::find($mailboxId);
505 if ($mailbox) {
506 return $mailbox->id;
507 }
508 }
509
510 $mailbox = Helper::getDefaultMailBox();
511
512 if ($mailbox) {
513 return $mailbox->id;
514 }
515 return null;
516 }
517 }
518