1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-09-20 00:11:35 +02:00

Support clients logging in with email/password

This commit is contained in:
Hillel Coren 2017-11-15 20:26:51 +02:00
parent 7c1c8898a0
commit bf1f540fdf
8 changed files with 100 additions and 20 deletions

View File

@ -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);
}
/**

View File

@ -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,
]);
}

View File

@ -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);

View File

@ -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]);

View File

@ -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;
}
}

View File

@ -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',
);

View File

@ -170,6 +170,10 @@
->label(trans('texts.send_portal_password'))
->value(1) !!}
</div>
<div class="col-md-10 col-md-offset-1">
{!! Former::plaintext('client_login')
->value(link_to($account->present()->clientLoginUrl, null, ['target' => '_blank'])) !!}
</div>
</div>
</div>
</div>

View File

@ -6,7 +6,7 @@
<div class="container">
{!! Former::open('client/login')
{!! Former::open()
->rules(['password' => 'required'])
->addClass('form-signin') !!}
@ -37,6 +37,9 @@
{{ Former::populateField('remember', 'true') }}
<div>
@if (! session('contact_key'))
{!! Former::text('email')->placeholder(trans('texts.email'))->raw() !!}
@endif
{!! Former::password('password')->placeholder(trans('texts.password'))->raw() !!}
</div>
{!! Former::hidden('remember')->raw() !!}