feat: add staff role functionality with dashboard access and service management

- 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.
This commit is contained in:
hamed
2026-07-30 10:18:41 +03:30
parent 6ec011e3ad
commit 57aeb40934
28 changed files with 1960 additions and 29 deletions
+28
View File
@@ -16,6 +16,8 @@ use App\Secretary\Repository\DoctorSecretaryRepository;
use App\Shared\Captcha\CaptchaGuard;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Controller\BaseController;
use App\Staff\Repository\ClinicStaffRepository;
use App\Staff\Security\StaffPermissions;
use Doctrine\ORM\EntityManagerInterface;
use OpenApi\Attributes as OA;
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -42,6 +44,7 @@ class AuthController extends BaseController
private readonly ClinicDoctorPermissionRepository $clinicDoctorPermRepo,
private readonly DoctorSecretaryRepository $secretaryRepo,
private readonly UserActiveContextRepository $contextRepo,
private readonly ClinicStaffRepository $staffRepo,
private readonly UserPasswordHasherInterface $hasher,
private readonly EntityManagerInterface $em,
private readonly CaptchaGuard $captcha,
@@ -694,6 +697,8 @@ class AuthController extends BaseController
if (in_array('ROLE_CLINIC', $roles, true)) return 'clinic';
if (in_array('ROLE_DOCTOR', $roles, true)) return 'doctor';
if (in_array('ROLE_SECRETARY', $roles, true)) return 'secretary';
// پرسنل عمداً بعد از منشی: کسی که هر دو نقش را دارد، نقش پرتوان‌ترش می‌ماند.
if (in_array('ROLE_STAFF', $roles, true)) return 'staff';
if (in_array('ROLE_REPRESENTATION', $roles, true)) return 'representation';
return 'user';
}
@@ -778,6 +783,29 @@ class AuthController extends BaseController
}
}
// پرسنل: هر ردیف فعالِ ClinicStaff یک محیط است. مجوزها ثابت‌اند (نه قابل
// ویرایش مثل منشی) تا پنل بداند این نقش فقط حق دیدن دارد.
foreach ($this->staffRepo->findActiveByUser($user) as $row) {
$owner = $row->getEntityType() === 'clinic'
? $this->clinicRepo->find($row->getEntityId())
: $this->doctorRepo->find($row->getEntityId());
if ($owner === null) {
continue;
}
$contexts[] = [
'type' => $row->getEntityType(),
'db_uuid' => $owner->getUuid(),
'name' => $row->getEntityType() === 'clinic'
? ($owner->getName() ?? '')
: 'مطب ' . $owner->getName(),
'role' => 'staff',
'scope' => $row->getEntityType(),
'permissions' => StaffPermissions::DEFAULT,
];
}
return $contexts;
}
+1
View File
@@ -123,6 +123,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this->hasRole('ROLE_DOCTOR')
|| $this->hasRole('ROLE_CLINIC')
|| $this->hasRole('ROLE_SECRETARY')
|| $this->hasRole('ROLE_STAFF') // پرسنل کلینیک/مطب — داشبورد محدود خودش
|| $this->hasRole('ROLE_ADMIN')
|| $this->hasRole('ROLE_REPRESENTATION') // نماینده — لاگین با نام‌کاربری/رمز مجاز است
|| $this->hasRole('ROLE_IMPORTER'); // کاربر سیستمی کرالر — لاگین با رمز؛ دسترسی فقط اندپوینت ایمپورت