makeDb(); $users = new UserRepository($pdo); $this->assertSame(0, $users->count()); $r = $users->upsertFromOidc( oid: 'oid-alice', email: 'alice@example.com', name: 'Alice', promoteToAdmin: true, // caller's decision — see BootstrapAdmin::matches ); $this->assertTrue($r['user']->isAdmin); $this->assertNull($r['before']); } public function testSecondUserDoesNotBecomeAdmin(): void { $pdo = $this->makeDb(); $users = new UserRepository($pdo); $users->upsertFromOidc('oid-alice', 'alice@x', 'Alice', true); // Caller passes promoteToAdmin=false because an admin already exists. $r2 = $users->upsertFromOidc('oid-bob', 'bob@x', 'Bob', false); $this->assertFalse($r2['user']->isAdmin); } public function testReLoginDoesNotRegressAdminStatus(): void { $pdo = $this->makeDb(); $users = new UserRepository($pdo); $users->upsertFromOidc('oid-alice', 'alice@x', 'Alice', true); // simulate a later login: count > 0 so promoteToAdmin=false $r = $users->upsertFromOidc('oid-alice', 'alice@x', 'Alice', false); $this->assertTrue($r['user']->isAdmin, 're-login must not demote admin'); $this->assertNotNull($r['before']); } public function testForceAdminPromotesEvenOnUpdate(): void { // Local-admin login path sets forceAdmin=true so a demoted user gets // promoted back on next sign-in. $pdo = $this->makeDb(); $users = new UserRepository($pdo); $r1 = $users->upsertFromOidc('local:admin@x', 'admin@x', 'Admin', true, true); $this->assertTrue($r1['user']->isAdmin); // Manually demote. $pdo->exec('UPDATE users SET is_admin = 0 WHERE id = ' . $r1['user']->id); $r2 = $users->upsertFromOidc('local:admin@x', 'admin@x', 'Admin', false, true); $this->assertTrue($r2['user']->isAdmin, 'forceAdmin must re-promote on update'); } public function testUpsertUpdatesEmailAndName(): void { $pdo = $this->makeDb(); $users = new UserRepository($pdo); $users->upsertFromOidc('oid-alice', 'old@x', 'Old Name', true); $r = $users->upsertFromOidc('oid-alice', 'new@x', 'New Name', false); $this->assertSame('new@x', $r['user']->email); $this->assertSame('New Name', $r['user']->displayName); } public function testCountReflectsInsertedUsers(): void { $pdo = $this->makeDb(); $users = new UserRepository($pdo); $this->assertSame(0, $users->count()); $users->upsertFromOidc('oid-1', 'a@x', 'A', true); $this->assertSame(1, $users->count()); $users->upsertFromOidc('oid-2', 'b@x', 'B', false); $this->assertSame(2, $users->count()); // Re-upsert existing user shouldn't add a row. $users->upsertFromOidc('oid-1', 'a@x', 'A', false); $this->assertSame(2, $users->count()); } // ------------------------------------------------------------------ // Phase 9: users management page helpers // ------------------------------------------------------------------ public function testAllReturnsEveryUserOrderedByEmail(): void { $pdo = $this->makeDb(); $users = new UserRepository($pdo); $users->upsertFromOidc('oid-c', 'carol@x', 'Carol', true); $users->upsertFromOidc('oid-a', 'alice@x', 'Alice', false); $users->upsertFromOidc('oid-b', 'BOB@x', 'Bob', false); $all = $users->all(); $this->assertCount(3, $all); $this->assertSame(['alice@x', 'BOB@x', 'carol@x'], array_map(fn($u) => $u->email, $all)); } public function testCountAdmins(): void { $pdo = $this->makeDb(); $users = new UserRepository($pdo); $this->assertSame(0, $users->countAdmins()); $users->upsertFromOidc('oid-a', 'a@x', 'A', true); $this->assertSame(1, $users->countAdmins()); $users->upsertFromOidc('oid-b', 'b@x', 'B', false); $this->assertSame(1, $users->countAdmins()); $users->upsertFromOidc('oid-c', 'c@x', 'C', false, true); // forceAdmin $this->assertSame(2, $users->countAdmins()); } public function testSetAdminTogglesAndReportsDiff(): void { $pdo = $this->makeDb(); $users = new UserRepository($pdo); $users->upsertFromOidc('oid-a', 'a@x', 'A', true); $users->upsertFromOidc('oid-b', 'b@x', 'B', false); $bob = $users->findByOid('oid-b'); $r = $users->setAdmin($bob->id, true); $this->assertFalse($r['before']->isAdmin); $this->assertTrue ($r['after']->isAdmin); $this->assertSame(2, $users->countAdmins()); $r = $users->setAdmin($bob->id, false); $this->assertTrue ($r['before']->isAdmin); $this->assertFalse($r['after']->isAdmin); $this->assertSame(1, $users->countAdmins()); } }