mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-31 12:34:35 -04:00
Finished - Client auth + password reset + mailables
This commit is contained in:
parent
7e4294fcc5
commit
f63803fe7b
@ -13,6 +13,8 @@ namespace App\Http\Controllers\Auth;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Password;
|
||||||
|
|
||||||
class ContactForgotPasswordController extends Controller
|
class ContactForgotPasswordController extends Controller
|
||||||
{
|
{
|
||||||
@ -36,11 +38,28 @@ class ContactForgotPasswordController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->middleware('guest');
|
$this->middleware('guest:contact');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the reset email form.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function showLinkRequestForm(){
|
||||||
|
return view('portal.default.auth.passwords.email',[
|
||||||
|
'title' => 'Client Password Reset',
|
||||||
|
'passwordEmailRoute' => 'client.password.email'
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function guard()
|
protected function guard()
|
||||||
{
|
{
|
||||||
return Auth::guard('contact');
|
return Auth::guard('contact');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function broker()
|
||||||
|
{
|
||||||
|
return Password::broker('contacts');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,9 @@ namespace App\Http\Controllers\Auth;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Password;
|
||||||
|
|
||||||
class ContactResetPasswordController extends Controller
|
class ContactResetPasswordController extends Controller
|
||||||
{
|
{
|
||||||
@ -34,7 +37,7 @@ class ContactResetPasswordController extends Controller
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $redirectTo = '/client';
|
protected $redirectTo = '/client/dashboard';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new controller instance.
|
* Create a new controller instance.
|
||||||
@ -43,11 +46,32 @@ class ContactResetPasswordController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->middleware('guest');
|
$this->middleware('guest:contact');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the password reset view for the given token.
|
||||||
|
*
|
||||||
|
* If no token is present, display the link request form.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param string|null $token
|
||||||
|
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||||
|
*/
|
||||||
|
public function showResetForm(Request $request, $token = null)
|
||||||
|
{
|
||||||
|
return view('portal.default.auth.passwords.reset')->with(
|
||||||
|
['token' => $token, 'email' => $request->email]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function guard()
|
protected function guard()
|
||||||
{
|
{
|
||||||
return Auth::guard('contact');
|
return Auth::guard('contact');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function broker()
|
||||||
|
{
|
||||||
|
return Password::broker('contacts');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ namespace App\Models;
|
|||||||
|
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Notifications\ClientContactResetPassword as ResetPasswordNotification;
|
||||||
|
use App\Notifications\ClientContactResetPassword;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Hashids\Hashids;
|
use Hashids\Hashids;
|
||||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
@ -89,4 +91,8 @@ class ClientContact extends Authenticatable
|
|||||||
return $this->belongsTo(User::class);
|
return $this->belongsTo(User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function sendPasswordResetNotification($token)
|
||||||
|
{
|
||||||
|
$this->notify(new ClientContactResetPassword($token));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"@coreui/coreui": "^2.1.12",
|
"@coreui/coreui": "^2.1.12",
|
||||||
"@coreui/icons": "^0.3.0",
|
"@coreui/icons": "^0.3.0",
|
||||||
"bootstrap": "^4.3.1",
|
"bootstrap": "^4.3.1",
|
||||||
|
"cross-env": "^5.2.0",
|
||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
"laravel-mix": "^4.1.2",
|
"laravel-mix": "^4.1.2",
|
||||||
"puppeteer": "^1.18.1"
|
"puppeteer": "^1.18.1"
|
||||||
|
@ -30,27 +30,6 @@
|
|||||||
<meta name="description" content="@yield('meta_description')"/>
|
<meta name="description" content="@yield('meta_description')"/>
|
||||||
<link href="{{ asset('favicon.png') }}" rel="shortcut icon" type="image/png">
|
<link href="{{ asset('favicon.png') }}" rel="shortcut icon" type="image/png">
|
||||||
|
|
||||||
<!--
|
|
||||||
TODO Setup social sharing info
|
|
||||||
<meta property="og:site_name" content="Invoice Ninja"/>
|
|
||||||
<meta property="og:url" content="{{ config('ninja.site_url') }}"/>
|
|
||||||
<meta property="og:title" content="Invoice Ninja"/>
|
|
||||||
<meta property="og:image" content="{{ config('ninja.site_url') }}/images/logo.png"/>
|
|
||||||
<meta property="og:description" content="Create. Send. Get Paid."/>
|
|
||||||
--/>
|
|
||||||
<!-- http://realfavicongenerator.net -->
|
|
||||||
<!--
|
|
||||||
TODO Setup favicon
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ url('apple-touch-icon.png') }}">
|
|
||||||
<link rel="icon" type="image/png" href="{{ url('favicon-32x32.png') }}" sizes="32x32">
|
|
||||||
<link rel="icon" type="image/png" href="{{ url('favicon-16x16.png') }}" sizes="16x16">
|
|
||||||
<link rel="manifest" href="{{ url('manifest.json') }}">
|
|
||||||
<link rel="mask-icon" href="{{ url('safari-pinned-tab.svg') }}" color="#3bc65c">
|
|
||||||
<link rel="shortcut icon" href="{{ url('favicon.ico') }}">
|
|
||||||
<meta name="apple-mobile-web-app-title" content="Invoice Ninja">
|
|
||||||
<meta name="application-name" content="Invoice Ninja">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
-->
|
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
@ -58,12 +37,10 @@
|
|||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.css">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
|
||||||
<link rel="canonical" href="{{ config('ninja.site_url') }}/{{ request()->path() }}"/>
|
<link rel="canonical" href="{{ config('ninja.site_url') }}/{{ request()->path() }}"/>
|
||||||
<link rel="stylesheet" href="{{ mix('/css/ninja.min.css') }}">
|
|
||||||
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
||||||
<script src=" {{ mix('/js/coreui.min.js') }}"></script>
|
|
||||||
<script defer src=" {{ mix('/js/ninja.min.js') }}"></script>
|
|
||||||
|
|
||||||
@yield('head')
|
@yield('head')
|
||||||
|
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
@extends('portal.default.layouts.guest')
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
<body class="app flex-row align-items-center">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card-group">
|
||||||
|
<div class="card p-4">
|
||||||
|
<div class="card-body">
|
||||||
|
@if (session('status'))
|
||||||
|
<div class="alert alert-success" role="alert">
|
||||||
|
{{ session('status') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<form method="POST" action="{{ route($passwordEmailRoute) }}">
|
||||||
|
@csrf
|
||||||
|
<h1>@lang('texts.password_recovery')</h1>
|
||||||
|
<p class="text-muted"></p>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">
|
||||||
|
<i class="icon-user"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ old('email') }}" placeholder="@lang('texts.email')" required autofocus>
|
||||||
|
|
||||||
|
@if ($errors->has('email'))
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $errors->first('email') }}</strong>
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<button class="btn btn-primary px-4" type="submit">@lang('texts.send_email')</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
|
@ -0,0 +1,71 @@
|
|||||||
|
@extends('portal.default.layouts.guest')
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
<body class="app flex-row align-items-center">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card-group">
|
||||||
|
<div class="card p-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="POST" action="{{ route('client.password.update') }}">
|
||||||
|
@csrf
|
||||||
|
<input type="hidden" name="token" value="{{ $token }}">
|
||||||
|
<h1>@lang('texts.change_password')</h1>
|
||||||
|
<p class="text-muted"></p>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">
|
||||||
|
<i class="icon-user"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ old('email') }}" placeholder="@lang('texts.email')" required autofocus>
|
||||||
|
|
||||||
|
@if ($errors->has('email'))
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $errors->first('email') }}</strong>
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-4">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">
|
||||||
|
<i class="icon-lock"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" placeholder="@lang('texts.password')" required>
|
||||||
|
|
||||||
|
@if ($errors->has('password'))
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $errors->first('password') }}</strong>
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-4">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">
|
||||||
|
<i class="icon-lock"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" placeholder="@lang('texts.confirm_password')" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<button class="btn btn-primary px-4" type="submit">@lang('texts.change_password')</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
@endsection
|
1
resources/views/vendor/mail/text/button.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/button.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{{ $slot }}: {{ $url }}
|
1
resources/views/vendor/mail/text/footer.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/footer.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{{ $slot }}
|
1
resources/views/vendor/mail/text/header.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/header.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{{ $slot }}]({{ $url }})
|
11
resources/views/vendor/mail/text/layout.blade.php
vendored
Normal file
11
resources/views/vendor/mail/text/layout.blade.php
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
@if(!is_array($header))
|
||||||
|
{!! strip_tags($header) !!}
|
||||||
|
@endisset
|
||||||
|
|
||||||
|
{!! strip_tags($slot) !!}
|
||||||
|
@isset($subcopy)
|
||||||
|
|
||||||
|
{!! strip_tags($subcopy) !!}
|
||||||
|
@endisset
|
||||||
|
|
||||||
|
{!! strip_tags($footer) !!}
|
27
resources/views/vendor/mail/text/message.blade.php
vendored
Normal file
27
resources/views/vendor/mail/text/message.blade.php
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
@component('mail::layout')
|
||||||
|
{{-- Header --}}
|
||||||
|
@slot('header')
|
||||||
|
@component('mail::header', ['url' => config('app.url')])
|
||||||
|
{{ config('app.name') }}
|
||||||
|
@endcomponent
|
||||||
|
@endslot
|
||||||
|
|
||||||
|
{{-- Body --}}
|
||||||
|
{{ $slot }}
|
||||||
|
|
||||||
|
{{-- Subcopy --}}
|
||||||
|
@isset($subcopy)
|
||||||
|
@slot('subcopy')
|
||||||
|
@component('mail::subcopy')
|
||||||
|
{{ $subcopy }}
|
||||||
|
@endcomponent
|
||||||
|
@endslot
|
||||||
|
@endisset
|
||||||
|
|
||||||
|
{{-- Footer --}}
|
||||||
|
@slot('footer')
|
||||||
|
@component('mail::footer')
|
||||||
|
© {{ date('Y') }} {{ config('app.name') }}. @lang('All rights reserved.')
|
||||||
|
@endcomponent
|
||||||
|
@endslot
|
||||||
|
@endcomponent
|
1
resources/views/vendor/mail/text/panel.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/panel.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{{ $slot }}
|
1
resources/views/vendor/mail/text/promotion.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/promotion.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{{ $slot }}
|
1
resources/views/vendor/mail/text/promotion/button.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/promotion/button.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{{ $slot }}]({{ $url }})
|
1
resources/views/vendor/mail/text/subcopy.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/subcopy.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{{ $slot }}
|
1
resources/views/vendor/mail/text/table.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/table.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{{ $slot }}
|
62
resources/views/vendor/notifications/email.blade.php
vendored
Normal file
62
resources/views/vendor/notifications/email.blade.php
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
@component('mail::message')
|
||||||
|
{{-- Greeting --}}
|
||||||
|
@if (! empty($greeting))
|
||||||
|
# {{ $greeting }}
|
||||||
|
@else
|
||||||
|
@if ($level === 'error')
|
||||||
|
# @lang('Whoops!')
|
||||||
|
@else
|
||||||
|
# @lang('Hello!')
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
|
||||||
|
{{-- Intro Lines --}}
|
||||||
|
@foreach ($introLines as $line)
|
||||||
|
{{ $line }}
|
||||||
|
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
{{-- Action Button --}}
|
||||||
|
@isset($actionText)
|
||||||
|
<?php
|
||||||
|
switch ($level) {
|
||||||
|
case 'success':
|
||||||
|
case 'error':
|
||||||
|
$color = $level;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$color = 'primary';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
@component('mail::button', ['url' => $actionUrl, 'color' => $color])
|
||||||
|
{{ $actionText }}
|
||||||
|
@endcomponent
|
||||||
|
@endisset
|
||||||
|
|
||||||
|
{{-- Outro Lines --}}
|
||||||
|
@foreach ($outroLines as $line)
|
||||||
|
{{ $line }}
|
||||||
|
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
{{-- Salutation --}}
|
||||||
|
@if (! empty($salutation))
|
||||||
|
{{ $salutation }}
|
||||||
|
@else
|
||||||
|
@lang('Regards'),<br>{{ config('app.name') }}
|
||||||
|
@endif
|
||||||
|
|
||||||
|
{{-- Subcopy --}}
|
||||||
|
@isset($actionText)
|
||||||
|
@slot('subcopy')
|
||||||
|
@lang(
|
||||||
|
"If you’re having trouble clicking the \":actionText\" button, copy and paste the URL below\n".
|
||||||
|
'into your web browser: [:actionURL](:actionURL)',
|
||||||
|
[
|
||||||
|
'actionText' => $actionText,
|
||||||
|
'actionURL' => $actionUrl,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
@endslot
|
||||||
|
@endisset
|
||||||
|
@endcomponent
|
Loading…
x
Reference in New Issue
Block a user