ldc-legaulois/app/Http/Controllers/AuthController.php
2022-03-10 13:31:10 +00:00

506 lines
19 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Http\Requests\CustomerRegisterRequest;
use App\Http\Requests\CustomerUpdatePassword;
use App\Http\Requests\LoginRequest;
use App\Http\Requests\ResetCustomerPassword;
use App\Http\Requests\UpdateInfosRequest;
use App\Lib\Utils;
use App\Mail\PasswordResetMail;
use App\Mail\RegisterConfirmMail;
use App\Models\Customers;
use App\Models\PasswordReset;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use LDC\LDCCRM\Enums\ApiError;
use LDC\LDCCRM\Exceptions\ApiErrorException;
use LDC\LDCCRM\Exceptions\CrmException;
use LDC\LDCCRM\Exceptions\ValidationException;
use LDC\LDCCRM\Models\Customer as CrmCustomer;
class AuthController extends Controller
{
/**
* Affiche le formulaire utilise view share vars
*/
public function register()
{
return view('front.auth.register');
}
/**
* Enregistre le customer dans la base de données
*/
public function registerSubmit(CustomerRegisterRequest $request)
{
$crmCustomer = null;
try {
$crmCustomer = new CrmCustomer(\array_intersect_key(
$request->all(),
[
'firstname' => '',
'lastname' => '',
'birth_date' => '',
'address' => '',
'postcode' => '',
'country' => '',
'city' => '',
'phone' => '',
'email' => '',
'password' => '',
'opt_in' => '',
]
));
$crmCustomer->password = $request->password;
$crmCustomer->save();
$customer = new Customers($request->all());
$customer->hashcode = $crmCustomer->hashcode;
$customer->save();
Mail::to($request->email)
->send(new RegisterConfirmMail($customer, $crmCustomer->firstname));
return view('front.auth.confirm-register');
} catch (ApiErrorException $e) {
if ($e->getApiError()->equals(ApiError::customerExists())) {
return back()->withErrors('Un compte est déjà associé à cette adresse email.');
}
if ($e->getApiError()->equals(ApiError::validationFailed())) {
return back()->withErrors($e->getMessage());
}
Utils::sendEmailErrorManually($e);
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} catch (ValidationException $e) {
return back()->withErrors($e->getMessage());
} catch (\Exception | \TypeError | CrmException $e) {
Utils::sendEmailErrorManually($e);
// Une erreur critique est survenue avec la CRM
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} //end try
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
}
/**
* Active le compte d'un customer
*/
public function activate(string $hashcode)
{
$hashcode = filter_var($hashcode, FILTER_SANITIZE_STRING);
if (!($customer = Customers::select('hashcode')->where('hashcode', $hashcode)->first())) {
return view('front.auth.activate')->with('message', "Ce lien d'activation n'est pas valide.");
}
try {
/** @var \LDC\LDCCRM\Models\Customer */
$crmCustomer = $customer->apiData;
if ($crmCustomer->activate()) {
return view('front.auth.activate')
->with('message', 'Votre compte a bien été activé, vous pouvez désormais vous connecter.');
}
} catch (ApiErrorException $e) {
if ($e->getApiError()->equals(ApiError::customerAlreadyActive())) {
return view('front.auth.activate')
->with('message', 'Votre compte est déjà activé, vous pouvez dès à présent vous connecter avec celui-ci.');
}
Utils::sendEmailErrorManually($e);
// Une erreur critique est survenue avec la CRM
return view('front.auth.activate')
->with('message', 'Une erreur est survenue, merci de réessayer ultérieurement.');
} catch (CrmException $e) {
Utils::sendEmailErrorManually($e);
// Une erreur critique est survenue avec la CRM
return view('front.auth.activate')
->with('message', 'Une erreur est survenue, merci de réessayer ultérieurement.');
} //end try
return view('front.auth.activate')->with('message', "Ce lien d'activation n'est pas valide.");
}
/**
* Retourne la page de connexion
*/
public function authenticate(Request $request)
{
if ($request->get('url')) {
Session::put('url.intended', $request->get('url'));
Session::save();
}
return view('front.auth.login');
}
/**
* Gère l'authentification des customers
*/
public function authenticateSubmit(LoginRequest $request)
{
/** @var Customers|null */
$customer = Customers::where('email', $request->email)->first();
try {
/** @var \LDC\LDCCRM\CrmApiV2 */
$crm = app('crmAPI');
// If login debug mode
if (config('app.debug') && config('crm.NOCRM')) {
$loginIsValid = true;
} else {
$loginIsValid = $crm->login($request->email, $request->password);
}
// ne devrait pas survenir, $crm->login throws ApiError::authFailed()
if (!$loginIsValid) {
// mauvais identifiants
return back()->withErrors("Email ou mot de passe incorrect.");
}
// Dans tout les cas : récupérer le crm user pour vérifier si il doit être complété
$crmCustomer = $crm->getCustomer($request->email);
// Test is user data valid ?
try {
// On va tester de mettre a jour uniquement les champs
// requis pour mes br afin de detecter si ils doivent etre mis à jour
// la validation va se faire par la crm (ou le client)
$crmCustomer->fill([
'birth_date' => $crmCustomer->birth_date,
'address' => $crmCustomer->address,
'postcode' => $crmCustomer->postcode,
'country' => $crmCustomer->country,
'city' => $crmCustomer->city
]);
// On valide les données selon les critères du site LG
$rules = collect((new UpdateInfosRequest())->rules());
$validator = Validator::make(
[
'birth_date' => $crmCustomer->birth_date,
'address' => $crmCustomer->address,
'postcode' => $crmCustomer->postcode,
'country' => $crmCustomer->country->value,
'city' => $crmCustomer->city
],
[
'birth_date' => $rules->get('birth_date'),
'address' => $rules->get('address'),
'postcode' => $rules->get('postcode'),
'country' => $rules->get('country'),
'city' => $rules->get('city')
]
);
if ($validator->fails()) {
throw new ValidationException();
} else {
Session::remove('needCrmInfoUpdate', true);
}
} catch (ValidationException $e) {
Session::push('needCrmInfoUpdate', true);
} catch (ApiErrorException $e) {
if (!$e->getApiError()->equals(ApiError::validationFailed())) {
throw $e;
}
Session::push('needCrmInfoUpdate', true);
} //end try
// Si pas de compte local mais existe en CRM
if (!$customer) {
$customer = $this->createLocalCustomer($crmCustomer);
}
return $this->processLogin($customer, $request->remember);
} catch (ApiErrorException $e) {
return $this->handleLoginApiErrorException($e, $request);
} catch (CrmException | \Exception $e) {
Utils::sendEmailErrorManually($e);
// Une erreur critique est survenue avec la CRM
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} //end try
}
/**
* Handle Api error exception
*
* @param ApiErrorException $e
* @param LoginRequest $request
* @return void
*/
private function handleLoginApiErrorException(ApiErrorException $e, LoginRequest $request)
{
/** @var Customers|null */
$customer = Customers::where('email', $request->email)->first();
/** @var \LDC\LDCCRM\CrmApiV2 */
$crm = app('crmAPI');
switch ($e->getApiError()) {
case ApiError::authFailed():
// mauvais identifiants
return back()->withErrors("Email ou mot de passe incorrect.");
case ApiError::customerNotActivated():
// le compte n'est pas activé
if (!$customer) {
try {
if (!($crmCustomer = $crm->getCustomer($request->email))) {
Log::critical(sprintf('Customer %s coulnd not be retrieved from crm', $request->email));
return back()->withErrors(
__('Une erreur est survenue, merci de réessayer ultérieurement.')
);
}
$customer = $this->createLocalCustomer($crmCustomer);
} catch (CrmException | ApiErrorException $e) {
Utils::sendEmailErrorManually($e);
// Une erreur critique est survenue avec la CRM
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
}
}
Mail::to($request->email)->send(new RegisterConfirmMail($customer));
return back()
->withErrors(
__('Votre compte n\'est pas activé, vérifiez dans vos emails pour y trouver
le mail de confirmation. Un lien d\'activation vous a été renvoyé.')
);
default:
Utils::sendEmailErrorManually($e);
// une erreur non gérée
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} //end switch
}
/**
* Create a local customer
*
* @param \LDC\LDCCRM\Models\Customer $customer
* @return \app\Models\Customers
*/
private function createLocalCustomer(CrmCustomer $crmCustomer): Customers
{
$pseudo = Utils::getUniquePseudo(
$crmCustomer->firstname,
$crmCustomer->lastname
);
$customer = Customers::firstOrNew([
'email' => $crmCustomer->email
]);
$customer->hashcode = $crmCustomer->hashcode;
$customer->username = $pseudo;
$customer->saveOrFail();
return $customer;
}
/**
* Login a customer
*
* @param Customers $customer
* @param boolean $remember
* @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
*/
private function processLogin(Customers $customer, bool $remember)
{
/** @var \Illuminate\Auth\SessionGuard */
$guard = auth('customer');
$guard->login($customer, $remember);
$url = Session::pull('url.intended');
Session::forget('url.intended');
Session::save();
return $url ? redirect()->to($url) : redirect()->to(Session::pull('previousurl'));
}
/**
* Deconnexion
*
* @return void
*/
public function logout()
{
/** @var \Illuminate\Auth\SessionGuard */
$guard = auth('customer');
if ($guard->check()) {
$guard->logout();
return redirect()->route('home');
}
}
/**
* Fomulaire reset mot de passe
* sur la page login
*
* @param Request $request
* @return void
*/
public function passwordReset(Request $request)
{
$request->validate([
'email' => 'required|email:rfc,filter|max:255',
]);
if (Customers::where('email', $request->email)->exists()) {
return $this->sendResetPasswordLink($request->email);
}
// Le customer n'existe pas en Local, donc il faut le créer d'abord
/** @var \LDC\LDCCRM\CrmApiV2 */
$crm = app('crmAPI');
try {
if (!($crmCustomer = $crm->getCustomer($request->email))) {
return back()->withErrors(__('Cette adresse email n\'est pas enregistrée dans nos services.'));
}
// TODO remove this test
if (!$crmCustomer->hashcode) {
Utils::sendEmailErrorManually(new \Exception(sprintf(
'Reset pwd user hascode was null for %s,%s,%s,%s',
$crmCustomer->hashcode,
$crmCustomer->email,
$crmCustomer->city,
$crmCustomer->lastname
)));
}
$customer = $this->createLocalCustomer($crmCustomer);
return $this->sendResetPasswordLink($customer->email);
} catch (CrmException | ApiErrorException $e) {
Utils::sendEmailErrorManually($e);
// Une erreur critique est survenue avec la CRM
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} //end try
}
/**
* Send password reset email
*
* @param [type] $email
* @return void
*/
private function sendResetPasswordLink(string $email): RedirectResponse
{
// Suppression des anciens tokens
PasswordReset::where('email', $email)->delete();
$token = Str::random(80);
$passwordReset = new PasswordReset();
$passwordReset->email = $email;
$passwordReset->token = $token;
$passwordReset->created_at = now();
$passwordReset->save();
Mail::to($email)->send(new PasswordResetMail($token));
return back()->with(
'success',
__("La procédure pour changer votre mot de passe a été envoyé sur votre email.")
);
}
/**
* Print the view used to change the password of a user when he required it
* @param $token Token used to identificate the user to change the password of
* @return View The view to print
*/
public function viewChangePassword($token)
{
$pwdReset = PasswordReset::where('token', $token)->first();
if (!$pwdReset) {
abort(419);
}
$customer = Customers::where('email', $pwdReset->email)->first();
if (!$customer) {
abort(404);
}
return view('front.auth.password-reset', compact('customer'))->with('token', $token);
}
/**
* Modification du mot de passe par lien via le formulaire
* reset mot de passe
*
* @param ResetCustomerPassword $request
* @param string $token
* @return void
*/
public function changePassword(ResetCustomerPassword $request, string $token)
{
$passwordReset = PasswordReset::where('token', $token)->first();
$customer = Customers::where('email', $passwordReset->email)->first();
/** @var \LDC\LDCCRM\CrmApiV2 */
$crm = app('crmAPI');
try {
// ne devrait pas survenir, $crm->login throws ApiError::authFailed()
if ($crm->login($customer->email, $request->password)) {
// mauvais identifiants
return back()->withErrors('Vous ne pouvez pas utiliser un de vos anciens mot de passe.');
}
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
} catch (ApiErrorException $e) {
// continue
}
try {
if (!($crmCustomer = $crm->getCustomer($customer->hashcode))) {
return back()
->withErrors('Changement impossible, compte inexistant.');
}
$crmCustomer->password = $request->password;
$crmCustomer->save();
} catch (\TypeError | CrmException | ApiErrorException $e) {
Utils::sendEmailErrorManually($e);
// Une erreur critique est survenue avec la CRM
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} catch (ValidationException $e) {
return back()->withErrors(sprintf('Nouveau mot de passe : %s', $e->getMessage()));
}
$passwordReset->delete();
return view('front.auth.password-reset-ok', compact('customer'));
}
/**
* Mettre à jour le mot de passe lorsque l'on est connecté
*
* @param CustomerUpdatePassword $request
* @return void
*/
public function changePasswordWhenAuthenticated(CustomerUpdatePassword $request)
{
/** @var \App\Models\Customers */
$customer = auth('customer')->user();
/** @var \LDC\LDCCRM\CrmApiV2 */
$crm = app('crmAPI');
// Test old password
try {
// ne devrait pas survenir, $crm->login throws ApiError::authFailed()
if (!$crm->login($customer->email, $request->password_old)) {
// mauvais identifiants
return back()->withErrors('L\'ancien mot de passe ne correspond pas.');
}
$crmCustomer = $crm->getCustomer($customer->hashcode);
$crmCustomer->password = $request->password;
$crmCustomer->save();
} catch (ApiErrorException $e) {
if ($e->getApiError() === ApiError::authFailed()) {
return back()->withErrors('L\'ancien mot de passe ne correspond pas.');
}
Utils::sendEmailErrorManually($e);
// Une erreur critique est survenue avec la CRM
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} catch (\TypeError | CrmException $e) {
Utils::sendEmailErrorManually($e);
// Une erreur critique est survenue avec la CRM
return back()->withErrors('Une erreur est survenue, merci de réessayer ultérieurement.');
} catch (ValidationException $e) {
return back()->withErrors(sprintf('Nouveau mot de passe : %s', $e->getMessage()));
} //end try
return back()->with('success', __("Modifications enregistrés !"));
}
}