PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 1.10.1
Fluent Support – Helpdesk & Customer Support Ticket System v1.10.1
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 / Models / Conversation.php

Conversation.php in Fluent Support – Helpdesk & Customer Support Ticket System 1.10.1, at app/Models/Conversation.php

440 lines 12.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\Models;
4
5 use Exception;
6 use FluentSupport\App\Models\Ticket;
7 use FluentSupport\App\Models\Attachment;
8 use FluentSupport\App\Services\Tickets\ResponseService;
9 use FluentSupport\App\Modules\PermissionManager;
10 use FluentSupport\App\Services\Helper;
11 use FluentSupport\Framework\Support\Arr;
12
13 class Conversation extends Model
14 {
15 protected $table = 'fs_conversations';
16
17 /**
18 * The attributes that are mass assignable.
19 *
20 * @var array
21 */
22 protected $fillable = [
23 'ticket_id',
24 'person_id',
25 'message_id',
26 'conversation_type',
27 'content',
28 'source',
29 'is_important'
30 ];
31
32 public static function boot()
33 {
34 parent::boot();
35
36 static::creating(function ($model) {
37 if(empty($model->content_hash)) {
38 $model->content_hash = md5($model->content);
39 }
40 $model->created_at = current_time('mysql');
41 $model->updated_at = current_time('mysql');
42 });
43
44 static::deleting(function ($model) {
45 //Delete cc info
46 Meta::where('object_type', 'response')->where('object_id', $model->id)->delete();
47 });
48 }
49
50 /**
51 * $searchable Columns in table to search
52 * @var array
53 */
54 protected $searchable = [
55 'content'
56 ];
57
58 /**
59 * Local scope to filter subscribers by search/query string
60 * @param ModelQueryBuilder $query
61 * @param string $search
62 * @return ModelQueryBuilder
63 */
64 public function scopeSearchBy($query, $search)
65 {
66 if ($search) {
67 $fields = $this->searchable;
68 $query->where(function ($query) use ($fields, $search) {
69 $query->where(array_shift($fields), 'LIKE', "%$search%");
70
71 foreach ($fields as $field) {
72 $query->orWhere($field, 'LIKE', "$search%");
73 }
74 });
75 }
76
77 return $query;
78 }
79
80 /**
81 * Local scope to filter subscribers by search/query string
82 * @param ModelQueryBuilder $query
83 * @param string $type
84 * @return ModelQueryBuilder
85 */
86 public function scopeFilterByType($query, $type)
87 {
88 $query->whereIn('conversation_type', $type);
89
90 return $query;
91 }
92
93 /**
94 * One2Many: Customer has to many Click Tickets
95 * @return Model Collection
96 */
97 public function ticket()
98 {
99 $class = __NAMESPACE__ . '\Ticket';
100
101 return $this->belongsTo(
102 $class, 'ticket_id', 'id'
103 );
104 }
105
106 /**
107 * One2Many: Customer has to many Click Tickets
108 * @return Model Collection
109 */
110 public function person()
111 {
112 $class = __NAMESPACE__ . '\Person';
113
114 return $this->belongsTo(
115 $class, 'person_id', 'id'
116 );
117 }
118
119 /**
120 * A Conversation belongs to a Customer.
121 *
122 * @return \FluentSupport\App\Models\Model
123 */
124 public function customer()
125 {
126 return $this->person();
127 }
128
129 public function attachments()
130 {
131 $class = __NAMESPACE__ . '\Attachment';
132 return $this->hasMany($class, 'conversation_id', 'id');
133 }
134
135 /**
136 * One2One: Conversation has cc info
137 * @return Model Collection
138 */
139 public function ccinfo()
140 {
141 $class = __NAMESPACE__ . '\Meta';
142
143 return $this->hasOne(
144 $class, 'object_id', 'id'
145 )->where('object_type', 'response')->where('key', 'settings');
146 }
147
148
149 /**
150 * This `doBulkReplies` will handle bulk replies
151 * @param array $data
152 * @return array
153 * @throws Exception
154 */
155 public function doBulkReplies ( $data )
156 {
157 $agent = Helper::getAgentByUserId();
158 $tickets = $this->getTicketsToForBulkReply( $data, $agent );
159
160 $responseData = [
161 'content' => wp_kses_post(Arr::get($data, 'content', '')),
162 'conversation_type' => 'response',
163 'close_ticket' => Arr::get($data, 'close_ticket'),
164 ];
165
166 $attachments = Arr::get($data, 'attachments', []);
167 $attachments = $this->getAttachsForBulkReplies( $attachments );
168
169 foreach ( $tickets as $ticket ) {
170 if ( $attachments ) {
171 $responseData['attachments'] = [];
172 foreach ( $attachments as $attachment ) {
173 $responseData['attachments'][] = $this->handleAttachmentOnBulkReplies ( $attachment, $ticket );
174 }
175 }
176 (new ResponseService())->createResponse( $responseData, $agent, $ticket );
177 }
178
179 return [
180 'message' => __( 'Response has been added to the selected tickets', 'fluent-support' )
181 ];
182 }
183
184 // This is a supporting method of `doBulkReplies` it will return all selected tickets
185 // Also it will check all check permission
186 // @param array $data
187 // @param object $agent
188 private function getTicketsToForBulkReply( $data, $agent )
189 {
190 $ticketIds = array_filter($data['ticket_ids'], 'absint');
191
192 //Get logged in agent information
193 $hasAllPermission = PermissionManager::currentUserCan('fst_manage_other_tickets');
194 $query = Ticket::whereIn('id', $ticketIds)->where('status', '!=', 'closed');
195
196 //If the agent does not have permission
197 if ( !$hasAllPermission ) {
198 $query->where('agent_id', $agent->id); //Filter ticket by agent_id
199 }
200
201 $tickets = $query->get();
202
203 //if not ticket found
204 if ( $tickets->isEmpty() ) {
205 throw new \Exception( 'Sorry no tickets found based on your filter and bulk actions');
206 }
207
208 return $tickets;
209 }
210
211 // This is a supporting method of `doBulkReplies` it will return it will return attachments
212 // if agent add attachments to bulk replies if there is no attachments then it will return false
213 // @param array $attachments
214 private function getAttachsForBulkReplies ( $attachments )
215 {
216 if ( $attachments ) {
217 $attachs = Attachment::whereNull('ticket_id')
218 ->orderBy('id', 'asc')
219 ->whereIn('file_hash', $attachments)
220 ->get();
221 return $attachs;
222 }
223 return false;
224 }
225
226 // This is a supporting method of `doBulkReplies` this method will prepare the uploaded attachments
227 // for adding in response
228 // @param object $attachment
229 // @param object $ticket
230 private function handleAttachmentOnBulkReplies ( $attachment, $ticket )
231 {
232 $attachedFile = $attachment->replicate();
233 $attachedFile->ticket_id = $ticket->id;
234 $attachedFile->save();
235 return $attachedFile->file_hash;
236 }
237
238
239 /**
240 * This `deleteResponse` is responsible for deleting response
241 * @param int $ticketId
242 * @param int $responseId
243 * @return array
244 * @throws Exception
245 */
246 public function deleteResponse($ticketId, $responseId)
247 {
248 $ticket = Ticket::findOrFail($ticketId);
249 $response = static::findOrFail($responseId);
250 $agent = Helper::getAgentByUserId();
251
252 $this->checkUserTaskPermission($ticket->agent_id, $agent->id, 'delete');
253
254 static::where('id', $response->id)->delete();
255 $response->ccinfo()->delete();
256
257 return [
258 'message' => __('Selected response has been deleted', 'fluent-support')
259 ];
260 }
261
262 /**
263 * Update the conversation type for a response.
264 *
265 * @param array $data
266 * @param int $ticketId
267 * @param int $responseId
268 * @param string $conversationType
269 *
270 * @return array
271 * @throws Exception
272 */
273 public function publishDraftResponse ( $data, $ticketId, $responseId, $conversationType )
274 {
275 $ticket = Ticket::findOrFail($ticketId);
276 $response = static::findOrFail($responseId);
277
278 $content = wp_unslash(wp_kses_post($data['content']));
279 $resetWaitingSince = apply_filters('fluent_support/reset_waiting_since', true, $content);
280
281 $person = Helper::getAgentByUserId(get_current_user_id());
282
283 $approveDraftResponsePermission = PermissionManager::currentUserCan('fst_approve_draft_reply');
284
285 if ( !$approveDraftResponsePermission ) {
286 throw new \Exception("Sorry, You do not have permission to approve this draft response");
287 }
288
289 $response->conversation_type = $conversationType;
290 $response->created_at = current_time('mysql');
291 $response->save();
292
293 if ($person->person_type == 'agent' && $ticket->status == 'new') {
294 $ticket->status = 'active';
295 if ($ticket->created_at) {
296 $ticket->first_response_time = strtotime(current_time('mysql')) - strtotime($ticket->created_at);
297 } else {
298 $ticket->first_response_time = 300;
299 }
300 }
301
302 if ($resetWaitingSince) {
303 $ticket->last_agent_response = current_time('mysql');
304 $ticket->waiting_since = current_time('mysql');
305 }
306
307 $ticket->response_count += 1;
308 $ticket->save();
309
310 do_action('fluent_support/' . $conversationType . '_added_by_' . $person->person_type, $response, $ticket, $person);
311
312 return [
313 'message' => __('Draft response has been successfully approved.', 'fluent-support'),
314 'response' => $response,
315 ];
316 }
317
318 public function updateResponse($data, $ticketId, $responseId)
319 {
320 $ticket = Ticket::findOrFail($ticketId);
321 $response = static::findOrFail($responseId);
322
323 $agent = Helper::getAgentByUserId();
324
325 $this->checkUserTaskPermission($ticket->agent_id, $agent->id, 'update');
326
327 $response->content = wp_unslash(wp_kses_post($data['content']));
328
329 if ( $response->conversation_type == 'draft_response' ) {
330 $this->updateDraftResponseData($response);
331 }
332
333 $response->save();
334
335 return [
336 'message' => __('Selected response has been updated', 'fluent-support'),
337 'response' => $response
338 ];
339 }
340
341 public function updateDraftResponseData($response)
342 {
343 $agent = Helper::getAgentByUserId();
344 $approveDraftResponsePermission = PermissionManager::currentUserCan('fst_approve_draft_reply');
345
346 if ($response->person_id == $agent->id) {
347 return null;
348 }
349
350 if ($approveDraftResponsePermission) {
351 $response->conversation_type = 'response';
352 $response->save();
353 return [
354 'message' => __('Selected draft response has been approved and updated', 'fluent-support'),
355 'response' => $response
356 ];
357 } else {
358 throw new \Exception("Sorry, You do not have permission to approve this draft response");
359 }
360 }
361
362 public function getSettingsValue($valueKey = false, $default = false)
363 {
364 $exist = Meta::where('object_type', 'response')
365 ->where('key', 'settings')
366 ->where('object_id', $this->id)
367 ->first();
368
369 if ($exist) {
370 $value = Helper::safeUnserialize($exist->value);
371 if ($valueKey) {
372 if (!is_array($value)) {
373 return $default;
374 }
375 return Arr::get($value, $valueKey, $default);
376 }
377 return $value;
378 }
379
380 return $default;
381 }
382
383 public function updateSettingsValue($valueKey, $value)
384 {
385 $exist = Meta::where('object_type', 'response')
386 ->where('key', 'settings')
387 ->where('object_id', $this->id)
388 ->first();
389
390 if ($exist) {
391 $existingValue = Helper::safeUnserialize($exist->value);
392
393 if (!is_array($existingValue)) {
394 $existingValue = [];
395 }
396
397 $existingValue[$valueKey] = $value;
398
399 $exist->value = maybe_serialize($existingValue);
400 $exist->save();
401 return $this;
402 }
403
404 $settings = [
405 'object_type' => 'response',
406 'key' => 'settings',
407 'object_id' => $this->id,
408 'value' => maybe_serialize([
409 $valueKey => $value
410 ])
411 ];
412
413 Meta::create($settings);
414
415 return $this;
416
417 }
418
419 public static function deleteAll($ticketId){
420 $conversations = Conversation::where('ticket_id', $ticketId)->get();
421 foreach ($conversations as $conversation) {
422 $conversation->delete();
423 }
424 }
425
426 private function checkUserTaskPermission($ticketAgentId, $agentId, $task)
427 {
428 $permissionKey = $task === 'delete' ? 'fst_delete_tickets' : 'fst_manage_other_tickets';
429
430 if (!PermissionManager::currentUserCan($permissionKey) && $ticketAgentId !== $agentId) {
431 throw new \Exception(
432 esc_html(sprintf(__('Sorry, you do not have permission to %s this response.', 'fluent-support'), $task))
433 );
434 }
435
436 return true;
437 }
438
439 }
440