feat(permissions): render both permission forms from the catalog, fix borrowed gates
The three hardcoded resource lists in the admin panel are gone. MySecretariesPage, SecretariesPage and DoctorPermissionsModal now render from GET /api/v1/permission-catalog, so a resource added to the backend registry shows up in all of them with no frontend change. Each has a test that proves exactly that by adding a resource to the mock and asserting it renders. SecretaryPermissions was an interface with a field per resource, which made "dynamic" impossible in TypeScript — every new resource would have been a compile error. It is now an open map. Only two files consumed it. The borrowed gates are corrected: - five resource pages moved off appointment_settings onto their own 'resources' - treatment-cases moved off appointments onto 'treatment' - service-categories moved onto 'services', which is what ServiceCatalogController actually manages (categories, item groups, service relations) — not resources TreatmentCaseController had no permission gate at all, only IS_AUTHENTICATED_FULLY, so any secretary could read and edit treatment cases. All seven of its actions are now gated on treatment view/update. ResourcePermissionTrait takes the resource from an overridable method instead of hardcoding appointment_settings. HolidayController overrides it back, since the holidays page really is appointment settings. The booking gate keeps its appointments.view fallback so a secretary who may book is not blocked by a resource-config permission. Defaults were picked to preserve today's effective access, so no role gains or loses a page from this move. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,12 @@ class HolidayController extends BaseController
|
||||
{
|
||||
use ResourcePermissionTrait;
|
||||
|
||||
/** تعطیلات زیرمجموعهٔ تنظیمات نوبتدهی است، نه فهرست منابع. */
|
||||
private function permissionResource(): string
|
||||
{
|
||||
return 'appointment_settings';
|
||||
}
|
||||
|
||||
public function __construct(
|
||||
private readonly HolidayService $holidays,
|
||||
private readonly ResourceContext $context,
|
||||
|
||||
@@ -10,11 +10,14 @@ use App\Shared\Exception\AppException;
|
||||
use Symfony\Contracts\Service\Attribute\Required;
|
||||
|
||||
/**
|
||||
* گِیتِ مشترک چهار کنترلر این دامنه.
|
||||
* گِیتِ مشترک کنترلرهای این دامنه.
|
||||
*
|
||||
* مجوز `appointment_settings` بازاستفاده میشود و مجوز تازهای ساخته نمیشود: منابع
|
||||
* بخشی از پیکربندی نوبتدهیاند و افزودن یک کلید تازه یعنی یک ستون تازه در جدول
|
||||
* مجوزهای هر منشی و هر پزشکِ عضو، بدون اینکه کسی خواسته باشد آنها را جدا کند.
|
||||
* منابع مجوزِ خودشان را دارند (`resources`). پیش از رجیستریِ واحد، این کنترلرها
|
||||
* `appointment_settings` را قرض میگرفتند چون افزودن یک کلید تازه یعنی ویرایش
|
||||
* دستیِ شش فهرست؛ حالا یک ردیف در `PermissionCatalog` کافی است.
|
||||
*
|
||||
* تعطیلات از این قاعده مستثناست و `appointment_settings` میماند — صفحهاش
|
||||
* زیرمجموعهٔ تنظیمات نوبتدهی است، نه فهرست دستگاهها.
|
||||
*/
|
||||
trait ResourcePermissionTrait
|
||||
{
|
||||
@@ -30,11 +33,19 @@ trait ResourcePermissionTrait
|
||||
$this->clinicDoctorAccess = $clinicDoctorAccess;
|
||||
}
|
||||
|
||||
/** @param 'view'|'update' $action */
|
||||
/** کنترلری که منبعِ دیگری را گِیت میکند این را بازنویسی میکند. */
|
||||
private function permissionResource(): string
|
||||
{
|
||||
return 'resources';
|
||||
}
|
||||
|
||||
/** @param 'view'|'create'|'update'|'delete' $action */
|
||||
private function denyUnlessGranted(User $user, string $action): void
|
||||
{
|
||||
$this->secretaryAccess->denyUnlessGranted($user, 'appointment_settings', $action);
|
||||
$this->clinicDoctorAccess->denyUnlessGranted($user, 'appointment_settings', $action);
|
||||
$resource = $this->permissionResource();
|
||||
|
||||
$this->secretaryAccess->denyUnlessGranted($user, $resource, $action);
|
||||
$this->clinicDoctorAccess->denyUnlessGranted($user, $resource, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,9 +59,11 @@ trait ResourcePermissionTrait
|
||||
*/
|
||||
private function denyUnlessGrantedForBooking(User $user): void
|
||||
{
|
||||
$resource = $this->permissionResource();
|
||||
|
||||
$allowed =
|
||||
($this->secretaryAccess->canOrNonSecretary($user, 'appointment_settings', 'view')
|
||||
&& $this->clinicDoctorAccess->canOrNonMember($user, 'appointment_settings', 'view'))
|
||||
($this->secretaryAccess->canOrNonSecretary($user, $resource, 'view')
|
||||
&& $this->clinicDoctorAccess->canOrNonMember($user, $resource, 'view'))
|
||||
|| ($this->secretaryAccess->canOrNonSecretary($user, 'appointments', 'view')
|
||||
&& $this->clinicDoctorAccess->canOrNonMember($user, 'appointments', 'view'));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user