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:
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Staff\Service;
|
||||
|
||||
use App\Auth\Entity\User;
|
||||
use App\Auth\Repository\UserRepository;
|
||||
use App\Shared\Constant\ErrorCodes;
|
||||
use App\Shared\Exception\AppException;
|
||||
use App\Shared\Util\PersianText;
|
||||
use App\Staff\Entity\ClinicStaff;
|
||||
use App\Staff\Repository\ClinicStaffRepository;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* تنها نقطهٔ ساخت/اتصال/قطع حساب کاربری پرسنل.
|
||||
*
|
||||
* پرسنل مثل منشی یک `User` است که با شمارهٔ موبایل وارد پنل میشود؛ تفاوتش این
|
||||
* است که رابطهٔ او با محیط، همان ردیف `ClinicStaff` است (نه یک جدول واسط جدا).
|
||||
* قرینهٔ {@see \App\Secretary\Service\SecretaryService::resolveSecretaryUser()}.
|
||||
*/
|
||||
class StaffAccountService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserRepository $userRepo,
|
||||
private readonly ClinicStaffRepository $staffRepo,
|
||||
private readonly UserPasswordHasherInterface $hasher,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* حساب ورود پرسنل را میسازد یا به کاربر موجودِ همان موبایل وصل میکند و
|
||||
* ROLE_STAFF میدهد. شمارهٔ نرمالشده روی خود ردیف پرسنل هم ذخیره میشود تا
|
||||
* «شمارهٔ تماس» و «نام کاربری ورود» یکی بمانند.
|
||||
*
|
||||
* @param User $owner کاربرِ مالکِ محیط (پزشک/کلینیک) که این پرسنل را ثبت میکند
|
||||
*
|
||||
* @throws AppException ERR_STAFF_MOBILE_INVALID | ERR_STAFF_MOBILE_TAKEN
|
||||
*/
|
||||
public function attachAccount(ClinicStaff $staff, ?string $mobile, ?string $password, User $owner): User
|
||||
{
|
||||
$mobile = $this->normalizeMobile($mobile);
|
||||
|
||||
if ($mobile === $owner->getMobileNumber()) {
|
||||
throw new AppException(
|
||||
ErrorCodes::ERR_STAFF_MOBILE_INVALID,
|
||||
'شمارهٔ مالک نمیتواند بهعنوان پرسنل ثبت شود',
|
||||
422,
|
||||
'phone',
|
||||
);
|
||||
}
|
||||
|
||||
$duplicate = $this->staffRepo->findByEntityAndPhone($staff->getEntityType(), $staff->getEntityId(), $mobile);
|
||||
if ($duplicate !== null && $duplicate->getId() !== $staff->getId()) {
|
||||
throw new AppException(ErrorCodes::ERR_STAFF_MOBILE_TAKEN, null, 409, 'phone');
|
||||
}
|
||||
|
||||
$user = $this->userRepo->findByMobile($mobile) ?? new User($mobile);
|
||||
|
||||
// رمز خالی روی کاربر موجود، رمز فعلیاش را پاک نمیکند؛ کاربر تازهساخته هم
|
||||
// بدون رمز میماند و باید از «فراموشی رمز» استفاده کند.
|
||||
if ($password !== null && $password !== '') {
|
||||
$user->setPasswordHash($this->hasher->hashPassword($user, $password));
|
||||
}
|
||||
if ($user->getRealName() === null || $user->getRealName() === '') {
|
||||
$user->setRealName($staff->getFullName());
|
||||
}
|
||||
$user->addRole('ROLE_STAFF');
|
||||
$this->userRepo->save($user);
|
||||
|
||||
$staff->setUser($user)->setPhone($mobile);
|
||||
$this->staffRepo->save($staff);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
private function normalizeMobile(?string $mobile): string
|
||||
{
|
||||
$normalized = preg_replace('/\D+/', '', PersianText::digits((string) $mobile)) ?? '';
|
||||
|
||||
if (!preg_match('/^09\d{9}$/', $normalized)) {
|
||||
throw new AppException(ErrorCodes::ERR_STAFF_MOBILE_INVALID, null, 422, 'phone');
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user