Skip to content

Commit d133f90

Browse files
committed
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.
1 parent 69af9e0 commit d133f90

File tree

7 files changed

+83
-29
lines changed

7 files changed

+83
-29
lines changed

app/Access/Controllers/ConfirmEmailController.php

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,17 @@ public function show()
3232

3333
/**
3434
* Shows a notice that a user's email address has not been confirmed,
35-
* Also has the option to re-send the confirmation email.
35+
* along with the option to re-send the confirmation email.
3636
*/
3737
public function showAwaiting()
3838
{
3939
$user = $this->loginService->getLastLoginAttemptUser();
40+
if ($user === null) {
41+
$this->showErrorNotification(trans('errors.login_user_not_found'));
42+
return redirect('/login');
43+
}
4044

41-
return view('auth.user-unconfirmed', ['user' => $user]);
45+
return view('auth.register-confirm-awaiting');
4246
}
4347

4448
/**
@@ -90,19 +94,24 @@ public function confirm(Request $request)
9094
/**
9195
* Resend the confirmation email.
9296
*/
93-
public function resend(Request $request)
97+
public function resend()
9498
{
95-
$this->validate($request, [
96-
'email' => ['required', 'email', 'exists:users,email'],
97-
]);
98-
$user = $this->userRepo->getByEmail($request->get('email'));
99+
$user = $this->loginService->getLastLoginAttemptUser();
100+
if ($user === null) {
101+
$this->showErrorNotification(trans('errors.login_user_not_found'));
102+
return redirect('/login');
103+
}
99104

100105
try {
101106
$this->emailConfirmationService->sendConfirmation($user);
107+
} catch (ConfirmationEmailException $e) {
108+
$this->showErrorNotification($e->getMessage());
109+
110+
return redirect('/login');
102111
} catch (Exception $e) {
103112
$this->showErrorNotification(trans('auth.email_confirm_send_error'));
104113

105-
return redirect('/register/confirm');
114+
return redirect('/register/awaiting');
106115
}
107116

108117
$this->showSuccessNotification(trans('auth.email_confirm_resent'));

app/Access/Controllers/HandlesPartialLogins.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ protected function currentOrLastAttemptedUser(): User
1717
$user = auth()->user() ?? $loginService->getLastLoginAttemptUser();
1818

1919
if (!$user) {
20-
throw new NotFoundException('A user for this action could not be found');
20+
throw new NotFoundException(trans('errors.login_user_not_found'));
2121
}
2222

2323
return $user;

app/Access/EmailConfirmationService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class EmailConfirmationService extends UserTokenService
1717
*
1818
* @throws ConfirmationEmailException
1919
*/
20-
public function sendConfirmation(User $user)
20+
public function sendConfirmation(User $user): void
2121
{
2222
if ($user->email_confirmed) {
2323
throw new ConfirmationEmailException(trans('errors.email_already_confirmed'), '/login');

app/Exceptions/StoppedAuthenticationException.php

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,10 @@
99

1010
class StoppedAuthenticationException extends \Exception implements Responsable
1111
{
12-
protected $user;
13-
protected $loginService;
14-
15-
/**
16-
* StoppedAuthenticationException constructor.
17-
*/
18-
public function __construct(User $user, LoginService $loginService)
19-
{
20-
$this->user = $user;
21-
$this->loginService = $loginService;
12+
public function __construct(
13+
protected User $user,
14+
protected LoginService $loginService
15+
) {
2216
parent::__construct();
2317
}
2418

lang/en/errors.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
'social_driver_not_found' => 'Social driver not found',
3838
'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.',
3939
'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.',
40+
'login_user_not_found' => 'A user for this action could not be found.',
4041

4142
// System
4243
'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.',

resources/views/auth/user-unconfirmed.blade.php renamed to resources/views/auth/register-confirm-awaiting.blade.php

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,7 @@
1414
</p>
1515

1616
<form action="{{ url("/register/confirm/resend") }}" method="POST" class="stretch-inputs">
17-
{!! csrf_field() !!}
18-
<div class="form-group">
19-
<label for="email">{{ trans('auth.email') }}</label>
20-
@if($user)
21-
@include('form.text', ['name' => 'email', 'model' => $user])
22-
@else
23-
@include('form.text', ['name' => 'email'])
24-
@endif
25-
</div>
17+
{{ csrf_field() }}
2618
<div class="form-group text-right mt-m">
2719
<button type="submit" class="button">{{ trans('auth.email_not_confirmed_resend_button') }}</button>
2820
</div>

tests/Auth/RegistrationTest.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ public function test_confirmed_registration()
2525
$resp->assertRedirect('/register/confirm');
2626
$this->assertDatabaseHas('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]);
2727

28+
$resp = $this->get('/register/confirm');
29+
$resp->assertSee('Thanks for registering!');
30+
2831
// Ensure notification sent
2932
/** @var User $dbUser */
3033
$dbUser = User::query()->where('email', '=', $user->email)->first();
@@ -232,4 +235,59 @@ public function test_registration_confirmation_throttled()
232235

233236
$response->assertStatus(429);
234237
}
238+
239+
public function test_registration_confirmation_resend()
240+
{
241+
Notification::fake();
242+
$this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
243+
$user = User::factory()->make();
244+
245+
$resp = $this->post('/register', $user->only('name', 'email', 'password'));
246+
$resp->assertRedirect('/register/confirm');
247+
$dbUser = User::query()->where('email', '=', $user->email)->first();
248+
249+
$resp = $this->post('/login', ['email' => $user->email, 'password' => $user->password]);
250+
$resp->assertRedirect('/register/confirm/awaiting');
251+
252+
$resp = $this->post('/register/confirm/resend');
253+
$resp->assertRedirect('/register/confirm');
254+
Notification::assertSentToTimes($dbUser, ConfirmEmailNotification::class, 2);
255+
}
256+
257+
public function test_registration_confirmation_expired_resend()
258+
{
259+
Notification::fake();
260+
$this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
261+
$user = User::factory()->make();
262+
263+
$resp = $this->post('/register', $user->only('name', 'email', 'password'));
264+
$resp->assertRedirect('/register/confirm');
265+
$dbUser = User::query()->where('email', '=', $user->email)->first();
266+
267+
$resp = $this->post('/login', ['email' => $user->email, 'password' => $user->password]);
268+
$resp->assertRedirect('/register/confirm/awaiting');
269+
270+
$emailConfirmation = DB::table('email_confirmations')->where('user_id', '=', $dbUser->id)->first();
271+
$this->travel(2)->days();
272+
273+
$resp = $this->post("/register/confirm/accept", [
274+
'token' => $emailConfirmation->token,
275+
]);
276+
$resp->assertRedirect('/register/confirm');
277+
$this->assertSessionError('The confirmation token has expired, A new confirmation email has been sent.');
278+
279+
Notification::assertSentToTimes($dbUser, ConfirmEmailNotification::class, 2);
280+
}
281+
282+
public function test_registration_confirmation_awaiting_and_resend_returns_to_log_if_no_login_attempt_user_found()
283+
{
284+
$this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']);
285+
286+
$this->get('/register/confirm/awaiting')->assertRedirect('/login');
287+
$this->assertSessionError('A user for this action could not be found.');
288+
$this->flushSession();
289+
290+
$this->post('/register/confirm/resend')->assertRedirect('/login');
291+
$this->assertSessionError('A user for this action could not be found.');
292+
}
235293
}

0 commit comments

Comments
 (0)