Fix unhandled error on jetstream page with non-UUID id, fixes ST-274

This commit is contained in:
Constantin Graf
2024-06-24 13:05:26 +02:00
committed by Gregor Vostrak
parent 512089ccbd
commit f21a2d4bdd
4 changed files with 49 additions and 1 deletions

View File

@@ -8,9 +8,11 @@ use App\Models\Concerns\HasUuids;
use Database\Factories\OrganizationFactory; use Database\Factories\OrganizationFactory;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Laravel\Jetstream\Events\TeamCreated; use Laravel\Jetstream\Events\TeamCreated;
use Laravel\Jetstream\Events\TeamDeleted; use Laravel\Jetstream\Events\TeamDeleted;
use Laravel\Jetstream\Events\TeamUpdated; use Laravel\Jetstream\Events\TeamUpdated;
@@ -123,4 +125,21 @@ class Organization extends JetstreamTeam
return $this->users() return $this->users()
->where('is_placeholder', false); ->where('is_placeholder', false);
} }
/**
* This method prevents an unhandled exception when the ID is not a UUID.
* Normally this can be fixed with a route pattern, but Jetstream does not use route model binding.
*
* @param array<string> $columns
*/
public function findOrFail(string $id, array $columns = ['*']): \Laravel\Jetstream\Team
{
if (! Str::isUuid($id)) {
throw (new ModelNotFoundException)->setModel(
self::class, $id
);
}
return parent::findOrFail($id, $columns);
}
} }

View File

@@ -116,6 +116,7 @@ class UserFactory extends Factory
->when(is_callable($callback), $callback) ->when(is_callable($callback), $callback)
->create(); ->create();
$organization->owner()->associate($user);
$organization->users()->attach($user, ['role' => Role::Owner->value]); $organization->users()->attach($user, ['role' => Role::Owner->value]);
$user->currentTeam()->associate($organization); $user->currentTeam()->associate($organization);
$user->save(); $user->save();

View File

@@ -8,10 +8,23 @@ use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase; use Tests\TestCase;
class UpdateTeamNameTest extends TestCase class UpdateTeamTest extends TestCase
{ {
use RefreshDatabase; use RefreshDatabase;
public function test_team_update_page_shows_not_found_if_id_is_not_uuid(): void
{
// Arrange
$user = User::factory()->withPersonalOrganization()->create();
$this->actingAs($user);
// Act
$response = $this->get('/teams/1');
// Assert
$response->assertStatus(404);
}
public function test_team_names_can_be_updated(): void public function test_team_names_can_be_updated(): void
{ {
// Arrange // Arrange

View File

@@ -14,6 +14,21 @@ use PHPUnit\Framework\Attributes\UsesClass;
#[UsesClass(OrganizationController::class)] #[UsesClass(OrganizationController::class)]
class OrganizationEndpointTest extends ApiEndpointTestAbstract class OrganizationEndpointTest extends ApiEndpointTestAbstract
{ {
public function test_show_endpoint_fails_with_not_found_if_id_is_not_uuid(): void
{
// Arrange
$data = $this->createUserWithPermission([
'organizations:view',
]);
Passport::actingAs($data->user);
// Act
$response = $this->getJson(route('api.v1.organizations.show', ['not-uuid']));
// Assert
$response->assertNotFound();
}
public function test_show_endpoint_fails_if_user_has_no_permission_to_view_organizations(): void public function test_show_endpoint_fails_if_user_has_no_permission_to_view_organizations(): void
{ {
// Arrange // Arrange