Freescout Restricted Customers
Find a file
2024-07-09 14:30:30 +02:00
database/migrations Drop the unicity constraint on Customer emails 2024-07-09 14:30:30 +02:00
resources/views When editing a Customer, pre-select its current Mailbox 2024-07-08 17:52:13 +02:00
routes Fix the SPDX license identifier 2024-07-06 18:56:36 +02:00
src Add the ability to create new Customers with an already used e-mail 2024-07-09 14:00:52 +02:00
CHANGELOG 0.4.0 release 2024-07-08 17:53:43 +02:00
composer.json 0.4.0 release 2024-07-08 17:53:43 +02:00
COPYING Import a copy of the GNU Affero General Public License (AGPL) 2024-07-03 12:43:15 +02:00
README.md 0.4.0 release 2024-07-08 17:53:43 +02:00

Millions Missing France - Freescout Restricted Customers

Description

In a regular Freescout instance, all users have access to the e-mails of all customers. That can easily lead to confidentiality breaches when multiple organizations share a same Freescout instance.

This package tries to provide a solution to this problem, by linking each customer to a specific mailbox. The information related to a customer, especially their e-mail address, is only shown to users with access to the related mailbox.

Disclaimer

This is still a work in progress. Using any version prior to the (not yet released) 1.0.0 will lead to irrecuperable data loss. You have been warned.

Installation instructions

Install the package with composer

composer require "millions-missing-france/freescout-restricted-customers" "0.4.0"

Edit the application routes

This package does not seem to correctly override the routes of the main application. Overriding them has to be done manually, in the two following files.

routes/web.php

This section of the file:

// Customers
Route::get('/customers/{id}/edit', 'CustomersController@update')->name('customers.update');
Route::post('/customers/{id}/edit', 'CustomersController@updateSave');
Route::get('/customers/{id}/', 'CustomersController@conversations')->name('customers.conversations');
Route::get('/customers/ajax-search', ['uses' => 'CustomersController@ajaxSearch', 'laroute' => true])->name('customers.ajax_search');
Route::post('/customers/ajax', ['uses' => 'CustomersController@ajax', 'laroute' => true])->name('customers.ajax');

should be replaced with:

// Customers
Route::get('/customers/{id}/edit', '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CustomersController@update')->name('customers.update');
Route::post('/customers/{id}/edit', '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CustomersController@updateSave');
Route::get('/customers/{id}/', '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CustomersController@conversations')->name('customers.conversations');
Route::get('/customers/ajax-search', ['uses' => '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CustomersController@ajaxSearch', 'laroute' => true])->name('customers.ajax_search');
Route::post('/customers/ajax', ['uses' => '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CustomersController@ajax', 'laroute' => true])->name('customers.ajax');

This other section should be edited too:

// 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');

and replaced with:

// 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', '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\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');

Modules/Crm/Http/routes.php

The following list of routes:

Route::group(['middleware' => ['web', 'auth', 'roles'], 'roles' => ['user', 'admin'], 'prefix' => \Helper::getSubdirectory(), 'namespace' => 'Modules\Crm\Http\Controllers'], function()
{
    Route::get('/customers/new', 'CrmController@createCustomer')->name('crm.create_customer');
    Route::post('/customers/new', 'CrmController@createCustomerSave');
    Route::get('/crm/ajax-html/{action}/{param?}', ['uses' => 'CrmController@ajaxHtml'])->name('crm.ajax_html');
    Route::get('/customers/fields/ajax-search', ['uses' => 'CrmController@ajaxSearch', 'laroute' => true])->name('crm.ajax_search');
    Route::post('/crm/ajax', ['uses' => 'CrmController@ajax', 'laroute' => true])->name('crm.ajax');
});

Route::group(['middleware' => ['web', 'auth', 'roles'], 'roles' => ['admin'], 'prefix' => \Helper::getSubdirectory(), 'namespace' => 'Modules\Crm\Http\Controllers'], function()
{
    Route::post('/customers/export', ['uses' => 'CrmController@export'])->name('crm.export');
    Route::post('/crm/ajax-admin', ['uses' => 'CrmController@ajaxAdmin', 'laroute' => true])->name('crm.ajax_admin');
});

should be replaced with:

Route::group(['middleware' => ['web', 'auth', 'roles'], 'roles' => ['user', 'admin'], 'prefix' => \Helper::getSubdirectory(), 'namespace' => 'MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers'], function()
{
    Route::get('/customers/new', '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CrmController@createCustomer')->name('freescout-restricted-customers.create_customer');
    // The Crm module initialization will crash if no route named "crm.create_customer" is set.
    Route::get('/customers/new', '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CrmController@createCustomer')->name('crm.create_customer');
    Route::post('/customers/new', '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CrmController@createCustomerSave');
    Route::get('/crm/ajax-html/{action}/{param?}', ['uses' => '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CrmController@ajaxHtml'])->name('crm.ajax_html');
    Route::get('/customers/fields/ajax-search', ['uses' => '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CrmController@ajaxSearch', 'laroute' => true])->name('crm.ajax_search');
    Route::post('/crm/ajax', ['uses' => '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CrmController@ajax', 'laroute' => true])->name('crm.ajax');
});

Route::group(['middleware' => ['web', 'auth', 'roles'], 'roles' => ['admin'], 'prefix' => \Helper::getSubdirectory(), 'namespace' => '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers'], function()
{
    Route::post('/customers/export', ['uses' => '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CrmController@export'])->name('crm.export');
    Route::post('/crm/ajax-admin', ['uses' => '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CrmController@ajaxAdmin', 'laroute' => true])->name('crm.ajax_admin');
});

Update the database schema

php artisan migrate