diff --git a/app/Http/Controllers/Auth/AuthController.php b/app/Http/Controllers/Auth/AuthController.php index 98346b305..d533c8aeb 100644 --- a/app/Http/Controllers/Auth/AuthController.php +++ b/app/Http/Controllers/Auth/AuthController.php @@ -170,6 +170,18 @@ class AuthController extends Controller return view('auth/register-confirm'); } + /** + * View the confirmation email as a standard web page. + * @param $token + * @return \Illuminate\View\View + * @throws UserRegistrationException + */ + public function viewConfirmEmail($token) + { + $confirmation = $this->emailConfirmationService->getEmailConfirmationFromToken($token); + return view('emails/email-confirmation', ['token' => $confirmation->token]); + } + /** * Confirms an email via a token and logs the user into the system. * @param $token diff --git a/app/Http/routes.php b/app/Http/routes.php index 9681ad1f1..e605dbee1 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -94,6 +94,7 @@ Route::get('/register/confirm', 'Auth\AuthController@getRegisterConfirmation'); Route::get('/register/confirm/awaiting', 'Auth\AuthController@showAwaitingConfirmation'); Route::post('/register/confirm/resend', 'Auth\AuthController@resendConfirmation'); Route::get('/register/confirm/{token}', 'Auth\AuthController@confirmEmail'); +Route::get('/register/confirm/{token}/email', 'Auth\AuthController@viewConfirmEmail'); Route::get('/register/service/{socialDriver}', 'Auth\AuthController@socialRegister'); Route::post('/register', 'Auth\AuthController@postRegister'); diff --git a/app/User.php b/app/User.php index c7ce6b11e..ffe41229b 100644 --- a/app/User.php +++ b/app/User.php @@ -134,6 +134,10 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon return '//www.gravatar.com/avatar/' . $emailHash . '?s=' . $size . '&d=identicon'; } + /** + * Get the url for editing this user. + * @return string + */ public function getEditUrl() { return '/users/' . $this->id; diff --git a/config/mail.php b/config/mail.php index a45145309..0386e0198 100644 --- a/config/mail.php +++ b/config/mail.php @@ -119,6 +119,6 @@ return [ | */ - 'pretend' => false, + 'pretend' => env('MAIL_PRETEND', false), ]; diff --git a/phpunit.xml b/phpunit.xml index 59afb8613..0884937af 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -25,5 +25,6 @@ + diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index b981c64d8..2c3c6079f 100644 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -42,7 +42,7 @@
- @if($currentUser->id === $user->id) + @if($currentUser->id === $user->id && count($activeSocialDrivers) > 0)

Social Accounts

Here you can connect your other accounts for quicker and easier login.
diff --git a/tests/AuthTest.php b/tests/AuthTest.php index 343823687..99f132d3b 100644 --- a/tests/AuthTest.php +++ b/tests/AuthTest.php @@ -1,5 +1,7 @@ visit('/') - ->seePageIs('/login') - ->type('admin@admin.com', '#email') - ->type('password', '#password') - ->press('Sign In') + ->seePageIs('/login'); + + $this->login('admin@admin.com', 'password') ->seePageIs('/') ->see('BookStack'); } @@ -41,9 +42,11 @@ class AuthTest extends TestCase public function testNormalRegistration() { + // Set settings and get user instance $this->setSettings(['registration-enabled' => 'true']); $user = factory(\BookStack\User::class)->make(); + // Test form and ensure user is created $this->visit('/register') ->see('Sign Up') ->type($user->name, '#name') @@ -51,15 +54,52 @@ class AuthTest extends TestCase ->type($user->password, '#password') ->press('Create Account') ->seePageIs('/') - ->see($user->name); + ->see($user->name) + ->seeInDatabase('users', ['name' => $user->name, 'email' => $user->email]); } - private function setSettings($settingsArray) + public function testConfirmedRegistration() { - $settings = app('BookStack\Services\SettingService'); - foreach($settingsArray as $key => $value) { - $settings->put($key, $value); - } + // Set settings and get user instance + $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']); + $user = factory(\BookStack\User::class)->make(); + + // Mock Mailer to ensure mail is being sent + $mockMailer = Mockery::mock('Illuminate\Contracts\Mail\Mailer'); + $mockMailer->shouldReceive('send')->with('emails/email-confirmation', Mockery::type('array'), Mockery::type('callable'))->twice(); + $this->app->instance('mailer', $mockMailer); + + // Go through registration process + $this->visit('/register') + ->see('Sign Up') + ->type($user->name, '#name') + ->type($user->email, '#email') + ->type($user->password, '#password') + ->press('Create Account') + ->seePageIs('/register/confirm') + ->seeInDatabase('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => false]); + + // Test access and resend confirmation email + $this->login($user->email, $user->password) + ->seePageIs('/register/confirm/awaiting') + ->see('Resend') + ->visit('/books') + ->seePageIs('/register/confirm/awaiting') + ->press('Resend Confirmation Email'); + + // Get confirmation + $user = $user->where('email', '=', $user->email)->first(); + $emailConfirmation = EmailConfirmation::where('user_id', '=', $user->id)->first(); + + + // Check confirmation email button and confirmation activation. + $this->visit('/register/confirm/' . $emailConfirmation->token . '/email') + ->see('Email Confirmation') + ->click('Confirm Email') + ->seePageIs('/') + ->see($user->name) + ->notSeeInDatabase('email_confirmations', ['token' => $emailConfirmation->token]) + ->seeInDatabase('users', ['name' => $user->name, 'email' => $user->email, 'email_confirmed' => true]); } public function testLogout() @@ -71,4 +111,30 @@ class AuthTest extends TestCase ->visit('/') ->seePageIs('/login'); } + + /** + * Quickly sets an array of settings. + * @param $settingsArray + */ + private function setSettings($settingsArray) + { + $settings = app('BookStack\Services\SettingService'); + foreach ($settingsArray as $key => $value) { + $settings->put($key, $value); + } + } + + /** + * Perform a login + * @param string $email + * @param string $password + * @return $this + */ + private function login($email, $password) + { + return $this->visit('/login') + ->type($email, '#email') + ->type($password, '#password') + ->press('Sign In'); + } }