mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-11-25 09:42:10 +08:00
Auth: Changed email confirmations to use login attempt user
Negates the need for a public confirmation resend form since we can instead just send direct to the last session login attempter.
This commit is contained in:
parent
69af9e0dbd
commit
d133f904d3
|
@ -32,13 +32,17 @@ class ConfirmEmailController extends Controller
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a notice that a user's email address has not been confirmed,
|
* Shows a notice that a user's email address has not been confirmed,
|
||||||
* Also has the option to re-send the confirmation email.
|
* along with the option to re-send the confirmation email.
|
||||||
*/
|
*/
|
||||||
public function showAwaiting()
|
public function showAwaiting()
|
||||||
{
|
{
|
||||||
$user = $this->loginService->getLastLoginAttemptUser();
|
$user = $this->loginService->getLastLoginAttemptUser();
|
||||||
|
if ($user === null) {
|
||||||
|
$this->showErrorNotification(trans('errors.login_user_not_found'));
|
||||||
|
return redirect('/login');
|
||||||
|
}
|
||||||
|
|
||||||
return view('auth.user-unconfirmed', ['user' => $user]);
|
return view('auth.register-confirm-awaiting');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,19 +94,24 @@ class ConfirmEmailController extends Controller
|
||||||
/**
|
/**
|
||||||
* Resend the confirmation email.
|
* Resend the confirmation email.
|
||||||
*/
|
*/
|
||||||
public function resend(Request $request)
|
public function resend()
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$user = $this->loginService->getLastLoginAttemptUser();
|
||||||
'email' => ['required', 'email', 'exists:users,email'],
|
if ($user === null) {
|
||||||
]);
|
$this->showErrorNotification(trans('errors.login_user_not_found'));
|
||||||
$user = $this->userRepo->getByEmail($request->get('email'));
|
return redirect('/login');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->emailConfirmationService->sendConfirmation($user);
|
$this->emailConfirmationService->sendConfirmation($user);
|
||||||
|
} catch (ConfirmationEmailException $e) {
|
||||||
|
$this->showErrorNotification($e->getMessage());
|
||||||
|
|
||||||
|
return redirect('/login');
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->showErrorNotification(trans('auth.email_confirm_send_error'));
|
$this->showErrorNotification(trans('auth.email_confirm_send_error'));
|
||||||
|
|
||||||
return redirect('/register/confirm');
|
return redirect('/register/awaiting');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->showSuccessNotification(trans('auth.email_confirm_resent'));
|
$this->showSuccessNotification(trans('auth.email_confirm_resent'));
|
||||||
|
|
|
@ -17,7 +17,7 @@ trait HandlesPartialLogins
|
||||||
$user = auth()->user() ?? $loginService->getLastLoginAttemptUser();
|
$user = auth()->user() ?? $loginService->getLastLoginAttemptUser();
|
||||||
|
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
throw new NotFoundException('A user for this action could not be found');
|
throw new NotFoundException(trans('errors.login_user_not_found'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $user;
|
return $user;
|
||||||
|
|
|
@ -17,7 +17,7 @@ class EmailConfirmationService extends UserTokenService
|
||||||
*
|
*
|
||||||
* @throws ConfirmationEmailException
|
* @throws ConfirmationEmailException
|
||||||
*/
|
*/
|
||||||
public function sendConfirmation(User $user)
|
public function sendConfirmation(User $user): void
|
||||||
{
|
{
|
||||||
if ($user->email_confirmed) {
|
if ($user->email_confirmed) {
|
||||||
throw new ConfirmationEmailException(trans('errors.email_already_confirmed'), '/login');
|
throw new ConfirmationEmailException(trans('errors.email_already_confirmed'), '/login');
|
||||||
|
|
|
@ -9,16 +9,10 @@ use Illuminate\Http\Request;
|
||||||
|
|
||||||
class StoppedAuthenticationException extends \Exception implements Responsable
|
class StoppedAuthenticationException extends \Exception implements Responsable
|
||||||
{
|
{
|
||||||
protected $user;
|
public function __construct(
|
||||||
protected $loginService;
|
protected User $user,
|
||||||
|
protected LoginService $loginService
|
||||||
/**
|
) {
|
||||||
* StoppedAuthenticationException constructor.
|
|
||||||
*/
|
|
||||||
public function __construct(User $user, LoginService $loginService)
|
|
||||||
{
|
|
||||||
$this->user = $user;
|
|
||||||
$this->loginService = $loginService;
|
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ return [
|
||||||
'social_driver_not_found' => 'Social driver not found',
|
'social_driver_not_found' => 'Social driver not found',
|
||||||
'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.',
|
'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.',
|
||||||
'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.',
|
'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.',
|
||||||
|
'login_user_not_found' => 'A user for this action could not be found.',
|
||||||
|
|
||||||
// System
|
// System
|
||||||
'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.',
|
'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.',
|
||||||
|
|
|
@ -14,15 +14,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form action="{{ url("/register/confirm/resend") }}" method="POST" class="stretch-inputs">
|
<form action="{{ url("/register/confirm/resend") }}" method="POST" class="stretch-inputs">
|
||||||
{!! csrf_field() !!}
|
{{ csrf_field() }}
|
||||||
<div class="form-group">
|
|
||||||
<label for="email">{{ trans('auth.email') }}</label>
|
|
||||||
@if($user)
|
|
||||||
@include('form.text', ['name' => 'email', 'model' => $user])
|
|
||||||
@else
|
|
||||||
@include('form.text', ['name' => 'email'])
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
<div class="form-group text-right mt-m">
|
<div class="form-group text-right mt-m">
|
||||||
<button type="submit" class="button">{{ trans('auth.email_not_confirmed_resend_button') }}</button>
|
<button type="submit" class="button">{{ trans('auth.email_not_confirmed_resend_button') }}</button>
|
||||||
</div>
|
</div>
|
|
@ -25,6 +25,9 @@ class RegistrationTest extends TestCase
|
||||||
$resp->assertRedirect('/register/confirm');
|
$resp->assertRedirect('/register/confirm');
|
||||||
$this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
|
$this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
|
||||||
|
|
||||||
|
$resp = $this->get('/register/confirm');
|
||||||
|
$resp->assertSee('Thanks for registering!');
|
||||||
|
|
||||||
// Ensure notification sent
|
// Ensure notification sent
|
||||||
/** @var User $dbUser */
|
/** @var User $dbUser */
|
||||||
$dbUser = User::query()->where('email', '=', $user->email)->first();
|
$dbUser = User::query()->where('email', '=', $user->email)->first();
|
||||||
|
@ -232,4 +235,59 @@ class RegistrationTest extends TestCase
|
||||||
|
|
||||||
$response->assertStatus(429);
|
$response->assertStatus(429);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_registration_confirmation_resend()
|
||||||
|
{
|
||||||
|
Notification::fake();
|
||||||
|
$this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
|
||||||
|
$user = User::factory()->make();
|
||||||
|
|
||||||
|
$resp = $this->post('/register', $user->only('name', 'email', 'password'));
|
||||||
|
$resp->assertRedirect('/register/confirm');
|
||||||
|
$dbUser = User::query()->where('email', '=', $user->email)->first();
|
||||||
|
|
||||||
|
$resp = $this->post('/login', ['email' => $user->email, 'password' => $user->password]);
|
||||||
|
$resp->assertRedirect('/register/confirm/awaiting');
|
||||||
|
|
||||||
|
$resp = $this->post('/register/confirm/resend');
|
||||||
|
$resp->assertRedirect('/register/confirm');
|
||||||
|
Notification::assertSentToTimes($dbUser, ConfirmEmailNotification::class, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_registration_confirmation_expired_resend()
|
||||||
|
{
|
||||||
|
Notification::fake();
|
||||||
|
$this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
|
||||||
|
$user = User::factory()->make();
|
||||||
|
|
||||||
|
$resp = $this->post('/register', $user->only('name', 'email', 'password'));
|
||||||
|
$resp->assertRedirect('/register/confirm');
|
||||||
|
$dbUser = User::query()->where('email', '=', $user->email)->first();
|
||||||
|
|
||||||
|
$resp = $this->post('/login', ['email' => $user->email, 'password' => $user->password]);
|
||||||
|
$resp->assertRedirect('/register/confirm/awaiting');
|
||||||
|
|
||||||
|
$emailConfirmation = DB::table('email_confirmations')->where('user_id', '=', $dbUser->id)->first();
|
||||||
|
$this->travel(2)->days();
|
||||||
|
|
||||||
|
$resp = $this->post("/register/confirm/accept", [
|
||||||
|
'token' => $emailConfirmation->token,
|
||||||
|
]);
|
||||||
|
$resp->assertRedirect('/register/confirm');
|
||||||
|
$this->assertSessionError('The confirmation token has expired, A new confirmation email has been sent.');
|
||||||
|
|
||||||
|
Notification::assertSentToTimes($dbUser, ConfirmEmailNotification::class, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_registration_confirmation_awaiting_and_resend_returns_to_log_if_no_login_attempt_user_found()
|
||||||
|
{
|
||||||
|
$this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
|
||||||
|
|
||||||
|
$this->get('/register/confirm/awaiting')->assertRedirect('/login');
|
||||||
|
$this->assertSessionError('A user for this action could not be found.');
|
||||||
|
$this->flushSession();
|
||||||
|
|
||||||
|
$this->post('/register/confirm/resend')->assertRedirect('/login');
|
||||||
|
$this->assertSessionError('A user for this action could not be found.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user