Fixes for contact authentication + viewed entity notifications

This commit is contained in:
David Bomba 2021-10-23 10:06:30 +11:00
parent d807d51f67
commit 2bc8146f7c
10 changed files with 127 additions and 24 deletions

View File

@ -15,12 +15,15 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\ClientPortal\Contact\ContactPasswordResetRequest; use App\Http\Requests\ClientPortal\Contact\ContactPasswordResetRequest;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Models\Account; use App\Models\Account;
use App\Models\ClientContact;
use App\Models\Company;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails; use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Password; use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
use Illuminate\View\View; use Illuminate\View\View;
class ContactForgotPasswordController extends Controller class ContactForgotPasswordController extends Controller
@ -80,19 +83,35 @@ class ContactForgotPasswordController extends Controller
public function sendResetLinkEmail(ContactPasswordResetRequest $request) public function sendResetLinkEmail(ContactPasswordResetRequest $request)
{ {
if(Ninja::isHosted() && $request->has('db')) if(Ninja::isHosted() && $request->has('company_key'))
MultiDB::setDb($request->input('db')); MultiDB::findAndSetDbByCompanyKey($request->input('company_key'));
// $user = MultiDB::hasContact($request->input('email'));
$this->validateEmail($request); $this->validateEmail($request);
// $user = MultiDB::hasContact($request->input('email'));
$company = Company::where('company_key', $request->input('company_key'))->first();
$contact = MultiDB::findContact(['company_id' => $company->id, 'email' => $request->input('email')]);
$response = false;
if($contact){
/* Update all instances of the client */
$token = Str::random(60);
ClientContact::where('email', $contact->email)->update(['token' => $token]);
$contact->sendPasswordResetNotification($token);
$response = Password::RESET_LINK_SENT;
}
else
return $this->sendResetLinkFailedResponse($request, Password::INVALID_USER);
// We will send the password reset link to this user. Once we have attempted // We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we // to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response. // need to show to the user. Finally, we'll send out a proper response.
$response = $this->broker()->sendResetLink( // $response = $this->broker()->sendResetLink(
$this->credentials($request) // $this->credentials($request)
); // );
if ($request->ajax()) { if ($request->ajax()) {

View File

@ -14,11 +14,15 @@ namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Models\Account; use App\Models\Account;
use App\Models\ClientContact;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Foundation\Auth\ResetsPasswords; use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password; use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
use Illuminate\View\View; use Illuminate\View\View;
class ContactResetPasswordController extends Controller class ContactResetPasswordController extends Controller
@ -76,19 +80,28 @@ class ContactResetPasswordController extends Controller
public function reset(Request $request) public function reset(Request $request)
{ {
if($request->has('db')) if($request->has('company_key'))
MultiDB::setDb($request->input('db')); MultiDB::findAndSetDbByCompanyKey($request->input('company_key'));
$request->validate($this->rules(), $this->validationErrorMessages()); $request->validate($this->rules(), $this->validationErrorMessages());
// Here we will attempt to reset the user's password. If it is successful we $user = ClientContact::where($request->only(['email','token']))->first();
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response. if(!$user)
$response = $this->broker()->reset( return $this->sendResetFailedResponse($request, PASSWORD::INVALID_USER);
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password); $hashed_password = Hash::make($request->input('password'));
}
); ClientContact::where('email', $user->email)->update([
'password' => $hashed_password,
'remember_token' => Str::random(60)
]);
event(new PasswordReset($user));
auth()->login($user, true);
$response = Password::PASSWORD_RESET;
// Added this because it collides the session between // Added this because it collides the session between
// client & main portal giving unlimited redirects. // client & main portal giving unlimited redirects.

View File

@ -2,10 +2,13 @@
namespace App\Http\Controllers\ClientPortal; namespace App\Http\Controllers\ClientPortal;
use App\Events\Credit\CreditWasViewed;
use App\Events\Misc\InvitationWasViewed;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\ClientPortal\Credits\ShowCreditRequest; use App\Http\Requests\ClientPortal\Credits\ShowCreditRequest;
use App\Http\Requests\ClientPortal\Credits\ShowCreditsRequest; use App\Http\Requests\ClientPortal\Credits\ShowCreditsRequest;
use App\Models\Credit; use App\Models\Credit;
use App\Utils\Ninja;
class CreditController extends Controller class CreditController extends Controller
{ {
@ -20,6 +23,16 @@ class CreditController extends Controller
$data = ['credit' => $credit]; $data = ['credit' => $credit];
$invitation = $credit->invitations()->where('client_contact_id', auth()->user()->id)->first();
if ($invitation && auth()->guard('contact') && ! request()->has('silent') && ! $invitation->viewed_date) {
$invitation->markViewed();
event(new InvitationWasViewed($credit, $invitation, $credit->company, Ninja::eventVars()));
event(new CreditWasViewed($invitation, $invitation->company, Ninja::eventVars()));
}
if ($request->query('mode') === 'fullscreen') { if ($request->query('mode') === 'fullscreen') {
return render('credits.show-fullscreen', $data); return render('credits.show-fullscreen', $data);

View File

@ -11,11 +11,14 @@
namespace App\Http\Controllers\ClientPortal; namespace App\Http\Controllers\ClientPortal;
use App\Events\Invoice\InvoiceWasViewed;
use App\Events\Misc\InvitationWasViewed;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\ClientPortal\Invoices\ShowInvoicesRequest;
use App\Http\Requests\ClientPortal\Invoices\ProcessInvoicesInBulkRequest; use App\Http\Requests\ClientPortal\Invoices\ProcessInvoicesInBulkRequest;
use App\Http\Requests\ClientPortal\Invoices\ShowInvoiceRequest; use App\Http\Requests\ClientPortal\Invoices\ShowInvoiceRequest;
use App\Http\Requests\ClientPortal\Invoices\ShowInvoicesRequest;
use App\Models\Invoice; use App\Models\Invoice;
use App\Utils\Ninja;
use App\Utils\Number; use App\Utils\Number;
use App\Utils\TempFile; use App\Utils\TempFile;
use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesDates;
@ -23,10 +26,10 @@ use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View; use Illuminate\View\View;
use ZipStream\Option\Archive; use ZipStream\Option\Archive;
use ZipStream\ZipStream; use ZipStream\ZipStream;
use Illuminate\Support\Facades\Storage;
class InvoiceController extends Controller class InvoiceController extends Controller
{ {
@ -56,6 +59,18 @@ class InvoiceController extends Controller
$invoice->service()->removeUnpaidGatewayFees()->save(); $invoice->service()->removeUnpaidGatewayFees()->save();
$invitation = $invoice->invitations()->where('client_contact_id', auth()->user()->id)->first();
if ($invitation && auth()->guard('contact') && ! request()->has('silent') && ! $invitation->viewed_date) {
$invitation->markViewed();
event(new InvitationWasViewed($invoice, $invitation, $invoice->company, Ninja::eventVars()));
event(new InvoiceWasViewed($invitation, $invitation->company, Ninja::eventVars()));
}
$data = [ $data = [
'invoice' => $invoice, 'invoice' => $invoice,
]; ];

View File

@ -12,22 +12,24 @@
namespace App\Http\Controllers\ClientPortal; namespace App\Http\Controllers\ClientPortal;
use App\Events\Misc\InvitationWasViewed;
use App\Events\Quote\QuoteWasApproved; use App\Events\Quote\QuoteWasApproved;
use App\Events\Quote\QuoteWasViewed;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\ClientPortal\Quotes\ProcessQuotesInBulkRequest; use App\Http\Requests\ClientPortal\Quotes\ProcessQuotesInBulkRequest;
use App\Http\Requests\ClientPortal\Quotes\ShowQuotesRequest;
use App\Http\Requests\ClientPortal\Quotes\ShowQuoteRequest; use App\Http\Requests\ClientPortal\Quotes\ShowQuoteRequest;
use App\Http\Requests\ClientPortal\Quotes\ShowQuotesRequest;
use App\Jobs\Invoice\InjectSignature; use App\Jobs\Invoice\InjectSignature;
use App\Models\Quote; use App\Models\Quote;
use App\Utils\Ninja; use App\Utils\Ninja;
use App\Utils\TempFile; use App\Utils\TempFile;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View; use Illuminate\View\View;
use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\BinaryFileResponse;
use ZipStream\Option\Archive; use ZipStream\Option\Archive;
use ZipStream\ZipStream; use ZipStream\ZipStream;
use Illuminate\Support\Facades\Storage;
class QuoteController extends Controller class QuoteController extends Controller
{ {
@ -56,6 +58,18 @@ class QuoteController extends Controller
'quote' => $quote, 'quote' => $quote,
]; ];
$invitation = $quote->invitations()->where('client_contact_id', auth()->user()->id)->first();
if ($invitation && auth()->guard('contact') && ! request()->has('silent') && ! $invitation->viewed_date) {
$invitation->markViewed();
event(new InvitationWasViewed($quote, $invitation, $quote->company, Ninja::eventVars()));
event(new QuoteWasViewed($invitation, $invitation->company, Ninja::eventVars()));
}
if ($request->query('mode') === 'fullscreen') { if ($request->query('mode') === 'fullscreen') {
return render('quotes.show-fullscreen', $data); return render('quotes.show-fullscreen', $data);
} }

View File

@ -174,6 +174,32 @@ class MultiDB
return null; return null;
} }
/**
* @param array $data
* @return User|null
*/
public static function findContact(array $search) : ?ClientContact
{
if (! config('ninja.db.multi_db_enabled'))
return ClientContact::where($search)->first();
$current_db = config('database.default');
foreach (self::$dbs as $db) {
$user = ClientContact::on($db)->where($search)->first();
if ($user) {
self::setDb($db);
return $user;
}
}
self::setDB($current_db);
return null;
}
public static function contactFindAndSetDb($token) :bool public static function contactFindAndSetDb($token) :bool
{ {
$current_db = config('database.default'); $current_db = config('database.default');

View File

@ -191,6 +191,9 @@ class PaytracePaymentDriver extends BaseDriver
$auth_data = json_decode($response); $auth_data = json_decode($response);
if(!property_exists($auth_data, 'access_token'))
throw new \Exception('Error authenticating with PayTrace');
$headers = []; $headers = [];
$headers[] = 'Content-type: application/json'; $headers[] = 'Content-type: application/json';
$headers[] = 'Authorization: Bearer '.$auth_data->access_token; $headers[] = 'Authorization: Bearer '.$auth_data->access_token;

View File

@ -53,7 +53,7 @@
href="{{ route('client.password.request') }}">{{ trans('texts.forgot_password') }}</a> href="{{ route('client.password.request') }}">{{ trans('texts.forgot_password') }}</a>
</div> </div>
@if(isset($company) && !is_null($company)) @if(isset($company) && !is_null($company))
<input type="hidden" name="db" value="{{$company->db}}"> <input type="hidden" name="company_key" value="{{$company->company_key}}">
@endif @endif
<input type="password" name="password" id="password" <input type="password" name="password" id="password"
class="input" class="input"

View File

@ -34,7 +34,7 @@
<div class="flex flex-col"> <div class="flex flex-col">
<label for="email" class="input-label">{{ ctrans('texts.email_address') }}</label> <label for="email" class="input-label">{{ ctrans('texts.email_address') }}</label>
@if($company && !is_null($company)) @if($company && !is_null($company))
<input type="hidden" name="db" value="{{$company->db}}"> <input type="hidden" name="company_key" value="{{$company->company_key}}">
@endif @endif
<input type="email" name="email" id="email" <input type="email" name="email" id="email"
class="input" class="input"

View File

@ -33,8 +33,8 @@
<form action="{{ route('client.password.update') }}" method="post" class="mt-6"> <form action="{{ route('client.password.update') }}" method="post" class="mt-6">
@csrf @csrf
<input type="hidden" name="token" value="{{ $token }}"> <input type="hidden" name="token" value="{{ $token }}">
@if($db) @if($company)
<input type="hidden" name="db" value="{{$db}}"> <input type="hidden" name="company_key" value="{{$company->company_key}}">
@endif @endif
<div class="flex flex-col"> <div class="flex flex-col">
<label for="email" class="input-label">{{ ctrans('texts.email_address') }}</label> <label for="email" class="input-label">{{ ctrans('texts.email_address') }}</label>