Compare commits

...

5 commits

Author SHA1 Message Date
f07ecd9bdf
0.5.0 release
* Allow multiple Customers to use the same email, as long as they are linked to distinct Mailboxes.
2024-07-09 14:42:25 +02:00
c14e896371
[ReadMe] Update the routes override instructions 2024-07-09 14:40:59 +02:00
a2ee787747
Prevent the setting of an e-mail from a Customer from "stealing" it from other Customers 2024-07-09 14:38:35 +02:00
3a6de55d19
Drop the unicity constraint on Customer emails 2024-07-09 14:30:30 +02:00
9af30eef63
Add the ability to create new Customers with an already used e-mail
A same e-mail can only be used for several Customers as long as they are not linked to the same Mailbox.
2024-07-09 14:00:52 +02:00
7 changed files with 177 additions and 8 deletions

View file

@ -1,3 +1,7 @@
0.5.0
* Allow multiple Customers to use the same email, as long as they are linked to distinct Mailboxes.
0.4.0 0.4.0
* Display all Customers when using an admin account. * Display all Customers when using an admin account.

View file

@ -19,7 +19,7 @@ You have been warned.
### Install the package with composer ### Install the package with composer
``` ```
composer require "millions-missing-france/freescout-restricted-customers" "0.4.0" composer require "millions-missing-france/freescout-restricted-customers" "0.5.0"
``` ```
### Edit the application routes ### Edit the application routes
@ -110,8 +110,6 @@ should be replaced with:
Route::group(['middleware' => ['web', 'auth', 'roles'], 'roles' => ['user', 'admin'], 'prefix' => \Helper::getSubdirectory(), 'namespace' => 'MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers'], function() 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'); 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::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('/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::get('/customers/fields/ajax-search', ['uses' => '\MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers\CrmController@ajaxSearch', 'laroute' => true])->name('crm.ajax_search');
@ -125,7 +123,21 @@ Route::group(['middleware' => ['web', 'auth', 'roles'], 'roles' => ['admin'], 'p
}); });
``` ```
#### Update the database schema #### Modules/Crm/Providers/CrmServiceProvider.php
At line 173, this route call:
```php
$html = __('Customers').' <a href="#" data-trigger="modal" data-modal-title="'.__('Add Customer').'" data-modal-size="lg" data-modal-no-footer="true" data-modal-body=\'<iframe src="'.route('crm.create_customer', ['x_embed' => 1]).'" frameborder="0" class="modal-iframe"></iframe>\' class="btn btn-bordered btn-xs" style="position:relative;top:-1px;margin-left:4px;"><i class="glyphicon glyphicon-plus" title="'.__('Add Customer').'" data-toggle="tooltip"></i></a>';
```
should be replaced with:
```php
$html = __('Customers').' <a href="#" data-trigger="modal" data-modal-title="'.__('Add Customer').'" data-modal-size="lg" data-modal-no-footer="true" data-modal-body=\'<iframe src="'.route('freescout-restricted-customers.create_customer', ['x_embed' => 1]).'" frameborder="0" class="modal-iframe"></iframe>\' class="btn btn-bordered btn-xs" style="position:relative;top:-1px;margin-left:4px;"><i class="glyphicon glyphicon-plus" title="'.__('Add Customer').'" data-toggle="tooltip"></i></a>';
```
### Update the database schema
``` ```
php artisan migrate php artisan migrate

View file

@ -1,7 +1,7 @@
{ {
"name": "millions-missing-france/freescout-restricted-customers", "name": "millions-missing-france/freescout-restricted-customers",
"description": "Freescout restricted customers - Restrict access to Freescout customers to specific mailboxes", "description": "Freescout restricted customers - Restrict access to Freescout customers to specific mailboxes",
"version": "0.4.0", "version": "0.5.0",
"type": "library", "type": "library",
"license": ["AGPL-3.0-only"], "license": ["AGPL-3.0-only"],
"authors": [ "authors": [

View file

@ -0,0 +1,30 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class DropUnicityFromCustomerEmails extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up() {
Schema::table('emails', function (Blueprint $table) {
$table->dropUnique(['email']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down() {
Schema::table('emails', function (Blueprint $table) {
// TODO: Remove all duplicated e-mails.
$table->unique('email');
});
}
}

View file

@ -6,7 +6,6 @@
namespace MillionsMissingFrance\FreescoutRestrictedCustomers; namespace MillionsMissingFrance\FreescoutRestrictedCustomers;
use App\Email;
use App\CustomerChannel; use App\CustomerChannel;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
@ -105,4 +104,80 @@ class Customer extends BaseCustomer {
$this->save(); $this->save();
} }
} }
/**
* Set customer emails.
*
* @param array $emails
*/
public function syncEmails($emails) {
if (is_array($emails)) {
$deleted_emails = [];
foreach ($this->emails as $email) {
foreach ($emails as $email_address) {
if (Email::sanitizeEmail($email->email) == Email::sanitizeEmail($email_address)) {
continue 2;
}
}
$deleted_emails[] = $email;
}
$mailbox = $this->mailbox;
foreach ($emails as $email_address) {
$email_address = Email::sanitizeEmail($email_address);
if (!$email_address) {
continue;
}
$email = Email
::whereInMailbox($mailbox)
->where('email', $email_address)
->first();
$new_emails = [];
if ($email) {
// Assign email to current customer
if ($email->customer_id != $this->id) {
$email->customer()->associate($this);
$email->save();
}
} else {
$new_emails[] = new Email(['email' => $email_address]);
}
if ($new_emails) {
$this->emails()->saveMany($new_emails);
}
}
foreach ($deleted_emails as $email) {
if (Conversation::where('customer_email', $email->email)->exists()) {
// Create customers for deleted emails
// if there is a conversation with 'customer_email'.
$customer = new self();
$customer->save();
$email->customer()->associate($customer);
$email->save();
} else {
// Simply delete an email.
$email->delete();
}
}
}
}
/**
* Add new email to customer.
*/
public function addEmail($email_address, $check_if_exists = false) {
// Check if email already exists and belongs to another customer.
if ($check_if_exists) {
$mailbox = $this->mailbox;
$email = Email
::whereInMailbox($mailbox)
->where('email', $email_address)
->first();
if ($email && !empty($email->customer_id)) {
return false;
}
}
$new_email = new Email(['email' => $email_address]);
$this->emails()->save($new_email);
}
} }

46
src/Email.php Normal file
View file

@ -0,0 +1,46 @@
<?php
/*
SPDX-License-Identifier: AGPL-3.0-only
SPDX-FileCopyrightText: © 2024 Millions Missing FRANCE <info@millionsmissing.fr>
*/
namespace MillionsMissingFrance\FreescoutRestrictedCustomers;
use Illuminate\Database\Eloquent\Model;
use Watson\Rememberable\Rememberable;
use App\Email as BaseEmail;
class Email extends BaseEmail {
/**
* Check if an Email already exists for a given Mailbox.
*
* @param Mailbox $mailbox
* @param string $email
*
* @return bool
*/
public static function alreadyExistsInMailbox($mailbox, $email) {
$emails_count = self
::whereHas('customer', function($query) use($mailbox) {
$query->where('mailbox_id', '=', $mailbox->id);
})
->where('email', $email)
->count();
return ( $emails_count != 0 );
}
/**
* Return a query limited to a specific Mailbox
*
* @param Mailbox $mailbox
*
* @return QueryBuilder
*/
public static function whereInMailbox($mailbox) {
$query = self
::whereHas('customer', function($query) use($mailbox) {
$query->where('mailbox_id', '=', $mailbox->id);
});
return $query;
}
}

View file

@ -7,7 +7,6 @@
namespace MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers; namespace MillionsMissingFrance\FreescoutRestrictedCustomers\Http\Controllers;
use App\Conversation; use App\Conversation;
use App\Email;
use Modules\Crm\Entities\CustomerField; use Modules\Crm\Entities\CustomerField;
use Modules\Crm\Entities\CustomerCustomerField; use Modules\Crm\Entities\CustomerCustomerField;
use Validator; use Validator;
@ -16,6 +15,8 @@ use Illuminate\Http\Response;
use Illuminate\Routing\Controller; use Illuminate\Routing\Controller;
use Modules\Crm\Http\Controllers\CrmController as BaseCrmController; use Modules\Crm\Http\Controllers\CrmController as BaseCrmController;
use MillionsMissingFrance\FreescoutRestrictedCustomers\Customer; use MillionsMissingFrance\FreescoutRestrictedCustomers\Customer;
use MillionsMissingFrance\FreescoutRestrictedCustomers\Email;
use MillionsMissingFrance\FreescoutRestrictedCustomers\Mailbox;
class CrmController extends BaseCrmController { class CrmController extends BaseCrmController {
public function createCustomer(Request $request) { public function createCustomer(Request $request) {
@ -53,10 +54,11 @@ class CrmController extends BaseCrmController {
// Check email uniqueness. // Check email uniqueness.
$fail = false; $fail = false;
$mailbox = Mailbox::find($request->mailbox);
foreach ($request->emails as $i => $email) { foreach ($request->emails as $i => $email) {
$sanitized_email = Email::sanitizeEmail($email); $sanitized_email = Email::sanitizeEmail($email);
if ($sanitized_email) { if ($sanitized_email) {
$email_exists = Email::where('email', $sanitized_email)->first(); $email_exists = Email::alreadyExistsInMailbox($mailbox, $sanitized_email);
if ($email_exists) { if ($email_exists) {
$validator->getMessageBag()->add('emails.'.$i, __('A customer with this email already exists.')); $validator->getMessageBag()->add('emails.'.$i, __('A customer with this email already exists.'));