Add support for including password in email; include portal customizations

This commit is contained in:
Joshua Dwire 2016-03-05 18:09:50 -05:00
parent 793ba76415
commit d0d30e1e26
10 changed files with 129 additions and 41 deletions

View File

@ -431,7 +431,6 @@ class AccountController extends BaseController
$data = [ $data = [
'client_view_css' => $css, 'client_view_css' => $css,
'enable_portal_password' => $account->enable_portal_password, 'enable_portal_password' => $account->enable_portal_password,
'fill_portal_password' => $account->fill_portal_password,
'send_portal_password' => $account->send_portal_password, 'send_portal_password' => $account->send_portal_password,
'title' => trans("texts.client_portal"), 'title' => trans("texts.client_portal"),
'section' => ACCOUNT_CLIENT_PORTAL, 'section' => ACCOUNT_CLIENT_PORTAL,
@ -549,8 +548,8 @@ class AccountController extends BaseController
$account = Auth::user()->account; $account = Auth::user()->account;
$account->client_view_css = $sanitized_css; $account->client_view_css = $sanitized_css;
$account->enable_client_portal = !!Input::get('enable_client_portal');
$account->enable_portal_password = !!Input::get('enable_portal_password'); $account->enable_portal_password = !!Input::get('enable_portal_password');
$account->fill_portal_password = !!Input::get('fill_portal_password');
$account->send_portal_password = !!Input::get('send_portal_password'); $account->send_portal_password = !!Input::get('send_portal_password');
$account->save(); $account->save();

View File

@ -22,7 +22,24 @@ class AuthController extends Controller {
public function showLoginForm() public function showLoginForm()
{ {
return view('clientauth.login'); $data = array(
);
$invitation_key = session('invitation_key');
if($invitation_key){
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first();
if ($invitation && !$invitation->is_deleted) {
$invoice = $invitation->invoice;
$client = $invoice->client;
$account = $client->account;
$data['hideLogo'] = $account->isWhiteLabel();
$data['clientViewCSS'] = $account->clientViewCSS();
$data['clientFontUrl'] = $account->getFontsUrl();
}
}
return view('clientauth.login')->with($data);
} }
/** /**

View File

@ -2,7 +2,6 @@
use Config; use Config;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Brokers\ClientPasswordBroker;
use Illuminate\Foundation\Auth\ResetsPasswords; use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Mail\Message; use Illuminate\Mail\Message;
@ -42,7 +41,22 @@ class PasswordController extends Controller {
public function showLinkRequestForm() public function showLinkRequestForm()
{ {
return view('clientauth.password'); $data = array();
$invitation_key = session('invitation_key');
if($invitation_key){
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first();
if ($invitation && !$invitation->is_deleted) {
$invoice = $invitation->invoice;
$client = $invoice->client;
$account = $client->account;
$data['hideLogo'] = $account->isWhiteLabel();
$data['clientViewCSS'] = $account->clientViewCSS();
$data['clientFontUrl'] = $account->getFontsUrl();
}
}
return view('clientauth.password')->with($data);
} }
/** /**
@ -94,7 +108,22 @@ class PasswordController extends Controller {
return $this->getEmail(); return $this->getEmail();
} }
return view('clientauth.reset')->with(compact('token', 'invitation_key')); $data = compact('token', 'invitation_key');
$invitation_key = session('invitation_key');
if($invitation_key){
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first();
if ($invitation && !$invitation->is_deleted) {
$invoice = $invitation->invoice;
$client = $invoice->client;
$account = $client->account;
$data['hideLogo'] = $account->isWhiteLabel();
$data['clientViewCSS'] = $account->clientViewCSS();
$data['clientFontUrl'] = $account->getFontsUrl();
}
}
return view('clientauth.reset')->with($data);
} }

View File

@ -31,6 +31,7 @@ class ContactMailer extends Mailer
'viewButton', 'viewButton',
'paymentLink', 'paymentLink',
'paymentButton', 'paymentButton',
'password',
]; ];
public function sendInvoice(Invoice $invoice, $reminder = false, $pdfString = false) public function sendInvoice(Invoice $invoice, $reminder = false, $pdfString = false)
@ -110,6 +111,13 @@ class ContactMailer extends Mailer
'amount' => $invoice->getRequestedAmount() 'amount' => $invoice->getRequestedAmount()
]; ];
if (empty($invitation->contact->password) && $account->isPro() && $account->enable_portal_password && $account->send_portal_password) {
// The contact needs a password
$variables['password'] = $password = $this->generatePassword();
$invitation->contact->password = bcrypt($password);
$invitation->contact->save();
}
$data = [ $data = [
'body' => $this->processVariables($body, $variables), 'body' => $this->processVariables($body, $variables),
'link' => $invitation->getLink(), 'link' => $invitation->getLink(),
@ -144,6 +152,28 @@ class ContactMailer extends Mailer
} }
} }
protected function generatePassword($length = 9)
{
$sets = array(
'abcdefghjkmnpqrstuvwxyz',
'ABCDEFGHJKMNPQRSTUVWXYZ',
'23456789',
);
$all = '';
$password = '';
foreach($sets as $set)
{
$password .= $set[array_rand(str_split($set))];
$all .= $set;
}
$all = str_split($all);
for($i = 0; $i < $length - count($sets); $i++)
$password .= $all[array_rand($all)];
$password = str_shuffle($password);
return $password;
}
public function sendPaymentConfirmation(Payment $payment) public function sendPaymentConfirmation(Payment $payment)
{ {
$account = $payment->account; $account = $payment->account;
@ -253,6 +283,7 @@ class ContactMailer extends Mailer
'$customClient2' => $account->custom_client_label2, '$customClient2' => $account->custom_client_label2,
'$customInvoice1' => $account->custom_invoice_text_label1, '$customInvoice1' => $account->custom_invoice_text_label1,
'$customInvoice2' => $account->custom_invoice_text_label2, '$customInvoice2' => $account->custom_invoice_text_label2,
'$password' => isset($data['password'])?$data['password']:false,
]; ];
// Add variables for available payment types // Add variables for available payment types

View File

@ -14,7 +14,6 @@ class AddClientPassword extends Migration {
{ {
Schema::table('accounts', function ($table) { Schema::table('accounts', function ($table) {
$table->boolean('enable_portal_password')->default(0); $table->boolean('enable_portal_password')->default(0);
$table->boolean('fill_portal_password')->default(0);
$table->boolean('send_portal_password')->default(0); $table->boolean('send_portal_password')->default(0);
}); });
@ -34,7 +33,6 @@ class AddClientPassword extends Migration {
{ {
Schema::table('accounts', function ($table) { Schema::table('accounts', function ($table) {
$table->dropColumn('enable_portal_password'); $table->dropColumn('enable_portal_password');
$table->dropColumn('fill_portal_password');
$table->dropColumn('send_portal_password'); $table->dropColumn('send_portal_password');
}); });

View File

@ -1053,10 +1053,10 @@ $LANG = array(
'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.',
// Client Passwords // Client Passwords
'client_portal_login_settings'=>'Login', 'enable_portal_password'=>'Password protect invoices',
'enable_portal_password'=>'Require a password', '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 password automatically',
'fill_portal_password'=>'Include password in invoice emails', 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.',
); );
return $LANG; return $LANG;

View File

@ -15,6 +15,7 @@
{!! Former::populateField('enable_client_portal', intval($account->enable_client_portal)) !!} {!! Former::populateField('enable_client_portal', intval($account->enable_client_portal)) !!}
{!! Former::populateField('client_view_css', $client_view_css) !!} {!! Former::populateField('client_view_css', $client_view_css) !!}
{!! Former::populateField('enable_portal_password', $enable_portal_password) !!} {!! Former::populateField('enable_portal_password', $enable_portal_password) !!}
{!! Former::populateField('send_portal_password', $send_portal_password) !!}
@if (!Utils::isNinja() && !Auth::user()->account->isWhiteLabel()) @if (!Utils::isNinja() && !Auth::user()->account->isWhiteLabel())
<div class="alert alert-warning" style="font-size:larger;"> <div class="alert alert-warning" style="font-size:larger;">
@ -40,16 +41,13 @@
<div class="col-md-10 col-md-offset-1"> <div class="col-md-10 col-md-offset-1">
{!! Former::checkbox('enable_portal_password') {!! Former::checkbox('enable_portal_password')
->text(trans('texts.enable_portal_password')) ->text(trans('texts.enable_portal_password'))
->label('&nbsp;') !!} ->help(trans('texts.enable_portal_password_help'))
</div>
<div class="col-md-10 col-md-offset-1">
{!! Former::checkbox('fill_portal_password')
->text(trans('texts.fill_portal_password'))
->label('&nbsp;') !!} ->label('&nbsp;') !!}
</div> </div>
<div class="col-md-10 col-md-offset-1"> <div class="col-md-10 col-md-offset-1">
{!! Former::checkbox('send_portal_password') {!! Former::checkbox('send_portal_password')
->text(trans('texts.send_portal_password')) ->text(trans('texts.send_portal_password'))
->help(trans('texts.send_portal_password_help'))
->label('&nbsp;') !!} ->label('&nbsp;') !!}
</div> </div>
</div> </div>
@ -71,7 +69,6 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<center> <center>
{!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!} {!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
@ -82,7 +79,6 @@
$('#enable_portal_password').change(fixCheckboxes); $('#enable_portal_password').change(fixCheckboxes);
function fixCheckboxes(){ function fixCheckboxes(){
var checked = $('#enable_portal_password').is(':checked'); var checked = $('#enable_portal_password').is(':checked');
$('#fill_portal_password').prop('disabled', !checked);
$('#send_portal_password').prop('disabled', !checked); $('#send_portal_password').prop('disabled', !checked);
} }
fixCheckboxes(); fixCheckboxes();

View File

@ -1,10 +1,7 @@
@extends('master') @extends('public.header')
@section('head') @section('head')
@parent
<link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet" type="text/css"/>
<link href="{{ asset('css/style.css') }}" rel="stylesheet" type="text/css"/>
<style type="text/css"> <style type="text/css">
body { body {
padding-top: 40px; padding-top: 40px;
@ -13,6 +10,8 @@
.modal-header { .modal-header {
border-top-left-radius: 3px; border-top-left-radius: 3px;
border-top-right-radius: 3px; border-top-right-radius: 3px;
background:#222;
color:#fff
} }
.modal-header h4 { .modal-header h4 {
margin:0; margin:0;
@ -70,9 +69,14 @@
{{ Former::populateField('remember', 'true') }} {{ Former::populateField('remember', 'true') }}
<div class="modal-header"> <div class="modal-header">
@if (!isset($hideLogo) || !$hideLogo)
<a href="{{ NINJA_WEB_URL }}" target="_blank"> <a href="{{ NINJA_WEB_URL }}" target="_blank">
<h4>{{ trans('texts.account_login') }}</h4> <img src="{{ asset('images/icon-login.png') }}" />
<h4>Invoice Ninja | {{ trans('texts.account_login') }}</h4>
</a> </a>
@else
<h4>{{ trans('texts.account_login') }}</h4>
@endif
</div> </div>
<div class="inner"> <div class="inner">
<p> <p>

View File

@ -1,10 +1,7 @@
@extends('master') @extends('public.header')
@section('head') @section('head')
@parent
<link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet" type="text/css"/>
<link href="{{ asset('css/style.css') }}" rel="stylesheet" type="text/css"/>
<style type="text/css"> <style type="text/css">
body { body {
padding-top: 40px; padding-top: 40px;
@ -13,6 +10,8 @@
.modal-header { .modal-header {
border-top-left-radius: 3px; border-top-left-radius: 3px;
border-top-right-radius: 3px; border-top-right-radius: 3px;
background:#222;
color:#fff
} }
.modal-header h4 { .modal-header h4 {
margin:0; margin:0;
@ -55,7 +54,15 @@
{!! Former::open('client/forgot')->addClass('form-signin') !!} {!! Former::open('client/forgot')->addClass('form-signin') !!}
<div class="modal-header"> <div class="modal-header">
<h4>{{ trans('texts.password_recovery') }}</h4></div> @if (!isset($hideLogo) || !$hideLogo)
<a href="{{ NINJA_WEB_URL }}" target="_blank">
<img src="{{ asset('images/icon-login.png') }}" />
<h4>Invoice Ninja | {{ trans('texts.password_recovery') }}</h4>
</a>
@else
<h4>{{ trans('texts.password_recovery') }}</h4>
@endif
</div>
<div class="inner"> <div class="inner">
<p>{!! Button::success(trans('texts.send_email'))->large()->submit()->block() !!}</p> <p>{!! Button::success(trans('texts.send_email'))->large()->submit()->block() !!}</p>

View File

@ -1,10 +1,7 @@
@extends('master') @extends('public.header')
@section('head') @section('head')
@parent
<link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet" type="text/css"/>
<link href="{{ asset('css/style.css') }}" rel="stylesheet" type="text/css"/>
<style type="text/css"> <style type="text/css">
body { body {
padding-top: 40px; padding-top: 40px;
@ -13,6 +10,8 @@
.modal-header { .modal-header {
border-top-left-radius: 3px; border-top-left-radius: 3px;
border-top-right-radius: 3px; border-top-right-radius: 3px;
background:#222;
color:#fff
} }
.modal-header h4 { .modal-header h4 {
margin:0; margin:0;
@ -59,7 +58,15 @@
)) !!} )) !!}
<div class="modal-header"> <div class="modal-header">
<h4>{{ trans('texts.set_password') }}</h4></div> @if (!isset($hideLogo) || !$hideLogo)
<a href="{{ NINJA_WEB_URL }}" target="_blank">
<img src="{{ asset('images/icon-login.png') }}" />
<h4>Invoice Ninja | {{ trans('texts.set_password') }}</h4>
</a>
@else
<h4>{{ trans('texts.set_password') }}</h4>
@endif
</div>
<div class="inner"> <div class="inner">
<input type="hidden" name="token" value="{{{ $token }}}"> <input type="hidden" name="token" value="{{{ $token }}}">