From 8b6b15706a692e22dad66d711a3e6880d5369235 Mon Sep 17 00:00:00 2001 From: Antoine Le Gonidec Date: Mon, 22 Jul 2024 18:58:51 +0200 Subject: [PATCH] Fix creating a new Conversation with a new Customer --- Http/Controllers/ConversationsController.php | 742 +++++++++++++++++++ README.md | 32 + 2 files changed, 774 insertions(+) create mode 100644 Http/Controllers/ConversationsController.php diff --git a/Http/Controllers/ConversationsController.php b/Http/Controllers/ConversationsController.php new file mode 100644 index 0000000..fc59f26 --- /dev/null +++ b/Http/Controllers/ConversationsController.php @@ -0,0 +1,742 @@ + + */ + +namespace Modules\MMFRestrictedCustomers\Http\Controllers; + +use Validator; + +use Illuminate\Http\Request; + +use App\Attachment; +use App\Conversation; +use App\Events\ConversationStatusChanged; +use App\Events\ConversationUserChanged; +use App\Events\UserAddedNote; +use App\Events\UserCreatedConversation; +use App\Events\UserReplied; +use App\Mailbox; +use App\MailboxUser; +use App\Thread; + +use Modules\MMFRestrictedCustomers\Entities\Customer; + +use App\Http\Controllers\ConversationsController as BaseConversationsController; + +class ConversationsController extends BaseConversationsController { + /** + * Conversations ajax controller. + */ + public function ajax(Request $request) { + // This override is only required for "send_reply" requests. + if ( $request->action != 'send_reply' ) + return parent::ajax($request); + + $response = [ + 'status' => 'error', + 'msg' => '', // this is error message + ]; + + $user = auth()->user(); + + $mailbox = Mailbox::findOrFail($request->mailbox_id); + + if (!$response['msg'] && !$user->can('view', $mailbox)) { + $response['msg'] = __('Not enough permissions'); + } + + $conversation = null; + if (!$response['msg'] && !empty($request->conversation_id)) { + $conversation = Conversation::find($request->conversation_id); + if ($conversation && !$user->can('view', $conversation)) { + $response['msg'] = __('Not enough permissions'); + } + } + $new = false; + if (empty($request->conversation_id)) { + $new = true; + } + + $is_note = false; + if (!empty($request->is_note)) { + $is_note = true; + } + + // Conversation type. + $type = Conversation::TYPE_EMAIL; + if (!empty($request->type)) { + $type = (int)$request->type; + } elseif ($conversation) { + $type = $conversation->type; + } + + $is_phone = false; + if ($type == Conversation::TYPE_PHONE) { + $is_phone = true; + } + + $is_custom = false; + if ($type == Conversation::TYPE_CUSTOM) { + $is_custom = true; + } + + $is_create = false; + if (!empty($request->is_create)) { + //if ($new || ($from_draft && $conversation->threads_count == 1)) { + $is_create = $request->is_create; + } + + $is_forward = false; + if (!empty($request->subtype) && (int)$request->subtype == Thread::SUBTYPE_FORWARD) { + $is_forward = true; + } + + $is_multiple = false; + if (!empty($request->multiple_conversations)) { + $is_multiple = true; + } + + // If reply is being created from draft, there is already thread created + $thread = null; + $from_draft = false; + if (( ! $is_note || $is_phone || $is_custom ) && ! $response['msg'] && ! empty($request->thread_id)) { + $thread = Thread::find($request->thread_id); + if ($thread && (!$conversation || $thread->conversation_id != $conversation->id)) { + $response['msg'] = __('Incorrect thread'); + } else { + $from_draft = true; + } + } + + if (!$response['msg']) { + if ($thread && $from_draft && $thread->state == Thread::STATE_PUBLISHED) { + $response['msg'] = __('Message has been already sent. Please discard this draft.'); + } + } + + // Validate form + if (!$response['msg']) { + if ($new) { + if ($type == Conversation::TYPE_EMAIL) { + $validator = Validator::make($request->all(), [ + 'to' => 'required|array', + 'subject' => 'required|string|max:998', + 'body' => 'required|string', + 'cc' => 'nullable|array', + 'bcc' => 'nullable|array', + ]); + } elseif ($type === Conversation::TYPE_PHONE) { + // Phone conversation. + $validator = Validator::make($request->all(), [ + 'name' => 'required|string', + 'subject' => 'required|string|max:998', + 'body' => 'required|string', + 'phone' => 'nullable|string', + 'to_email' => 'nullable|string', + ]); + } elseif ($type === Conversation::TYPE_CUSTOM) { + $validation_rules = \Eventy::filter('conversation.custom.validation_rules', [ + 'body' => 'required|string', + 'cc' => 'nullable|array', + 'bcc' => 'nullable|array', + ], $request); + $validator = Validator::make($request->all(), $validation_rules); + } + } else { + $validator = Validator::make($request->all(), [ + 'body' => 'required|string', + 'cc' => 'nullable|array', + 'bcc' => 'nullable|array', + ]); + } + + if ($validator->fails()) { + foreach ($validator->errors()->getMessages()as $errors) { + foreach ($errors as $field => $message) { + $response['msg'] .= $message.' '; + } + } + } + } + + $body = $request->body; + + // Replace base64 images with attachment URLs in case text + // was copy and pasted into the editor. + // https://github.com/freescout-helpdesk/freescout/issues/3057 + $body = Thread::replaceBase64ImagesWithAttachments($body); + + // List of emails. + $to_array = []; + if ($is_forward) { + $to_array = Conversation::sanitizeEmails($request->to_email); + } else { + $to_array = Conversation::sanitizeEmails($request->to); + } + // Check To + if (! $response['msg'] && $new && ! $is_phone && ! $is_custom) { + if (!$to_array) { + $response['msg'] .= __('Incorrect recipients'); + } + } + + // Check max. message size. + if (!$response['msg']) { + + $max_message_size = (int)config('app.max_message_size'); + if ($max_message_size) { + // Todo: take into account conversation history. + $message_size = mb_strlen($body, '8bit'); + + // Calculate attachments size. + $attachments_ids = array_merge($request->attachments ?? [], $request->embeds ?? []); + $attachments_ids = $this->decodeAttachmentsIds($attachments_ids); + + if (count($attachments_ids)) { + $attachments_to_check = Attachment::select('size')->whereIn('id', $attachments_ids)->get(); + foreach ($attachments_to_check as $attachment) { + $message_size += (int)$attachment->size; + } + } + + if ($message_size > $max_message_size*1024*1024) { + $response['msg'] = __('Message is too large — :info. Please shorten your message or remove some attachments.', ['info' => __('Max. Message Size').': '.$max_message_size.' MB']); + } + } + } + + if (!$response['msg']) { + + // Get attachments info + // Delete removed attachments. + $attachments_info = $this->processReplyAttachments($request); + + // Determine redirect. + // Must be done before updating current conversation's status or assignee. + // Redirect URL for new no saved yet conversation is determined below. + if (!$new) { + $response['redirect_url'] = $this->getRedirectUrl($request, $conversation, $user); + } + + // Conversation + $now = date('Y-m-d H:i:s'); + $status_changed = false; + $user_changed = false; + // Chat conversations in chat mode can not be undone. + $can_undo = true; + + $request_status = (int)$request->status; + + if ($new) { + // New conversation + $conversation = new Conversation(); + $conversation->type = $type; + $conversation->subject = $request->subject; + $conversation->setPreview($body); + $conversation->mailbox_id = $request->mailbox_id; + $conversation->created_by_user_id = auth()->user()->id; + $conversation->source_via = Conversation::PERSON_USER; + $conversation->source_type = Conversation::SOURCE_TYPE_WEB; + } else { + // Reply or note + if ($request_status && $request_status != (int)$conversation->status) { + $status_changed = true; + } + if (!empty($request->subject)) { + $conversation->subject = $request->subject; + } + // When switching from regular message to phone and message sent + // without saving a draft type need to be saved here. + // Or vise versa. + if (($conversation->type == Conversation::TYPE_EMAIL && $type == Conversation::TYPE_PHONE) + || ($conversation->type == Conversation::TYPE_PHONE && $type == Conversation::TYPE_EMAIL) + ) { + $conversation->type = $type; + } + // Allow to convert phone conversations into email conversations. + if ($conversation->isPhone() && !$is_note && $conversation->customer + && $customer_email = $conversation->customer->getMainEmail() + ) { + $conversation->type = Conversation::TYPE_EMAIL; + $conversation->customer_email = $customer_email; + $is_phone = false; + } + } + + if ($attachments_info['has_attachments']) { + $conversation->has_attachments = true; + } + + // Customer can be empty in existing conversation if this is a draft. + $customer_email = ''; + $customer = null; + + if ($is_phone && $is_create) { + // Phone. + $phone_customer_data = $this->processPhoneCustomer($request); + + $customer_email = $phone_customer_data['customer_email']; + $customer = $phone_customer_data['customer']; + if (! $conversation->customer_id) { + $conversation->customer_id = $customer->id; + } + } elseif ($is_custom) { + // No customer for custom conversations. + } else { + // Email or reply to a phone conversation. + if (!empty($to_array)) { + $customer_email = $to_array[0]; + } elseif (!$conversation->customer_email + && ($conversation->isEmail() || $conversation->isPhone()) + && $conversation->customer_id + && $conversation->customer + ) { + // When replying to a phone conversation, we need to + // set 'customer_email' for the conversation. + $customer_email = $conversation->customer->getMainEmail(); + } + if (!$conversation->customer_id) { + // The new Customer must be linked to a specific Mailbox. + $data = []; + $data['mailbox_id'] = $conversation->mailbox_id; + $customer = Customer::create($customer_email, $data); + $conversation->customer_id = $customer->id; + } else { + $customer = $conversation->customer; + } + } + if ($customer_email && !$is_note && !$is_forward) { + $conversation->customer_email = $customer_email; + } + + $prev_status = $conversation->status; + + $conversation->status = $request_status ?: $conversation->status; + + if (($prev_status != $conversation->status || $is_create) + && $conversation->status == Conversation::STATUS_CLOSED + ) { + $conversation->closed_by_user_id = $user->id; + $conversation->closed_at = date('Y-m-d H:i:s'); + } + + // We need to set state, as it may have been a draft. + $prev_state = $conversation->state; + $conversation->state = Conversation::STATE_PUBLISHED; + + // Set assignee + $prev_user_id = $conversation->user_id; + if ((int) $request->user_id != -1) { + // Check if user has access to the current mailbox + if ((int) $conversation->user_id != (int) $request->user_id && $mailbox->userHasAccess($request->user_id)) { + $conversation->user_id = $request->user_id; + $user_changed = true; + } + } else { + $conversation->user_id = null; + } + + // To is a single email string. + $to = ''; + // List of emails. + $to_list = []; + if ($is_forward) { + if (empty($request->to_email[0])) { + $response['msg'] = __('Please specify a recipient.'); + return \Response::json($response); + } + $to = $request->to_email[0]; + } else { + if (!empty($request->to)) { + // When creating a new conversation, to is a list of emails. + if (is_array($request->to)) { + $to = $request->to[0]; + } else { + $to = $request->to; + } + } else { + $to = $conversation->customer_email; + } + } + + if (!$is_note && !$is_forward) { + // Save extra recipients to CC + if ($is_create && !$is_multiple && count($to_array) > 1) { + $conversation->setCc(array_merge(Conversation::sanitizeEmails($request->cc), $to_array)); + } else { + if (!$is_multiple) { + $conversation->setCc(array_merge(Conversation::sanitizeEmails($request->cc), [$to])); + } else { + $conversation->setCc(Conversation::sanitizeEmails($request->cc)); + } + } + $conversation->setBcc($request->bcc); + $conversation->last_reply_at = $now; + $conversation->last_reply_from = Conversation::PERSON_USER; + $conversation->user_updated_at = $now; + } + if ($conversation->isPhone() && $is_note) { + $conversation->last_reply_at = $now; + $conversation->last_reply_from = Conversation::PERSON_USER; + } + $conversation->updateFolder(); + if ($from_draft) { + // Increment number of replies in conversation + $conversation->threads_count++; + // We need to set preview here as when conversation is created from draft, + // ThreadObserver::created() method is not called. + $conversation->setPreview($body); + } + $conversation->save(); + + // Redirect URL for new not saved yet conversation must be determined here. + if ($new) { + $response['redirect_url'] = $this->getRedirectUrl($request, $conversation, $user); + } + + // Fire events + \Eventy::action('conversation.send_reply_save', $conversation, $request); + + if (!$new) { + if ($status_changed) { + event(new ConversationStatusChanged($conversation)); + \Eventy::action('conversation.status_changed', $conversation, $user, $changed_on_reply = true, $prev_status); + } + if ($user_changed) { + event(new ConversationUserChanged($conversation, $user)); + \Eventy::action('conversation.user_changed', $conversation, $user, $prev_user_id); + } + } + + if ($conversation->state != $prev_state) { + \Eventy::action('conversation.state_changed', $conversation, $user, $prev_state); + } + + // Create thread + if (!$thread) { + $thread = new Thread(); + $thread->conversation_id = $conversation->id; + if ($is_note || $is_forward) { + $thread->type = Thread::TYPE_NOTE; + } else { + $thread->type = Thread::TYPE_MESSAGE; + } + $thread->source_via = Thread::PERSON_USER; + $thread->source_type = Thread::SOURCE_TYPE_WEB; + } else { + if ($is_forward || $is_phone) { + $thread->type = Thread::TYPE_NOTE; + } else { + $thread->type = Thread::TYPE_MESSAGE; + } + $thread->created_at = $now; + } + if ($new) { + $thread->first = true; + } + $thread->user_id = $conversation->user_id; + $thread->status = $request_status ?? $conversation->status; + $thread->state = Thread::STATE_PUBLISHED; + if (!$is_custom) { + $thread->customer_id = $customer->id; + } + $thread->created_by_user_id = auth()->user()->id; + $thread->edited_by_user_id = null; + $thread->edited_at = null; + $thread->body = $body; + if ($is_create && !$is_multiple && count($to_array) > 1) { + $thread->setTo($to_array); + } else { + $thread->setTo($to); + } + // We save CC and BCC as is and filter emails when sending replies + $thread->setCc($request->cc); + $thread->setBcc($request->bcc); + if ($attachments_info['has_attachments'] && !$is_forward) { + $thread->has_attachments = true; + } + if (!empty($request->saved_reply_id)) { + $thread->saved_reply_id = $request->saved_reply_id; + } + + $forwarded_conversations = []; + $forwarded_threads = []; + + if ($is_forward) { + // Create forwarded conversations. + foreach ($to_array as $recipient_email) { + $forwarded_conversation = $conversation->replicate(); + $forwarded_conversation->type = Conversation::TYPE_EMAIL; + $forwarded_conversation->setPreview($thread->body); + $forwarded_conversation->created_by_user_id = auth()->user()->id; + $forwarded_conversation->source_via = Conversation::PERSON_USER; + $forwarded_conversation->source_type = Conversation::SOURCE_TYPE_WEB; + $forwarded_conversation->threads_count = 0; // Counter will be incremented in ThreadObserver. + $forwarded_customer = Customer::create($recipient_email); + $forwarded_conversation->customer_id = $forwarded_customer->id; + // Reload customer object, otherwise it stores previous customer. + $forwarded_conversation->load('customer'); + $forwarded_conversation->customer_email = $recipient_email; + $forwarded_conversation->subject = 'Fwd: '.$forwarded_conversation->subject; + //$forwarded_conversation->setCc(array_merge(Conversation::sanitizeEmails($request->cc), [$to])); + $forwarded_conversation->setCc(Conversation::sanitizeEmails($request->cc)); + $forwarded_conversation->setBcc($request->bcc); + $forwarded_conversation->last_reply_at = $now; + $forwarded_conversation->last_reply_from = Conversation::PERSON_USER; + $forwarded_conversation->user_updated_at = $now; + if ($attachments_info['has_attachments']) { + $forwarded_conversation->has_attachments = true; + } + $forwarded_conversation->updateFolder(); + $forwarded_conversation->save(); + + $forwarded_thread = $thread->replicate(); + + $forwarded_conversations[] = $forwarded_conversation; + $forwarded_threads[] = $forwarded_thread; + } + + // Set forwarding meta data. + // todo: store array of numbers and IDs. + $thread->subtype = Thread::SUBTYPE_FORWARD; + $thread->setMeta(Thread::META_FORWARD_CHILD_CONVERSATION_NUMBER, $forwarded_conversation->number); + $thread->setMeta(Thread::META_FORWARD_CHILD_CONVERSATION_ID, $forwarded_conversation->id); + } + + // Conversation history. + if (!empty($request->conv_history)) { + if ($request->conv_history != 'global') { + if ($is_forward && !empty($forwarded_threads)) { + foreach ($forwarded_threads as $forwarded_thread) { + $forwarded_thread->setMeta(Thread::META_CONVERSATION_HISTORY, $request->conv_history); + } + } else { + $thread->setMeta(Thread::META_CONVERSATION_HISTORY, $request->conv_history); + } + } + } + + // From (mailbox alias). + if (!empty($request->from_alias)) { + $thread->from = $request->from_alias; + } + + \Eventy::action('thread.before_save_from_request', $thread, $request); + $thread->save(); + + // Save forwarded thread. + if ($is_forward) { + foreach ($forwarded_conversations as $i => $forwarded_conversation) { + $forwarded_thread = $forwarded_threads[$i]; + + $forwarded_thread->conversation_id = $forwarded_conversation->id; + $forwarded_thread->type = Thread::TYPE_MESSAGE; + $forwarded_thread->subtype = null; + if ($attachments_info['has_attachments']) { + $forwarded_thread->has_attachments = true; + } + $forwarded_thread->setMeta(Thread::META_FORWARD_PARENT_CONVERSATION_NUMBER, $conversation->number); + $forwarded_thread->setMeta(Thread::META_FORWARD_PARENT_CONVERSATION_ID, $conversation->id); + $forwarded_thread->setMeta(Thread::META_FORWARD_PARENT_THREAD_ID, $thread->id); + \Eventy::action('send_reply.before_save_forwarded_thread', $forwarded_thread, $request); + $forwarded_thread->save(); + } + } + + // If thread has been created from draft, remove the draft + // if ($request->thread_id) { + // $draft_thread = Thread::find($request->thread_id); + // if ($draft_thread) { + // $draft_thread->delete(); + // } + // } + + if ($from_draft) { + // Remove conversation from drafts folder if needed + $conversation->maybeRemoveFromDrafts(); + } + + // Update folders counters + $conversation->mailbox->updateFoldersCounters(); + + $response['status'] = 'success'; + + // Set thread_id for uploaded attachments + if ($attachments_info['attachments']) { + if ($is_forward) { + // Copy attachments for each thread. + if (count($forwarded_threads) > 1) { + $attachments = Attachment::whereIn('id', $attachments_info['attachments'])->get(); + } + foreach ($forwarded_threads as $i => $forwarded_thread) { + if ($i == 0) { + Attachment::whereIn('id', $attachments_info['attachments'])->update(['thread_id' => $forwarded_thread->id]); + } else { + foreach ($attachments as $attachment) { + $attachment->duplicate($forwarded_thread->id); + } + } + } + } else { + Attachment::whereIn('id', $attachments_info['attachments']) + ->where('thread_id', null) + ->update(['thread_id' => $thread->id]); + } + } + + // Follow conversation if it's assigned to someone else. + if (!$is_create && !$new && !$is_forward && !$is_note + && $conversation->user_id != $user->id + ) { + $user->followConversation($conversation->id); + } + + if ($conversation->isChat() && \Helper::isChatMode()) { + $can_undo = false; + } + + // When user creates a new conversation it may be saved as draft first. + if ($is_create) { + // New conversation. + event(new UserCreatedConversation($conversation, $thread)); + \Eventy::action('conversation.created_by_user_can_undo', $conversation, $thread); + // After Conversation::UNDO_TIMOUT period trigger final event. + \Helper::backgroundAction('conversation.created_by_user', [$conversation, $thread], now()->addSeconds($this->getUndoTimeout($can_undo))); + } elseif ($is_forward) { + // Forward. + // Notifications to users not sent. + event(new UserAddedNote($conversation, $thread)); + foreach ($forwarded_conversations as $i => $forwarded_conversation) { + $forwarded_thread = $forwarded_threads[$i]; + + // To send email with forwarded conversation. + event(new UserReplied($forwarded_conversation, $forwarded_thread)); + \Eventy::action('conversation.user_forwarded_can_undo', $conversation, $thread, $forwarded_conversation, $forwarded_thread); + // After Conversation::UNDO_TIMOUT period trigger final event. + \Helper::backgroundAction('conversation.user_forwarded', [$conversation, $thread, $forwarded_conversation, $forwarded_thread], now()->addSeconds(Conversation::UNDO_TIMOUT)); + } + } elseif ($is_note) { + // Note. + event(new UserAddedNote($conversation, $thread)); + \Eventy::action('conversation.note_added', $conversation, $thread); + } else { + // Reply. + event(new UserReplied($conversation, $thread)); + \Eventy::action('conversation.user_replied_can_undo', $conversation, $thread); + // After Conversation::UNDO_TIMOUT period trigger final event. + \Helper::backgroundAction('conversation.user_replied', [$conversation, $thread], now()->addSeconds($this->getUndoTimeout($can_undo))); + } + + // Send new conversation separately to each customer. + if ($is_create && count($to_array) > 1 && $is_multiple) { + $prev_customers_ids = []; + foreach ($to_array as $i => $customer_email) { + // Skip first email, as conversation has already been created for it. + if ($i == 0) { + continue; + } + // Get customer by email. + $customer_tmp = Customer::getByEmail($customer_email); + // Skip same customers. + if ($customer_tmp && in_array($customer_tmp->id, $prev_customers_ids)) { + continue; + } + + if (!$customer_tmp) { + $customer_tmp = Customer::create($customer_email); + } + + $prev_customers_ids[] = $customer_tmp->id; + + // Copy conversation and thread. + $conversation_copy = $conversation->replicate(); + $thread_copy = $thread->replicate(); + + // Save conversation. + $conversation_copy->threads_count = 0; + $conversation_copy->customer_id = $customer_tmp->id; + // Reload customer, otherwise all recipients will have the same name. + $conversation_copy->load('customer'); + $conversation_copy->customer_email = $customer_email; + $conversation_copy->has_attachments = $conversation->has_attachments; + $conversation_copy->push(); + + $thread_copy->conversation_id = $conversation_copy->id; + $thread_copy->customer_id = $customer_tmp->id; + $thread_copy->has_attachments = $conversation->has_attachments; + $thread_copy->setTo($customer_email); + // Reload the conversation, otherwise Thread observer will be + // increasing threads_count for the first conversation. + $thread_copy->load('conversation'); + $thread_copy->push(); + + // Copy attachments. + if (!empty($attachments_info['attachments'])) { + $attachments = Attachment::whereIn('id', $attachments_info['attachments'])->get(); + foreach ($attachments as $attachment) { + $attachment->duplicate($thread_copy->id); + } + } + + // Events. + // todo: allow to undo all emails + event(new UserCreatedConversation($conversation_copy, $thread_copy)); + \Eventy::action('conversation.created_by_user_can_undo', $conversation_copy, $thread_copy); + // After Conversation::UNDO_TIMOUT period trigger final event. + \Helper::backgroundAction('conversation.created_by_user', [$conversation_copy, $thread_copy], now()->addSeconds($this->getUndoTimeout($can_undo))); + } + } + + // Compose flash message. + $show_view_link = true; + if (!empty($request->after_send) && $request->after_send == MailboxUser::AFTER_SEND_STAY) { + $show_view_link = false; + } + + $flash_vars = ['%tag_start%' => '', '%tag_end%' => '', '%view_start%' => ' ', '%a_end%' => ' ', '%undo_start%' => ' ']; + + if ($is_phone) { + $flash_type = 'warning'; + if ($show_view_link) { + $flash_text = __(':%tag_start%Conversation created:%tag_end% :%view_start%View:%a_end% or :%undo_start%Undo:%a_end%', $flash_vars); + } else { + $flash_text = ''.__('Conversation created').''; + } + } elseif ($is_custom) { + $flash_type = 'warning'; + $identifier = \Eventy::filter('conversation.custom.identifier', __('Custom conversation'), $request); + if ($show_view_link) { + $flash_text = __(':%tag_start%' . $identifier . ' added:%tag_end% :%view_start%View:%a_end%', $flash_vars); + } else { + $flash_text = ''.__('%identifier% added',['%identifier%'=>$identifier]).''; + } + } elseif ($is_note) { + $flash_type = 'warning'; + if ($show_view_link) { + $flash_text = __(':%tag_start%Note added:%tag_end% :%view_start%View:%a_end%', $flash_vars); + } else { + $flash_text = ''.__('Note added').''; + } + } else { + $flash_type = 'success'; + if ($show_view_link) { + $flash_text = __(':%tag_start%Email Sent:%tag_end% :%view_start%View:%a_end% or :%undo_start%Undo:%a_end%', $flash_vars); + } else { + $flash_text = __(':%tag_start%Email Sent:%tag_end% :%undo_start%Undo:%a_end%', $flash_vars); + } + } + + if ($can_undo) { + \Session::flash('flash_'.$flash_type.'_floating', $flash_text); + } + } + + if ($response['status'] == 'error' && empty($response['msg'])) { + $response['msg'] = 'Unknown error occurred'; + } + + return \Response::json($response); + } +} diff --git a/README.md b/README.md index 2560024..9f90a9a 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,38 @@ Route::get('/customers/ajax-search', ['uses' => '\Modules\MMFRestrictedCustomers Route::post('/customers/ajax', ['uses' => '\Modules\MMFRestrictedCustomers\Http\Controllers\CustomersController@ajax', 'laroute' => true])->name('customers.ajax'); ``` +This other section: + +```php +// Conversations +Route::get('/conversation/{id}', ['uses' => 'ConversationsController@view', 'laroute' => true])->name('conversations.view'); +Route::post('/conversation/ajax', ['uses' => 'ConversationsController@ajax', 'laroute' => true])->name('conversations.ajax'); +Route::post('/conversation/upload', ['uses' => 'ConversationsController@upload', 'laroute' => true])->name('conversations.upload'); +Route::get('/mailbox/{mailbox_id}/new-ticket', 'ConversationsController@create')->name('conversations.create'); +Route::get('/mailbox/{mailbox_id}/clone-ticket/{from_thread_id}', 'ConversationsController@cloneConversation')->name('conversations.clone_conversation'); +//Route::get('/conversation/draft/{id}', 'ConversationsController@draft')->name('conversations.draft'); +Route::get('/conversation/ajax-html/{action}', ['uses' => 'ConversationsController@ajaxHtml', 'laroute' => true])->name('conversations.ajax_html'); +Route::get('/search', 'ConversationsController@search')->name('conversations.search'); +Route::get('/conversation/undo-reply/{thread_id}', 'ConversationsController@undoReply')->name('conversations.undo'); +Route::get('/mailbox/{mailbox_id}/chats', 'ConversationsController@chats')->name('conversations.chats'); +``` + +should be replaced with: + +```php +// Conversations +Route::get('/conversation/{id}', ['uses' => 'ConversationsController@view', 'laroute' => true])->name('conversations.view'); +Route::post('/conversation/ajax', ['uses' => '\Modules\MMFRestrictedCustomers\Http\Controllers\ConversationsController@ajax', 'laroute' => true])->name('conversations.ajax'); +Route::post('/conversation/upload', ['uses' => 'ConversationsController@upload', 'laroute' => true])->name('conversations.upload'); +Route::get('/mailbox/{mailbox_id}/new-ticket', 'ConversationsController@create')->name('conversations.create'); +Route::get('/mailbox/{mailbox_id}/clone-ticket/{from_thread_id}', 'ConversationsController@cloneConversation')->name('conversations.clone_conversation'); +//Route::get('/conversation/draft/{id}', 'ConversationsController@draft')->name('conversations.draft'); +Route::get('/conversation/ajax-html/{action}', ['uses' => 'ConversationsController@ajaxHtml', 'laroute' => true])->name('conversations.ajax_html'); +Route::get('/search', 'ConversationsController@search')->name('conversations.search'); +Route::get('/conversation/undo-reply/{thread_id}', 'ConversationsController@undoReply')->name('conversations.undo'); +Route::get('/mailbox/{mailbox_id}/chats', 'ConversationsController@chats')->name('conversations.chats'); +``` + ### Edit the artisan commands Console commands set in other modules or in Freescout itself can not be automatically overridden.