mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-08 05:54:29 -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;
|
namespace App\Http\Livewire;
|
||||||
|
|
||||||
use App\Factory\ClientFactory;
|
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\Subscription;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
@ -102,6 +105,7 @@ class BillingPortalPurchase extends Component
|
|||||||
'fetched_payment_methods' => false,
|
'fetched_payment_methods' => false,
|
||||||
'fetched_client' => false,
|
'fetched_client' => false,
|
||||||
'show_start_trial' => false,
|
'show_start_trial' => false,
|
||||||
|
'passwordless_login_sent' => false,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,6 +148,13 @@ class BillingPortalPurchase extends Component
|
|||||||
*/
|
*/
|
||||||
public $price;
|
public $price;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disabled state of passwordless login button.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $passwordless_login_btn = false;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->price = $this->subscription->service()->price();
|
$this->price = $this->subscription->service()->price();
|
||||||
@ -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()
|
public function render()
|
||||||
{
|
{
|
||||||
if ($this->contact instanceof ClientContact) {
|
if ($this->contact instanceof ClientContact) {
|
||||||
|
@ -74,6 +74,11 @@ nlog($request->all());
|
|||||||
nlog("double merp");
|
nlog("double merp");
|
||||||
if($client_contact = ClientContact::where('email', $contact_email)->first()){
|
if($client_contact = ClientContact::where('email', $contact_email)->first()){
|
||||||
Auth::guard('contact')->login($client_contact, true);
|
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');
|
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');
|
||||||
|
}
|
||||||
|
}
|
@ -18,13 +18,13 @@ class MagicLink
|
|||||||
{
|
{
|
||||||
|
|
||||||
//return a magic login link URL
|
//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);
|
$magic_key = Str::random(64);
|
||||||
$timeout = 600; //seconds
|
$timeout = 600; //seconds
|
||||||
|
|
||||||
Cache::add($magic_key, $email, $timeout);
|
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>
|
</p>
|
||||||
@enderror
|
@enderror
|
||||||
</label>
|
</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
|
@endif
|
||||||
|
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user