fix(secretary): allow insurance pages; add grantable subscription resource
Insurance pages redirected to the dashboard: the insurance-pricing/claims routes never listed `secretary`, so RoleRoute bounced a secretary who had insurances.view and saw the menu item. Added secretary + permission ['insurances','view'] to both routes; also gated my-financial with ['payments','view'] for consistency. «خرید اشتراک» was owner-only with no permission toggle, so it could not be granted. Added a `subscription` secretary resource (view/create) end-to-end: - entity DEFAULT_PERMISSIONS + SecretaryPermissions type + both secretary forms. - backend: SubscriptionController::my (view) and trial (create), PaymentController::initiateSubscription (create). resolveEntity in SubscriptionController was already secretary-aware. - frontend: subscription + subscription/success routes accept secretary + permission; settings navs gate «خرید اشتراک» by ['subscription','view']. Tests: subscription denied-by-default / allowed-when-granted. docs/api secretary.md updated (resource list, enforcement map, JSON example). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -386,6 +386,7 @@ class PaymentController extends BaseController
|
||||
#[Route('/api/v1/subscription-payment', methods: ['POST'])]
|
||||
public function initiateSubscription(Request $request, #[CurrentUser] User $user): JsonResponse
|
||||
{
|
||||
$this->secretaryAccess->denyUnlessGranted($user, 'subscription', 'create');
|
||||
$data = json_decode($request->getContent(), true) ?? [];
|
||||
$gatewayName = trim($data['gateway'] ?? 'mellat');
|
||||
$frontendAddress = trim($data['frontend_address'] ?? '');
|
||||
|
||||
@@ -34,6 +34,7 @@ class DoctorSecretary
|
||||
'sms' => ['view' => false, 'create' => false, 'update' => false, 'delete' => false],
|
||||
'appointment_settings' => ['view' => false, 'update' => false],
|
||||
'clinic_doctors' => ['view' => false, 'create' => false, 'update' => false, 'delete' => false],
|
||||
'subscription' => ['view' => false, 'create' => false],
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ class SubscriptionController extends BaseController
|
||||
private readonly ClinicRepository $clinicRepo,
|
||||
private readonly UserActiveContextRepository $contextRepo,
|
||||
private readonly EntityManagerInterface $em,
|
||||
private readonly \App\Secretary\Security\SecretaryAccessChecker $secretaryAccess,
|
||||
) {}
|
||||
|
||||
// ── Public ──────────────────────────────────────────────────────────────
|
||||
@@ -56,6 +57,7 @@ class SubscriptionController extends BaseController
|
||||
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||
public function my(#[CurrentUser] User $user): JsonResponse
|
||||
{
|
||||
$this->secretaryAccess->denyUnlessGranted($user, 'subscription', 'view');
|
||||
[$entityType, $entityId] = $this->resolveEntity($user);
|
||||
if ($entityId === null) {
|
||||
return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'پروفایل یافت نشد', 403);
|
||||
@@ -76,6 +78,7 @@ class SubscriptionController extends BaseController
|
||||
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||
public function trial(#[CurrentUser] User $user): JsonResponse
|
||||
{
|
||||
$this->secretaryAccess->denyUnlessGranted($user, 'subscription', 'create');
|
||||
[$entityType, $entityId] = $this->resolveEntity($user);
|
||||
if ($entityId === null) {
|
||||
return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'پروفایل یافت نشد', 403);
|
||||
|
||||
Reference in New Issue
Block a user