PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 1.4.0
Fluent Support – Helpdesk & Customer Support Ticket System v1.4.0
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 / TicketController.php

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

612 lines 19.8 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\Agent;
6 use FluentSupport\App\Models\Attachment;
7 use FluentSupport\App\Models\Customer;
8 use FluentSupport\App\Models\MailBox;
9 use FluentSupport\App\Models\Conversation;
10 use FluentSupport\App\Models\Ticket;
11 use FluentSupport\App\Modules\PermissionManager;
12 use FluentSupport\App\Services\Helper;
13 use FluentSupport\App\Services\ProfileInfoService;
14 use FluentSupport\App\Services\TicketHelper;
15 use FluentSupport\App\Services\Tickets\ResponseService;
16 use FluentSupport\App\Services\Tickets\TicketService;
17 use FluentSupport\Framework\Request\Request;
18
19 class TicketController extends Controller
20 {
21 public function me(Request $request)
22 {
23 $user = wp_get_current_user();
24
25 return [
26 'user_id' => $user->id,
27 'email' => $user->user_email,
28 'person' => Helper::getAgentByUserId($user->ID),
29 'permissions' => PermissionManager::currentUserPermissions(),
30 'request' => $request->all()
31 ];
32 }
33
34 public function index(Request $request)
35 {
36 $ticketsQuery = Ticket::with([
37 'customer' => function ($query) {
38 $query->select(['first_name', 'last_name', 'email', 'id']);
39 }, 'agent' => function ($query) {
40 $query->select(['first_name', 'last_name', 'id']);
41 },
42 'product',
43 'tags',
44 'preview_response' => function ($query) {
45 $query->orderBy('id', 'desc');
46 }
47 ]);
48
49 // apply filters by access level
50 $permissionLevel = PermissionManager::currentUserTicketsPermissionLevel();
51 if ($permissionLevel != 'all') {
52 $agent = Helper::getAgentByUserId();
53 if ($permissionLevel == 'own') {
54 $ticketsQuery->where('agent_id', $agent->id);
55 } else {
56 $ticketsQuery->where(function ($q) use ($agent) {
57 $q->where('agent_id', $agent->id);
58 $q->orWhereNull('agent_id');
59 });
60 }
61 }
62
63 if ($customerId = $request->get('customer_id')) {
64 $ticketsQuery = $ticketsQuery->where('customer_id', $customerId);
65 }
66
67 if ($filters = $request->get('filters', [])) {
68 $ticketsQuery->applyFilters($filters);
69 }
70
71 if ($search = $request->get('search')) {
72 $ticketsQuery->searchBy($search);
73 }
74
75 $ticketsQuery->orderBy($request->get('order_by', 'id'), $request->get('order_type', 'ASC'));
76
77 $tickets = $ticketsQuery->paginate();
78
79 $perPage = $request->get('per_page');
80
81 foreach ($tickets as $ticket) {
82 if ($perPage < 15) {
83 if ($ticket->status != 'closed') {
84 $ticket->live_activity = TicketHelper::getActivity($ticket->id);
85 } else {
86 $ticket->live_activity = [];
87 }
88 }
89 }
90
91 return [
92 'tickets' => $tickets
93 ];
94 }
95
96 public function createTicket(Request $request)
97 {
98 $ticketData = $request->get('ticket', []);
99 $this->validate($ticketData, [
100 'customer_id' => 'required',
101 'title' => 'required',
102 'content' => 'required'
103 ]);
104
105 $customer = Customer::findOrFail($ticketData['customer_id']);
106
107 if (empty($ticketData['mailbox_id'])) {
108 $mailbox = Helper::getDefaultMailBox();
109 $ticketData['mailbox_id'] = $mailbox->id;
110 } else {
111 $mailbox = MailBox::findOrFail($ticketData['mailbox_id']); // just for validation
112 }
113
114 if (!empty($ticketData['product_id'])) {
115 $data['product_source'] = 'local';
116 }
117
118 $ticketData['title'] = sanitize_text_field(wp_unslash($ticketData['title']));
119
120 $ticketData['content'] = wp_unslash(wp_kses_post($ticketData['content']));
121
122 if (!empty($ticketData['priority'])) {
123 $ticketData['priority'] = sanitize_text_field($ticketData['priority']);
124 }
125
126 $ticketData['client_priority'] = sanitize_text_field($ticketData['client_priority']);
127
128 $ticketData = apply_filters('fluent_support/create_ticket_data', $ticketData, $customer);
129 do_action('fluent_support/before_ticket_create', $ticketData, $customer);
130
131 $createdTicket = Ticket::create($ticketData);
132
133 if (defined('FLUENTSUPPORTPRO') && !empty($ticketData['custom_fields'])) {
134 $createdTicket->syncCustomFields($ticketData['custom_fields']);
135 $createdTicket->custom_fields = $createdTicket->customData();
136 }
137
138 do_action('fluent_support/ticket_created', $createdTicket, $customer);
139
140 return [
141 'message' => __('Ticket has been created successfully', 'fluent-support'),
142 'ticket' => $createdTicket
143 ];
144
145 }
146
147 public function getTicket(Request $request, $ticketId)
148 {
149 $agent = Helper::getAgentByUserId();
150 $ticketWith = $request->get('with', ['customer', 'agent', 'product', 'mailbox', 'tags', 'attachments' => function ($q) {
151 $q->where('status', 'active');
152 }]);
153 $responseWith = $request->get('response_with', ['person', 'attachments']);
154
155 $ticket = Ticket::with($ticketWith)
156 ->findOrFail($ticketId);
157
158 if ($ticket->customer) {
159 $ticket->customer->profile_edit_url = $ticket->customer->getUserProfileEditUrl();
160 }
161
162 if (!PermissionManager::hasTicketPermission($ticket)) {
163 return $this->sendError([
164 'message' => __('Sorry, You do not have permission to this ticket', 'fluent-support')
165 ]);
166 }
167
168
169 if ($ticket->status == 'closed') {
170 $ticket->load('closed_by_person');
171 }
172
173 $responses = Conversation::where('ticket_id', $ticketId)
174 ->with($responseWith)
175 ->orderBy('id', 'DESC')
176 ->get();
177
178 foreach ($responses as $response) {
179 $response->content = make_clickable(wpautop($response->content, false));
180 }
181
182 $ticket->content = make_clickable(wpautop($ticket->content, false));
183
184 $ticket->live_activity = TicketHelper::getActivity($ticketId, $agent->id);
185
186 if (defined('FLUENTSUPPORTPRO')) {
187 $ticket->custom_fields = $ticket->customData('admin', true);
188 }
189
190 return [
191 'ticket' => $ticket,
192 'responses' => $responses,
193 'agent_id' => $agent->id
194 ];
195 }
196
197 public function createResponse(Request $request, $ticketId)
198 {
199 $data = $request->all();
200
201 $this->validate($data, [
202 'content' => 'required'
203 ]);
204
205 $agent = Helper::getAgentByUserId(get_current_user_id());
206
207 if (!$agent) {
208 return $this->sendError([
209 'message' => __('Sorry, You do not have permission. Please add yourself as support agent first', 'fluent-support')
210 ]);
211 }
212
213 $ticket = Ticket::findOrFail($ticketId);
214
215 if (!PermissionManager::hasTicketPermission($ticket)) {
216 return $this->sendError([
217 'message' => __('Sorry, You do not have permission to this ticket', 'fluent-support')
218 ]);
219 }
220
221 $responseData = (new ResponseService())->createResponse($data, $agent, $ticket);
222
223 $responseData['response']->content = make_clickable(wpautop($responseData['response']->content, false));
224
225 return [
226 'message' => __('Response has been added'),
227 'response' => $responseData['response'],
228 'ticket' => $responseData['ticket'],
229 'update_data' => $responseData['update_data']
230 ];
231 }
232
233 public function getTicketWidgets(Request $request, $ticketId)
234 {
235 $ticket = Ticket::with('customer')->findOrFail($ticketId);
236
237 if (!PermissionManager::hasTicketPermission($ticket)) {
238 return $this->sendError([
239 'message' => __('Sorry, You do not have permission to this ticket', 'fluent-support')
240 ]);
241 }
242
243 $otherTickets = Ticket::where('id', '!=', $ticketId)
244 ->select(['id', 'title', 'status', 'created_at'])
245 ->where('customer_id', $ticket->customer_id)
246 ->orderBy('id', 'DESC')
247 ->limit(10)
248 ->get();
249
250 return [
251 'other_tickets' => $otherTickets,
252 'extra_widgets' => ProfileInfoService::getProfileExtraWidgets($ticket->customer)
253 ];
254 }
255
256 public function updateTicketProperty(Request $request, $ticketId)
257 {
258 $assigner = Helper::getAgentByUserId(get_current_user_id());
259 $ticket = Ticket::findOrFail($ticketId);
260 $propName = $request->get('prop_name');
261 $propValue = $request->get('prop_value');
262
263 if (!PermissionManager::hasTicketPermission($ticket)) {
264 return $this->sendError([
265 'message' => __('Sorry, You do not have permission to this ticket', 'fluent-support')
266 ]);
267 }
268
269 $prevValue = $ticket->{$propName};
270 if ($propName && $propValue && $prevValue != $propValue) {
271 $ticket->{$propName} = $propValue;
272 $ticket->save();
273 }
274
275 $updateData = [];
276
277 if ($propName == 'product_id') {
278 $ticket->load('product');
279 $updateData['product'] = $ticket->product;
280 } else if ($propName == 'agent_id') {
281 $ticket->load('agent');
282 $updateData['agent'] = $ticket->agent;
283 $updateData['assigner'] = (new TicketService())->onAgentChange($ticket, $assigner);
284 if ($prevValue != $ticket->{$propName}) {
285 do_action('fluent_support/agent_assigned_to_ticket', $ticket->agent, $ticket);
286 }
287 }
288
289 return [
290 'message' => __(str_replace('_', ' ', ucwords($propName)) . ' has been updated', 'fluent-support'),
291 'update_data' => $updateData
292 ];
293 }
294
295 public function closeTicket(Request $request, $ticketId)
296 {
297 $agent = Helper::getAgentByUserId(get_current_user_id());
298
299 $ticket = Ticket::findOrFail($ticketId);
300
301 if (!PermissionManager::hasTicketPermission($ticket)) {
302 return $this->sendError([
303 'message' => __('Sorry, You do not have permission to this ticket', 'fluent-support')
304 ]);
305 }
306
307 return [
308 'message' => __('Ticket has been closed', 'fluent_support'),
309 'ticket' => (new TicketService())->close($ticket, $agent)
310 ];
311 }
312
313 public function reOpenTicket(Request $request, $ticketId)
314 {
315 $agent = Helper::getAgentByUserId(get_current_user_id());
316
317 $ticket = Ticket::findOrFail($ticketId);
318
319 if (!PermissionManager::hasTicketPermission($ticket)) {
320 return $this->sendError([
321 'message' => __('Sorry, You do not have permission to this ticket', 'fluent-support')
322 ]);
323 }
324
325 return [
326 'message' => __('Ticket has been opened again', 'fluent_support'),
327 'ticket' => (new TicketService())->reopen($ticket, $agent)
328 ];
329 }
330
331 public function doBulkActions(Request $request)
332 {
333 $ticketIds = $request->get('ticket_ids', []);
334 $action = $request->get('bulk_action');
335 $hasAllPermission = PermissionManager::currentUserCan('fst_manage_other_tickets');
336 $agent = Helper::getAgentByUserId();
337 $query = Ticket::whereIn('id', $ticketIds);
338
339 if (!$hasAllPermission) {
340 $query->where('agent_id', $agent->id);
341 }
342
343 if ($action == 'close_tickets') {
344 $query->where('status', '!=', 'closed');
345 $tickets = $query->get();
346 foreach ($tickets as $ticket) {
347 (new TicketService())->close($ticket, $agent);
348 }
349
350 return [
351 'message' => sprintf( __('%d tickets have been closed', 'fluent-support'), count($tickets))
352 ];
353 } else if ($action == 'delete_tickets') {
354 $tickets = $query->get();
355
356 foreach ($tickets as $ticket) {
357 $ticket->deleteTicket();
358 }
359
360 return [
361 'message' => __(count($tickets) . ' tickets have been deleted', 'fluent-support')
362 ];
363 } else if ($action == 'assign_agent') {
364 $agentId = absint($request->get('agent_id'));
365 if (!$agentId) {
366 $this->sendError([
367 'message' => __('agent_id param is required', 'fluent-support')
368 ]);
369 }
370
371 $agent = Agent::findOrFail($agentId);
372
373 $query->where(function ($q) use ($agent) {
374 $q->where('agent_id', '!=', $agent->id)
375 ->orWhereNull('agent_id');
376 });
377
378 $tickets = $query->get();
379
380 foreach ($tickets as $ticket) {
381 $ticket->agent_id = $agent->id;
382 $ticket->save();
383 do_action('fluent_support/agent_assigned_to_ticket', $agent, $ticket);
384 }
385
386 return [
387 'message' => __(count($tickets) . ' tickets has been assigned to', 'fluent-support') . ' ' . $agent->full_name
388 ];
389 } else if ($action == 'assign_tags') {
390
391 $tags = array_filter(array_map('absint', $request->get('tag_ids', [])));
392 if (!$tags) {
393 $this->sendError([
394 'message' => __('tag_ids param is required', 'fluent-support')
395 ]);
396 }
397
398 $tickets = $query->get();
399
400 foreach ($tickets as $ticket) {
401 $ticket->applyTags($tags);
402 }
403
404 return [
405 'message' => __('Selected tags has been added to tickets', 'fluent-support')
406 ];
407
408 }
409
410 $this->sendError([
411 'message' => __('Sorry no action found as available', 'fluent-support')
412 ]);
413 }
414
415 public function doBulkReplies(Request $request)
416 {
417 $data = $request->all();
418 $this->validate($data, [
419 'content' => 'required',
420 'ticket_ids' => 'required|array'
421 ]);
422
423 $ticketIds = $request->get('ticket_ids');
424 $ticketIds = array_filter($ticketIds, 'absint');
425
426 $agent = Helper::getAgentByUserId();
427
428 $hasAllPermission = PermissionManager::currentUserCan('fst_manage_other_tickets');
429
430 $query = Ticket::whereIn('id', $ticketIds)->where('status', '!=', 'closed');
431
432 if (!$hasAllPermission) {
433 $query->where('agent_id', $agent->id);
434 }
435
436 $tickets = $query->get();
437
438 if ($tickets->isEmpty()) {
439 $this->sendError([
440 'message' => __('Sorry no tickets found based on your filter and bulk actions', 'fluent-support')
441 ]);
442 }
443
444 $responseData = [
445 'content' => $request->get('content'),
446 'conversation_type' => $request->get('conversation_type', 'response'),
447 'close_ticket' => $request->get('close_ticket', 'no')
448 ];
449
450 $attachments = $request->get('attachments', []);
451
452 if ($attachments) {
453 $attachments = Attachment::whereNull('ticket_id')
454 ->orderBy('id', 'asc')
455 ->whereIn('file_hash', $attachments)
456 ->get();
457 }
458
459
460 $responseService = new ResponseService();
461
462 foreach ($tickets as $ticket) {
463 if ($attachments) {
464 $responseData['attachments'] = [];
465 foreach ($attachments as $attachment) {
466 $attachedFile = $attachment->replicate();
467 $attachedFile->ticket_id = $ticket->id;
468 $attachedFile->save();
469 $responseData['attachments'][] = $attachedFile->file_hash;
470 }
471 }
472
473 $responseService->createResponse($responseData, $agent, $ticket);
474 }
475
476
477 return [
478 'message' => __('Response has been added to the selected tickets', 'fluent-support')
479 ];
480
481 }
482
483
484 public function deleteResponse(Request $request, $ticketId, $responseId)
485 {
486 $ticket = Ticket::findOrFail($ticketId);
487 $response = Conversation::findOrFail($responseId);
488 $agent = Helper::getAgentByUserId();
489
490 $hasAllPermission = PermissionManager::currentUserCan('fst_manage_other_tickets');
491
492 if (!$hasAllPermission) {
493 if ($ticket->agent_id != $agent->id) {
494 return $this->sendError([
495 'message' => __('Sorry, You do not have permission to delete this response', 'fluent-support')
496 ]);
497 }
498 }
499
500 Conversation::where('id', $response->id)->delete();
501
502 return [
503 'message' => __('Selected response has been deleted', 'fluent-support')
504 ];
505
506 }
507
508 public function updateResponse(Request $request, $ticketId, $responseId)
509 {
510 $data = $request->all();
511
512 $this->validate($data, [
513 'content' => 'required'
514 ]);
515
516 $ticket = Ticket::findOrFail($ticketId);
517 $response = Conversation::findOrFail($responseId);
518 $agent = Helper::getAgentByUserId();
519
520 $hasAllPermission = PermissionManager::currentUserCan('fst_manage_other_tickets');
521
522 if (!$hasAllPermission) {
523 if ($ticket->agent_id != $agent->id) {
524 return $this->sendError([
525 'message' => __('Sorry, You do not have permission to delete this response', 'fluent-support')
526 ]);
527 }
528 }
529
530 $response->content = wp_unslash(wp_kses_post($data['content']));
531 $response->save();
532
533 return [
534 'message' => __('Selected response has been updated', 'fluent-support'),
535 'response' => $response
536 ];
537 }
538
539 public function getLiveActivity(Request $request, $ticketId)
540 {
541 $agent = Helper::getAgentByUserId();
542
543 return [
544 'live_activity' => TicketHelper::getActivity($ticketId, $agent->id)
545 ];
546 }
547
548 public function removeLiveActivity(Request $request, $ticketId)
549 {
550 $agent = Helper::getAgentByUserId();
551
552 return [
553 'result' => TicketHelper::removeFromActivities($ticketId, $agent->id),
554 'agent_id' => $agent->id
555 ];
556 }
557
558 public function addTag(Request $request, $ticketId)
559 {
560 $ticket = Ticket::findOrFail($ticketId);
561
562 $tagId = intval($request->get('tag_id'));
563
564 if (!$ticket->hasTag($tagId)) {
565 $ticket->tags()->attach($tagId, ['source_type' => 'ticket_tag']);
566 }
567
568 return [
569 'message' => __('Tag has been added to this ticket', 'fluent-support'),
570 'tags' => $ticket->tags
571 ];
572 }
573
574 public function detachTag($ticketId, $tagId)
575 {
576 $ticket = Ticket::findOrFail($ticketId);
577 $ticket->tags()->detach($tagId);
578
579 return [
580 'message' => __('Tag has been removed from this ticket', 'fluent-support'),
581 'tags' => $ticket->tags
582 ];
583 }
584
585 public function changeTicketCustomer(Request $request)
586 {
587 $updateCustomer = Ticket::where('id', $request->get('ticket_id'))
588 ->update(['customer_id' => $request->get('customer')]);
589 return [
590 'message' => __('Customer has been updated', 'fluent-support'),
591 'updatedCustomer' => $updateCustomer
592 ];
593 }
594
595 public function getTicketCustomData(Request $request, $ticketId)
596 {
597 if (!defined('FLUENTSUPPORTPRO')) {
598 return [
599 'custom_data' => [],
600 'rendered_fields' => []
601 ];
602 }
603
604 $ticket = Ticket::findOrFail($ticketId);
605
606 return [
607 'custom_data' => (object) $ticket->customData(),
608 'rendered_fields' => \FluentSupportPro\App\Services\CustomFieldsService::getRenderedPublicFields($ticket->customer)
609 ];
610 }
611 }
612