183 lines
6.3 KiB
PHP
183 lines
6.3 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Auth;
|
||
|
|
|
||
|
|
use App\Models\Customer;
|
||
|
|
use Illuminate\Auth\EloquentUserProvider;
|
||
|
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||
|
|
use Illuminate\Contracts\Auth\UserProvider;
|
||
|
|
use Illuminate\Support\Facades\Log;
|
||
|
|
use Illuminate\Support\Facades\Session;
|
||
|
|
use Illuminate\Support\Str;
|
||
|
|
use LDC\LDCCRM\Enums\ApiError;
|
||
|
|
use LDC\LDCCRM\Exceptions\ApiErrorException;
|
||
|
|
use LDC\LDCCRM\Exceptions\CrmException;
|
||
|
|
use LDC\LDCCRM\Models\Customer as CrmCustomer;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Crm user provider to integrate nicely with Laravel
|
||
|
|
*/
|
||
|
|
class CrmUserProvider extends EloquentUserProvider implements UserProvider
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* The model to use, specified in auth config guard.
|
||
|
|
*
|
||
|
|
* @var string
|
||
|
|
*/
|
||
|
|
private $usedModel = Customer::class;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Retrieve a user by the given credentials.
|
||
|
|
*
|
||
|
|
* @param array $credentials
|
||
|
|
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||
|
|
*/
|
||
|
|
public function retrieveByCredentials(array $credentials): \Illuminate\Contracts\Auth\Authenticatable|null
|
||
|
|
{
|
||
|
|
// * Let laravel find a model
|
||
|
|
$model = parent::retrieveByCredentials($credentials) ?? self::retrieveTrashed($credentials);
|
||
|
|
|
||
|
|
try {
|
||
|
|
/** @var \LDC\LDCCRM\CrmApiV4 */
|
||
|
|
$crm = app('crmAPI');
|
||
|
|
|
||
|
|
// Si pas de compte local.
|
||
|
|
if (!$model) {
|
||
|
|
$crmCustomer = $crm->getCustomer($credentials['email']);
|
||
|
|
|
||
|
|
if (!$crmCustomer) {
|
||
|
|
// * Customer is not found on CRM.
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
$model = $this->createLocalCustomer($crmCustomer);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $model;
|
||
|
|
} catch (ApiErrorException $e) {
|
||
|
|
// * Customer is not found.
|
||
|
|
if ($e->getApiError()->equals(ApiError::modelNotFound)) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
report($e);
|
||
|
|
Log::error('Unhandled response ' . $e->getApiError()->label());
|
||
|
|
} catch (CrmException | \Exception $e) {
|
||
|
|
report($e);
|
||
|
|
// Une erreur critique est survenue avec la CRM.
|
||
|
|
return null;
|
||
|
|
} //end try
|
||
|
|
Log::error(__CLASS__ . '::retrieveByCredentials reached end of possibilities.');
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Validate a user against the given credentials.
|
||
|
|
*
|
||
|
|
* @param \Illuminate\Contracts\Auth\Authenticatable $model
|
||
|
|
* @param array $credentials
|
||
|
|
* @return boolean
|
||
|
|
* @throws \RuntimeException If model provided is not a Customer or connection to server fails.
|
||
|
|
* @throws \LDC\LDCCRM\Exceptions\CrmException On CRM call error.
|
||
|
|
* @throws \Exception On CRM call error.
|
||
|
|
*/
|
||
|
|
public function validateCredentials(Authenticatable $model, array $credentials): bool
|
||
|
|
{
|
||
|
|
/** @var \Illuminate\Database\Eloquent\Model $model */
|
||
|
|
if (\get_class($model) !== $this->usedModel) {
|
||
|
|
throw new \RuntimeException('Cannot authenticate any thing else than ' . $this->usedModel);
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
/** @var \LDC\LDCCRM\CrmApiV4 */
|
||
|
|
$crm = app('crmAPI');
|
||
|
|
|
||
|
|
// * If has trait soft delete and customer trashed, then restore customer.
|
||
|
|
if (
|
||
|
|
\in_array(\Illuminate\Database\Eloquent\SoftDeletes::class, \class_uses_recursive($model)) and
|
||
|
|
// @phpstan-ignore-next-line
|
||
|
|
$model->trashed()
|
||
|
|
) {
|
||
|
|
// @phpstan-ignore-next-line
|
||
|
|
$model->restore();
|
||
|
|
}
|
||
|
|
|
||
|
|
// * Ne devrait pas survenir, $crm->login throws ApiError::authFailed
|
||
|
|
return $crm->login($credentials['email'], $credentials['password']);
|
||
|
|
} catch (ApiErrorException $e) {
|
||
|
|
// @phpstan-ignore-next-line
|
||
|
|
if (!$model->hashcode or !CrmCustomer::find($model->hashcode)) {
|
||
|
|
$model->forceDelete();
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if ($e->getApiError()->equals(ApiError::authFailed)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
// ! Assert Authenticable model must be valided (MustValidate trait).
|
||
|
|
if ($e->getApiError()->equals(ApiError::customerNotActivated)) {
|
||
|
|
Session::flash('warning', \trans('Vous devez activer votre compte'));
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
} catch (CrmException | \Exception $e) {
|
||
|
|
report($e);
|
||
|
|
if (config('app.debug')) {
|
||
|
|
throw $e;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
} //end try
|
||
|
|
|
||
|
|
Log::error(__CLASS__ . '::validateCredentials reached end of possibilities.');
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create a local customer
|
||
|
|
*
|
||
|
|
* @param \LDC\LDCCRM\Models\Customer $crmCustomer
|
||
|
|
* @return \Illuminate\Database\Eloquent\Model
|
||
|
|
* @throws \Throwable If saving to DB failed.
|
||
|
|
*/
|
||
|
|
private function createLocalCustomer(\LDC\LDCCRM\Models\Customer $crmCustomer): \Illuminate\Database\Eloquent\Model
|
||
|
|
{
|
||
|
|
/** @var \Illuminate\Database\Eloquent\Model $model */
|
||
|
|
$model = $this->usedModel::firstOrNew([
|
||
|
|
'email' => $crmCustomer->email
|
||
|
|
]);
|
||
|
|
// @phpstan-ignore-next-line
|
||
|
|
$model->hashcode = $crmCustomer->hashcode;
|
||
|
|
// @phpstan-ignore-next-line
|
||
|
|
$model->email_verified_at = $crmCustomer->status ? now() : null;
|
||
|
|
$model->saveOrFail();
|
||
|
|
|
||
|
|
return $model;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Retrieve a trashed customer by the given credentials.
|
||
|
|
*
|
||
|
|
* @param array $credentials
|
||
|
|
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||
|
|
* @throws \ErrorException If cannot connect to LDAP.
|
||
|
|
*/
|
||
|
|
private function retrieveTrashed(array $credentials): ?\Illuminate\Contracts\Auth\Authenticatable
|
||
|
|
{
|
||
|
|
// * Make changes
|
||
|
|
if (empty($credentials)) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
// First we will add each credential element to the query as a where clause.
|
||
|
|
// Then we can execute the query and, if we found a customer, return it in a
|
||
|
|
// Eloquent User "model" that will be utilized by the Guard instances.
|
||
|
|
$query = $this->createModel()->newQuery();
|
||
|
|
|
||
|
|
foreach ($credentials as $key => $value) {
|
||
|
|
if (!Str::contains($key, 'password')) {
|
||
|
|
$query->where($key, $value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// @phpstan-ignore-next-line
|
||
|
|
return $query->withTrashed()->first();
|
||
|
|
}
|
||
|
|
}
|