PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.1.1
Fluent Support – Helpdesk & Customer Support Ticket System v2.1.1
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 1.5.6 All 67 releases
fluent-support / app / Http / Controllers / CustomerPortalController.php

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

413 lines 14.5 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 Exception;
6 use FluentSupport\App\Http\Requests\TicketResponseRequest;
7 use FluentSupport\App\Models\Product;
8 use FluentSupport\App\Models\Ticket;
9 use FluentSupport\App\Services\CustomerPortalService;
10 use FluentSupport\App\Services\Helper;
11 use FluentSupport\Framework\Http\Request\Request;
12 use FluentSupport\Framework\Support\Arr;
13
14 /**
15 * CustomerPortalController class for REST API
16 * This class is responsible for getting data for all request related to customer and customer portal
17 * @package FluentSupport\App\Http\Controllers
18 *
19 * @version 1.0.0
20 */
21 class CustomerPortalController extends Controller
22 {
23 /**
24 * getTickets will generate ticket information with customer and agents by customer
25 * @param Request $request
26 * @return array|\WP_REST_Response
27 */
28 public function getTickets(Request $request)
29 {
30
31 $onBehalf = $request->get('on_behalf', []);
32 if ($onBehalf) {
33 $onBehalf = array_map(function ($item) {
34 return sanitize_text_field($item);
35 }, $onBehalf);
36 }
37
38 $userIP = $request->getIp();
39 $requestedStatus = $request->getSafe('filter_type', 'sanitize_text_field');
40 $ticketOptions = $request->getSafe([
41 'search' => 'sanitize_text_field',
42 'filters.product_id' => 'intval',
43 'sorting.sort_type' => 'sanitize_sql_orderby',
44 'sorting.sort_by' => 'sanitize_sql_orderby'
45 ]);
46
47 $customer = (new CustomerPortalService)->resolveCustomer($onBehalf, $userIP);
48
49 if (!$customer) {
50 return [
51 'tickets' => [
52 'data' => [],
53 'current_page' => $request->getSafe('page', 'intval', 1),
54 'last_page' => 1,
55 'per_page' => $request->getSafe('per_page', 'intval', 10),
56 'total' => 0,
57 'from' => null,
58 'to' => null
59 ]
60 ];
61 }
62
63 if ($customer->status !== 'active') {
64 return $this->sendError([
65 'message' => __('Your account is not active. Please contact support.', 'fluent-support'),
66 'error_type' => '403'
67 ], 403);
68 }
69
70 $canAccess = apply_filters('fluent_support/can_customer_access_portal', true, $customer);
71
72 if (is_wp_error($canAccess)) {
73 return $this->sendError([
74 'message' => $canAccess->get_error_message(),
75 'error_type' => $canAccess->get_error_code()
76 ], 403);
77 }
78
79 $statuses = [
80 'open' => ['new', 'active', 'on-hold'],
81 'all' => [],
82 'closed' => ['closed']
83 ];
84
85 $statusFilter = $statuses[$requestedStatus] ?? $statuses['all'];
86
87 $sortBy = Arr::get($ticketOptions, 'sorting.sort_by', 'created_at');
88 $sortType = Arr::get($ticketOptions, 'sorting.sort_type', 'desc');
89
90 $ticketsQuery = Ticket::where('customer_id', $customer->id)
91 ->filterByStatues($statusFilter)
92 ->searchBy(Arr::get($ticketOptions, 'search'))
93 ->filterByProductId(Arr::get($ticketOptions, 'filters.product_id'))
94 ->orderBy($sortBy, $sortType);
95
96 do_action_ref_array('fluent_support/customer_portal/tickets_query', [&$ticketsQuery, $customer, $request]);
97
98 $tickets = $ticketsQuery->paginate($request->getInt('per_page', 10));
99
100 foreach ($tickets as $ticket) {
101 $ticket->human_date = sprintf(__('%s ago', 'fluent-support'), human_time_diff(strtotime($ticket->created_at), current_time('timestamp')));
102 $ticket->preview_response = $ticket->getLastResponse();
103 }
104
105 return [
106 'tickets' => $tickets
107 ];
108 }
109
110 /**
111 * createTicket method will create ticket submitted by customers
112 * @param Request $request
113 * @return array | \WP_REST_Response
114 */
115 public function createTicket(Request $request)
116 {
117 $dataRules = $this->app->applyCustomFilters('custom_field_required_before_ticket_create', [
118 'required_fields' => [
119 'title' => 'required',
120 'content' => 'required'
121 ],
122 'error_messages' => [
123 'title.required' => __('Title is required', 'fluent-support'),
124 'content.required' => __('Content is required', 'fluent-support')
125 ]
126 ]);
127
128 $settings = Helper::getOption('_ticket_form_settings', []);
129
130 if (!empty($settings['product_required_field']) && $settings['product_required_field'] === 'yes') {
131 $productCount = Product::count();
132 if ($productCount > 0) {
133 $dataRules['required_fields']['product_id'] = 'required';
134 $dataRules['error_messages']['product_id.required'] = __('Product is required', 'fluent-support');
135 }
136 }
137
138 $defaultData = [
139 'ticket_title' => $request->getSafe('title', 'sanitize_text_field'),
140 'ticket_content' => $request->getSafe('content', 'wp_kses_post')
141 ];
142
143 if ($request->has('product_id')) {
144 $defaultData['ticket_product_id'] = $request->getSafe('product_id', 'intval');
145 }
146
147 if ($request->has('client_priority')) {
148 $defaultData['ticket_client_priority'] = $request->getSafe('client_priority', 'sanitize_text_field');
149 }
150
151 $customData = $request->get('custom_data', []);
152 $customData = is_array($customData) ? map_deep($customData, 'sanitize_text_field') : [];
153
154 $dataRules = $this->app->applyCustomFilters('custom_field_required_by_conditions_before_ticket_create', [
155 'required_fields' => $dataRules['required_fields'],
156 'error_messages' => $dataRules['error_messages'],
157 'custom_data' => $customData,
158 'default_data' => $defaultData
159 ]);
160
161 if (!isset($dataRules['required_fields']) && !isset($dataRules['error_messages'])) {
162 return $this->sendError([
163 'message' => __('Invalid form data submitted', 'fluent-support'),
164 'error_type' => '400'
165 ], 400);
166 }
167
168 $data = $this->validate($request->get(), $dataRules['required_fields'], $dataRules['error_messages']);
169
170 $data['title'] = sanitize_text_field($data['title']);
171 $data['content'] = wp_kses_post($data['content']);
172
173 $onBehalf = $request->get('on_behalf', []);
174 $userIP = $request->getIp();
175
176 if ($onBehalf) {
177 $onBehalf = array_map(function ($item) {
178 return sanitize_text_field($item);
179 }, $onBehalf);
180
181 if (!empty($onBehalf['last_ip_address'])) {
182 $userIP = $onBehalf['last_ip_address'];
183 }
184 }
185
186 try {
187 $customer = (new CustomerPortalService())->resolveCustomer($onBehalf, $userIP, true);
188
189 if (!$customer) {
190 return $this->sendError([
191 'message' => __('Unable to identify. Please make sure you have provided correct information.', 'fluent-support'),
192 'error_type' => '403'
193 ], 403);
194 }
195
196 $canCreateTicket = apply_filters('fluent_support/can_customer_create_ticket', true, $customer, $data);
197
198 if (!$canCreateTicket || is_wp_error($canCreateTicket)) {
199 $isWpError = is_wp_error($canCreateTicket);
200
201 $message = ($isWpError) ? $canCreateTicket->get_error_message() : __('Sorry you cannot create ticket', 'fluent-support');
202 $errorCode = ($isWpError) ? $canCreateTicket->get_error_code() : 'general_error';
203
204 return $this->sendError([
205 'message' => $message,
206 'error_type' => $errorCode
207 ]);
208 }
209
210 if ($messageId = Helper::generateMessageID($customer->email)) {
211 $data['message_id'] = $messageId;
212 }
213
214 $defaultMailbox = Helper::getDefaultMailBox();
215 $defaultMailboxId = $defaultMailbox ? $defaultMailbox->id : null;
216 $ticket = (new CustomerPortalService())->createTicket($customer, $data, $request->getSafe('mailbox_id', 'intval', $defaultMailboxId));
217
218 return [
219 'message' => __('Ticket has been created successfully', 'fluent-support'),
220 'ticket' => $ticket
221 ];
222 } catch (\Exception $e) {
223 return $this->sendError([
224 'message' => Helper::getSafeErrorMessage($e),
225 'error_type' => $e->getCode()
226 ]);
227 }
228 }
229
230 /**
231 * getTicket method will get the ticket information with customer and agent as well as response in a ticket by ticket id
232 * @param Request $request
233 * @param $ticket_id
234 * @return array|\WP_REST_Response
235 */
236 public function getTicket(Request $request, $ticket_id)
237 {
238 $customerAdditionalData = $this->getCustomerAdditionalData($request);
239
240 try {
241 return (new CustomerPortalService())->getTicket($customerAdditionalData, $ticket_id);
242 } catch (\Exception $e) {
243 return $this->sendError([
244 'message' => Helper::getSafeErrorMessage($e),
245 'error_type' => $e->getCode()
246 ]);
247 }
248 }
249
250 /**
251 * createResponse method will create response by customer in a ticket by ticket id
252 * @param Request $request
253 * @param $ticket_id
254 * @return array|\WP_REST_Response
255 * @throws \FluentSupport\Framework\Validator\ValidationException
256 */
257 public function createResponse(TicketResponseRequest $request, $ticket_id)
258 {
259
260 $customerAdditionalData = $this->getCustomerAdditionalData($request);
261
262 $ticket = Ticket::findOrFail($ticket_id);
263
264 $data = $request->sanitize();
265
266 $canCreateResponse = apply_filters('fluent_support/can_customer_create_response', true, $ticket->customer, $ticket, $data);
267
268 if (!$canCreateResponse || is_wp_error($canCreateResponse)) {
269 return [
270 'type' => 'error',
271 'message' => (is_wp_error($canCreateResponse)) ? $canCreateResponse->get_error_message() : __('Sorry you cannot create response', 'fluent-support')
272 ];
273 }
274
275 try {
276 return (new CustomerPortalService())->createResponse($customerAdditionalData, $ticket_id, $data);
277 } catch (\Exception $e) {
278 return $this->sendError([
279 'message' => Helper::getSafeErrorMessage($e),
280 'error_type' => $e->getCode()
281 ]);
282 }
283 }
284
285 /**
286 * This `closeTicket` is responsible for closing ticket by ticket id
287 * @param Request $request
288 * @param $ticket_id
289 * @return array
290 */
291 public function closeTicket(Request $request, $ticket_id)
292 {
293 $customerAdditionalData = $this->getCustomerAdditionalData($request);
294
295 try {
296 return (new CustomerPortalService())->closeTicket($customerAdditionalData, $ticket_id);
297 } catch (Exception $e) {
298 return $this->sendError([
299 'message' => Helper::getSafeErrorMessage($e),
300 'error_type' => $e->getCode()
301 ]);
302 }
303 }
304
305 /**
306 * closeTicket method will re-open a ticket by customer using ticket id
307 * @param Request $request
308 * @param $ticket_id
309 * @return array
310 */
311 public function reOpenTicket(Request $request, $ticket_id)
312 {
313 $customerAdditionalData = $this->getCustomerAdditionalData($request);
314
315 try {
316 return (new CustomerPortalService())->reOpenTicket($customerAdditionalData, $ticket_id);
317 } catch (Exception $e) {
318 return $this->sendError([
319 'message' => Helper::getSafeErrorMessage($e),
320 'error_type' => $e->getCode()
321 ]);
322 }
323 }
324
325 public function agentFeedbackRating(Request $request, $ticketId)
326 {
327
328 $customerPortalService = new CustomerPortalService();
329
330 // just for validation
331 $ticket = Ticket::with(['customer'])->findOrFail($ticketId);
332 $customerAdditionalData = $this->getCustomerAdditionalData($request);
333 $customer = $customerPortalService->getCustomer($customerAdditionalData, $ticket);
334 $customerPortalService->checkCustomerTicketAccess($customer, $ticket, 'feedback');
335
336 $conversationID = $request->getSafe('conversation_id', 'intval');
337 $approvalStatus = $request->getSafe('approval_status', 'sanitize_text_field');
338
339 try {
340 return $customerPortalService->addUserFeedback($approvalStatus, $conversationID);
341 } catch (Exception $e) {
342 return $this->sendError([
343 'message' => Helper::getSafeErrorMessage($e),
344 'error_type' => $e->getCode()
345 ]);
346 }
347 }
348
349 /**
350 * getPublicOptions method will return the list of product and customer priorities
351 * @return array
352 */
353 public function getPublicOptions()
354 {
355 $products = Product::select(['id', 'title'])->get();
356
357 return [
358 'support_products' => $products,
359 'customer_ticket_priorities' => Helper::customerTicketPriorities()
360 ];
361 }
362
363 /**
364 * getCustomFieldsRender method will return the list of custom fields
365 * @return array|array[]
366 */
367 public function getCustomFieldsRender()
368 {
369 if (!defined('FLUENTSUPPORTPRO')) {
370 return [
371 'custom_fields_rendered' => []
372 ];
373 }
374
375 return [
376 'custom_fields_rendered' => \FluentSupportPro\App\Services\CustomFieldsService::getRenderedPublicFields()
377 ];
378 }
379
380
381 /**
382 * logout method will logout the customer
383 * @return mixed
384 */
385 public function logout()
386 {
387 wp_logout();
388
389 return $this->sendSuccess([
390 'message' => __('You have been logged out', 'fluent-support')
391 ]);
392 }
393
394 private function getCustomerAdditionalData($request)
395 {
396
397 $onBehalf = $request->get('on_behalf', []);
398 if ($onBehalf) {
399 $onBehalf = array_map(function ($item) {
400 return sanitize_text_field($item);
401 }, $onBehalf);
402 }
403
404 $customerAdditionalData = [
405 'intended_ticket_hash' => $request->getSafe('intended_ticket_hash', 'sanitize_text_field'),
406 'on_behalf' => $onBehalf,
407 'user_ip' => $request->getIp()
408 ];
409
410 return $customerAdditionalData;
411 }
412 }
413