From bf1f540fdf950cd6c17d4b297ccdb8f42beb7588 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Wed, 15 Nov 2017 20:26:51 +0200 Subject: [PATCH] Support clients logging in with email/password --- .../ClientAuth/LoginController.php | 75 +++++++++++++++---- .../Controllers/ClientPortalController.php | 2 +- app/Http/Middleware/DatabaseLookup.php | 2 + app/Models/LookupAccount.php | 2 +- app/Ninja/Presenters/AccountPresenter.php | 27 +++++++ resources/lang/en/texts.php | 3 +- .../views/accounts/client_portal.blade.php | 4 + resources/views/clientauth/login.blade.php | 5 +- 8 files changed, 100 insertions(+), 20 deletions(-) diff --git a/app/Http/Controllers/ClientAuth/LoginController.php b/app/Http/Controllers/ClientAuth/LoginController.php index becb723d59..a6a779b439 100644 --- a/app/Http/Controllers/ClientAuth/LoginController.php +++ b/app/Http/Controllers/ClientAuth/LoginController.php @@ -2,10 +2,13 @@ namespace App\Http\Controllers\ClientAuth; +use Utils; use Illuminate\Http\Request; use App\Http\Controllers\Controller; use App\Models\Contact; +use App\Models\Account; use Illuminate\Foundation\Auth\AuthenticatesUsers; +use Illuminate\Contracts\Auth\Authenticatable; class LoginController extends Controller { @@ -54,15 +57,22 @@ class LoginController extends Controller */ public function showLoginForm() { + $subdomain = Utils::getSubdomain(\Request::server('HTTP_HOST')); + $hasAccountIndentifier = request()->account_key || ($subdomain && $subdomain != 'app'); + if (! session('contact_key')) { - return redirect('/client/session_expired'); + if (Utils::isNinja()) { + if (! $hasAccountIndentifier) { + return redirect('/client/session_expired'); + } + } else { + if (! $hasAccountIndentifier && Account::count() > 1) { + return redirect('/client/session_expired'); + } + } } - $data = [ - 'clientauth' => true, - ]; - - return view('clientauth.login')->with($data); + return view('clientauth.login')->with(['clientauth' => true]); } /** @@ -74,20 +84,47 @@ class LoginController extends Controller */ protected function credentials(Request $request) { - $credentials = $request->only('password'); - $credentials['id'] = null; + if ($contactKey = session('contact_key')) { + $credentials = $request->only('password'); + $credentials['contact_key'] = $contactKey; + } else { + $credentials = $request->only('email', 'password'); + $account = false; - $contactKey = session('contact_key'); - if ($contactKey) { - $contact = Contact::where('contact_key', '=', $contactKey)->first(); - if ($contact && ! $contact->is_deleted) { - $credentials['id'] = $contact->id; + // resovle the email to a contact/account + if ($accountKey = request()->account_key) { + $account = Account::whereAccountKey($accountKey)->first(); + } else { + $subdomain = Utils::getSubdomain(\Request::server('HTTP_HOST')); + if ($subdomain != 'app') { + $account = Account::whereSubdomain($subdomain)->first(); + } + } + + if ($account) { + $credentials['account_id'] = $account->id; + } else { + abort(500, 'Account not resolved in client login'); } } return $credentials; } + /** + * Send the post-authentication response. + * + * @param \Illuminate\Http\Request $request + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @return \Illuminate\Http\Response + */ + private function authenticated(Request $request, Authenticatable $contact) + { + session(['contact_key' => $contact->contact_key]); + + return redirect()->intended($this->redirectPath()); + } + /** * Get the failed login response instance. * @@ -101,7 +138,7 @@ class LoginController extends Controller ->withErrors([ $this->username() => trans('texts.invalid_credentials'), ]); - } + } /** * Validate the user login request - don't require the email @@ -112,9 +149,15 @@ class LoginController extends Controller */ protected function validateLogin(Request $request) { - $this->validate($request, [ + $rules = [ 'password' => 'required', - ]); + ]; + + if (! session('contact_key')) { + $rules['email'] = 'required|email'; + } + + $this->validate($request, $rules); } /** diff --git a/app/Http/Controllers/ClientPortalController.php b/app/Http/Controllers/ClientPortalController.php index 6d0d5b1ad0..0a874a514a 100644 --- a/app/Http/Controllers/ClientPortalController.php +++ b/app/Http/Controllers/ClientPortalController.php @@ -601,7 +601,7 @@ class ClientPortalController extends BaseController return response()->view('error', [ 'error' => $error ?: trans('texts.invoice_not_found'), 'hideHeader' => true, - 'account' => $this->getContact()->account, + 'account' => $this->getContact() ? $this->getContact()->account : false, ]); } diff --git a/app/Http/Middleware/DatabaseLookup.php b/app/Http/Middleware/DatabaseLookup.php index 27f2d64830..d76f56e695 100644 --- a/app/Http/Middleware/DatabaseLookup.php +++ b/app/Http/Middleware/DatabaseLookup.php @@ -44,6 +44,8 @@ class DatabaseLookup LookupInvitation::setServerByField('invitation_key', $key); } elseif ($key = request()->contact_key ?: session('contact_key')) { LookupContact::setServerByField('contact_key', $key); + } elseif ($key = request()->account_key) { + LookupAccount::setServerByField('account_key', $key); } } elseif ($guard == 'postmark') { LookupInvitation::setServerByField('message_id', request()->MessageID); diff --git a/app/Models/LookupAccount.php b/app/Models/LookupAccount.php index 65c4536078..ae682bcf56 100644 --- a/app/Models/LookupAccount.php +++ b/app/Models/LookupAccount.php @@ -67,7 +67,7 @@ class LookupAccount extends LookupModel $lookupAccount = LookupAccount::whereAccountKey($accountKey) ->firstOrFail(); - $lookupAccount->subdomain = $account->subdomain; + $lookupAccount->subdomain = $account->subdomain ?: null; $lookupAccount->save(); config(['database.default' => $current]); diff --git a/app/Ninja/Presenters/AccountPresenter.php b/app/Ninja/Presenters/AccountPresenter.php index b3f3e07ad2..df806c981c 100644 --- a/app/Ninja/Presenters/AccountPresenter.php +++ b/app/Ninja/Presenters/AccountPresenter.php @@ -236,4 +236,31 @@ class AccountPresenter extends Presenter return $data; } + + public function clientLoginUrl() + { + $account = $this->entity; + + if (Utils::isNinjaProd()) { + $url = 'https://'; + $url .= $account->subdomain ?: 'app'; + $url .= '.' . Domain::getDomainFromId($account->domain_id); + } else { + $url = SITE_URL; + } + + $url .= '/client/login'; + + if (Utils::isNinja()) { + if (! $account->subdomain) { + $url .= '?account_key=' . $account->account_key; + } + } else { + if (Account::count() > 1) { + $url .= '?account_key=' . $account->account_key; + } + } + + return $url; + } } diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 2ccb13ff28..f00c4d867b 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -1050,7 +1050,7 @@ $LANG = array( // Client Passwords 'enable_portal_password' => 'Password Protect Invoices', 'enable_portal_password_help' => 'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', - 'send_portal_password' => 'Generate Password Automatically', + 'send_portal_password' => 'Generate Automatically', 'send_portal_password_help' => 'If no password is set, one will be generated and sent with the first invoice.', 'expired' => 'Expired', @@ -2523,6 +2523,7 @@ $LANG = array( 'local_storage_required' => 'Error: local storage is not available.', 'your_password_reset_link' => 'Your Password Reset Link', 'subdomain_taken' => 'The subdomain is already in use', + 'client_login' => 'Client Login', ); diff --git a/resources/views/accounts/client_portal.blade.php b/resources/views/accounts/client_portal.blade.php index ce767f19a8..8a10a53d6e 100644 --- a/resources/views/accounts/client_portal.blade.php +++ b/resources/views/accounts/client_portal.blade.php @@ -170,6 +170,10 @@ ->label(trans('texts.send_portal_password')) ->value(1) !!} +
+ {!! Former::plaintext('client_login') + ->value(link_to($account->present()->clientLoginUrl, null, ['target' => '_blank'])) !!} +
diff --git a/resources/views/clientauth/login.blade.php b/resources/views/clientauth/login.blade.php index 8835c6525b..860869d3b7 100644 --- a/resources/views/clientauth/login.blade.php +++ b/resources/views/clientauth/login.blade.php @@ -6,7 +6,7 @@
- {!! Former::open('client/login') + {!! Former::open() ->rules(['password' => 'required']) ->addClass('form-signin') !!} @@ -37,6 +37,9 @@ {{ Former::populateField('remember', 'true') }}
+ @if (! session('contact_key')) + {!! Former::text('email')->placeholder(trans('texts.email'))->raw() !!} + @endif {!! Former::password('password')->placeholder(trans('texts.password'))->raw() !!}
{!! Former::hidden('remember')->raw() !!}