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);
}
}