Refactor authentication logic in Authentication component

This commit is contained in:
Benjamin Beganović 2024-02-09 17:53:44 +01:00
parent 4b971157c1
commit 4013437115

View File

@ -12,49 +12,179 @@
namespace App\Livewire\BillingPortal; namespace App\Livewire\BillingPortal;
use App\DataMapper\ClientSettings;
use App\Factory\ClientFactory;
use App\Jobs\Mail\NinjaMailerJob; use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject; use App\Jobs\Mail\NinjaMailerObject;
use App\Mail\Subscription\OtpCode; use App\Mail\Subscription\OtpCode;
use App\Models\ClientContact; use App\Models\ClientContact;
use App\Models\Subscription; use App\Models\Subscription;
use App\Repositories\ClientContactRepository;
use App\Repositories\ClientRepository;
use Livewire\Component; use Livewire\Component;
use Illuminate\Support\Str;
class Authentication extends Component class Authentication extends Component
{ {
public Subscription $subscription; public Subscription $subscription;
public string $email; public array $context;
public ?string $email;
public ?string $password;
public ?int $otp;
public array $state = [ public array $state = [
'code' => false, 'otp' => true, // Use as preference. E-mail/password or OTP.
'login_form' => false,
'otp_form' => false,
'initial_completed' => false,
]; ];
public function authenticate() public function initial()
{ {
$this->validateOnly('email', ['email' => 'required|bail|email:rfc']); $this->validateOnly('email', ['email' => 'required|bail|email:rfc']);
$code = rand(100000, 999999); $this->state['initial_completed'] = true;
$hash = sprintf('subscriptions:otp:%s', $code);
cache()->put($hash, $code, ttl: 120); if ($this->state['otp']) {
return $this->withOtp();
}
return $this->withPassword();
}
public function withPassword()
{
$contact = ClientContact::where('email', $this->email)
->where('company_id', $this->subscription->company_id)
->first();
if ($contact) {
return $this->state['login_form'] = true;
}
$this->state['login_form'] = false;
$contact = $this->createClientContact();
auth()->guard('contact')->loginUsingId($contact->id, true);
$this->dispatch('purchase.context', property: 'contact', value: $contact);
$this->dispatch('purchase.next');
}
public function handlePassword()
{
$this->validate([
'email' => 'required|bail|email:rfc',
'password' => 'required',
]);
$attempt = auth()->guard('contact')->attempt([
'email' => $this->email,
'password' => $this->password,
'company_id' => $this->subscription->company_id,
]);
if ($attempt) {
$this->dispatch('purchase.next');
}
session()->flash('message', 'These credentials do not match our records.');
}
public function withOtp()
{
$code = rand(100000, 999999);
$email_hash = "subscriptions:otp:{$this->email}";
cache()->put($email_hash, $code, 120);
$cc = new ClientContact(); $cc = new ClientContact();
$cc->email = $this->email; $cc->email = $this->email;
$nmo = new NinjaMailerObject(); $nmo = new NinjaMailerObject();
$nmo->mailable = new OtpCode($this->subscription->company, $this->contact, $code); $nmo->mailable = new OtpCode($this->subscription->company, $this->context['contact'] ?? null, $code);
$nmo->company = $this->subscription->company; $nmo->company = $this->subscription->company;
$nmo->settings = $this->subscription->company->settings; $nmo->settings = $this->subscription->company->settings;
$nmo->to_user = $cc; $nmo->to_user = $cc;
NinjaMailerJob::dispatch($nmo); NinjaMailerJob::dispatch($nmo);
$this->state['code'] = true; if (app()->environment('local')) {
session()->flash('message', "[dev]: Your OTP is: {$code}");
}
$this->state['otp_form'] = true;
}
public function handleOtp()
{
$this->validate([
'otp' => 'required|numeric|digits:6',
]);
$code = cache()->get("subscriptions:otp:{$this->email}");
if ($this->otp !== $code) {
$errors = $this->getErrorBag();
$errors->add('otp', ctrans('texts.invalid_code'));
return;
}
$contact = ClientContact::where('email', $this->email)
->where('company_id', $this->subscription->company_id)
->first();
if ($contact) {
auth()->guard('contact')->loginUsingId($contact->id, true);
$this->dispatch('purchase.context', property: 'contact', value: $contact);
$this->dispatch('purchase.next');
return;
}
$contact = $this->createClientContact();
auth()->guard('contact')->loginUsingId($contact->id, true);
$this->dispatch('purchase.context', property: 'contact', value: $contact);
$this->dispatch('purchase.next');
}
private function createClientContact()
{
$company = $this->subscription->company;
$user = $this->subscription->user;
$user->setCompany($company);
$client_repo = new ClientRepository(new ClientContactRepository());
$data = [
'name' => '',
'group_settings_id' => $this->subscription->group_id,
'contacts' => [
['email' => $this->email],
],
'client_hash' => Str::random(40),
'settings' => ClientSettings::defaults(),
];
$client = $client_repo->save($data, ClientFactory::create($company->id, $user->id));
$contact = $client->fresh()->contacts()->first();
return $contact;
} }
public function mount() public function mount()
{ {
if (auth()->guard('contact')->check()) { if (auth()->guard('contact')->check()) {
$this->dispatch('purchase.context', property: 'contact', value: auth()->guard('contact')->user());
$this->dispatch('purchase.next'); $this->dispatch('purchase.next');
} }
} }