mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-07 17:04:45 -04:00
Merge pull request #5304 from beganovich/v5-3103-billing-portal
(v5) Billing portal: Passwordless (magic link) login
This commit is contained in:
commit
b7f14507ce
@ -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) {
|
||||
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
54
app/Mail/ContactPasswordlessLogin.php
Normal file
54
app/Mail/ContactPasswordlessLogin.php
Normal 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');
|
||||
}
|
||||
}
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
16
resources/views/email/billing/passwordless-login.blade.php
Normal file
16
resources/views/email/billing/passwordless-login.blade.php
Normal 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
|
@ -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">
|
||||
|
Loading…
x
Reference in New Issue
Block a user