Skip to content

Commit

Permalink
Merge branch '10.5'
Browse files Browse the repository at this point in the history
  • Loading branch information
crynobone committed Jun 26, 2024
2 parents e86f5b0 + ddcf0c8 commit 20a2458
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 88 deletions.
7 changes: 6 additions & 1 deletion app/Providers/NovaServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules\Password;
use Laravel\Fortify\Features;
use Laravel\Nova\Events\ServingNova;
use Laravel\Nova\Events\StartedImpersonating;
use Laravel\Nova\Events\StoppedImpersonating;
Expand Down Expand Up @@ -236,9 +237,13 @@ public function registerFieldMacros()
protected function routes()
{
Nova::routes()
->withFortifyFeatures([
Features::emailVerification(),
Features::twoFactorAuthentication(['confirm' => true, 'confirmPassword' => true]),
])
->withAuthenticationRoutes()
->withPasswordResetRoutes()
->register();
->register(fortify: false);
}

/**
Expand Down
26 changes: 26 additions & 0 deletions app/Providers/NovaWithoutAuthenticationServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace App\Providers;

use Laravel\Nova\Nova;

class NovaWithoutAuthenticationServiceProvider extends NovaServiceProvider
{
/**
* Register the Nova routes.
*
* @return void
*/
protected function routes()
{
config([
'nova.routes.login' => '/login',
'nova.routes.logout' => '/logout',
]);

Nova::routes()
->withoutAuthenticationRoutes()
->withPasswordResetRoutes()
->register(fortify: false);
}
}
1 change: 1 addition & 0 deletions config/nova.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
'nova',
Authenticate::class,
Authorize::class,
// 'nova.verified',
],

/*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Laravel\Fortify\Fortify;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->text('two_factor_secret')
->after('password')
->nullable();

$table->text('two_factor_recovery_codes')
->after('two_factor_secret')
->nullable();

if (Fortify::confirmsTwoFactorAuthentication()) {
$table->timestamp('two_factor_confirmed_at')
->after('two_factor_recovery_codes')
->nullable();
}
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(array_merge([
'two_factor_secret',
'two_factor_recovery_codes',
], Fortify::confirmsTwoFactorAuthentication() ? [
'two_factor_confirmed_at',
] : []));
});
}
};
7 changes: 7 additions & 0 deletions lang/vendor/nova/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@
"Reset Password": "Reset Password",
"Sorry! You are not authorized to perform this action.": "Sorry! You are not authorized to perform this action.",
"You are receiving this email because we received a password reset request for your account.": "You are receiving this email because we received a password reset request for your account.",
"Before continuing, could you verify your email address by clicking on the link we just emailed to you? If you didn't receive the email, we will gladly send you another.": "Before continuing, could you verify your email address by clicking on the link we just emailed to you? If you didn't receive the email, we will gladly send you another.",
"A new verification link has been sent to the email address you provided in your profile settings.": "A new verification link has been sent to the email address you provided in your profile settings.",
"This is a secure area of the application. Please confirm your password before continuing.": "This is a secure area of the application. Please confirm your password before continuing.",
"Error": "Error",
"Confirm Password": "Confirm Password",
"We have emailed your password reset link!": "We have emailed your password reset link!",
"Dashboard": "Dashboard",
"Email Address": "Email Address",
"Username": "Username",
"Forgot Password": "Forgot Password",
"Forgot your password?": "Forgot your password?",
"Log In": "Log In",
"Logout": "Logout",
"Password": "Password",
"Remember me": "Remember me",
"Email Verification": "Email Verification",
"Secure Area": "Secure Area",
"Resources": "Resources",
"Send Password Reset Link": "Send Password Reset Link",
"Welcome Back!": "Welcome Back!",
Expand All @@ -32,6 +38,7 @@
"Restore": "Restore",
"Force Delete Resource": "Force Delete Resource",
"Force Delete": "Force Delete",
"Confirm": "Confirm",
"Are you sure you want to delete this resource?": "Are you sure you want to delete this resource?",
"Are you sure you want to delete the selected resources?": "Are you sure you want to delete the selected resources?",
"Are you sure you want to detach this resource?": "Are you sure you want to detach this resource?",
Expand Down
25 changes: 4 additions & 21 deletions tests/Browser/AuthenticatesUserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

namespace Laravel\Nova\Tests\Browser;

use Database\Factories\UserFactory;
use Laravel\Dusk\Browser;
use Laravel\Nova\Nova;
use Laravel\Nova\Testing\Browser\Components\SidebarComponent;
use Laravel\Nova\Testing\Browser\Pages\Dashboard;
use Laravel\Nova\Testing\Browser\Pages\Login;
use Laravel\Nova\Tests\DuskTestCase;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;

#[Group('auth')]
class AuthenticatesUserTest extends DuskTestCase
{
#[DataProvider('intendedUrlDataProvider')]
Expand All @@ -24,7 +25,8 @@ public function test_it_redirect_to_intended_url_after_login($targetUrl, $expect
->type('email', '[email protected]')
->type('password', 'password')
->clickAndWaitForReload('button[type="submit"]')
->assertPathIs(Nova::url($expectedUrl));
->assertPathIs(Nova::url($expectedUrl))
->assertAuthenticated();

$browser->blank();
});
Expand Down Expand Up @@ -112,25 +114,6 @@ public function test_redirect_outside_of_nova_after_login()
});
}

public function test_it_redirect_to_login_after_password_reset()
{
$this->browse(function (Browser $browser) {
$user = UserFactory::new()->create();

$browser->logout()
->assertGuest()
->visit(Nova::url('password/reset'))
->waitForText('Forgot your password?')
->type('input[id="email"]', $user->email)
->click('button[type="submit"]')
->waitForText(__('passwords.sent'))
->pause(5000)
->waitForLocation(Nova::url('login'));

$browser->blank();
});
}

public static function intendedUrlDataProvider()
{
yield ['/resources/users/3', '/resources/users/3'];
Expand Down
78 changes: 17 additions & 61 deletions tests/Browser/CustomAuthenticatesUserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

namespace Laravel\Nova\Tests\Browser;

use Database\Factories\UserFactory;
use App\Providers\NovaServiceProvider;
use App\Providers\NovaWithoutAuthenticationServiceProvider;
use Laravel\Dusk\Browser;
use Laravel\Nova\Nova;
use Laravel\Nova\Testing\Browser\Components\SidebarComponent;
Expand All @@ -11,19 +12,27 @@
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;

#[Group('auth')]
#[Group('internal-server')]
class CustomAuthenticatesUserTest extends DuskTestCase
{
/**
* Get package providers.
*
* @param \Illuminate\Foundation\Application $app
* @return array<int, class-string>
*/
protected function getPackageProviders($app)
{
return collect(parent::getPackageProviders($app))
->replace([
NovaServiceProvider::class => NovaWithoutAuthenticationServiceProvider::class,
])->all();
}

#[DataProvider('intendedUrlDataProvider')]
public function test_it_redirect_to_intended_url_after_login($targetUrl, $expectedUrl)
{
$this->beforeServingApplication(function ($app, $config) {
$config->set('nova.routes.login', '/login');
$config->set('nova.routes.logout', '/logout');

Nova::$withAuthentication = false;
});

$this->browse(function (Browser $browser) use ($targetUrl, $expectedUrl) {
$browser->logout()
->assertGuest()
Expand All @@ -40,13 +49,6 @@ public function test_it_redirect_to_intended_url_after_login($targetUrl, $expect

public function test_it_redirect_to_login_after_logout()
{
$this->beforeServingApplication(function ($app, $config) {
$config->set('nova.routes.login', '/login');
$config->set('nova.routes.logout', '/logout');

Nova::$withAuthentication = false;
});

$this->browse(function (Browser $browser) {
$browser->loginAs(1)
->visit(new Dashboard())
Expand All @@ -64,13 +66,6 @@ public function test_it_redirect_to_login_after_logout()

public function test_it_clear_user_association_after_logout()
{
$this->beforeServingApplication(function ($app, $config) {
$config->set('nova.routes.login', '/login');
$config->set('nova.routes.logout', '/logout');

Nova::$withAuthentication = false;
});

$this->browse(function (Browser $browser) {
$browser->loginAs(1)
->visit(new Dashboard())
Expand All @@ -85,13 +80,6 @@ public function test_it_clear_user_association_after_logout()

public function test_it_clear_user_association_after_session_timeout()
{
$this->beforeServingApplication(function ($app, $config) {
$config->set('nova.routes.login', '/login');
$config->set('nova.routes.logout', '/logout');

Nova::$withAuthentication = false;
});

$this->browse(function (Browser $browser) {
$browser->loginAs(1)->visit(new Dashboard());

Expand All @@ -108,13 +96,6 @@ public function test_it_clear_user_association_after_session_timeout()

public function test_it_can_relogin_after_session_timeout()
{
$this->beforeServingApplication(function ($app, $config) {
$config->set('nova.routes.login', '/login');
$config->set('nova.routes.logout', '/logout');

Nova::$withAuthentication = false;
});

$this->browse(function (Browser $browser) {
$browser->loginAs(1)->visit(new Dashboard());

Expand All @@ -131,31 +112,6 @@ public function test_it_can_relogin_after_session_timeout()
});
}

public function test_it_redirect_to_login_after_password_reset()
{
$this->beforeServingApplication(function ($app, $config) {
$config->set('mail.default', 'log');
$config->set('nova.routes.login', '/login');
$config->set('nova.routes.logout', '/logout');

Nova::$withAuthentication = false;
});

$this->browse(function (Browser $browser) {
$user = UserFactory::new()->create();

$browser->logout()
->assertGuest()
->visit(Nova::url('password/reset'))
->waitForText('Forgot your password?')
->type('input[id="email"]', $user->email)
->clickAndWaitForReload('button[type="submit"]', 40)
->assertPathIs('/login');

$browser->blank();
});
}

public static function intendedUrlDataProvider()
{
yield ['/resources/users/3', '/resources/users/3'];
Expand Down
52 changes: 52 additions & 0 deletions tests/Browser/CustomForgotUserPasswordTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace Laravel\Nova\Tests\Browser;

use App\Providers\NovaServiceProvider;
use App\Providers\NovaWithoutAuthenticationServiceProvider;
use Database\Factories\UserFactory;
use Laravel\Dusk\Browser;
use Laravel\Nova\Nova;
use Laravel\Nova\Tests\DuskTestCase;
use Orchestra\Testbench\Attributes\WithConfig;
use PHPUnit\Framework\Attributes\Group;

#[Group('auth')]
#[WithConfig('mail.default', 'log')]
class CustomForgotUserPasswordTest extends DuskTestCase
{
/**
* Get package providers.
*
* @param \Illuminate\Foundation\Application $app
* @return array<int, class-string>
*/
protected function getPackageProviders($app)
{
return collect(parent::getPackageProviders($app))
->replace([
NovaServiceProvider::class => NovaWithoutAuthenticationServiceProvider::class,
])->all();
}

public function test_it_redirect_to_login_after_password_reset()
{
$this->beforeServingApplication(function ($app, $config) {
$config->set('mail.default', 'log');
});

$this->browse(function (Browser $browser) {
$user = UserFactory::new()->create();

$browser->logout()
->assertGuest()
->visit(Nova::url('password/reset'))
->waitForText('Forgot your password?')
->type('input[id="email"]', $user->email)
->clickAndWaitForReload('button[type="submit"]', 40)
->assertPathIs('/login');

$browser->blank();
});
}
}
Loading

0 comments on commit 20a2458

Please sign in to comment.