get(UserRepository::class), static::getContainer()->get(ClinicStaffRepository::class), static::getContainer()->get(UserPasswordHasherInterface::class), ); } /** @return array{0: Doctor, 1: ClinicStaff, 2: string} */ private function staffWithAccount(bool $active = true): array { $ownerUser = $this->createUser(['ROLE_DOCTOR']); $doctor = new Doctor($ownerUser, 'دکتر تست'); $this->em->persist($doctor); $this->em->flush(); $staff = new ClinicStaff('doctor', $doctor->getId(), 'زهرا احمدی'); $staff->setActive($active); $this->em->persist($staff); $this->em->flush(); $mobile = '0912' . str_pad((string) random_int(0, 9_999_999), 7, '0', STR_PAD_LEFT); $this->service()->attachAccount($staff, $mobile, 'Staff@1234', $ownerUser); return [$doctor, $staff, $mobile]; } private function json(): array { return json_decode($this->client->getResponse()->getContent(), true); } public function testStaffCanLogInAndSeesOwnEnvironment(): void { [$doctor, , $mobile] = $this->staffWithAccount(); $this->client->request('POST', '/api/v1/user/login', [], [], ['CONTENT_TYPE' => 'application/json'], json_encode([ 'mobile_number' => $mobile, 'password' => 'Staff@1234', ])); self::assertSame(200, $this->client->getResponse()->getStatusCode()); $token = $this->json()['access_token'] ?? null; self::assertNotNull($token); $this->client->request('GET', '/oauth/userinfo', [], [], ['HTTP_AUTHORIZATION' => 'Bearer ' . $token]); self::assertSame(200, $this->client->getResponse()->getStatusCode()); $data = $this->json()['data']; self::assertSame('staff', $data['primary_role']); $staffContexts = array_values(array_filter($data['available_contexts'], fn(array $c) => $c['role'] === 'staff')); self::assertCount(1, $staffContexts); self::assertSame($doctor->getUuid(), $staffContexts[0]['db_uuid']); self::assertTrue($staffContexts[0]['permissions']['resources']['services']['view']); self::assertArrayNotHasKey('patients', $staffContexts[0]['permissions']['resources']); } /** پرسنل غیرفعال: لاگین باز است ولی هیچ محیطی ندارد. */ public function testInactiveStaffGetsNoContext(): void { [, , $mobile] = $this->staffWithAccount(active: false); $this->client->request('POST', '/api/v1/user/login', [], [], ['CONTENT_TYPE' => 'application/json'], json_encode([ 'mobile_number' => $mobile, 'password' => 'Staff@1234', ])); $token = $this->json()['access_token'] ?? null; self::assertNotNull($token); $this->client->request('GET', '/oauth/userinfo', [], [], ['HTTP_AUTHORIZATION' => 'Bearer ' . $token]); $data = $this->json()['data']; self::assertSame('staff', $data['primary_role']); self::assertSame([], array_values(array_filter($data['available_contexts'], fn(array $c) => $c['role'] === 'staff'))); } /** مرزی: منشی‌ای که پرسنل هم هست، نقش قوی‌ترش را نگه می‌دارد. */ public function testSecretaryRoleWinsOverStaffRole(): void { [, $staff, $mobile] = $this->staffWithAccount(); $user = static::getContainer()->get(UserRepository::class)->findByMobile($mobile); $user->addRole('ROLE_SECRETARY'); $this->em->flush(); $this->client->request('POST', '/api/v1/user/login', [], [], ['CONTENT_TYPE' => 'application/json'], json_encode([ 'mobile_number' => $mobile, 'password' => 'Staff@1234', ])); $token = $this->json()['access_token']; $this->client->request('GET', '/oauth/userinfo', [], [], ['HTTP_AUTHORIZATION' => 'Bearer ' . $token]); $data = $this->json()['data']; self::assertSame('secretary', $data['primary_role']); // محیطِ پرسنلی‌اش همچنان در فهرست هست self::assertNotEmpty(array_filter($data['available_contexts'], fn(array $c) => $c['role'] === 'staff')); self::assertTrue($staff->hasAccount()); } }