mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-17 12:42:15 +01:00
Added email verified as requirement for non-local environments
This commit is contained in:
@@ -9,6 +9,7 @@ use App\Models\User;
|
|||||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
|
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
|
||||||
|
|
||||||
class UpdateUserProfileInformation implements UpdatesUserProfileInformation
|
class UpdateUserProfileInformation implements UpdatesUserProfileInformation
|
||||||
@@ -17,6 +18,8 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
|
|||||||
* Validate and update the given user's profile information.
|
* Validate and update the given user's profile information.
|
||||||
*
|
*
|
||||||
* @param array<string, mixed> $input
|
* @param array<string, mixed> $input
|
||||||
|
*
|
||||||
|
* @throws ValidationException
|
||||||
*/
|
*/
|
||||||
public function update(User $user, array $input): void
|
public function update(User $user, array $input): void
|
||||||
{
|
{
|
||||||
@@ -34,30 +37,21 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
|
|||||||
|
|
||||||
if ($input['email'] !== $user->email &&
|
if ($input['email'] !== $user->email &&
|
||||||
$user instanceof MustVerifyEmail) {
|
$user instanceof MustVerifyEmail) {
|
||||||
$this->updateVerifiedUser($user, $input);
|
|
||||||
} else {
|
|
||||||
$user->forceFill([
|
$user->forceFill([
|
||||||
'name' => $input['name'],
|
'name' => $input['name'],
|
||||||
'email' => $input['email'],
|
'email' => $input['email'],
|
||||||
|
'email_verified_at' => null,
|
||||||
|
'timezone' => $input['timezone'],
|
||||||
|
'week_start' => $input['week_start'],
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
$user->sendEmailVerificationNotification();
|
||||||
|
} else {
|
||||||
|
$user->forceFill([
|
||||||
|
'name' => $input['name'],
|
||||||
'timezone' => $input['timezone'],
|
'timezone' => $input['timezone'],
|
||||||
'week_start' => $input['week_start'],
|
'week_start' => $input['week_start'],
|
||||||
])->save();
|
])->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the given verified user's profile information.
|
|
||||||
*
|
|
||||||
* @param array<string, string> $input
|
|
||||||
*/
|
|
||||||
protected function updateVerifiedUser(User $user, array $input): void
|
|
||||||
{
|
|
||||||
$user->forceFill([
|
|
||||||
'name' => $input['name'],
|
|
||||||
'email' => $input['email'],
|
|
||||||
'email_verified_at' => null,
|
|
||||||
])->save();
|
|
||||||
|
|
||||||
$user->sendEmailVerificationNotification();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,6 @@ class Kernel extends HttpKernel
|
|||||||
'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
|
'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
|
||||||
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
'verified' => \App\Http\Middleware\EnsureEmailIsVerified::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
33
app/Http/Middleware/EnsureEmailIsVerified.php
Normal file
33
app/Http/Middleware/EnsureEmailIsVerified.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Redirect;
|
||||||
|
use Illuminate\Support\Facades\URL;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class EnsureEmailIsVerified
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next, ?string $redirectToRoute = null): Response
|
||||||
|
{
|
||||||
|
if (! app()->isLocal()) {
|
||||||
|
if ($request->user() === null ||
|
||||||
|
($request->user() instanceof MustVerifyEmail &&
|
||||||
|
! $request->user()->hasVerifiedEmail())) {
|
||||||
|
return $request->expectsJson()
|
||||||
|
? abort(403, 'Your email address is not verified.')
|
||||||
|
: Redirect::guest(URL::route($redirectToRoute ?: 'verification.notice'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ use App\Enums\Weekday;
|
|||||||
use Database\Factories\UserFactory;
|
use Database\Factories\UserFactory;
|
||||||
use Filament\Models\Contracts\FilamentUser;
|
use Filament\Models\Contracts\FilamentUser;
|
||||||
use Filament\Panel;
|
use Filament\Panel;
|
||||||
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||||
@@ -40,7 +41,7 @@ use Laravel\Passport\HasApiTokens;
|
|||||||
* @method Builder<User> belongsToOrganization(Organization $organization)
|
* @method Builder<User> belongsToOrganization(Organization $organization)
|
||||||
* @method Builder<User> active()
|
* @method Builder<User> active()
|
||||||
*/
|
*/
|
||||||
class User extends Authenticatable implements FilamentUser
|
class User extends Authenticatable implements FilamentUser, MustVerifyEmail
|
||||||
{
|
{
|
||||||
use HasApiTokens;
|
use HasApiTokens;
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Unit\Middleware;
|
||||||
|
|
||||||
|
use App\Http\Middleware\EnsureEmailIsVerified;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use PHPUnit\Framework\Attributes\UsesClass;
|
||||||
|
|
||||||
|
#[CoversClass(EnsureEmailIsVerified::class)]
|
||||||
|
#[UsesClass(EnsureEmailIsVerified::class)]
|
||||||
|
class EnsureEmailIsVerifiedMiddlewareTest extends MiddlewareTestAbstract
|
||||||
|
{
|
||||||
|
private function createTestRoute(): string
|
||||||
|
{
|
||||||
|
return Route::get('/test-route', function () {
|
||||||
|
return 'test-response';
|
||||||
|
})->middleware(EnsureEmailIsVerified::class)->uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_guests_are_redirected_to_verification_notice_route(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$route = $this->createTestRoute();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->get($route);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertRedirect(route('verification.notice'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_users_with_unverified_email_are_redirected_to_verification_notice_route(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$user = User::factory()->unverified()->create();
|
||||||
|
$route = $this->createTestRoute();
|
||||||
|
$this->actingAs($user);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->get($route);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertRedirect(route('verification.notice'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_users_with_verified_email_can_access_route(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$route = $this->createTestRoute();
|
||||||
|
$this->actingAs($user);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->get($route);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_users_with_unverified_email_can_access_route_in_local_environment(): void
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
$user = User::factory()->unverified()->create();
|
||||||
|
$route = $this->createTestRoute();
|
||||||
|
$this->actingAs($user);
|
||||||
|
$this->app->detectEnvironment(fn () => 'local');
|
||||||
|
|
||||||
|
// Act
|
||||||
|
$response = $this->get($route);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
$response->assertOk();
|
||||||
|
}
|
||||||
|
}
|
||||||
13
tests/Unit/Middleware/MiddlewareTestAbstract.php
Normal file
13
tests/Unit/Middleware/MiddlewareTestAbstract.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Unit\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
abstract class MiddlewareTestAbstract extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user