feat: Implement permission gate for appointment and billing controllers
- Added PermissionGateTrait to manage access control for AppointmentPlanController and BillingController. - Introduced denyUnlessGrantedForPlanning method in AppointmentPlanController to handle specific permission checks for planning appointments. - Updated existing methods in both controllers to utilize the new permission checks. - Refactored ResourcePermissionTrait to use PermissionGateTrait for cleaner permission management. - Added tests to ensure proper permission enforcement across different scenarios, including cross-tenant access restrictions for staff.
This commit is contained in:
+26
-8
@@ -524,7 +524,13 @@ The doctor dashboard filter bar uses the paginated form, defaulting `statuses` t
|
||||
|
||||
Get all appointments for the authenticated user.
|
||||
|
||||
**Permission:** `AUTH`
|
||||
**Permission:** `AUTH` — عمداً بدون مجوزِ رجیستری.
|
||||
|
||||
> این اندپوینت `a.user = خودِ کاربر` را میدهد، یعنی نوبتهای خودِ فرد **بهعنوان
|
||||
> بیمار**، نه دادهٔ محیط. مصرفکنندهاش داشبورد بیمار در `nobat724_front` است.
|
||||
> آدیت ۲۰۲۶-۰۸-۰۷ آن را در فهرست گَپها آورده بود؛ در ۲۰۲۶-۰۸-۰۸ مثبت کاذب تشخیص
|
||||
> داده شد: گِیتِ `appointments.view` یعنی منشیای که جایی بیمار است نوبتهای شخصیاش
|
||||
> را نبیند. در `ApiLeastPrivilegeTest::ALLOWED_200` با همین دلیل ثبت است.
|
||||
|
||||
### Query Parameters
|
||||
| Param | Type | Required | Description |
|
||||
@@ -780,6 +786,9 @@ Events are ordered oldest → newest. `data` is a flat array (single nesting). `
|
||||
|
||||
## POST `/api/v1/my/appointment`
|
||||
|
||||
**Permission:** `appointments.create` — علاوه بر بررسی نقش (`ROLE_DOCTOR`/`ROLE_CLINIC`/`ROLE_SECRETARY`/`ROLE_ADMIN`).
|
||||
تا پیش از ۲۰۲۶-۰۸-۰۸ فقط نقش بررسی میشد، پس منشیِ `appointments.create:false` هم نوبت ثبت میکرد.
|
||||
|
||||
Create a new appointment for a patient. Used by doctor/clinic/secretary to book appointments on behalf of patients. If no user exists with the given mobile, a new user account is created automatically.
|
||||
|
||||
> **Initial status is `pending` («ثبت شده»), not `confirmed`.** Every appointment —
|
||||
@@ -854,9 +863,12 @@ Create a new appointment for a patient. Used by doctor/clinic/secretary to book
|
||||
|
||||
جستجوی بیمار با شماره موبایل **یا** کد ملی، پیش از ثبت نوبت. فرم ثبت نوبت با یکی از این دو معیار جستجو میکند؛ اگر بیمار یافت شد و کد ملی دارد، مستقیم استفاده میشود، وگرنه بقیهٔ مشخصات (نام و موبایل یا کد ملی) از کاربر گرفته میشود.
|
||||
|
||||
**Auth:** `IS_AUTHENTICATED_FULLY` — Roles: `ROLE_DOCTOR`, `ROLE_CLINIC`, `ROLE_SECRETARY`, `ROLE_ADMIN`
|
||||
**Auth:** `IS_AUTHENTICATED_FULLY` — Roles: `ROLE_DOCTOR`, `ROLE_CLINIC`, `ROLE_SECRETARY`, `ROLE_ADMIN` — **Permission:** `appointments.create`
|
||||
|
||||
> برخلاف `GET /api/v1/patient/search-user`، این endpoint به فیچر `patient_records` اشتراک وابسته نیست و `ROLE_ADMIN` را هم میپذیرد، چون ثبت نوبت باید مستقل از اشتراک کار کند.
|
||||
>
|
||||
> مجوزش عمداً `appointments.create` است نه `patients.view`: بخشی از فرمِ ثبت نوبت است،
|
||||
> و با گیتِ پروندهٔ بیمار، منشیای که فقط اجازهٔ نوبتدهی دارد فرمش را از دست میداد.
|
||||
|
||||
### Query Parameters
|
||||
یکی از `mobile` یا `national_code` الزامی است. اگر هر دو ارسال شوند، `national_code` اولویت دارد.
|
||||
@@ -897,7 +909,10 @@ Create a new appointment for a patient. Used by doctor/clinic/secretary to book
|
||||
|
||||
Role-aware paginated list of appointments. Returns only what the authenticated user is authorized to see.
|
||||
|
||||
**Auth:** `IS_AUTHENTICATED_FULLY` (any role)
|
||||
**Auth:** `IS_AUTHENTICATED_FULLY` — **Permission:** `appointments.view`
|
||||
|
||||
> از ۲۰۲۶-۰۸-۰۸ گِیت دارد. پیش از آن منشیِ `appointments:false` با درخواست مستقیم به
|
||||
> API همان فهرستی را میگرفت که توگل، دکمهاش را در پنل پنهان کرده بود.
|
||||
|
||||
**Role behavior:**
|
||||
| Role | Scope |
|
||||
@@ -913,10 +928,13 @@ Role-aware paginated list of appointments. Returns only what the authenticated u
|
||||
Same scoping rules as the list above, aggregated into `{ total, completed, waiting, cancelled }`
|
||||
for one day (`?date=Y-m-d`, defaults to today).
|
||||
|
||||
**Auth:** `IS_AUTHENTICATED_FULLY`. A caller with no resolvable scope (clinic/doctor row
|
||||
missing, secretary without `appointments.view` or with no assigned doctors) gets all-zero
|
||||
counts rather than an unscoped, system-wide count. A plain patient gets counts over their
|
||||
own appointments only.
|
||||
**Auth:** `IS_AUTHENTICATED_FULLY` — **Permission:** `appointments.view`. A caller with no
|
||||
resolvable scope (clinic/doctor row missing, or no assigned doctors) gets all-zero counts
|
||||
rather than an unscoped, system-wide count. A plain patient gets counts over their own
|
||||
appointments only.
|
||||
|
||||
> پیش از ۲۰۲۶-۰۸-۰۸ منشیِ بدون `appointments.view` بهجای ۴۰۳ صفر میگرفت. صفرِ خاموش
|
||||
> با «اجازه نداری» یکی نیست؛ حالا ۴۰۳ میگیرد.
|
||||
|
||||
### Query Parameters
|
||||
| Param | Type | Default | Description |
|
||||
@@ -1399,7 +1417,7 @@ active — the request simply carried no `clinic_uuid`.
|
||||
|
||||
## GET /api/v1/my/clinic-doctors
|
||||
|
||||
**Permission:** `IS_AUTHENTICATED_FULLY`
|
||||
**Permission:** `IS_AUTHENTICATED_FULLY` + `appointments.view`
|
||||
|
||||
پزشکانِ در دسترسِ کاربرِ پنل، برای ساختِ تبها/تایملاینِ صفحهٔ نوبتها. برخلاف
|
||||
`GET /api/v1/clinic/doctor-list/{clinicUuid}` که روی firewallِ عمومی است و **همهٔ** پزشکانِ
|
||||
|
||||
Reference in New Issue
Block a user