-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Disable Signups for new users #7254
base: main
Are you sure you want to change the base?
Changes from all commits
b4d79c5
74854ee
5be941b
bdd4a66
9fe936f
e9a4521
3bdd89d
500aaf7
adbadab
5776ba8
889dab6
1aba912
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Helpers; | ||
|
||
use App\Models\Account; | ||
use Illuminate\Contracts\Config\Repository as Config; | ||
|
||
class SignupHelper | ||
{ | ||
public function __construct( | ||
protected Config $config | ||
) { | ||
} | ||
|
||
public function isEnabled(): bool | ||
{ | ||
return ! ($this->isDisabledByConfig() && $this->hasAtLeastOneAccount()); | ||
} | ||
|
||
protected function isDisabledByConfig(): bool | ||
{ | ||
return (bool) $this->config->get('monica.disable_signup'); | ||
} | ||
|
||
protected function hasAtLeastOneAccount(): bool | ||
{ | ||
return ! empty(Account::first()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2,6 +2,7 @@ | |||||
|
||||||
namespace App\Http\Controllers\Auth; | ||||||
|
||||||
use App\Helpers\SignupHelper; | ||||||
use App\Helpers\WallpaperHelper; | ||||||
use App\Http\Controllers\Controller; | ||||||
use App\Models\User; | ||||||
|
@@ -14,6 +15,11 @@ | |||||
|
||||||
class LoginController extends Controller | ||||||
{ | ||||||
public function __construct( | ||||||
protected SignupHelper $signupHelper | ||||||
) { | ||||||
} | ||||||
|
||||||
/** | ||||||
* Display the login view. | ||||||
*/ | ||||||
|
@@ -40,6 +46,7 @@ public function __invoke(Request $request): Response | |||||
} | ||||||
|
||||||
return Inertia::render('Auth/Login', $data + [ | ||||||
'isSignupEnabled' => $this->signupHelper->isEnabled(), | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should fix it
Suggested change
|
||||||
'canResetPassword' => Route::has('password.request'), | ||||||
'status' => session('status'), | ||||||
'wallpaperUrl' => WallpaperHelper::getRandomWallpaper(), | ||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,25 @@ | ||||||||||||||||||||||||
<?php | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
declare(strict_types=1); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
namespace App\Http\Middleware; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
use App\Helpers\SignupHelper; | ||||||||||||||||||||||||
use Closure; | ||||||||||||||||||||||||
use Illuminate\Http\Request; | ||||||||||||||||||||||||
use Symfony\Component\HttpFoundation\Response; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
class EnsureSignupIsEnabled | ||||||||||||||||||||||||
{ | ||||||||||||||||||||||||
public function __construct( | ||||||||||||||||||||||||
protected SignupHelper $signupHelper, | ||||||||||||||||||||||||
) { | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
public function handle(Request $request, Closure $next): Response | ||||||||||||||||||||||||
{ | ||||||||||||||||||||||||
abort_if(! $this->signupHelper->isEnabled(), 403, trans('Registration is currently disabled')); | ||||||||||||||||||||||||
Comment on lines
+14
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
return $next($request); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -1,47 +1,68 @@ | ||||||||
<?php | ||||||||
|
||||||||
declare(strict_types=1); | ||||||||
|
||||||||
namespace Tests\Feature\Auth; | ||||||||
|
||||||||
use App\Helpers\SignupHelper; | ||||||||
use Illuminate\Foundation\Testing\DatabaseTransactions; | ||||||||
use Laravel\Fortify\Features; | ||||||||
use Illuminate\Http\Response; | ||||||||
use Laravel\Jetstream\Jetstream; | ||||||||
use PHPUnit\Framework\Attributes\Test; | ||||||||
use Mockery; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
use Tests\TestCase; | ||||||||
|
||||||||
class RegistrationTest extends TestCase | ||||||||
{ | ||||||||
use DatabaseTransactions; | ||||||||
|
||||||||
#[Test] | ||||||||
public function registration_screen_can_be_rendered() | ||||||||
public function testAccessToRegistrationPage(): void | ||||||||
davpsh marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's keep the new syntax
Suggested change
|
||||||||
{ | ||||||||
$this->withoutVite(); | ||||||||
|
||||||||
if (! Features::enabled(Features::registration())) { | ||||||||
return $this->markTestSkipped('Registration support is not enabled.'); | ||||||||
} | ||||||||
$isSignupEnabled = null; | ||||||||
$this->app->bind(SignupHelper::class, function () use (&$isSignupEnabled) { | ||||||||
$mock = Mockery::mock(SignupHelper::class)->makePartial(); | ||||||||
$mock->shouldReceive('isEnabled')->andReturn($isSignupEnabled); | ||||||||
|
||||||||
return $mock; | ||||||||
}); | ||||||||
|
||||||||
$isSignupEnabled = true; | ||||||||
$response = $this->get('/register'); | ||||||||
$response->assertStatus(Response::HTTP_OK); | ||||||||
|
||||||||
$response->assertStatus(200); | ||||||||
$isSignupEnabled = false; | ||||||||
$response = $this->get('/register'); | ||||||||
$response->assertStatus(Response::HTTP_FORBIDDEN); | ||||||||
$response->assertSeeText('Registration is currently disabled'); | ||||||||
} | ||||||||
|
||||||||
#[Test] | ||||||||
public function new_users_can_register() | ||||||||
public function testRegistration(): void | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
{ | ||||||||
if (! Features::enabled(Features::registration())) { | ||||||||
return $this->markTestSkipped('Registration support is not enabled.'); | ||||||||
} | ||||||||
$isSignupEnabled = null; | ||||||||
$this->app->bind(SignupHelper::class, function () use (&$isSignupEnabled) { | ||||||||
$mock = Mockery::mock(SignupHelper::class)->makePartial(); | ||||||||
$mock->shouldReceive('isEnabled')->andReturn($isSignupEnabled); | ||||||||
|
||||||||
$response = $this->post('/register', [ | ||||||||
return $mock; | ||||||||
}); | ||||||||
|
||||||||
$data = [ | ||||||||
'first_name' => 'Test', | ||||||||
'last_name' => 'User', | ||||||||
'email' => '[email protected]', | ||||||||
'password' => 'Password$123', | ||||||||
'password_confirmation' => 'Password$123', | ||||||||
'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature(), | ||||||||
]); | ||||||||
]; | ||||||||
|
||||||||
$isSignupEnabled = false; | ||||||||
$response = $this->post('/register', $data); | ||||||||
$response->assertStatus(Response::HTTP_FORBIDDEN); | ||||||||
$response->assertSeeText('Registration is currently disabled'); | ||||||||
|
||||||||
$isSignupEnabled = true; | ||||||||
$response = $this->post('/register', $data); | ||||||||
$this->assertAuthenticated(); | ||||||||
$response->assertRedirect('/vaults'); | ||||||||
} | ||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Tests\Unit\Helpers; | ||
|
||
use App\Helpers\SignupHelper; | ||
use Illuminate\Contracts\Config\Repository as ConfigRepository; | ||
use Mockery; | ||
use PHPUnit\Framework\Attributes\DataProvider; | ||
use Tests\TestCase; | ||
|
||
#[CoversClass(SignupHelper::class)] | ||
class SignupHelperTest extends TestCase | ||
{ | ||
#[DataProvider('isEnabledDataProvider')] | ||
public function testIsEnabled(bool $isSignupDisabled, bool $hasAtLeastOneAccount, bool $expectedResult): void | ||
{ | ||
$helper = Mockery::mock(SignupHelper::class)->shouldAllowMockingProtectedMethods()->makePartial(); | ||
$helper->shouldReceive('isDisabledByConfig')->andReturn($isSignupDisabled); | ||
$helper->shouldReceive('hasAtLeastOneAccount')->andReturn($hasAtLeastOneAccount); | ||
|
||
$this->assertEquals($expectedResult, $helper->isEnabled()); | ||
} | ||
|
||
public function isEnabledDataProvider(): iterable | ||
{ | ||
// $isSignupDisabled, $hasAtLeastOneAccount, $expectedResult | ||
return [ | ||
[true, true, false], | ||
[true, false, true], | ||
[false, true, true], | ||
[false, false, true], | ||
]; | ||
} | ||
|
||
public function testIsDisabledByConfig(): void | ||
{ | ||
$configRepository = Mockery::mock(ConfigRepository::class)->makePartial(); | ||
$configRepository->shouldReceive('get') | ||
->once() | ||
->withArgs(function ($name) { | ||
return $name === 'monica.disable_signup'; | ||
}) | ||
->andReturnTrue(); | ||
|
||
$helper = Mockery::mock(SignupHelper::class, [$configRepository])->makePartial(); | ||
$helper->isDisabledByConfig(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't working actually