1
0
mirror of https://github.com/freescout-helpdesk/freescout.git synced 2025-01-31 20:11:38 +01:00

Default redirect

This commit is contained in:
FreeScout 2018-08-10 07:28:35 -07:00
parent da4120032e
commit 627e8ac480
29 changed files with 500 additions and 193 deletions

View File

@ -3,6 +3,7 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Input;
class Conversation extends Model
{
@ -543,9 +544,15 @@ class Conversation extends Model
*
* @return string
*/
public function url()
public function url($folder_id = null)
{
return route('conversations.view', ['id' => $this->id]);
$params = ['id' => $this->id];
if (!$folder_id) {
$folder_id = self::getCurrentFolder();
}
$params['folder_id'] = $folder_id;
return route('conversations.view', $params);
}
/**
@ -557,4 +564,50 @@ class Conversation extends Model
{
return self::$status_colors[$this->status];
}
/**
* Get folder ID from request or use the default one.
*/
public function getCurrentFolder($default_folder_id = null)
{
$folder_id = self::getFolderParam();
if ($folder_id) {
return $folder_id;
}
if ($this->folder_id) {
return $this->folder_id;
} else {
return $default_folder_id;
}
}
public static function getFolderParam()
{
if (!empty(request()->folder_id)) {
return request()->folder_id;
} elseif (!empty(Input::get('folder_id'))) {
return Input::get('folder_id');
}
return '';
}
/**
* Check if conversation can be in the folder.
*/
public function isInFolderAllowed($folder)
{
if (in_array($folder->type, Folder::$public_types)) {
return ($folder->id == $this->folder_id);
} elseif ($folder->type == Folder::TYPE_MINE) {
$user = auth()->user();
if ($user && $user->id == $folder->user_id && $this->user_id == $user->id) {
return true;
} else {
return false;
}
} else {
// todo: check ConversationFolder here
}
return false;
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Input;
class ConversationFolder extends Model
{
}

View File

@ -10,8 +10,10 @@ use App\Events\UserCreatedConversation;
use App\Events\UserReplied;
use App\Folder;
use App\Mailbox;
use App\MailboxUser;
use App\Thread;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Input;
use Validator;
class ConversationsController extends Controller
@ -29,18 +31,37 @@ class ConversationsController extends Controller
/**
* View conversation.
*/
public function view($id)
public function view(Request $request, $id)
{
$conversation = Conversation::findOrFail($id);
$this->authorize('view', $conversation);
$user = auth()->user();
// Detect folder
if ($conversation->user_id == auth()->user()->id) {
$folder = $conversation->mailbox->folders()->where('type', Folder::TYPE_MINE)->first();
} else {
$folder = $conversation->folder;
$folder = null;
if (Conversation::getFolderParam()) {
$folder = $conversation->mailbox->folders()->where('folders.id', Conversation::getFolderParam())->first();
// Check if conversation can be located in the passed folder_id
if (!$conversation->isInFolderAllowed($folder)) {
$request->session()->reflash();
return redirect()->away($conversation->url($conversation->folder_id));
}
}
if (!$folder) {
if ($conversation->user_id == $user->id) {
$folder = $conversation->mailbox->folders()->where('type', Folder::TYPE_MINE)->first();
} else {
$folder = $conversation->folder;
}
return redirect()->away($conversation->url($folder->id));
}
$after_send = $conversation->mailbox->getUserSettings($user->id)->after_send;
return view('conversations/view', [
'conversation' => $conversation,
'mailbox' => $conversation->mailbox,
@ -48,6 +69,7 @@ class ConversationsController extends Controller
'threads' => $conversation->threads()->orderBy('created_at', 'desc')->get(),
'folder' => $folder,
'folders' => $conversation->mailbox->getAssesibleFolders(),
'after_send' => $after_send,
]);
}
@ -64,11 +86,14 @@ class ConversationsController extends Controller
$folder = $mailbox->folders()->where('type', Folder::TYPE_DRAFTS)->first();
$after_send = $mailbox->getUserSettings(auth()->user()->id)->after_send;
return view('conversations/create', [
'conversation' => $conversation,
'mailbox' => $mailbox,
'folder' => $folder,
'folders' => $mailbox->getAssesibleFolders(),
'after_send' => $after_send,
]);
}
@ -89,89 +114,6 @@ class ConversationsController extends Controller
]);
}
/**
* Save new conversation.
*/
/*public function createSave($mailbox_id, Request $request)
{
$mailbox = Mailbox::findOrFail($mailbox_id);
$this->authorize('view', $mailbox);
$validator = Validator::make($request->all(), [
'to' => 'required|string',
'subject' => 'required|string|max:998',
'body' => 'required|string',
'cc' => 'nullable|string',
'bcc' => 'nullable|string',
]);
if ($validator->fails()) {
return redirect()->route('conversations.create', ['mailbox_id' => $mailbox_id])
->withErrors($validator)
->withInput();
}
$to_array = Conversation::sanitizeEmails($request->to);
// Check if there are any emails
if (!$to_array) {
return redirect()->route('conversations.create', ['mailbox_id' => $mailbox_id])
->withErrors(['to' => __('Incorrect recipients')])
->withInput();
}
$now = date('Y-m-d H:i:s');
$customer = Customer::create($to_array[0]);
$conversation = new Conversation();
$conversation->type = Conversation::TYPE_EMAIL;
$conversation->status = $request->status;
$conversation->state = Conversation::STATE_PUBLISHED;
$conversation->subject = $request->subject;
$conversation->setCc($request->cc);
$conversation->setBcc($request->bcc);
$conversation->setPreview($request->body);
// todo: attachments
//$conversation->has_attachments = ;
// Set folder id
$conversation->mailbox_id = $mailbox_id;
if ((int)$request->user_id != -1) {
// Check if user has access to the current mailbox
if ($mailbox->userHasAccess($request->user_id)) {
$conversation->user_id = $request->user_id;
}
}
$conversation->customer_id = $customer->id;
$conversation->created_by_user_id = auth()->user()->id;
$conversation->source_via = Conversation::PERSON_USER;
$conversation->source_type = Conversation::SOURCE_TYPE_WEB;
$conversation->user_updated_at = $now;
$conversation->last_reply_at = $now;
$conversation->last_reply_from = Conversation::PERSON_USER;
$conversation->updateFolder();
$conversation->save();
// Create thread
$thread = new Thread();
$thread->conversation_id = $conversation->id;
$thread->user_id = auth()->user()->id;
$thread->type = Thread::TYPE_MESSAGE;
$thread->status = $request->status;
$thread->state = Thread::STATE_PUBLISHED;
$thread->body = $request->body;
$thread->setTo($request->to);
$thread->setCc($request->cc);
$thread->setBcc($request->bcc);
$thread->source_via = Thread::PERSON_USER;
$thread->source_type = Thread::SOURCE_TYPE_WEB;
$thread->customer_id = $customer->id;
$thread->created_by_user_id = auth()->user()->id;
$thread->save();
return redirect()->route('conversations.view', ['id' => $conversation->id]);
}*/
/**
* Conversations ajax controller.
*/
@ -179,7 +121,7 @@ class ConversationsController extends Controller
{
$response = [
'status' => 'error',
'msg' => '',
'msg' => '', // this is error message
];
$user = auth()->user();
@ -233,10 +175,10 @@ class ConversationsController extends Controller
// Flash
$flash_message = __('Assignee updated');
if ($new_user_id != $user->id) {
$flash_message .= ' <a href="'.route('conversations.view', ['id' => $conversation->id]).'">'.__('View').'</a>';
$flash_message .= ' <a href="'.$conversation->url().'">'.__('View').'</a>';
if ($next_conversation) {
$response['redirect_url'] = route('conversations.view', ['id' => $next_conversation->id]);
$response['redirect_url'] = $next_conversation->url();
} else {
// Show conversations list
$response['redirect_url'] = route('mailboxes.view.folder', ['id' => $conversation->mailbox_id, 'folder_id' => $conversation->folder_id]);
@ -295,10 +237,10 @@ class ConversationsController extends Controller
// Flash
$flash_message = __('Status updated');
if ($new_status != Conversation::STATUS_ACTIVE) {
$flash_message .= ' <a href="'.route('conversations.view', ['id' => $conversation->id]).'">'.__('View').'</a>';
$flash_message .= ' <a href="'.$conversation->url().'">'.__('View').'</a>';
if ($next_conversation) {
$response['redirect_url'] = route('conversations.view', ['id' => $next_conversation->id]);
$response['redirect_url'] = $next_conversation->url();
} else {
// Show conversations list
$response['redirect_url'] = route('mailboxes.view.folder', ['id' => $conversation->mailbox_id, 'folder_id' => $conversation->folder_id]);
@ -446,16 +388,70 @@ class ConversationsController extends Controller
}
$response['status'] = 'success';
$response['redirect_url'] = route('conversations.view', ['id' => $conversation->id]);
$flash_message = __(
':%tag_start%Email Sent:%tag_end% :%view_start%View:%a_end% or :%undo_start%Undo:%a_end%',
['%tag_start%' => '<strong>', '%tag_end%' => '</strong>', '%view_start%' => '&nbsp;<a href="'.route('conversations.view', ['id' => $conversation->id]).'">', '%a_end%' => '</a>&nbsp;', '%undo_start%' => '&nbsp;<a href="'.route('conversations.draft', ['id' => $conversation->id]).'" class="text-danger">']
);
// Determine redirect
if (!empty($request->after_send)) {
switch ($request->after_send) {
case MailboxUser::AFTER_SEND_STAY:
default:
$response['redirect_url'] = $conversation->url();
break;
case MailboxUser::AFTER_SEND_FOLDER:
$response['redirect_url'] = route('mailboxes.view.folder', ['id' => $conversation->mailbox_id, 'folder_id' => $conversation->folder_id]);
break;
case MailboxUser::AFTER_SEND_NEXT:
$next_conversation = $conversation->getNearby();
if ($next_conversation) {
$response['redirect_url'] = $next_conversation->url();
} else {
// Show folder
$response['redirect_url'] = route('mailboxes.view.folder', ['id' => $conversation->mailbox_id, 'folder_id' => Conversation::getCurrentFolder($conversation->folder_id)]);
}
break;
}
} else {
// If something went wrong and after_send not set, just show the reply
$response['redirect_url'] = $conversation->url();
}
if (!empty($request->after_send) && $request->after_send == MailboxUser::AFTER_SEND_STAY) {
// Message without View link
$flash_message = __(
':%tag_start%Email Sent:%tag_end% :%undo_start%Undo:%a_end%',
['%tag_start%' => '<strong>', '%tag_end%' => '</strong>', '%view_start%' => '&nbsp;<a href="'.$conversation->url().'">', '%a_end%' => '</a>&nbsp;', '%undo_start%' => '&nbsp;<a href="'.route('conversations.draft', ['id' => $conversation->id]).'" class="text-danger">']
);
} else {
$flash_message = __(
':%tag_start%Email Sent:%tag_end% :%view_start%View:%a_end% or :%undo_start%Undo:%a_end%',
['%tag_start%' => '<strong>', '%tag_end%' => '</strong>', '%view_start%' => '&nbsp;<a href="'.$conversation->url().'">', '%a_end%' => '</a>&nbsp;', '%undo_start%' => '&nbsp;<a href="'.route('conversations.draft', ['id' => $conversation->id]).'" class="text-danger">']
);
}
\Session::flash('flash_success_floating', $flash_message);
}
break;
// Save default redirect
case 'save_after_send':
$mailbox = Mailbox::find($request->mailbox_id);
if (!$mailbox) {
$response['msg'] .= __('Mailbox not found');
} elseif (!$mailbox->userHasAccess($user->id)) {
$response['msg'] .= __('Action not authorized');
}
if (!$response['msg']) {
$mailbox_user = $user->mailboxes()->where('mailbox_id', $request->mailbox_id)->first();
if (!$mailbox_user) {
$mailbox_user = new MailboxUser();
$mailbox_user->mailbox_id = $mailbox->id;
$mailbox_user->user_id = $user->id;
}
$mailbox_user->settings->after_send = $request->value;
$mailbox_user->settings->save();
$response['status'] = 'success';
}
break;
default:
$response['msg'] = 'Unknown action';
break;

View File

@ -277,7 +277,8 @@ class MailboxesController extends Controller
if ($folder->type == Folder::TYPE_MINE) {
// Get conversations from personal folder
$query_conversations = Conversation::where('user_id', $user->id);
$query_conversations = Conversation::where('user_id', $user->id)
->whereIn('status', [Conversation::STATUS_ACTIVE, Conversation::STATUS_PENDING]);
} elseif ($folder->type == Folder::TYPE_ASSIGNED) {
// Assigned - do not show my conversations
$query_conversations = $folder->conversations()->where('user_id', '<>', $user->id);

View File

@ -6,6 +6,7 @@ use App\Mailbox;
use App\Subscription;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
use Validator;
@ -75,6 +76,7 @@ class UsersController extends Controller
if (!empty($request->send_invite)) {
$password = $user->generatePassword();
}
$user->password = Hash::make($user->password);
$user->save();

View File

@ -2,6 +2,7 @@
namespace App;
use App\MailboxUser;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Hash;
@ -107,7 +108,7 @@ class Mailbox extends Model
*/
public function users()
{
return $this->belongsToMany('App\User');
return $this->belongsToMany('App\User')->as('settings')->withPivot('after_send');;
}
/**
@ -131,36 +132,40 @@ class Mailbox extends Model
*
* @param mixed $users
*/
public function syncPersonalFolders($users)
public function syncPersonalFolders($users = null)
{
if (is_array($users)) {
if (!empty($users) && is_array($users)) {
$user_ids = $users;
} else {
$user_ids = $this->users()->pluck('id')->toArray();
$user_ids = $this->users()->pluck('users.id')->toArray();
}
// Add admins
$admin_user_ids = User::where('role', User::ROLE_ADMIN)->pluck('id')->toArray();
$user_ids = array_merge($user_ids, $admin_user_ids);
self::createUsersFolders($user_ids, $this->id, Folder::$personal_types);
}
/**
* Created folders of specific type for passed users.
*/
public static function createUsersFolders($user_ids, $mailbox_id, $folder_types)
{
$cur_users = Folder::select('user_id')
->where('mailbox_id', $this->id)
->where('mailbox_id', $mailbox_id)
->whereIn('user_id', $user_ids)
->groupBy('user_id')
->pluck('user_id')
->toArray();
// $new_users = Mailbox::whereDoesntHave('folders', function ($query) {
// $query->where('mailbox_id', $this->id);
// $query->whereNotIn('user_id', $user_ids);
// })->get();
foreach ($user_ids as $user_id) {
if (in_array($user_id, $cur_users)) {
continue;
}
foreach (Folder::$personal_types as $type) {
foreach ($folder_types as $type) {
$folder = new Folder();
$folder->mailbox_id = $this->id;
$folder->mailbox_id = $mailbox_id;
$folder->user_id = $user_id;
$folder->type = $type;
$folder->save();
@ -168,28 +173,30 @@ class Mailbox extends Model
}
}
public function createPublicFolders()
{
foreach (Folder::$public_types as $type) {
$folder = new Folder();
$folder->mailbox_id = $this->id;
$folder->type = $type;
$folder->save();
}
}
public function createAdminPersonalFolders()
{
$user_ids = User::where('role', User::ROLE_ADMIN)->pluck('id')->toArray();
self::createUsersFolders($user_ids, $this->id, Folder::$personal_types);
}
$cur_users = Folder::select('user_id')
->where('mailbox_id', $this->id)
->whereIn('user_id', $user_ids)
->groupBy('user_id')
->pluck('user_id')
->toArray();
foreach ($user_ids as $user_id) {
if (in_array($user_id, $cur_users)) {
continue;
}
foreach (Folder::$personal_types as $type) {
$folder = new Folder();
$folder->mailbox_id = $this->id;
$folder->user_id = $user_id;
$folder->type = $type;
$folder->save();
}
public static function createAdminPersonalFoldersAllMailboxes($user_ids = null)
{
if (empty($user_ids)) {
$user_ids = User::where('role', User::ROLE_ADMIN)->pluck('id')->toArray();
}
$mailbox_ids = Mailbox::pluck('id');
foreach ($mailbox_ids as $mailbox_id) {
self::createUsersFolders($user_ids, $mailbox_id, Folder::$personal_types);
}
}
@ -407,4 +414,21 @@ class Mailbox extends Model
{
return self::$in_protocols[$this->in_protocol];
}
/**
* Get pivot table parameters for the user.
*/
public function getUserSettings($user_id)
{
$mailbox_user = $this->users()->where('users.id', $user_id)->first();
if ($mailbox_user) {
return $mailbox_user->settings;
} else {
// Admin may have no record in mailbox_user table
// Create dummy object with default parameters
$settings = new \StdClass();
$settings->after_send = MailboxUser::AFTER_SEND_NEXT;
return $settings;
}
}
}

View File

@ -6,5 +6,11 @@ use Illuminate\Database\Eloquent\Model;
class MailboxUser extends Model
{
protected $table = 'mailbox_user';
// Action after sending a message
const AFTER_SEND_STAY = 1;
const AFTER_SEND_NEXT = 2;
const AFTER_SEND_FOLDER = 3;
protected $table = 'mailbox_user';
public $timestamps = false;
}

View File

@ -17,12 +17,8 @@ class MailboxObserver
public function created(Mailbox $mailbox)
{
// Create folders
foreach (Folder::$public_types as $type) {
$folder = new Folder();
$folder->mailbox_id = $mailbox->id;
$folder->type = $type;
$folder->save();
}
$mailbox->createPublicFolders();
$mailbox->syncPersonalFolders();
$mailbox->createAdminPersonalFolders();
}

View File

@ -2,6 +2,7 @@
namespace App\Observers;
use App\Mailbox;
use App\Subscription;
use App\User;
@ -14,7 +15,9 @@ class UserObserver
*/
public function created(User $user)
{
// We can not create user folders here, as user is not connected to mailboxes yet
// We can not create folders for regular users here, as user is not connected to mailboxes yet
// But we can create admin personal folders
Mailbox::createAdminPersonalFoldersAllMailboxes();
// Add default subscriptions
Subscription::addDefaultSubscriptions($user->id);

View File

@ -23,7 +23,7 @@ class ConversationPolicy
if ($user->isAdmin()) {
return true;
} else {
if ($conversation->mailbox()->users->contains($user)) {
if ($conversation->mailbox->users->contains($user)) {
return true;
} else {
return false;

View File

@ -33,12 +33,12 @@ class MailboxPolicy
*
* @return mixed
*/
public function view(User $user)
public function view(User $user, Mailbox $mailbox)
{
if ($user->isAdmin()) {
return true;
} else {
if ($mailbox()->users->contains($user)) {
if ($mailbox->users->contains($user)) {
return true;
} else {
return false;

View File

@ -86,7 +86,7 @@ class User extends Authenticatable
*/
public function mailboxes()
{
return $this->belongsToMany('App\Mailbox');
return $this->belongsToMany('App\Mailbox')->as('settings')->withPivot('after_send');
}
/**
@ -166,7 +166,7 @@ class User extends Authenticatable
if ($this->isAdmin()) {
return Mailbox::all();
} else {
$this->mailboxes;
return $this->mailboxes;
}
}
@ -202,10 +202,15 @@ class User extends Authenticatable
*/
public function syncPersonalFolders($mailboxes)
{
if (is_array($mailboxes)) {
$mailbox_ids = $mailboxes;
if ($this->isAdmin()) {
// For admin we get all mailboxes
$mailbox_ids = Mailbox::pluck('mailboxes.id');
} else {
$mailbox_ids = $this->mailboxes()->pluck('mailboxes.id');
if (is_array($mailboxes)) {
$mailbox_ids = $mailboxes;
} else {
$mailbox_ids = $this->mailboxes()->pluck('mailboxes.id');
}
}
$cur_mailboxes = Folder::select('mailbox_id')

View File

@ -166,7 +166,7 @@ return [
| PHP extensions required by the app
|-------------------------------------------------------------------------
*/
'required_extensions' => ['mysql / mysqli', 'mbstring', 'xml', 'imap', 'mcrypt'/*, 'openssl', 'dom', 'xmlwriter', 'tokenizer', 'json', 'libxml', 'phar'*/],
'required_extensions' => ['mysql / mysqli', 'mbstring', 'xml', 'imap', 'mcrypt', 'json', 'openssl', 'tokenizer'/*, 'dom', 'xmlwriter', 'tokenizer', 'libxml', 'phar'*/],
/*
|--------------------------------------------------------------------------

View File

@ -1,5 +1,6 @@
<?php
use App\MailboxUser;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
@ -17,6 +18,8 @@ class CreateMailboxUserTable extends Migration
$table->increments('id');
$table->integer('mailbox_id');
$table->integer('user_id');
$table->unsignedTinyInteger('after_send')->default(MailboxUser::AFTER_SEND_NEXT);
});
}

View File

@ -5960,6 +5960,7 @@ button.close {
.modal-title {
margin: 0;
line-height: 1.42857143;
font-weight: normal;
}
.modal-body {
position: relative;

26
public/css/style.css vendored
View File

@ -1406,6 +1406,7 @@ table.table-conversations td.conv-attachment {
}
.conv-new-form {
padding-top: 15px;
padding-bottom: 150px;
}
.conv-new-form .form-group {
margin-bottom: 10px;
@ -1742,6 +1743,27 @@ table.table-conversations td.conv-attachment {
font-size: 14px;
}
/**
* Modal
*/
.modal-header {
cursor: default;
}
.modal .close {
opacity: 0.7;
}
.modal-body {
min-height: 150px;
}
.modal-loader img {
position: absolute;
top: 50%;
height: 31px;
margin-top: -15px;
}
.modal-body p.help-block {
font-size: 11.4px;
}
/**
* Misc
@ -2005,8 +2027,8 @@ a.help-icon:hover {
width: 100%;
height: 100%;
z-index: 9999;
background: url('../img/loader-main.gif') 50% 50% no-repeat transparent;
opacity: 0.85;
background: url('../img/loader-main.gif') 50% 50% no-repeat #fff;
opacity: 0.55;
filter: alpha(opacity=85); /* For IE8 and earlier */
}
a.text-danger,

BIN
public/img/loader-grey.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

147
public/js/main.js vendored
View File

@ -212,7 +212,7 @@ function multiInputInit()
} );
}
function fsAjax(data, url, success_callback, error_callback, no_loader)
function fsAjax(data, url, success_callback, no_loader, error_callback)
{
// Setup AJAX
$.ajaxSetup({
@ -233,6 +233,14 @@ function fsAjax(data, url, success_callback, error_callback, no_loader)
};
}
// If this is conversation ajax request, add folder_id to the URL
if (url.indexOf('/conversation/') != -1) {
var folder_id = getQueryParam('folder_id');
if (folder_id) {
url += '?folder_id='+folder_id;
}
}
$.ajax({
url: url,
method: 'post',
@ -414,15 +422,25 @@ function newConversationInit()
convEditorInit();
// Show CC
$('.toggle-cc a:first').click(function() {
$('.field-cc').removeClass('hidden');
$(this).parent().remove();
});
$('.dropdown-after-send a').click(function() {
$('.dropdown-after-send li').removeClass('active');
$(this).parent().addClass('active');
alert('todo: implement choosing action after sending a message');
// After send
$('.dropdown-after-send a:lt(3)').click(function(e) {
if (!$(this).parent().hasClass('active')) {
$("#after_send").val($(this).attr('data-after-send'));
$('.dropdown-after-send li').removeClass('active');
$(this).parent().addClass('active');
}
e.preventDefault();
});
// After send
$('.after-send-change').click(function(e) {
showModal($(this));
});
// Send reply or new conversation
@ -473,4 +491,123 @@ function notificationsInit()
}
});
});
}
function getQueryParam(name, qs) {
if (typeof(qs) == "undefined") {
qs = document.location.search;
}
qs = qs.split('+').join(' ');
var params = {},
tokens,
re = /[?&]?([^=]+)=([^&]*)/g;
while (tokens = re.exec(qs)) {
params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
}
if (typeof(params[name]) != "undefined") {
return params[name];
} else {
return '';
}
}
// Show bootstrap modal
function showModal(a, onshow)
{
var options = {};
var title = a.attr('data-modal-title');
if (title && title.charAt(0) == '#') {
title = $(title).html();
}
if (!title) {
title = a.text();
}
var remote = a.attr('data-remote');
var body = a.attr('data-modal-body');
var footer = a.attr('data-modal-footer');
var no_close_btn = a.attr('data-no-close-btn');
var no_footer = a.attr('data-modal-no-footer');
var modal_class = a.attr('data-modal-class');
var modal;
var html = [
'<div class="modal fade" tabindex="-1" role="dialog" aria-labelledby="jsmodal-label" aria-hidden="true">',
'<div class="modal-dialog '+modal_class+'">',
'<div class="modal-content">',
'<div class="modal-header">',
'<button type="button" class="close" data-dismiss="modal" aria-label="'+Lang.get("messages.close")+'"><span aria-hidden="true">&times;</span></button>',
'<h3 class="modal-title" id="jsmodal-label">'+title+'</h3>',
'</div>',
'<div class="modal-body"><div class="text-center modal-loader"><img src="'+Vars.public_url+'/img/loader-grey.gif" width="31" height="31"/></div></div>',
'<div class="modal-footer '+(no_footer == 'true' ? 'hidden' : '')+'">',
(no_close_btn == 'true' ? '': '<button type="button" class="btn btn-default" data-dismiss="modal">'+Lang.get("messages.close")+'</button>'),
footer,
'</div>',
'</div>',
'</div>',
'</div>'].join('');
modal = $(html);
if (typeof(onshow) !== "undefined") {
modal.on('shown.bs.modal', onshow);
}
modal.modal(options);
if (body) {
modal.children().find(".modal-body").html($(body).html());
} else {
setTimeout(function(){
$.ajax({
url: remote,
success: function(html) {
modal.children().find(".modal-body").html(html);
},
error: function(data) {
modal.children().find(".modal-body").html('<p class="alert alert-danger">'+Lang.get("messages.error_occured")+'</p>');
}
});
}, 500);
}
}
// Show floating error message on ajax error
function showAjaxError(response)
{
if (typeof(response.msg) != "undefined") {
fsShowFloatingAlert('error', response.msg);
} else {
fsShowFloatingAlert('error', Lang.get("messages.error_occured"));
}
}
// Save default redirect
function saveAfterSend(el)
{
var button = $(el);
button.button('loading');
var value = $(el).parents('.modal-body:first').children().find('[name="after_send_default"]:first').val();
data = {
value: value,
mailbox_id: fsGetGlobalAttr('mailbox_id'),
action: 'save_after_send'
};
fsAjax(data, laroute.route('conversations.ajax'), function(response) {
if (typeof(response.status) != "undefined" && response.status == 'success') {
// Show selected option in the dropdown
console.log('.dropdown-after-send [data-after-send='+value+']:first');
console.log($('.dropdown-after-send [data-after-send='+value+']:first'));
$('.dropdown-after-send [data-after-send='+value+']:first').click();
fsShowFloatingAlert('success', Lang.get("messages.settings_saved"));
$('.modal').modal('hide');
} else {
showAjaxError(response);
}
button.button('reset');
}, true);
}

6
public/js/vars.js vendored
View File

@ -4,7 +4,7 @@
*/
var Vars = {
public_url: 'https://devfreescout.likebtn.com'
};
@ -16,7 +16,9 @@ var lang_messages = {
"upload_attachments": "Upload Attachments",
"saved_replies": "Saved Replies",
"save_draft": "Save Draft",
"discard": "Discard"
"discard": "Discard",
"close": "Close",
"settings_saved": "Settings saved"
} };
(function () {

View File

@ -1,3 +1,3 @@
<div class="banner">
<img alt="" title="" src="/img/banner.png"/>
<img alt="" title="" src="/img/banner.png" width="184" height="36"/>
</div>

View File

@ -4,6 +4,9 @@
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
@include('auth/banner')
<div class="panel panel-default">
<div class="panel-heading">Reset Password</div>

View File

@ -1,3 +1,5 @@
@section('body_attrs')@parent data-mailbox_id="{{ $mailbox->id }}"@endsection
<div id="editor_bottom_toolbar" style="display:none">
{{ __('Status') }}:
<select name="status" class="form-control" data-parsley-exclude="true">
@ -6,29 +8,63 @@
<option value="{{ App\Mailbox::TICKET_STATUS_CLOSED }}" @if (old('status', $mailbox->ticket_status) == App\Mailbox::TICKET_STATUS_CLOSED)selected="selected"@endif>{{ __('Closed') }}</option>
</select>
<small class="glyphicon glyphicon-chevron-right note-bottom-div"></small>
{{ __('Asisgn to') }}:
{{ __('Assign to') }}:
<select name="user_id" class="form-control" data-parsley-exclude="true">
<option value="-1" @if ((int)old('user_id') == -1 || (!old('user_id') && $mailbox->ticket_assignee == App\Mailbox::TICKET_ASSIGNEE_ANYONE))selected="selected"@endif>{{ __('Anyone') }}</option>
<option value="{{ Auth::user()->id }}" @if (old('user_id') == Auth::user()->id || (!old('user_id') && (!$conversation->user_id && $mailbox->ticket_assignee == App\Mailbox::TICKET_ASSIGNEE_REPLYING_UNASSIGNED) || $mailbox->ticket_assignee == App\Mailbox::TICKET_ASSIGNEE_REPLYING))selected="selected"@endif>{{ __('Me') }}</option>
<option value="-1" @if ($mailbox->ticket_assignee == App\Mailbox::TICKET_ASSIGNEE_ANYONE))selected="selected"@endif>{{ __('Anyone') }}</option>
<option value="{{ Auth::user()->id }}" @if (((!$conversation->user_id || $conversation->user_id == Auth::user()->id) && $mailbox->ticket_assignee == App\Mailbox::TICKET_ASSIGNEE_REPLYING_UNASSIGNED) || $mailbox->ticket_assignee == App\Mailbox::TICKET_ASSIGNEE_REPLYING)selected="selected"@endif>{{ __('Me') }}</option>
@foreach ($mailbox->usersHavingAccess() as $user)
@if ($user->id != Auth::user()->id)
<option value="{{ $user->id }}" @if (old('user_id') == $user->id)selected="selected"@endif>{{ $user->getFullName() }}</option>
<option value="{{ $user->id }}" @if ($conversation->user_id == $user->id && $mailbox->ticket_assignee == App\Mailbox::TICKET_ASSIGNEE_REPLYING_UNASSIGNED)selected="selected"@endif>{{ $user->getFullName() }}</option>
@endif
@endforeach
</select>
<input type="hidden" name="after_send" id="after_send" value="{{ $after_send }}"/>
<div class="btn-group btn-group-send">
<button class="hidden"></button>
<button type="button" class="btn btn-primary btn-send-text" data-loading-text="{{ __('Sending…') }}">{{ __('Send') }}</button>
<button type="button" class="btn btn-primary btn-send-menu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><small class="glyphicon glyphicon-chevron-down"></small></button>
<ul class="dropdown-menu dropdown-menu-right dropdown-after-send">
<li @if (0) class="active" @endif><a href="javascript:void(0)" class="after-send-stay">{{ __('Send and stay on page') }}</a></li>
<li @if (0) class="active" @endif><a href="#" class="after-send-folder">{{ __('Send and back to folder') }}</a></li>
<li @if (0) class="active" @endif><a href="#" class="after-send-next">{{ __('Send and next active') }}</a></li>
<li @if ($after_send == App\MailboxUser::AFTER_SEND_STAY) class="active" @endif><a href="javascript:void(0)" data-after-send="{{ App\MailboxUser::AFTER_SEND_STAY }}">{{ __('Send and stay on page') }}</a></li>
<li @if ($after_send == App\MailboxUser::AFTER_SEND_NEXT) class="active" @endif><a href="#" data-after-send="{{ App\MailboxUser::AFTER_SEND_NEXT }}">{{ __('Send and next active') }}</a></li>
<li @if ($after_send == App\MailboxUser::AFTER_SEND_FOLDER) class="active" @endif><a href="#" data-after-send="{{ App\MailboxUser::AFTER_SEND_FOLDER }}">{{ __('Send and back to folder') }}</a></li>
@if (empty($is_reply))
<li class="divider"></li>
<li @if (0) class="active" @endif><a href="#" class="after-send-change">{{ __('Change default redirect') }}</a></li>
<li><a href="#" class="after-send-change" data-modal-body="#after-send-change-body" data-modal-title="{{ __('Default Redirect') }}" data-no-close-btn="true" data-modal-no-footer="true">{{ __('Change default redirect') }}</a></li>
@endif
</ul>
</div>
<div id="after-send-change-body" class="hidden">
<div class="row-container">
<div class="row">
<div class="form-horizontal">
<div class="form-group{{ $errors->has('after_send') ? ' has-error' : '' }}">
<label for="after_send" class="col-sm-3 control-label">{{ __('After Sending') }}</label>
<div class="col-sm-9">
<select class="form-control input-sized" name="after_send_default" required autofocus>
<option value="{{ App\MailboxUser::AFTER_SEND_STAY }}" @if ($after_send == App\MailboxUser::AFTER_SEND_STAY)selected="selected"@endif>{{ __('Stay on the same page') }}</option>
<option value="{{ App\MailboxUser::AFTER_SEND_NEXT }}" @if ($after_send == App\MailboxUser::AFTER_SEND_NEXT)selected="selected"@endif>{{ __('Next active conversation') }}</option>
<option value="{{ App\MailboxUser::AFTER_SEND_FOLDER }}" @if ($after_send == App\MailboxUser::AFTER_SEND_FOLDER)selected="selected"@endif>{{ __('Back to folder') }}</option>
</select>
<p class="help-block">
{{ __('This setting gives you control over what page loads after you perform an action (send a reply, add a note, etc.).') }}
</p>
</div>
</div>
<div class="form-group">
<div class="col-sm-9 col-sm-offset-3">
<button type="submit" class="btn btn-primary" data-loading-text="{{ __('Saving…') }}" onclick="saveAfterSend(this)">
{{ __('Save') }}
</button>
<a href="#" class="btn btn-link" data-dismiss="modal">{{ __('Cancel') }}</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -9,7 +9,7 @@
*/
{{-- Global vars for JS. Set in /app/Console/Commands/GenerateJs.php --}}
var Vars = {
public_url: '{{ url('/') }}'
};
{{--
@ -27,7 +27,9 @@ var lang_messages = {
"upload_attachments": "{{ __("Upload Attachments") }}",
"saved_replies": "{{ __("Saved Replies") }}",
"save_draft": "{{ __("Save Draft") }}",
"discard": "{{ __("Discard") }}"
"discard": "{{ __("Discard") }}",
"close": "{{ __("Close") }}",
"settings_saved": "{{ __("Settings saved") }}"
}@if (!$loop->last),@endif
@endforeach
};

View File

@ -17,7 +17,7 @@
<body class="@if (Auth::user() && Auth::user()->isAdmin()) user-is-admin @endif @yield('body_class')" @yield('body_attrs')>
<div id="app">
@if (!in_array(Route::currentRouteName(), array('login', 'register')))
@if (Auth::user())
<nav class="navbar navbar-default navbar-static-top">
<div class="container">
@ -68,21 +68,21 @@
<li><a href="#">{{ __('New Site...') }} (todo)</a></li>
</ul>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true" v-pre>
{{ __('Reports') }} <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="#">{{ __('Conversations') }} (todo)</a></li>
<li><a href="#">{{ __('Productivity') }} (todo)</a></li>
<li><a href="#">{{ __('Team') }} (todo)</a></li>
<li><a href="#">{{ __('Happiness') }} (todo)</a></li>
<li><a href="#">{{ __('Docs') }} (todo)</a></li>
</ul>
</li>
@endif
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true" v-pre>
{{ __('Reports') }} <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="#">{{ __('Conversations') }} (todo)</a></li>
<li><a href="#">{{ __('Productivity') }} (todo)</a></li>
<li><a href="#">{{ __('Team') }} (todo)</a></li>
<li><a href="#">{{ __('Happiness') }} (todo)</a></li>
<li><a href="#">{{ __('Docs') }} (todo)</a></li>
</ul>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true" v-pre>
{{ __('Manage') }} <span class="caret"></span>

View File

@ -5,7 +5,7 @@
<ul class="sidebar-menu">
@foreach ($folders as $folder_item)
@if (
($folder_item->type != App\Folder::TYPE_DELETED || ($folder_item->type == App\Folder::TYPE_DELETED && $folder_item->total_count)) && ($folder_item->type != App\Folder::TYPE_DRAFTS || ($folder_item->type == App\Folder::TYPE_DRAFTS && $folder_item->total_count))
($folder_item->type != App\Folder::TYPE_DELETED || ($folder_item->type == App\Folder::TYPE_DELETED && $folder_item->total_count)) && ($folder_item->type != App\Folder::TYPE_DRAFTS || ($folder_item->type == App\Folder::TYPE_DRAFTS && $folder_item->total_count)) && (/*todo: starred*/$folder_item->type != App\Folder::TYPE_STARRED)
)
<li class="@if ($folder_item->id == $folder->id) active @endif">
<a href="{{ route('mailboxes.view.folder', ['id'=>$mailbox->id, 'folder_id'=>$folder_item->id]) }}" @if (!$folder_item->active_count) class="no-active" @endif><i class="glyphicon glyphicon-{{ $folder_item->getTypeIcon() }}"></i> {{ $folder_item->getTypeName() }}

View File

@ -74,7 +74,7 @@
<input type="checkbox" id="cb-{{ $conversation->id }}" name="cb_{{ $conversation->id }}" value="{{ $conversation->id }}">
</td>
<td class="conv-customer">
<a href="{{ route('conversations.view', ['id' => $conversation->id]) }}">
<a href="{{ $conversation->url() }}">
{{ $conversation->customer->getFullName(true)}}
</a>
</td>
@ -86,25 +86,25 @@
@endif
</td>
<td class="conv-subject">
<a href="{{ route('conversations.view', ['id' => $conversation->id]) }}" title="{{ __('View conversation') }}">
<a href="{{ $conversation->url() }}" title="{{ __('View conversation') }}">
<span class="conv-fader"></span>
<p><span class="conv-subject-number">#{{ $conversation->number }} </span>{{ $conversation->subject }}</p>
<p class="conv-preview">{{ $conversation->preview }}</p>
</a>
</td>
<td class="conv-thread-count">
<a href="{{ route('conversations.view', ['id' => $conversation->id]) }}" title="{{ __('View conversation') }}">@if ($conversation->threads_count <= 1)&nbsp;@else<span>{{ $conversation->threads_count }}</span>@endif</a>
<a href="{{ $conversation->url() }}" title="{{ __('View conversation') }}">@if ($conversation->threads_count <= 1)&nbsp;@else<span>{{ $conversation->threads_count }}</span>@endif</a>
</td>
@if ($folder->type == App\Folder::TYPE_ASSIGNED || $folder->type == App\Folder::TYPE_CLOSED)
<td class="conv-owner">
@if ($conversation->user)<a href="{{ route('conversations.view', ['id' => $conversation->id]) }}" title="{{ __('View conversation') }}"> {{ $conversation->user->getFullName() }} </a>@else &nbsp;@endif
@if ($conversation->user)<a href="{{ $conversation->url() }}" title="{{ __('View conversation') }}"> {{ $conversation->user->getFullName() }} </a>@else &nbsp;@endif
</td>
@endif
<td class="conv-number">
<a href="{{ route('conversations.view', ['id' => $conversation->id]) }}" title="{{ __('View conversation') }}">{{ $conversation->number }}</a>
<a href="{{ $conversation->url() }}" title="{{ __('View conversation') }}">{{ $conversation->number }}</a>
</td>
<td class="conv-date">
<a href="{{ route('conversations.view', ['id' => $conversation->id]) }}" @if (!in_array($conversation->type, [App\Folder::TYPE_CLOSED, App\Folder::TYPE_DRAFTS, App\Folder::TYPE_DELETED])) data-toggle="tooltip" data-html="true" data-placement="left" title="{{ $conversation->getDateTitle() }}"@else title="{{ __('View conversation') }}" @endif >
<a href="{{ $conversation->url() }}" @if (!in_array($conversation->type, [App\Folder::TYPE_CLOSED, App\Folder::TYPE_DRAFTS, App\Folder::TYPE_DELETED])) data-toggle="tooltip" data-html="true" data-placement="left" title="{{ $conversation->getDateTitle() }}"@else title="{{ __('View conversation') }}" @endif >
@if ($folder->type == App\Folder::TYPE_CLOSED)
{{ App\User::dateDiffForHumans($conversation->closed_at) }}
@elseif ($folder->type == App\Folder::TYPE_DRAFTS)

View File

@ -12,8 +12,9 @@
</div>
<ul class="sidebar-menu">
<li @if (Route::currentRouteName() == 'users.profile')class="active"@endif><a href="{{ route('users.profile', ['id'=>$user->id]) }}"><i class="glyphicon glyphicon-user"></i> {{ __('Profile') }}</a></li>
<li @if (Route::currentRouteName() == 'user_permissions')class="active"@endif><a href="{{ route('users.permissions', ['id'=>$user->id]) }}"><i class="glyphicon glyphicon-ok"></i> {{ __('Permissions') }}</a></li>
<li @if (Route::currentRouteName() == 'user_notifications')class="active"@endif><a href="{{ route('users.notifications', ['id'=>$user->id]) }}"><i class="glyphicon glyphicon-bell"></i> {{ __('Notifications') }}</a></li>
<li @if (Route::currentRouteName() == 'users.permissions')class="active"@endif><a href="{{ route('users.permissions', ['id'=>$user->id]) }}"><i class="glyphicon glyphicon-ok"></i> {{ __('Permissions') }}</a></li>
<li @if (Route::currentRouteName() == 'users.notifications')class="active"@endif><a href="{{ route('users.notifications', ['id'=>$user->id]) }}"><i class="glyphicon glyphicon-bell"></i> {{ __('Notifications') }}</a></li>
<li @if (Route::currentRouteName() == 'user_autobcc')class="active"@endif><a href="#"><i class="glyphicon glyphicon-duplicate"></i> {{ __('Auto Bcc') }} (todo)</a></li>
<li @if (Route::currentRouteName() == 'user_myapps')class="active"@endif><a href="#"><i class="glyphicon glyphicon-gift"></i> {{ __('My Apps') }} (todo)</a></li>
</ul>
</ul>
<a href="{{ route('users.create') }}" class="btn btn-default btn-sidebar">{{ __("New User") }}</a>

View File

@ -9,7 +9,7 @@
<span class="heading">{{ __('Users') }}</span>
</div>
<div class="flexy-item margin-left">
<a href="/users/wizard/" class="btn btn-primary">{{ __('New User') }}</a>
<a href="{{ route('users.create') }}" class="btn btn-primary">{{ __('New User') }}</a>
</div>
<div class="flexy-block"></div>
</div>

View File

@ -15,6 +15,9 @@
Auth::routes();
// Redirects
Route::redirect('/home', '/', 301);
// Public routes
// General routes for logged in users