From e6e2c3f40590a72c40207b2c214a823202204bc5 Mon Sep 17 00:00:00 2001 From: Holger Schmermbeck Date: Sat, 15 Nov 2025 14:27:10 +0100 Subject: [PATCH] refactor: remove redundant /api/ prefix from routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #168 BREAKING CHANGE: Routes now accessible at /v1/* instead of /api/v1/* This change aligns internal routing with production API URLs. Changes: - Set apiPrefix="" in bootstrap/app.php (Laravel 12) - Updated all 167 test URLs from /api/v1/* to /v1/* - Updated health endpoint tests from /api/health to /health Rationale: - Production URL: https://api.secpal.app/v1/users - Old internal: /api/v1/users (confusing) - New internal: /v1/users (matches production) Quality Checks: ✅ All 279 tests passing (916 assertions) ✅ Laravel Pint: PASS (103 files) ✅ PHPStan Level Max: No errors Impact: Since we are v0.x.x, breaking changes are allowed. --- bootstrap/app.php | 1 + .../Feature/Auth/PasswordResetRequestTest.php | 26 +++++----- tests/Feature/Auth/PasswordResetTest.php | 22 ++++---- tests/Feature/AuthTest.php | 38 +++++++------- tests/Feature/ExampleTest.php | 2 +- .../Integration/RbacIntegrationTest.php | 36 ++++++------- tests/Feature/LocaleMiddlewareTest.php | 12 ++--- tests/Feature/PermissionManagementApiTest.php | 48 ++++++++--------- tests/Feature/PersonApiTest.php | 32 ++++++------ tests/Feature/RoleApiTest.php | 48 ++++++++--------- tests/Feature/RoleManagementApiTest.php | 52 +++++++++---------- .../UserPermissionAssignmentApiTest.php | 32 ++++++------ 12 files changed, 175 insertions(+), 174 deletions(-) diff --git a/bootstrap/app.php b/bootstrap/app.php index f8dcb07..44171a5 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -13,6 +13,7 @@ return Application::configure(basePath: dirname(__DIR__)) ->withRouting( api: __DIR__.'/../routes/api.php', + apiPrefix: '', // Remove /api/ prefix - routes accessible at /v1/* directly commands: __DIR__.'/../routes/console.php', health: '/up', ) diff --git a/tests/Feature/Auth/PasswordResetRequestTest.php b/tests/Feature/Auth/PasswordResetRequestTest.php index 539d3d9..8cfc0da 100644 --- a/tests/Feature/Auth/PasswordResetRequestTest.php +++ b/tests/Feature/Auth/PasswordResetRequestTest.php @@ -14,7 +14,7 @@ /** * Feature tests for password reset request endpoint. * - * @covers POST /api/v1/auth/password/reset-request + * @covers POST /v1/auth/password/reset-request */ uses(RefreshDatabase::class); @@ -25,7 +25,7 @@ 'email' => 'test@example.com', ]); - $response = $this->postJson('/api/v1/auth/password/reset-request', [ + $response = $this->postJson('/v1/auth/password/reset-request', [ 'email' => 'test@example.com', ]); @@ -43,7 +43,7 @@ it('returns same response for non-existent email', function () { Mail::fake(); - $response = $this->postJson('/api/v1/auth/password/reset-request', [ + $response = $this->postJson('/v1/auth/password/reset-request', [ 'email' => 'nonexistent@example.com', ]); @@ -57,14 +57,14 @@ }); it('requires email field', function () { - $response = $this->postJson('/api/v1/auth/password/reset-request', []); + $response = $this->postJson('/v1/auth/password/reset-request', []); $response->assertStatus(422) ->assertJsonValidationErrors(['email']); }); it('requires valid email format', function () { - $response = $this->postJson('/api/v1/auth/password/reset-request', [ + $response = $this->postJson('/v1/auth/password/reset-request', [ 'email' => 'invalid-email', ]); @@ -76,12 +76,12 @@ $email = 'test@example.com'; // Make 5 requests (should all be allowed) - collect(range(1, 5))->each(fn () => $this->postJson('/api/v1/auth/password/reset-request', [ + collect(range(1, 5))->each(fn () => $this->postJson('/v1/auth/password/reset-request', [ 'email' => $email, ])->assertOk()); // 6th request should be rate limited - $response = $this->postJson('/api/v1/auth/password/reset-request', [ + $response = $this->postJson('/v1/auth/password/reset-request', [ 'email' => $email, ]); @@ -95,7 +95,7 @@ 'email' => 'test@example.com', ]); - $this->postJson('/api/v1/auth/password/reset-request', [ + $this->postJson('/v1/auth/password/reset-request', [ 'email' => 'test@example.com', ]); @@ -113,7 +113,7 @@ 'email' => 'test@example.com', ]); - $this->postJson('/api/v1/auth/password/reset-request', [ + $this->postJson('/v1/auth/password/reset-request', [ 'email' => 'test@example.com', ]); @@ -132,7 +132,7 @@ 'email' => 'test+special@example.com', ]); - $this->postJson('/api/v1/auth/password/reset-request', [ + $this->postJson('/v1/auth/password/reset-request', [ 'email' => 'test+special@example.com', ]); @@ -159,7 +159,7 @@ 'email' => 'test@example.com', ]); - $this->postJson('/api/v1/auth/password/reset-request', [ + $this->postJson('/v1/auth/password/reset-request', [ 'email' => 'test@example.com', ]); @@ -183,7 +183,7 @@ ]); // Request password reset first time - $this->postJson('/api/v1/auth/password/reset-request', [ + $this->postJson('/v1/auth/password/reset-request', [ 'email' => 'test@example.com', ]); @@ -194,7 +194,7 @@ expect($firstTokenCount)->toBe(1); // Request again - should replace old token - $this->postJson('/api/v1/auth/password/reset-request', [ + $this->postJson('/v1/auth/password/reset-request', [ 'email' => 'test@example.com', ]); diff --git a/tests/Feature/Auth/PasswordResetTest.php b/tests/Feature/Auth/PasswordResetTest.php index 39bbc0c..7549b64 100644 --- a/tests/Feature/Auth/PasswordResetTest.php +++ b/tests/Feature/Auth/PasswordResetTest.php @@ -14,7 +14,7 @@ /** * Feature tests for password reset confirmation endpoint. * - * @covers POST /api/v1/auth/password/reset + * @covers POST /v1/auth/password/reset */ uses(RefreshDatabase::class); @@ -42,7 +42,7 @@ function createPasswordResetToken(User $user, ?\DateTimeInterface $createdAt = n $token = createPasswordResetToken($user); - $response = $this->postJson('/api/v1/auth/password/reset', [ + $response = $this->postJson('/v1/auth/password/reset', [ 'token' => $token, 'email' => 'test@example.com', 'password' => 'new-secure-password-123', @@ -65,7 +65,7 @@ function createPasswordResetToken(User $user, ?\DateTimeInterface $createdAt = n $expiredToken = createPasswordResetToken($user, now()->subMinutes(61)); - $response = $this->postJson('/api/v1/auth/password/reset', [ + $response = $this->postJson('/v1/auth/password/reset', [ 'token' => $expiredToken, 'email' => 'test@example.com', 'password' => 'new-password-123', @@ -83,7 +83,7 @@ function createPasswordResetToken(User $user, ?\DateTimeInterface $createdAt = n 'email' => 'test@example.com', ]); - $response = $this->postJson('/api/v1/auth/password/reset', [ + $response = $this->postJson('/v1/auth/password/reset', [ 'token' => 'invalid-token-123', 'email' => 'test@example.com', 'password' => 'new-password-123', @@ -97,14 +97,14 @@ function createPasswordResetToken(User $user, ?\DateTimeInterface $createdAt = n }); it('requires all fields', function () { - $response = $this->postJson('/api/v1/auth/password/reset', []); + $response = $this->postJson('/v1/auth/password/reset', []); $response->assertStatus(422) ->assertJsonValidationErrors(['token', 'email', 'password']); }); it('requires password confirmation', function () { - $response = $this->postJson('/api/v1/auth/password/reset', [ + $response = $this->postJson('/v1/auth/password/reset', [ 'token' => 'some-token', 'email' => 'test@example.com', 'password' => 'new-password-123', @@ -121,7 +121,7 @@ function createPasswordResetToken(User $user, ?\DateTimeInterface $createdAt = n $token = createPasswordResetToken($user); - $response = $this->postJson('/api/v1/auth/password/reset', [ + $response = $this->postJson('/v1/auth/password/reset', [ 'token' => $token, 'email' => 'test@example.com', 'password' => 'short', @@ -140,7 +140,7 @@ function createPasswordResetToken(User $user, ?\DateTimeInterface $createdAt = n $token = createPasswordResetToken($user); // First reset succeeds - $this->postJson('/api/v1/auth/password/reset', [ + $this->postJson('/v1/auth/password/reset', [ 'token' => $token, 'email' => 'test@example.com', 'password' => 'new-password-123', @@ -148,7 +148,7 @@ function createPasswordResetToken(User $user, ?\DateTimeInterface $createdAt = n ])->assertOk(); // Second attempt with same token fails - $response = $this->postJson('/api/v1/auth/password/reset', [ + $response = $this->postJson('/v1/auth/password/reset', [ 'token' => $token, 'email' => 'test@example.com', 'password' => 'another-password-456', @@ -167,7 +167,7 @@ function createPasswordResetToken(User $user, ?\DateTimeInterface $createdAt = n ]); // Make 5 requests (should all be allowed) - collect(range(1, 5))->each(fn () => $this->postJson('/api/v1/auth/password/reset', [ + collect(range(1, 5))->each(fn () => $this->postJson('/v1/auth/password/reset', [ 'token' => 'wrong-token', 'email' => 'test@example.com', 'password' => 'new-password-123', @@ -175,7 +175,7 @@ function createPasswordResetToken(User $user, ?\DateTimeInterface $createdAt = n ])->assertStatus(400)); // Wrong token, but not rate limited // 6th request should be rate limited - $response = $this->postJson('/api/v1/auth/password/reset', [ + $response = $this->postJson('/v1/auth/password/reset', [ 'token' => 'wrong-token', 'email' => 'test@example.com', 'password' => 'new-password-123', diff --git a/tests/Feature/AuthTest.php b/tests/Feature/AuthTest.php index d06885f..77f6aaa 100644 --- a/tests/Feature/AuthTest.php +++ b/tests/Feature/AuthTest.php @@ -15,7 +15,7 @@ 'password' => bcrypt('password123'), ]); - $response = $this->postJson('/api/v1/auth/token', [ + $response = $this->postJson('/v1/auth/token', [ 'email' => 'test@example.com', 'password' => 'password123', 'device_name' => 'test-device', @@ -32,7 +32,7 @@ }); test('token generation fails with invalid email', function () { - $response = $this->postJson('/api/v1/auth/token', [ + $response = $this->postJson('/v1/auth/token', [ 'email' => 'nonexistent@example.com', 'password' => 'password123', ]); @@ -47,7 +47,7 @@ 'password' => bcrypt('correct-password'), ]); - $response = $this->postJson('/api/v1/auth/token', [ + $response = $this->postJson('/v1/auth/token', [ 'email' => 'test@example.com', 'password' => 'wrong-password', ]); @@ -57,7 +57,7 @@ }); test('token generation requires email', function () { - $response = $this->postJson('/api/v1/auth/token', [ + $response = $this->postJson('/v1/auth/token', [ 'password' => 'password123', ]); @@ -66,7 +66,7 @@ }); test('token generation requires password', function () { - $response = $this->postJson('/api/v1/auth/token', [ + $response = $this->postJson('/v1/auth/token', [ 'email' => 'test@example.com', ]); @@ -80,7 +80,7 @@ 'password' => bcrypt('password123'), ]); - $response = $this->postJson('/api/v1/auth/token', [ + $response = $this->postJson('/v1/auth/token', [ 'email' => 'test@example.com', 'password' => 'password123', ]); @@ -95,13 +95,13 @@ 'password' => bcrypt('password123'), ]); - $this->postJson('/api/v1/auth/token', [ + $this->postJson('/v1/auth/token', [ 'email' => 'test@example.com', 'password' => 'password123', 'device_name' => 'mobile', ])->assertCreated(); - $this->postJson('/api/v1/auth/token', [ + $this->postJson('/v1/auth/token', [ 'email' => 'test@example.com', 'password' => 'password123', 'device_name' => 'desktop', @@ -114,7 +114,7 @@ describe('Protected Endpoints', function () { test('protected endpoint requires authentication', function () { - $response = $this->getJson('/api/v1/me'); + $response = $this->getJson('/v1/me'); $response->assertUnauthorized(); }); @@ -128,7 +128,7 @@ $token = $user->createToken('test-device')->plainTextToken; $response = $this->withHeader('Authorization', "Bearer {$token}") - ->getJson('/api/v1/me'); + ->getJson('/v1/me'); $response->assertOk() ->assertJson([ @@ -140,7 +140,7 @@ test('protected endpoint rejects invalid token', function () { $response = $this->withHeader('Authorization', 'Bearer invalid-token-here') - ->getJson('/api/v1/me'); + ->getJson('/v1/me'); $response->assertUnauthorized(); }); @@ -156,7 +156,7 @@ $token = $user->createToken('device-1')->plainTextToken; $response = $this->withHeader('Authorization', "Bearer {$token}") - ->postJson('/api/v1/auth/logout'); + ->postJson('/v1/auth/logout'); $response->assertOk() ->assertJson(['message' => 'Token revoked successfully.']); @@ -177,7 +177,7 @@ expect($user->tokens()->count())->toBe(3); $response = $this->withHeader('Authorization', "Bearer {$token1}") - ->postJson('/api/v1/auth/logout-all'); + ->postJson('/v1/auth/logout-all'); $response->assertOk() ->assertJson(['message' => 'All tokens revoked successfully.']); @@ -194,7 +194,7 @@ // Logout (revoke token) $this->withHeader('Authorization', "Bearer {$token}") - ->postJson('/api/v1/auth/logout') + ->postJson('/v1/auth/logout') ->assertOk(); // Token deleted after logout @@ -202,13 +202,13 @@ }); test('logout requires authentication', function () { - $response = $this->postJson('/api/v1/auth/logout'); + $response = $this->postJson('/v1/auth/logout'); $response->assertUnauthorized(); }); test('logout-all requires authentication', function () { - $response = $this->postJson('/api/v1/auth/logout-all'); + $response = $this->postJson('/v1/auth/logout-all'); $response->assertUnauthorized(); }); @@ -220,7 +220,7 @@ 'password' => bcrypt('secret-password'), ]); - $response = $this->postJson('/api/v1/auth/token', [ + $response = $this->postJson('/v1/auth/token', [ 'email' => $user->email, 'password' => 'secret-password', ]); @@ -235,7 +235,7 @@ $token = $user->createToken('test')->plainTextToken; $response = $this->withHeader('Authorization', "Bearer {$token}") - ->getJson('/api/v1/me'); + ->getJson('/v1/me'); $response->assertOk() ->assertJsonMissing(['password']) @@ -248,7 +248,7 @@ 'password' => bcrypt('password123'), ]); - $response = $this->postJson('/api/v1/auth/token', [ + $response = $this->postJson('/v1/auth/token', [ 'email' => 'test@example.com', 'password' => 'password123', ]); diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php index 7d4052f..3307f16 100644 --- a/tests/Feature/ExampleTest.php +++ b/tests/Feature/ExampleTest.php @@ -15,7 +15,7 @@ class ExampleTest extends TestCase */ public function test_health_endpoint_returns_ok(): void { - $response = $this->get('/api/health'); + $response = $this->get('/health'); $response->assertStatus(200) ->assertJson([ diff --git a/tests/Feature/Integration/RbacIntegrationTest.php b/tests/Feature/Integration/RbacIntegrationTest.php index 35e1fef..b9cdb9e 100644 --- a/tests/Feature/Integration/RbacIntegrationTest.php +++ b/tests/Feature/Integration/RbacIntegrationTest.php @@ -49,7 +49,7 @@ $validUntil = now()->addHours(3); actingAs($this->admin) - ->postJson("/api/v1/users/{$guard->id}/roles", [ + ->postJson("/v1/users/{$guard->id}/roles", [ 'role' => 'Manager', 'valid_from' => $validFrom->toIso8601String(), 'valid_until' => $validUntil->toIso8601String(), @@ -84,14 +84,14 @@ // Assign Manager role (permanent) actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/roles", [ + ->postJson("/v1/users/{$user->id}/roles", [ 'role' => 'Manager', ]) ->assertSuccessful(); // Assign temporary Admin role (24 hours) actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/roles", [ + ->postJson("/v1/users/{$user->id}/roles", [ 'role' => 'Admin', 'valid_until' => now()->addHours(24)->toIso8601String(), 'auto_revoke' => true, @@ -119,28 +119,28 @@ // Assign Guard role actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/roles", [ + ->postJson("/v1/users/{$user->id}/roles", [ 'role' => 'Guard', ]) ->assertSuccessful(); // Assign Client role actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/roles", [ + ->postJson("/v1/users/{$user->id}/roles", [ 'role' => 'Client', ]) ->assertSuccessful(); // Assign direct permission actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/permissions", [ + ->postJson("/v1/users/{$user->id}/permissions", [ 'permissions' => ['employees.export'], ]) ->assertSuccessful(); // Get all permissions $response = actingAs($this->admin) - ->getJson("/api/v1/users/{$user->id}/permissions") + ->getJson("/v1/users/{$user->id}/permissions") ->assertOk() ->json(); @@ -160,14 +160,14 @@ // Assign Manager role actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/roles", [ + ->postJson("/v1/users/{$user->id}/roles", [ 'role' => 'Manager', ]) ->assertSuccessful(); // Assign direct permission actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/permissions", [ + ->postJson("/v1/users/{$user->id}/permissions", [ 'permissions' => ['reports.generate'], ]) ->assertSuccessful(); @@ -179,7 +179,7 @@ // Revoke Manager role (use role name, not ID) actingAs($this->admin) - ->deleteJson("/api/v1/users/{$user->id}/roles/Manager") + ->deleteJson("/v1/users/{$user->id}/roles/Manager") ->assertSuccessful(); // Direct permission remains @@ -196,7 +196,7 @@ // Manager A has permanent role actingAs($this->admin) - ->postJson("/api/v1/users/{$managerA->id}/roles", [ + ->postJson("/v1/users/{$managerA->id}/roles", [ 'role' => 'Manager', ]) ->assertSuccessful(); @@ -206,7 +206,7 @@ $vacationEnd = now()->setDate(2025, 12, 14)->endOfDay(); actingAs($this->admin) - ->postJson("/api/v1/users/{$managerB->id}/roles", [ + ->postJson("/v1/users/{$managerB->id}/roles", [ 'role' => 'Manager', 'valid_from' => $vacationStart->toIso8601String(), 'valid_until' => $vacationEnd->toIso8601String(), @@ -238,7 +238,7 @@ $user = User::factory()->create(); actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/roles", [ + ->postJson("/v1/users/{$user->id}/roles", [ 'role' => 'NonExistentRole', ]) ->assertUnprocessable() @@ -250,7 +250,7 @@ // valid_from is after valid_until (invalid) $response = actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/roles", [ + ->postJson("/v1/users/{$user->id}/roles", [ 'role' => 'Manager', 'valid_from' => now()->addDays(10)->toIso8601String(), 'valid_until' => now()->addDays(5)->toIso8601String(), @@ -265,14 +265,14 @@ // Assign role first time actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/roles", [ + ->postJson("/v1/users/{$user->id}/roles", [ 'role' => 'Manager', ]) ->assertSuccessful(); // Assign same role again - should be idempotent (return 200 OK) actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/roles", [ + ->postJson("/v1/users/{$user->id}/roles", [ 'role' => 'Manager', ]) ->assertOk() // 200 OK (not 201 Created) @@ -290,7 +290,7 @@ // Assign permanent role (without temporal constraints) actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/roles", [ + ->postJson("/v1/users/{$user->id}/roles", [ 'role' => 'Manager', ]) ->assertCreated(); @@ -298,7 +298,7 @@ // Try to assign same role again with temporal parameters // Should return 200 OK with existing assignment unchanged $response = actingAs($this->admin) - ->postJson("/api/v1/users/{$user->id}/roles", [ + ->postJson("/v1/users/{$user->id}/roles", [ 'role' => 'Manager', 'valid_from' => now()->toIso8601String(), 'valid_until' => now()->addDays(7)->toIso8601String(), diff --git a/tests/Feature/LocaleMiddlewareTest.php b/tests/Feature/LocaleMiddlewareTest.php index 898544f..0b664c3 100644 --- a/tests/Feature/LocaleMiddlewareTest.php +++ b/tests/Feature/LocaleMiddlewareTest.php @@ -8,7 +8,7 @@ test('middleware sets locale from Accept-Language header to German', function (): void { $response = $this->withHeaders([ 'Accept-Language' => 'de', - ])->get('/api/health'); + ])->get('/health'); expect(App::getLocale())->toBe('de'); $response->assertOk(); @@ -17,14 +17,14 @@ test('middleware sets locale from Accept-Language header to English', function (): void { $response = $this->withHeaders([ 'Accept-Language' => 'en', - ])->get('/api/health'); + ])->get('/health'); expect(App::getLocale())->toBe('en'); $response->assertOk(); }); test('middleware defaults to configured locale when no Accept-Language header', function (): void { - $response = $this->get('/api/health'); + $response = $this->get('/health'); expect(App::getLocale())->toBe(config('app.locale')); $response->assertOk(); @@ -33,7 +33,7 @@ test('middleware defaults to configured locale for unsupported language', function (): void { $response = $this->withHeaders([ 'Accept-Language' => 'fr', - ])->get('/api/health'); + ])->get('/health'); expect(App::getLocale())->toBe(config('app.locale')); $response->assertOk(); @@ -42,7 +42,7 @@ test('middleware handles complex Accept-Language header with quality values', function (): void { $response = $this->withHeaders([ 'Accept-Language' => 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7', - ])->get('/api/health'); + ])->get('/health'); expect(App::getLocale())->toBe('de'); $response->assertOk(); @@ -51,7 +51,7 @@ test('middleware prefers higher quality language from Accept-Language header', function (): void { $response = $this->withHeaders([ 'Accept-Language' => 'en;q=0.5,de;q=0.9', - ])->get('/api/health'); + ])->get('/health'); expect(App::getLocale())->toBe('de'); $response->assertOk(); diff --git a/tests/Feature/PermissionManagementApiTest.php b/tests/Feature/PermissionManagementApiTest.php index afa96e7..01e16f4 100644 --- a/tests/Feature/PermissionManagementApiTest.php +++ b/tests/Feature/PermissionManagementApiTest.php @@ -51,14 +51,14 @@ describe('GET /v1/permissions - List Permissions', function () { test('returns 401 when not authenticated', function (): void { - $response = $this->getJson('/api/v1/permissions'); + $response = $this->getJson('/v1/permissions'); $response->assertUnauthorized(); }); test('returns 403 when user lacks permissions.read permission', function (): void { $response = $this->withToken($this->token) - ->getJson('/api/v1/permissions'); + ->getJson('/v1/permissions'); $response->assertForbidden(); }); @@ -67,7 +67,7 @@ $this->user->givePermissionTo('permissions.read'); $response = $this->withToken($this->token) - ->getJson('/api/v1/permissions'); + ->getJson('/v1/permissions'); $response->assertOk() ->assertJsonStructure([ @@ -94,7 +94,7 @@ describe('POST /v1/permissions - Create Permission', function () { test('returns 401 when not authenticated', function (): void { - $response = $this->postJson('/api/v1/permissions', [ + $response = $this->postJson('/v1/permissions', [ 'name' => 'reports.generate', ]); @@ -105,7 +105,7 @@ $this->user->givePermissionTo('permissions.read'); $response = $this->withToken($this->token) - ->postJson('/api/v1/permissions', [ + ->postJson('/v1/permissions', [ 'name' => 'reports.generate', ]); @@ -116,7 +116,7 @@ $this->user->givePermissionTo('permissions.create'); $response = $this->withToken($this->token) - ->postJson('/api/v1/permissions', []); + ->postJson('/v1/permissions', []); $response->assertStatus(422) ->assertJsonValidationErrors(['name']); @@ -126,7 +126,7 @@ $this->user->givePermissionTo('permissions.create'); $response = $this->withToken($this->token) - ->postJson('/api/v1/permissions', [ + ->postJson('/v1/permissions', [ 'name' => 'invalid_format', ]); @@ -139,7 +139,7 @@ Permission::create(['name' => 'reports.generate', 'guard_name' => 'sanctum']); $response = $this->withToken($this->token) - ->postJson('/api/v1/permissions', [ + ->postJson('/v1/permissions', [ 'name' => 'reports.generate', ]); @@ -151,7 +151,7 @@ $this->user->givePermissionTo('permissions.create'); $response = $this->withToken($this->token) - ->postJson('/api/v1/permissions', [ + ->postJson('/v1/permissions', [ 'name' => 'reports.generate', 'description' => 'Generate reports', ]); @@ -170,7 +170,7 @@ $this->user->givePermissionTo('permissions.create'); $response = $this->withToken($this->token) - ->postJson('/api/v1/permissions', [ + ->postJson('/v1/permissions', [ 'name' => 'reports.export', ]); @@ -183,7 +183,7 @@ test('returns 401 when not authenticated', function (): void { $permission = Permission::where('name', 'employees.read')->first(); - $response = $this->getJson("/api/v1/permissions/{$permission->id}"); + $response = $this->getJson("/v1/permissions/{$permission->id}"); $response->assertUnauthorized(); }); @@ -192,7 +192,7 @@ $permission = Permission::where('name', 'employees.read')->first(); $response = $this->withToken($this->token) - ->getJson("/api/v1/permissions/{$permission->id}"); + ->getJson("/v1/permissions/{$permission->id}"); $response->assertForbidden(); }); @@ -201,7 +201,7 @@ $this->user->givePermissionTo('permissions.read'); $response = $this->withToken($this->token) - ->getJson('/api/v1/permissions/999999'); + ->getJson('/v1/permissions/999999'); $response->assertNotFound(); }); @@ -214,7 +214,7 @@ $role->givePermissionTo('employees.read'); $response = $this->withToken($this->token) - ->getJson("/api/v1/permissions/{$permission->id}"); + ->getJson("/v1/permissions/{$permission->id}"); $response->assertOk() ->assertJsonStructure([ @@ -229,7 +229,7 @@ test('returns 401 when not authenticated', function (): void { $permission = Permission::where('name', 'employees.read')->first(); - $response = $this->patchJson("/api/v1/permissions/{$permission->id}", [ + $response = $this->patchJson("/v1/permissions/{$permission->id}", [ 'description' => 'Updated description', ]); @@ -241,7 +241,7 @@ $permission = Permission::where('name', 'employees.read')->first(); $response = $this->withToken($this->token) - ->patchJson("/api/v1/permissions/{$permission->id}", [ + ->patchJson("/v1/permissions/{$permission->id}", [ 'description' => 'Updated description', ]); @@ -252,7 +252,7 @@ $this->user->givePermissionTo('permissions.update'); $response = $this->withToken($this->token) - ->patchJson('/api/v1/permissions/999999', [ + ->patchJson('/v1/permissions/999999', [ 'description' => 'Updated description', ]); @@ -264,7 +264,7 @@ $permission = Permission::where('name', 'employees.read')->first(); $response = $this->withToken($this->token) - ->patchJson("/api/v1/permissions/{$permission->id}", [ + ->patchJson("/v1/permissions/{$permission->id}", [ 'name' => 'employees.write', ]); @@ -277,7 +277,7 @@ $permission = Permission::where('name', 'employees.read')->first(); $response = $this->withToken($this->token) - ->patchJson("/api/v1/permissions/{$permission->id}", [ + ->patchJson("/v1/permissions/{$permission->id}", [ 'description' => 'View employee data', ]); @@ -292,7 +292,7 @@ test('returns 401 when not authenticated', function (): void { $permission = Permission::create(['name' => 'temp.permission', 'guard_name' => 'sanctum']); - $response = $this->deleteJson("/api/v1/permissions/{$permission->id}"); + $response = $this->deleteJson("/v1/permissions/{$permission->id}"); $response->assertUnauthorized(); }); @@ -302,7 +302,7 @@ $permission = Permission::create(['name' => 'temp.permission', 'guard_name' => 'sanctum']); $response = $this->withToken($this->token) - ->deleteJson("/api/v1/permissions/{$permission->id}"); + ->deleteJson("/v1/permissions/{$permission->id}"); $response->assertForbidden(); }); @@ -311,7 +311,7 @@ $this->user->givePermissionTo('permissions.delete'); $response = $this->withToken($this->token) - ->deleteJson('/api/v1/permissions/999999'); + ->deleteJson('/v1/permissions/999999'); $response->assertNotFound(); }); @@ -323,7 +323,7 @@ $role->givePermissionTo('employees.read'); $response = $this->withToken($this->token) - ->deleteJson("/api/v1/permissions/{$permission->id}"); + ->deleteJson("/v1/permissions/{$permission->id}"); $response->assertStatus(422) ->assertJsonFragment(['message' => 'Cannot delete permission while assigned to roles']) @@ -335,7 +335,7 @@ $permission = Permission::create(['name' => 'temp.permission', 'guard_name' => 'sanctum']); $response = $this->withToken($this->token) - ->deleteJson("/api/v1/permissions/{$permission->id}"); + ->deleteJson("/v1/permissions/{$permission->id}"); $response->assertNoContent(); diff --git a/tests/Feature/PersonApiTest.php b/tests/Feature/PersonApiTest.php index 7c667df..1927c86 100644 --- a/tests/Feature/PersonApiTest.php +++ b/tests/Feature/PersonApiTest.php @@ -39,7 +39,7 @@ describe('POST /v1/tenants/{tenant}/persons', function () { test('returns 401 when not authenticated', function (): void { - $response = $this->postJson("/api/v1/tenants/{$this->tenant->id}/persons", [ + $response = $this->postJson("/v1/tenants/{$this->tenant->id}/persons", [ 'email_plain' => 'test@example.com', ]); @@ -48,7 +48,7 @@ test('returns 403 when user lacks person.write permission', function (): void { $response = $this->withToken($this->token) - ->postJson("/api/v1/tenants/{$this->tenant->id}/persons", [ + ->postJson("/v1/tenants/{$this->tenant->id}/persons", [ 'email_plain' => 'test@example.com', ]); @@ -59,7 +59,7 @@ givePermissionWithTenant($this->user, $this->tenant->id, 'person.write'); $response = $this->withToken($this->token) - ->postJson("/api/v1/tenants/{$this->tenant->id}/persons", [ + ->postJson("/v1/tenants/{$this->tenant->id}/persons", [ 'phone_plain' => '+49 123 456789', ]); @@ -71,7 +71,7 @@ givePermissionWithTenant($this->user, $this->tenant->id, 'person.write'); $response = $this->withToken($this->token) - ->postJson("/api/v1/tenants/{$this->tenant->id}/persons", [ + ->postJson("/v1/tenants/{$this->tenant->id}/persons", [ 'email_plain' => 'not-an-email', ]); @@ -83,7 +83,7 @@ givePermissionWithTenant($this->user, $this->tenant->id, 'person.write'); $response = $this->withToken($this->token) - ->postJson("/api/v1/tenants/{$this->tenant->id}/persons", [ + ->postJson("/v1/tenants/{$this->tenant->id}/persons", [ 'email_plain' => 'test@example.com', 'phone_plain' => '+49 123 456789', 'note_enc' => 'Test note', @@ -113,7 +113,7 @@ givePermissionWithTenant($this->user, $this->tenant->id, 'person.write'); $response = $this->withToken($this->token) - ->postJson("/api/v1/tenants/{$this->tenant->id}/persons", [ + ->postJson("/v1/tenants/{$this->tenant->id}/persons", [ 'email_plain' => 'test@example.com', 'phone_plain' => '+49 123 456789', ]); @@ -132,7 +132,7 @@ givePermissionWithTenant($this->user, $this->tenant->id, 'person.write'); $response = $this->withToken($this->token) - ->postJson("/api/v1/tenants/{$this->tenant->id}/persons", [ + ->postJson("/v1/tenants/{$this->tenant->id}/persons", [ 'email_plain' => 'minimal@example.com', ]); @@ -149,7 +149,7 @@ $nonExistentTenantId = 99999; $response = $this->withToken($this->token) - ->postJson("/api/v1/tenants/{$nonExistentTenantId}/persons", [ + ->postJson("/v1/tenants/{$nonExistentTenantId}/persons", [ 'email_plain' => 'test@example.com', ]); @@ -169,14 +169,14 @@ }); test('returns 401 when not authenticated', function (): void { - $response = $this->getJson("/api/v1/tenants/{$this->tenant->id}/persons/by-email?email=search@example.com"); + $response = $this->getJson("/v1/tenants/{$this->tenant->id}/persons/by-email?email=search@example.com"); $response->assertStatus(401); }); test('returns 403 when user lacks person.read permission', function (): void { $response = $this->withToken($this->token) - ->getJson("/api/v1/tenants/{$this->tenant->id}/persons/by-email?email=search@example.com"); + ->getJson("/v1/tenants/{$this->tenant->id}/persons/by-email?email=search@example.com"); $response->assertStatus(403); }); @@ -185,7 +185,7 @@ givePermissionWithTenant($this->user, $this->tenant->id, 'person.read'); $response = $this->withToken($this->token) - ->getJson("/api/v1/tenants/{$this->tenant->id}/persons/by-email"); + ->getJson("/v1/tenants/{$this->tenant->id}/persons/by-email"); $response->assertStatus(400) ->assertJson([ @@ -197,7 +197,7 @@ givePermissionWithTenant($this->user, $this->tenant->id, 'person.read'); $response = $this->withToken($this->token) - ->getJson("/api/v1/tenants/{$this->tenant->id}/persons/by-email?email=notfound@example.com"); + ->getJson("/v1/tenants/{$this->tenant->id}/persons/by-email?email=notfound@example.com"); $response->assertStatus(404) ->assertJson([ @@ -209,7 +209,7 @@ givePermissionWithTenant($this->user, $this->tenant->id, 'person.read'); $response = $this->withToken($this->token) - ->getJson("/api/v1/tenants/{$this->tenant->id}/persons/by-email?email=search@example.com"); + ->getJson("/v1/tenants/{$this->tenant->id}/persons/by-email?email=search@example.com"); $response->assertStatus(200) ->assertJsonStructure([ @@ -228,7 +228,7 @@ givePermissionWithTenant($this->user, $this->tenant->id, 'person.read'); $response = $this->withToken($this->token) - ->getJson("/api/v1/tenants/{$this->tenant->id}/persons/by-email?email=SEARCH@EXAMPLE.COM"); + ->getJson("/v1/tenants/{$this->tenant->id}/persons/by-email?email=SEARCH@EXAMPLE.COM"); $response->assertStatus(200) ->assertJsonFragment([ @@ -240,7 +240,7 @@ givePermissionWithTenant($this->user, $this->tenant->id, 'person.read'); $response = $this->withToken($this->token) - ->getJson("/api/v1/tenants/{$this->tenant->id}/persons/by-email?email=search@example.com"); + ->getJson("/v1/tenants/{$this->tenant->id}/persons/by-email?email=search@example.com"); $response->assertStatus(200); $json = $response->json(); @@ -266,7 +266,7 @@ // Try to find tenant2's person using tenant1's endpoint $response = $this->withToken($this->token) - ->getJson("/api/v1/tenants/{$this->tenant->id}/persons/by-email?email=other@example.com"); + ->getJson("/v1/tenants/{$this->tenant->id}/persons/by-email?email=other@example.com"); $response->assertStatus(404); }); diff --git a/tests/Feature/RoleApiTest.php b/tests/Feature/RoleApiTest.php index f31fcff..8608b03 100644 --- a/tests/Feature/RoleApiTest.php +++ b/tests/Feature/RoleApiTest.php @@ -51,7 +51,7 @@ describe('POST /v1/users/{id}/roles - Assign Role', function () { test('returns 401 when not authenticated', function (): void { - $response = $this->postJson("/api/v1/users/{$this->targetUser->id}/roles", [ + $response = $this->postJson("/v1/users/{$this->targetUser->id}/roles", [ 'role' => 'manager', 'valid_from' => now()->toIso8601String(), 'valid_until' => now()->addDays(7)->toIso8601String(), @@ -62,7 +62,7 @@ test('returns 403 when user lacks role.assign permission', function (): void { $response = $this->withToken($this->token) - ->postJson("/api/v1/users/{$this->targetUser->id}/roles", [ + ->postJson("/v1/users/{$this->targetUser->id}/roles", [ 'role' => 'manager', 'valid_from' => now()->toIso8601String(), 'valid_until' => now()->addDays(7)->toIso8601String(), @@ -75,7 +75,7 @@ $this->user->givePermissionTo('role.assign'); $response = $this->withToken($this->token) - ->postJson("/api/v1/users/{$this->targetUser->id}/roles", [ + ->postJson("/v1/users/{$this->targetUser->id}/roles", [ 'valid_from' => now()->toIso8601String(), 'valid_until' => now()->addDays(7)->toIso8601String(), ]); @@ -88,7 +88,7 @@ $this->user->givePermissionTo('role.assign'); $response = $this->withToken($this->token) - ->postJson("/api/v1/users/{$this->targetUser->id}/roles", [ + ->postJson("/v1/users/{$this->targetUser->id}/roles", [ 'role' => 'manager', 'valid_from' => now()->addDays(7)->toIso8601String(), 'valid_until' => now()->toIso8601String(), // before valid_from @@ -105,7 +105,7 @@ $validUntil = now()->addDays(7); $response = $this->withToken($this->token) - ->postJson("/api/v1/users/{$this->targetUser->id}/roles", [ + ->postJson("/v1/users/{$this->targetUser->id}/roles", [ 'role' => 'manager', 'valid_from' => $validFrom->toIso8601String(), 'valid_until' => $validUntil->toIso8601String(), @@ -136,14 +136,14 @@ describe('GET /v1/users/{id}/roles - List Roles', function () { test('returns 401 when not authenticated', function (): void { - $response = $this->getJson("/api/v1/users/{$this->targetUser->id}/roles"); + $response = $this->getJson("/v1/users/{$this->targetUser->id}/roles"); $response->assertUnauthorized(); }); test('returns 403 when user lacks role.read permission', function (): void { $response = $this->withToken($this->token) - ->getJson("/api/v1/users/{$this->targetUser->id}/roles"); + ->getJson("/v1/users/{$this->targetUser->id}/roles"); $response->assertForbidden(); }); @@ -152,7 +152,7 @@ $this->user->givePermissionTo('role.read'); $response = $this->withToken($this->token) - ->getJson("/api/v1/users/{$this->targetUser->id}/roles"); + ->getJson("/v1/users/{$this->targetUser->id}/roles"); $response->assertOk() ->assertJson(['roles' => []]); @@ -174,7 +174,7 @@ ]); $response = $this->withToken($this->token) - ->getJson("/api/v1/users/{$this->targetUser->id}/roles"); + ->getJson("/v1/users/{$this->targetUser->id}/roles"); $response->assertOk() ->assertJsonStructure([ @@ -200,14 +200,14 @@ describe('DELETE /v1/users/{id}/roles/{role} - Revoke Role', function () { test('returns 401 when not authenticated', function (): void { - $response = $this->deleteJson("/api/v1/users/{$this->targetUser->id}/roles/manager"); + $response = $this->deleteJson("/v1/users/{$this->targetUser->id}/roles/manager"); $response->assertUnauthorized(); }); test('returns 403 when user lacks role.revoke permission', function (): void { $response = $this->withToken($this->token) - ->deleteJson("/api/v1/users/{$this->targetUser->id}/roles/manager"); + ->deleteJson("/v1/users/{$this->targetUser->id}/roles/manager"); $response->assertForbidden(); }); @@ -216,7 +216,7 @@ $this->user->givePermissionTo('role.revoke'); $response = $this->withToken($this->token) - ->deleteJson("/api/v1/users/{$this->targetUser->id}/roles/manager"); + ->deleteJson("/v1/users/{$this->targetUser->id}/roles/manager"); $response->assertNotFound(); }); @@ -235,7 +235,7 @@ expect($this->targetUser->hasRole('manager'))->toBeTrue(); $response = $this->withToken($this->token) - ->deleteJson("/api/v1/users/{$this->targetUser->id}/roles/manager"); + ->deleteJson("/v1/users/{$this->targetUser->id}/roles/manager"); $response->assertNoContent(); @@ -247,7 +247,7 @@ describe('PATCH /v1/users/{id}/roles/{role}/extend - Extend Role', function () { test('returns 401 when not authenticated', function (): void { - $response = $this->patchJson("/api/v1/users/{$this->targetUser->id}/roles/manager/extend", [ + $response = $this->patchJson("/v1/users/{$this->targetUser->id}/roles/manager/extend", [ 'valid_until' => now()->addDays(14)->toIso8601String(), ]); @@ -256,7 +256,7 @@ test('returns 403 when user lacks role.assign permission', function (): void { $response = $this->withToken($this->token) - ->patchJson("/api/v1/users/{$this->targetUser->id}/roles/manager/extend", [ + ->patchJson("/v1/users/{$this->targetUser->id}/roles/manager/extend", [ 'valid_until' => now()->addDays(14)->toIso8601String(), ]); @@ -267,7 +267,7 @@ $this->user->givePermissionTo('role.assign'); $response = $this->withToken($this->token) - ->patchJson("/api/v1/users/{$this->targetUser->id}/roles/manager/extend", [ + ->patchJson("/v1/users/{$this->targetUser->id}/roles/manager/extend", [ 'valid_until' => now()->addDays(14)->toIso8601String(), ]); @@ -287,7 +287,7 @@ // Try to "extend" to 7 days (actually shortening) $response = $this->withToken($this->token) - ->patchJson("/api/v1/users/{$this->targetUser->id}/roles/manager/extend", [ + ->patchJson("/v1/users/{$this->targetUser->id}/roles/manager/extend", [ 'valid_until' => now()->addDays(7)->toIso8601String(), ]); @@ -311,7 +311,7 @@ // Extend role $response = $this->withToken($this->token) - ->patchJson("/api/v1/users/{$this->targetUser->id}/roles/manager/extend", [ + ->patchJson("/v1/users/{$this->targetUser->id}/roles/manager/extend", [ 'valid_until' => $newValidUntil->toIso8601String(), 'reason' => 'Extended vacation period', ]); @@ -345,7 +345,7 @@ $this->user->givePermissionTo('role.assign'); $response = $this->withToken($this->token) - ->postJson("/api/v1/users/{$this->targetUser->id}/roles", [ + ->postJson("/v1/users/{$this->targetUser->id}/roles", [ 'role' => 'manager', 'valid_from' => now()->subDays(10)->toIso8601String(), 'valid_until' => now()->subDays(5)->toIso8601String(), @@ -359,7 +359,7 @@ $this->user->givePermissionTo('role.assign'); $response = $this->withToken($this->token) - ->postJson("/api/v1/users/{$this->targetUser->id}/roles", [ + ->postJson("/v1/users/{$this->targetUser->id}/roles", [ 'role' => 'manager', 'valid_from' => now()->toIso8601String(), ]); @@ -375,7 +375,7 @@ $this->user->givePermissionTo('role.assign'); $response = $this->withToken($this->token) - ->postJson("/api/v1/users/{$this->targetUser->id}/roles", [ + ->postJson("/v1/users/{$this->targetUser->id}/roles", [ 'role' => 'manager', 'valid_until' => now()->addDays(7)->toIso8601String(), ]); @@ -391,7 +391,7 @@ $this->user->givePermissionTo('role.assign'); $response = $this->withToken($this->token) - ->postJson("/api/v1/users/{$this->targetUser->id}/roles", [ + ->postJson("/v1/users/{$this->targetUser->id}/roles", [ 'role' => 'manager', ]); @@ -413,7 +413,7 @@ ]); $response = $this->withToken($this->token) - ->patchJson("/api/v1/users/{$this->targetUser->id}/roles/manager/extend", [ + ->patchJson("/v1/users/{$this->targetUser->id}/roles/manager/extend", [ 'valid_until' => now()->subDay()->toIso8601String(), ]); @@ -454,7 +454,7 @@ DB::enableQueryLog(); $response = $this->withToken($this->token) - ->getJson("/api/v1/users/{$this->targetUser->id}/roles"); + ->getJson("/v1/users/{$this->targetUser->id}/roles"); $queries = DB::getQueryLog(); DB::disableQueryLog(); diff --git a/tests/Feature/RoleManagementApiTest.php b/tests/Feature/RoleManagementApiTest.php index 7e07122..c362cc3 100644 --- a/tests/Feature/RoleManagementApiTest.php +++ b/tests/Feature/RoleManagementApiTest.php @@ -50,7 +50,7 @@ describe('GET /v1/roles - List Roles', function () { test('returns 401 when not authenticated', function (): void { - $response = $this->getJson('/api/v1/roles'); + $response = $this->getJson('/v1/roles'); $response->assertUnauthorized(); }); @@ -59,7 +59,7 @@ // User has no permissions $response = $this->withToken($this->token) - ->getJson('/api/v1/roles'); + ->getJson('/v1/roles'); $response->assertForbidden(); }); @@ -68,7 +68,7 @@ $this->user->givePermissionTo('roles.read'); $response = $this->withToken($this->token) - ->getJson('/api/v1/roles'); + ->getJson('/v1/roles'); $response->assertOk() ->assertJsonStructure(['data']) @@ -87,7 +87,7 @@ $guard->givePermissionTo('shifts.read'); $response = $this->withToken($this->token) - ->getJson('/api/v1/roles'); + ->getJson('/v1/roles'); $response->assertOk() ->assertJsonStructure([ @@ -102,7 +102,7 @@ describe('POST /v1/roles - Create Role', function () { test('returns 401 when not authenticated', function (): void { - $response = $this->postJson('/api/v1/roles', [ + $response = $this->postJson('/v1/roles', [ 'name' => 'Regional Manager', 'permissions' => ['employees.read'], ]); @@ -114,7 +114,7 @@ $this->user->givePermissionTo('roles.read'); $response = $this->withToken($this->token) - ->postJson('/api/v1/roles', [ + ->postJson('/v1/roles', [ 'name' => 'Regional Manager', 'permissions' => ['employees.read'], ]); @@ -126,7 +126,7 @@ $this->user->givePermissionTo('roles.create'); $response = $this->withToken($this->token) - ->postJson('/api/v1/roles', [ + ->postJson('/v1/roles', [ 'permissions' => ['employees.read'], ]); @@ -139,7 +139,7 @@ Role::create(['name' => 'Manager', 'guard_name' => 'sanctum']); $response = $this->withToken($this->token) - ->postJson('/api/v1/roles', [ + ->postJson('/v1/roles', [ 'name' => 'Manager', 'permissions' => ['employees.read'], ]); @@ -152,7 +152,7 @@ $this->user->givePermissionTo('roles.create'); $response = $this->withToken($this->token) - ->postJson('/api/v1/roles', [ + ->postJson('/v1/roles', [ 'name' => 'Regional Manager', 'permissions' => ['non.existent.permission'], ]); @@ -165,7 +165,7 @@ $this->user->givePermissionTo('roles.create'); $response = $this->withToken($this->token) - ->postJson('/api/v1/roles', [ + ->postJson('/v1/roles', [ 'name' => 'Regional Manager', 'permissions' => ['employees.read', 'shifts.read'], ]); @@ -184,7 +184,7 @@ $this->user->givePermissionTo('roles.create'); $response = $this->withToken($this->token) - ->postJson('/api/v1/roles', [ + ->postJson('/v1/roles', [ 'name' => 'Empty Role', 'permissions' => [], ]); @@ -198,7 +198,7 @@ test('returns 401 when not authenticated', function (): void { $role = Role::create(['name' => 'Manager', 'guard_name' => 'sanctum']); - $response = $this->getJson("/api/v1/roles/{$role->id}"); + $response = $this->getJson("/v1/roles/{$role->id}"); $response->assertUnauthorized(); }); @@ -207,7 +207,7 @@ $role = Role::create(['name' => 'Manager', 'guard_name' => 'sanctum']); $response = $this->withToken($this->token) - ->getJson("/api/v1/roles/{$role->id}"); + ->getJson("/v1/roles/{$role->id}"); $response->assertForbidden(); }); @@ -216,7 +216,7 @@ $this->user->givePermissionTo('roles.read'); $response = $this->withToken($this->token) - ->getJson('/api/v1/roles/999999'); + ->getJson('/v1/roles/999999'); $response->assertNotFound(); }); @@ -228,7 +228,7 @@ $role->givePermissionTo(['employees.read', 'shifts.read']); $response = $this->withToken($this->token) - ->getJson("/api/v1/roles/{$role->id}"); + ->getJson("/v1/roles/{$role->id}"); $response->assertOk() ->assertJsonStructure([ @@ -243,7 +243,7 @@ test('returns 401 when not authenticated', function (): void { $role = Role::create(['name' => 'Manager', 'guard_name' => 'sanctum']); - $response = $this->patchJson("/api/v1/roles/{$role->id}", [ + $response = $this->patchJson("/v1/roles/{$role->id}", [ 'name' => 'Senior Manager', ]); @@ -255,7 +255,7 @@ $role = Role::create(['name' => 'Manager', 'guard_name' => 'sanctum']); $response = $this->withToken($this->token) - ->patchJson("/api/v1/roles/{$role->id}", [ + ->patchJson("/v1/roles/{$role->id}", [ 'name' => 'Senior Manager', ]); @@ -266,7 +266,7 @@ $this->user->givePermissionTo('roles.update'); $response = $this->withToken($this->token) - ->patchJson('/api/v1/roles/999999', [ + ->patchJson('/v1/roles/999999', [ 'name' => 'New Name', ]); @@ -279,7 +279,7 @@ $guard = Role::create(['name' => 'Guard', 'guard_name' => 'sanctum']); $response = $this->withToken($this->token) - ->patchJson("/api/v1/roles/{$guard->id}", [ + ->patchJson("/v1/roles/{$guard->id}", [ 'name' => 'Manager', ]); @@ -292,7 +292,7 @@ $role = Role::create(['name' => 'Manager', 'guard_name' => 'sanctum']); $response = $this->withToken($this->token) - ->patchJson("/api/v1/roles/{$role->id}", [ + ->patchJson("/v1/roles/{$role->id}", [ 'name' => 'Senior Manager', ]); @@ -308,7 +308,7 @@ $role->givePermissionTo('employees.read'); $response = $this->withToken($this->token) - ->patchJson("/api/v1/roles/{$role->id}", [ + ->patchJson("/v1/roles/{$role->id}", [ 'permissions' => ['shifts.read', 'employees.create'], ]); @@ -326,7 +326,7 @@ test('returns 401 when not authenticated', function (): void { $role = Role::create(['name' => 'Manager', 'guard_name' => 'sanctum']); - $response = $this->deleteJson("/api/v1/roles/{$role->id}"); + $response = $this->deleteJson("/v1/roles/{$role->id}"); $response->assertUnauthorized(); }); @@ -336,7 +336,7 @@ $role = Role::create(['name' => 'Manager', 'guard_name' => 'sanctum']); $response = $this->withToken($this->token) - ->deleteJson("/api/v1/roles/{$role->id}"); + ->deleteJson("/v1/roles/{$role->id}"); $response->assertForbidden(); }); @@ -345,7 +345,7 @@ $this->user->givePermissionTo('roles.delete'); $response = $this->withToken($this->token) - ->deleteJson('/api/v1/roles/999999'); + ->deleteJson('/v1/roles/999999'); $response->assertNotFound(); }); @@ -359,7 +359,7 @@ $otherUser->assignRole($role); $response = $this->withToken($this->token) - ->deleteJson("/api/v1/roles/{$role->id}"); + ->deleteJson("/v1/roles/{$role->id}"); $response->assertStatus(422) ->assertJsonFragment(['message' => 'Cannot delete role while assigned to users']) @@ -371,7 +371,7 @@ $role = Role::create(['name' => 'Manager', 'guard_name' => 'sanctum']); $response = $this->withToken($this->token) - ->deleteJson("/api/v1/roles/{$role->id}"); + ->deleteJson("/v1/roles/{$role->id}"); $response->assertNoContent(); diff --git a/tests/Feature/UserPermissionAssignmentApiTest.php b/tests/Feature/UserPermissionAssignmentApiTest.php index 1e8cd2c..3d6fa0c 100644 --- a/tests/Feature/UserPermissionAssignmentApiTest.php +++ b/tests/Feature/UserPermissionAssignmentApiTest.php @@ -56,7 +56,7 @@ $user->givePermissionTo('employees.export'); // Direct permission $response = $this->actingAs($user, 'sanctum') - ->getJson("/api/v1/users/{$user->id}/permissions"); + ->getJson("/v1/users/{$user->id}/permissions"); $response->assertOk() ->assertJsonStructure([ @@ -83,7 +83,7 @@ $targetUser->assignRole('Manager'); $response = $this->actingAs($admin, 'sanctum') - ->getJson("/api/v1/users/{$targetUser->id}/permissions"); + ->getJson("/v1/users/{$targetUser->id}/permissions"); $response->assertOk() ->assertJsonStructure(['data' => ['via_roles', 'direct', 'all']]); @@ -94,7 +94,7 @@ $otherUser = User::factory()->create(); $response = $this->actingAs($user, 'sanctum') - ->getJson("/api/v1/users/{$otherUser->id}/permissions"); + ->getJson("/v1/users/{$otherUser->id}/permissions"); $response->assertForbidden(); }); @@ -106,7 +106,7 @@ $targetUser = User::factory()->create(); $response = $this->actingAs($admin, 'sanctum') - ->postJson("/api/v1/users/{$targetUser->id}/permissions", [ + ->postJson("/v1/users/{$targetUser->id}/permissions", [ 'permissions' => ['employees.export'], ]); @@ -126,7 +126,7 @@ $validUntil = now()->addDays(7)->toIso8601String(); $response = $this->actingAs($admin, 'sanctum') - ->postJson("/api/v1/users/{$targetUser->id}/permissions", [ + ->postJson("/v1/users/{$targetUser->id}/permissions", [ 'permissions' => ['reports.generate'], 'valid_from' => $validFrom, 'valid_until' => $validUntil, @@ -144,7 +144,7 @@ $targetUser = User::factory()->create(); $response = $this->actingAs($user, 'sanctum') - ->postJson("/api/v1/users/{$targetUser->id}/permissions", [ + ->postJson("/v1/users/{$targetUser->id}/permissions", [ 'permissions' => ['employees.export'], ]); @@ -161,7 +161,7 @@ expect($targetUser->hasDirectPermission('employees.export'))->toBeTrue(); $response = $this->actingAs($admin, 'sanctum') - ->deleteJson("/api/v1/users/{$targetUser->id}/permissions/employees.export"); + ->deleteJson("/v1/users/{$targetUser->id}/permissions/employees.export"); $response->assertOk(); @@ -177,7 +177,7 @@ $targetUser->givePermissionTo('employees.read'); // Also has it directly $response = $this->actingAs($admin, 'sanctum') - ->deleteJson("/api/v1/users/{$targetUser->id}/permissions/employees.read"); + ->deleteJson("/v1/users/{$targetUser->id}/permissions/employees.read"); $response->assertOk(); @@ -192,7 +192,7 @@ $user->givePermissionTo('employees.export'); // Direct $response = $this->actingAs($user, 'sanctum') - ->getJson("/api/v1/users/{$user->id}/permissions/direct"); + ->getJson("/v1/users/{$user->id}/permissions/direct"); $response->assertOk() ->assertJsonCount(1, 'data.direct') @@ -202,17 +202,17 @@ test('unauthenticated user cannot access permissions endpoints', function () { $user = User::factory()->create(); - $this->getJson("/api/v1/users/{$user->id}/permissions") + $this->getJson("/v1/users/{$user->id}/permissions") ->assertUnauthorized(); - $this->postJson("/api/v1/users/{$user->id}/permissions", [ + $this->postJson("/v1/users/{$user->id}/permissions", [ 'permissions' => ['employees.read'], ])->assertUnauthorized(); - $this->deleteJson("/api/v1/users/{$user->id}/permissions/employees.read") + $this->deleteJson("/v1/users/{$user->id}/permissions/employees.read") ->assertUnauthorized(); - $this->getJson("/api/v1/users/{$user->id}/permissions/direct") + $this->getJson("/v1/users/{$user->id}/permissions/direct") ->assertUnauthorized(); }); @@ -223,7 +223,7 @@ $targetUser = User::factory()->create(); $response = $this->actingAs($admin, 'sanctum') - ->postJson("/api/v1/users/{$targetUser->id}/permissions", [ + ->postJson("/v1/users/{$targetUser->id}/permissions", [ 'permissions' => [], ]); @@ -238,7 +238,7 @@ $targetUser = User::factory()->create(); $response = $this->actingAs($admin, 'sanctum') - ->postJson("/api/v1/users/{$targetUser->id}/permissions", [ + ->postJson("/v1/users/{$targetUser->id}/permissions", [ 'permissions' => ['nonexistent.permission'], ]); @@ -253,7 +253,7 @@ $targetUser = User::factory()->create(); $response = $this->actingAs($admin, 'sanctum') - ->postJson("/api/v1/users/{$targetUser->id}/permissions", [ + ->postJson("/v1/users/{$targetUser->id}/permissions", [ 'permissions' => ['employees.export'], 'valid_from' => now()->addDays(7)->toIso8601String(), 'valid_until' => now()->toIso8601String(),