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
← All changes | app/Models/Conversation.php +9 -240 1.10.3 → 2.4.5 View file →
@@ -1,13 +1,8 @@
1 1 <?php
2 2
3 3 namespace FluentSupport\App\Models;
4 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 5 use FluentSupport\App\Services\Helper;
11 6 use FluentSupport\Framework\Support\Arr;
12 7
13 8 class Conversation extends Model
@@ -43,13 +38,17 @@
43 38
44 39 static::deleting(function ($model) {
45 40 //Delete cc info
46 41 Meta::where('object_type', 'response')->where('object_id', $model->id)->delete();
42 + // Attachment files first, then their rows
43 + $class = __NAMESPACE__ . '\Attachment';
44 + $attachments = $class::where('conversation_id', $model->id)->get();
45 + $class::purgeAttachments($attachments);
46 + $class::where('conversation_id', $model->id)->delete();
47 47 });
48 48 }
49 49
50 50 /**
51 - * $searchable Columns in table to search
52 51 * @var array
53 52 */
54 53 protected $searchable = [
55 54 'content'
@@ -55,9 +54,8 @@
55 54 'content'
56 55 ];
57 56
58 57 /**
59 - * Local scope to filter subscribers by search/query string
60 58 * @param ModelQueryBuilder $query
61 59 * @param string $search
62 60 * @return ModelQueryBuilder
63 61 */
@@ -77,11 +75,10 @@
77 75 return $query;
78 76 }
79 77
80 78 /**
81 - * Local scope to filter subscribers by search/query string
82 79 * @param ModelQueryBuilder $query
83 - * @param string $type
80 + * @param array $type
84 81 * @return ModelQueryBuilder
85 82 */
86 83 public function scopeFilterByType($query, $type)
87 84 {
@@ -90,9 +87,8 @@
90 87 return $query;
91 88 }
92 89
93 90 /**
94 - * One2Many: Customer has to many Click Tickets
95 91 * @return Model Collection
96 92 */
97 93 public function ticket()
98 94 {
@@ -103,9 +99,8 @@
103 99 );
104 100 }
105 101
106 102 /**
107 - * One2Many: Customer has to many Click Tickets
108 103 * @return Model Collection
109 104 */
110 105 public function person()
111 106 {
@@ -116,9 +111,9 @@
116 111 );
117 112 }
118 113
119 114 /**
120 - * A Conversation belongs to a Customer.
115 + * Alias of person(). The author may be an agent, not only a customer.
121 116 *
122 117 * @return \FluentSupport\App\Models\Model
123 118 */
124 119 public function customer()
@@ -132,9 +127,10 @@
132 127 return $this->hasMany($class, 'conversation_id', 'id');
133 128 }
134 129
135 130 /**
136 - * One2One: Conversation has cc info
131 + * CC info stored in fs_meta.
132 + *
137 133 * @return Model Collection
138 134 */
139 135 public function ccinfo()
140 136 {
@@ -145,221 +141,8 @@
145 141 )->where('object_type', 'response')->where('key', 'settings');
146 142 }
147 143
148 144
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 145 public function getSettingsValue($valueKey = false, $default = false)
363 146 {
364 147 $exist = Meta::where('object_type', 'response')
365 148 ->where('key', 'settings')
@@ -420,21 +203,7 @@
420 203 $conversations = Conversation::where('ticket_id', $ticketId)->get();
421 204 foreach ($conversations as $conversation) {
422 205 $conversation->delete();
423 206 }
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 - // translators: %s is the action being performed (e.g., "view", "edit", "delete")
433 - esc_html(sprintf(__('Sorry, you do not have permission to %s this response.', 'fluent-support'), $task))
434 - );
435 - }
436 -
437 - return true;
438 207 }
439 208
440 209 }