Merge pull request #5304 from beganovich/v5-3103-billing-portal

(v5) Billing portal: Passwordless (magic link) login
This commit is contained in:
Benjamin Beganović 2021-03-31 18:15:06 +02:00 committed by GitHub
commit b7f14507ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 123 additions and 9 deletions

View File

@ -12,6 +12,9 @@
namespace App\Http\Livewire;
use App\Factory\ClientFactory;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Mail\ContactPasswordlessLogin;
use App\Models\Subscription;
use App\Models\ClientContact;
use App\Models\Invoice;
@ -102,6 +105,7 @@ class BillingPortalPurchase extends Component
'fetched_payment_methods' => false,
'fetched_client' => false,
'show_start_trial' => false,
'passwordless_login_sent' => false,
];
/**
@ -144,6 +148,13 @@ class BillingPortalPurchase extends Component
*/
public $price;
/**
* Disabled state of passwordless login button.
*
* @var bool
*/
public $passwordless_login_btn = false;
public function mount()
{
$this->price = $this->subscription->service()->price();
@ -290,11 +301,11 @@ class BillingPortalPurchase extends Component
->save();
Cache::put($this->hash, [
'subscription_id' => $this->subscription->id,
'email' => $this->email ?? $this->contact->email,
'client_id' => $this->contact->client->id,
'invoice_id' => $this->invoice->id,
now()->addMinutes(60)]
'subscription_id' => $this->subscription->id,
'email' => $this->email ?? $this->contact->email,
'client_id' => $this->contact->client->id,
'invoice_id' => $this->invoice->id,
now()->addMinutes(60)]
);
$this->emit('beforePaymentEventsCompleted');
@ -348,6 +359,26 @@ class BillingPortalPurchase extends Component
}
}
public function passwordlessLogin()
{
$this->passwordless_login_btn = true;
$contact = ClientContact::query()
->where('email', $this->email)
->first();
$mailer = new NinjaMailerObject();
$mailer->mailable = new ContactPasswordlessLogin($this->email, (string)route('client.subscription.purchase', $this->subscription->hashed_id));
$mailer->company = $this->subscription->company;
$mailer->settings = $this->subscription->company->settings;
$mailer->to_user = $contact;
NinjaMailerJob::dispatchNow($mailer);
$this->steps['passwordless_login_sent'] = true;
$this->passwordless_login_btn = false;
}
public function render()
{
if ($this->contact instanceof ClientContact) {

View File

@ -74,6 +74,11 @@ nlog($request->all());
nlog("double merp");
if($client_contact = ClientContact::where('email', $contact_email)->first()){
Auth::guard('contact')->login($client_contact, true);
if ($request->query('redirect') && !empty($request->query('redirect'))) {
return redirect()->to($request->query('redirect'));
}
return redirect()->to('client/dashboard');
}
}

View File

@ -0,0 +1,54 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Mail;
use App\Utils\ClientPortal\MagicLink;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class ContactPasswordlessLogin extends Mailable
{
use Queueable, SerializesModels;
/**
* @var string
*/
public $email;
public $url = 'https://google.com';
/**
* Create a new message instance.
*
* @param string $email
* @param string $redirect
*/
public function __construct(string $email, string $redirect = '')
{
$this->email = $email;
$this->url = MagicLink::create($email, $redirect);
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('email.billing.passwordless-login');
}
}

View File

@ -16,15 +16,15 @@ use Illuminate\Support\Str;
class MagicLink
{
//return a magic login link URL
public static function create($email) :string
public static function create($email, $url = null) :string
{
$magic_key = Str::random(64);
$timeout = 600; //seconds
Cache::add($magic_key, $email, $timeout);
return route('client.contact_magic_link', ['magic_link' => $magic_key]);
return route('client.contact_magic_link', ['magic_link' => $magic_key, 'redirect' => $url]);
}
}

View File

@ -0,0 +1,16 @@
@component('email.template.master', ['design' => 'light'])
@slot('header')
@include('email.components.header', ['logo' => 'https://www.invoiceninja.com/wp-content/uploads/2015/10/logo-white-horizontal-1.png'])
@endslot
<h2>Passwordless login link requested</h2>
<p>Hey, there was a request to log in using passwordless link.</p>
<a href="{{ $url }}" target="_blank" class="button">Sign in to Invoice Ninja</a>
<span style="margin-top: 35px; display: block;">Link above is only for you. Don't share it anyone.</span>
<span>If you didn't request this, just ignore it.</span>
<span style="margin-top: 25px; display: block;">If you can't click on the button, copy following link:</span>
<a href="{{ $url }}">{{ $url }}</a>
@endcomponent

View File

@ -166,6 +166,14 @@
</p>
@enderror
</label>
<button wire:loading.attr="disabled" type="button" wire:click="passwordlessLogin" class="mt-4 text-sm active:outline-none focus:outline-none">
Log in without password
</button>
@if($steps['passwordless_login_sent'])
<span class="block mt-2 text-sm text-green-600">E-mail sent. Please check your inbox!</span>
@endif
@endif
<button type="submit"
@ -184,7 +192,7 @@
</div>
</div>
<form wire:submit.prevent="handleCoupon" class="flex items-center mt-4">
<form wire:submit.prevent="handleCoupon" class="flex items-center mt-4">
@csrf
<label class="w-full mr-2">