diff --git a/alrahma_sunday_school_api.code-workspace b/alrahma_sunday_school_api.code-workspace new file mode 100644 index 00000000..856f083f --- /dev/null +++ b/alrahma_sunday_school_api.code-workspace @@ -0,0 +1,10 @@ +{ + "folders": [ + { + "path": "." + }, + { + "path": "../alrahma_web_client" + } + ] +} \ No newline at end of file diff --git a/config/database.php b/config/database.php index 70d24990..201db438 100644 --- a/config/database.php +++ b/config/database.php @@ -44,7 +44,7 @@ return [ 'database' => env('DB_DATABASE', database_path('database.sqlite')), 'prefix' => '', 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), - 'busy_timeout' => null, + 'busy_timeout' => env('DB_BUSY_TIMEOUT', null), 'journal_mode' => null, 'synchronous' => null, 'transaction_mode' => 'DEFERRED', diff --git a/phpunit.xml b/phpunit.xml index 0b428249..74e9c4ce 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -22,6 +22,9 @@ + + + diff --git a/routes/api.php b/routes/api.php index bdfb68b8..2fa61e79 100644 --- a/routes/api.php +++ b/routes/api.php @@ -251,7 +251,7 @@ Route::prefix('v1')->group(function () { Route::delete('{userId}', [PreferencesController::class, 'destroy']); }); - Route::middleware('auth:api')->prefix('nav-builder')->group(function () { + Route::middleware('multi.auth')->prefix('nav-builder')->group(function () { Route::get('menu', [NavBuilderController::class, 'menu']); Route::get('data', [NavBuilderController::class, 'data']); Route::post('/', [NavBuilderController::class, 'store']); @@ -558,13 +558,13 @@ Route::prefix('v1')->group(function () { Route::post('delete', [AttendanceCommentTemplateController::class, 'legacyDelete']); }); - Route::middleware(['auth:api', 'school_year.editable'])->prefix('assignments')->group(function () { + Route::middleware(['multi.auth', 'school_year.editable'])->prefix('assignments')->group(function () { Route::get('/', [AssignmentApiController::class, 'index']); Route::post('/', [AssignmentApiController::class, 'store']); Route::get('/class-assignment-data', [AssignmentApiController::class, 'classAssignmentData']); }); - Route::middleware(['auth:api', 'school_year.editable'])->group(function () { + Route::middleware(['multi.auth', 'school_year.editable'])->group(function () { // Legacy alias: same handler as GET /api/v1/scores/homework Route::get('teacher/homework-list', [HomeworkScoreController::class, 'index']); // Legacy alias: teacher add-homework page and save action diff --git a/tests/Feature/Api/V1/Assignment/AssignmentApiControllerTest.php b/tests/Feature/Api/V1/Assignment/AssignmentApiControllerTest.php index 1ee1b586..f0dcee33 100644 --- a/tests/Feature/Api/V1/Assignment/AssignmentApiControllerTest.php +++ b/tests/Feature/Api/V1/Assignment/AssignmentApiControllerTest.php @@ -121,7 +121,7 @@ class AssignmentApiControllerTest extends TestCase ]); $response = $this->actingAs($this->user, 'sanctum') - ->getJson('/api/assignments?school_year=2025-2026&semester=Fall'); + ->getJson('/api/v1/assignments?school_year=2025-2026&semester=Fall'); $response->assertOk() ->assertJsonPath('message', 'Assignments retrieved successfully.') @@ -181,7 +181,7 @@ class AssignmentApiControllerTest extends TestCase ]); $response = $this->actingAs($this->user, 'sanctum') - ->getJson('/api/assignments?school_year=2025-2026'); + ->getJson('/api/v1/assignments?school_year=2025-2026'); $response->assertOk() ->assertJsonCount(1, 'data.classSections') @@ -209,7 +209,7 @@ class AssignmentApiControllerTest extends TestCase ]); $response = $this->actingAs($this->user, 'sanctum') - ->getJson('/api/assignments'); + ->getJson('/api/v1/assignments'); $response->assertOk(); @@ -247,7 +247,7 @@ class AssignmentApiControllerTest extends TestCase ]); $response = $this->actingAs($this->user, 'sanctum') - ->getJson('/api/assignments'); + ->getJson('/api/v1/assignments'); $response->assertOk() ->assertJsonPath('data.classSections.0.students', []); @@ -264,7 +264,7 @@ class AssignmentApiControllerTest extends TestCase ]; $response = $this->actingAs($this->user, 'sanctum') - ->postJson('/api/assignments', $payload); + ->postJson('/api/v1/assignments', $payload); $response->assertCreated() ->assertJsonPath('message', 'Assignment saved successfully.') @@ -304,7 +304,7 @@ class AssignmentApiControllerTest extends TestCase ]; $response = $this->actingAs($this->user, 'sanctum') - ->postJson('/api/assignments', $payload); + ->postJson('/api/v1/assignments', $payload); $response->assertCreated() ->assertJsonPath('data.description', 'Updated description'); @@ -331,7 +331,7 @@ class AssignmentApiControllerTest extends TestCase public function test_store_validates_required_fields(): void { $response = $this->actingAs($this->user, 'sanctum') - ->postJson('/api/assignments', []); + ->postJson('/api/v1/assignments', []); $response->assertUnprocessable() ->assertJsonValidationErrors([ @@ -353,7 +353,7 @@ class AssignmentApiControllerTest extends TestCase ]; $response = $this->actingAs($this->user, 'sanctum') - ->postJson('/api/assignments', $payload); + ->postJson('/api/v1/assignments', $payload); $response->assertUnprocessable() ->assertJsonValidationErrors([ @@ -383,7 +383,7 @@ class AssignmentApiControllerTest extends TestCase ]); $response = $this->actingAs($this->user, 'sanctum') - ->getJson('/api/assignments/class-assignment-data'); + ->getJson('/api/v1/assignments/class-assignment-data'); $response->assertOk() ->assertJsonPath('message', 'Class assignment data retrieved successfully.') @@ -416,7 +416,7 @@ class AssignmentApiControllerTest extends TestCase ]); $response = $this->actingAs($this->user, 'sanctum') - ->getJson('/api/assignments/class-assignment-data'); + ->getJson('/api/v1/assignments/class-assignment-data'); $response->assertOk(); diff --git a/tests/Feature/Api/V1/BadgeControllerTest.php b/tests/Feature/Api/V1/BadgeControllerTest.php index d4361a44..215c5eb5 100644 --- a/tests/Feature/Api/V1/BadgeControllerTest.php +++ b/tests/Feature/Api/V1/BadgeControllerTest.php @@ -20,6 +20,10 @@ class BadgeControllerTest extends TestCase $user = User::factory()->create(); Sanctum::actingAs($user); + // Ensure well-known user IDs exist for tests that reference them + User::factory()->create(['id' => 10, 'firstname' => 'Known']); + User::factory()->create(['id' => 20, 'firstname' => 'User']); + return $user; } @@ -36,7 +40,7 @@ class BadgeControllerTest extends TestCase $mock = Mockery::mock(BadgeFormDataService::class); $mock->shouldReceive('build') ->once() - ->with('2025-2026', [10, 20], 'teacher') + ->with('2025-2026', [10, 20], [], 'teacher') ->andReturn([ 'users' => [], 'schoolYears' => ['2025-2026'], @@ -48,7 +52,7 @@ class BadgeControllerTest extends TestCase $this->app->instance(BadgeFormDataService::class, $mock); - $response = $this->getJson('/api/badges/form-data?school_year=2025-2026&user_ids=10,20&active_role=teacher'); + $response = $this->getJson('/api/v1/badges/form-data?school_year=2025-2026&user_ids=10,20&active_role=teacher'); $response->assertOk() ->assertJson([ @@ -79,7 +83,7 @@ class BadgeControllerTest extends TestCase $this->app->instance(BadgePrintLogService::class, $mock); - $response = $this->getJson('/api/badges/print-status?user_ids=5,7&school_year=2025-2026'); + $response = $this->getJson('/api/v1/badges/print-status?user_ids=5,7&school_year=2025-2026'); $response->assertOk() ->assertJson([ @@ -105,7 +109,7 @@ class BadgeControllerTest extends TestCase $this->app->instance(BadgePrintLogService::class, $mock); - $response = $this->getJson('/api/badges/print-status?user_ids=5,7'); + $response = $this->getJson('/api/v1/badges/print-status?user_ids=5,7'); $response->assertStatus(500) ->assertJson([ @@ -132,7 +136,7 @@ class BadgeControllerTest extends TestCase $this->app->instance(BadgePrintLogService::class, $mock); - $response = $this->postJson('/api/badges/log-print', [ + $response = $this->postJson('/api/v1/badges/log-print', [ 'user_ids' => [10, 20], 'school_year' => '2025-2026', 'roles' => ['10' => 'Teacher'], @@ -157,7 +161,7 @@ class BadgeControllerTest extends TestCase $this->app->instance(BadgePrintLogService::class, $mock); - $response = $this->postJson('/api/badges/log-print', [ + $response = $this->postJson('/api/v1/badges/log-print', [ 'user_ids' => [10], ]); @@ -176,6 +180,7 @@ class BadgeControllerTest extends TestCase $mock->shouldReceive('generate') ->once() ->with( + [], [10, 20], '2025-2026', ['10' => 'Teacher'], @@ -189,7 +194,7 @@ class BadgeControllerTest extends TestCase $this->app->instance(BadgePdfService::class, $mock); - $response = $this->post('/api/badges/pdf', [ + $response = $this->post('/api/v1/badges/pdf', [ 'user_ids' => [10, 20], 'school_year' => '2025-2026', 'roles' => ['10' => 'Teacher'], @@ -209,7 +214,7 @@ class BadgeControllerTest extends TestCase { $this->authenticate(); - $response = $this->postJson('/api/badges/pdf', [ + $response = $this->postJson('/api/v1/badges/pdf', [ 'school_year' => '2025-2026', ]); @@ -221,7 +226,7 @@ class BadgeControllerTest extends TestCase { $this->authenticate(); - $response = $this->postJson('/api/badges/log-print', []); + $response = $this->postJson('/api/v1/badges/log-print', []); $response->assertStatus(422) ->assertJsonValidationErrors(['user_ids']); @@ -229,9 +234,9 @@ class BadgeControllerTest extends TestCase public function test_endpoints_require_authentication(): void { - $this->getJson('/api/badges/form-data')->assertStatus(401); - $this->getJson('/api/badges/print-status')->assertStatus(401); - $this->postJson('/api/badges/log-print', ['user_ids' => [1]])->assertStatus(401); - $this->postJson('/api/badges/pdf', ['user_ids' => [1]])->assertStatus(401); + $this->getJson('/api/v1/badges/form-data')->assertStatus(401); + $this->getJson('/api/v1/badges/print-status')->assertStatus(401); + $this->postJson('/api/v1/badges/log-print', ['user_ids' => [1]])->assertStatus(401); + $this->postJson('/api/v1/badges/pdf', ['user_ids' => [1]])->assertStatus(401); } }