- Implemented SidebarStaff component tests to ensure staff users see only their dashboard and services. - Created StaffMyServicesPage to display assigned services for staff users. - Added migration to link clinic staff rows to user accounts for ROLE_STAFF access. - Defined StaffPermissions class for static permissions related to staff role. - Introduced StaffRouteGuardSubscriber to restrict API access for staff users. - Developed StaffAccountService for managing staff user accounts and linking them to clinic staff. - Added comprehensive tests for StaffAccountService to validate user creation, mobile number handling, and account attachment. - Implemented tests for staff dashboard access to ensure proper permissions and access control. - Created tests for staff login context to verify correct environment visibility based on user roles.
121 lines
5.0 KiB
PHP
121 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Staff;
|
|
|
|
use App\Auth\Repository\UserRepository;
|
|
use App\Doctor\Entity\Doctor;
|
|
use App\Staff\Entity\ClinicStaff;
|
|
use App\Staff\Repository\ClinicStaffRepository;
|
|
use App\Staff\Service\StaffAccountService;
|
|
use App\Tests\ApiTestCase;
|
|
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
|
|
|
/**
|
|
* پرسنلِ دارای حساب باید مثل بقیهٔ نقشهای پنل لاگین کند و محیط کاریاش را در
|
|
* userinfo ببیند؛ پرسنل غیرفعال هیچ محیطی نمیگیرد.
|
|
*/
|
|
class StaffLoginContextTest extends ApiTestCase
|
|
{
|
|
private function service(): StaffAccountService
|
|
{
|
|
return new StaffAccountService(
|
|
static::getContainer()->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());
|
|
}
|
|
}
|