createUser('teacher'); Sanctum::actingAs($user); $response = $this->getJson('/api/v1/ip-bans'); $response->assertForbidden(); } public function test_index_returns_bans(): void { $admin = $this->createUser('admin'); Sanctum::actingAs($admin); DB::table('ip_attempts')->insert([ 'ip_address' => '10.0.0.1', 'attempts' => 5, 'last_attempt_at' => now('UTC'), 'blocked_until' => now('UTC')->addHours(2), ]); $response = $this->getJson('/api/v1/ip-bans?status=active'); $response->assertOk(); $response->assertJsonPath('data.bans.0.ip_address', '10.0.0.1'); $response->assertJsonStructure(['data' => ['meta']]); } public function test_show_returns_ban(): void { $admin = $this->createUser('admin'); Sanctum::actingAs($admin); DB::table('ip_attempts')->insert([ 'ip_address' => '10.0.0.2', 'attempts' => 3, 'last_attempt_at' => now('UTC'), 'blocked_until' => now('UTC')->addHours(1), ]); $response = $this->getJson('/api/v1/ip-bans/1'); $response->assertOk(); $response->assertJsonPath('data.ban.ip_address', '10.0.0.2'); } public function test_ban_creates_block(): void { $admin = $this->createUser('admin'); Sanctum::actingAs($admin); DB::table('ip_attempts')->insert([ 'ip_address' => '10.0.0.3', 'attempts' => 1, 'last_attempt_at' => now('UTC'), ]); $response = $this->postJson('/api/v1/ip-bans/ban', [ 'ip' => '10.0.0.3', 'hours' => 12, ]); $response->assertOk(); $response->assertJsonPath('data.ban.ip_address', '10.0.0.3'); $this->assertDatabaseHas('ip_attempts', [ 'ip_address' => '10.0.0.3', ]); } public function test_unban_single(): void { $admin = $this->createUser('admin'); Sanctum::actingAs($admin); DB::table('ip_attempts')->insert([ 'ip_address' => '10.0.0.4', 'attempts' => 5, 'last_attempt_at' => now('UTC'), 'blocked_until' => now('UTC')->addHours(2), ]); $response = $this->postJson('/api/v1/ip-bans/unban', [ 'ip' => '10.0.0.4', ]); $response->assertOk(); $this->assertDatabaseHas('ip_attempts', [ 'ip_address' => '10.0.0.4', 'blocked_until' => null, 'attempts' => 0, ]); } public function test_unban_all(): void { $admin = $this->createUser('admin'); Sanctum::actingAs($admin); DB::table('ip_attempts')->insert([ [ 'ip_address' => '10.0.0.5', 'attempts' => 5, 'last_attempt_at' => now('UTC'), 'blocked_until' => now('UTC')->addHours(2), ], [ 'ip_address' => '10.0.0.6', 'attempts' => 2, 'last_attempt_at' => now('UTC'), 'blocked_until' => now('UTC')->addHours(2), ], ]); $response = $this->postJson('/api/v1/ip-bans/unban', [ 'all' => true, ]); $response->assertOk(); $this->assertDatabaseHas('ip_attempts', [ 'ip_address' => '10.0.0.5', 'blocked_until' => null, ]); $this->assertDatabaseHas('ip_attempts', [ 'ip_address' => '10.0.0.6', 'blocked_until' => null, ]); } public function test_ban_validation_requires_ip_or_id(): void { $admin = $this->createUser('admin'); Sanctum::actingAs($admin); $response = $this->postJson('/api/v1/ip-bans/ban', [ 'hours' => 12, ]); $response->assertStatus(422); $response->assertJsonStructure(['message', 'errors']); } private function createUser(string $roleName): User { $roleId = DB::table('roles')->insertGetId([ 'name' => $roleName, 'priority' => 1, 'is_active' => 1, ]); $user = User::query()->create([ 'firstname' => 'Test', 'lastname' => 'User', 'email' => $roleName.'@example.com', 'cellphone' => '5555555555', 'address_street' => '123 Main', 'city' => 'City', 'state' => 'ST', 'zip' => '12345', 'accept_school_policy' => 1, 'status' => 'Active', 'password' => bcrypt('secret'), 'semester' => 'Fall', 'school_year' => '2025-2026', ]); DB::table('user_roles')->insert([ 'user_id' => $user->id, 'role_id' => $roleId, ]); return $user; } }