feat: add per-doctor permissions management in clinics
- Implement DoctorPermissionsModal for managing doctor permissions in clinics. - Create usePermissions hook to handle user permissions context. - Add migration for clinic_doctor_permissions table with default permissions. - Develop ClinicDoctorPermissionController for handling permissions API. - Create ClinicDoctorPermission entity to manage permissions data. - Implement ClinicDoctorPermissionRepository for database interactions. - Add ClinicDoctorPermissionChecker for permission validation logic. - Write tests for clinic doctor permissions functionality.
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace App\Clinic\Controller;
|
||||
|
||||
use App\Auth\Entity\User;
|
||||
use App\Clinic\Entity\Clinic;
|
||||
use App\Clinic\Entity\ClinicDoctorPermission;
|
||||
use App\Clinic\Repository\ClinicDoctorPermissionRepository;
|
||||
use App\Clinic\Repository\ClinicRepository;
|
||||
use App\Doctor\Repository\DoctorRepository;
|
||||
use App\Shared\Constant\ErrorCodes;
|
||||
use App\Shared\Controller\BaseController;
|
||||
use App\Shared\Exception\AppException;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\CurrentUser;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
#[OA\Tag(name: 'Clinic Doctor Permissions')]
|
||||
class ClinicDoctorPermissionController extends BaseController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClinicRepository $clinicRepo,
|
||||
private readonly DoctorRepository $doctorRepo,
|
||||
private readonly ClinicDoctorPermissionRepository $permRepo,
|
||||
private readonly EntityManagerInterface $em,
|
||||
) {}
|
||||
|
||||
#[Route('/api/v1/admin/clinic/{clinicUuid}/doctor-permissions', methods: ['GET'])]
|
||||
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||
public function listPermissions(string $clinicUuid, #[CurrentUser] User $user): JsonResponse
|
||||
{
|
||||
$clinic = $this->resolveClinic($clinicUuid, $user);
|
||||
|
||||
$data = array_map(
|
||||
fn(ClinicDoctorPermission $p) => $p->toArray(),
|
||||
$this->permRepo->findByClinic($clinic),
|
||||
);
|
||||
|
||||
return $this->success($data);
|
||||
}
|
||||
|
||||
#[Route('/api/v1/admin/clinic/{clinicUuid}/doctor/{doctorUuid}/permissions', methods: ['GET'])]
|
||||
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||
public function showPermissions(string $clinicUuid, string $doctorUuid, #[CurrentUser] User $user): JsonResponse
|
||||
{
|
||||
$clinic = $this->resolveClinic($clinicUuid, $user);
|
||||
$doctor = $this->resolveMember($clinic, $doctorUuid);
|
||||
|
||||
return $this->success($this->permRepo->getOrCreate($clinic, $doctor)->toArray());
|
||||
}
|
||||
|
||||
#[Route('/api/v1/admin/clinic/{clinicUuid}/doctor/{doctorUuid}/permissions', methods: ['PATCH'])]
|
||||
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||
public function updatePermissions(string $clinicUuid, string $doctorUuid, Request $request, #[CurrentUser] User $user): JsonResponse
|
||||
{
|
||||
$clinic = $this->resolveClinic($clinicUuid, $user);
|
||||
$doctor = $this->resolveMember($clinic, $doctorUuid);
|
||||
$perm = $this->permRepo->getOrCreate($clinic, $doctor);
|
||||
|
||||
$body = json_decode($request->getContent(), true) ?? [];
|
||||
|
||||
if (array_key_exists('permissions', $body)) {
|
||||
if (!is_array($body['permissions'])) {
|
||||
throw new AppException(ErrorCodes::ERR_VALIDATION_001, 'permissions باید آبجکت باشد', 422, 'permissions');
|
||||
}
|
||||
$perm->mergePermissions($body['permissions']);
|
||||
}
|
||||
|
||||
if (array_key_exists('active', $body)) {
|
||||
$perm->setActive((bool) $body['active']);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
return $this->success($perm->toArray());
|
||||
}
|
||||
|
||||
private function resolveClinic(string $clinicUuid, User $user): Clinic
|
||||
{
|
||||
$clinic = $this->clinicRepo->findByUuid($clinicUuid);
|
||||
if ($clinic === null) {
|
||||
throw new AppException(ErrorCodes::ERR_NOT_FOUND_001, 'کلینیک یافت نشد', 404);
|
||||
}
|
||||
|
||||
$isOwner = $clinic->getUser()->getId() === $user->getId();
|
||||
if (!$user->hasRole('ROLE_ADMIN') && !$isOwner) {
|
||||
throw new AppException(ErrorCodes::ERR_ACCESS_DENIED, 'دسترسی ندارید', 403);
|
||||
}
|
||||
|
||||
return $clinic;
|
||||
}
|
||||
|
||||
private function resolveMember(Clinic $clinic, string $doctorUuid): \App\Doctor\Entity\Doctor
|
||||
{
|
||||
$doctor = $this->doctorRepo->findByUuid($doctorUuid);
|
||||
if ($doctor === null || !$clinic->hasDoctor($doctor)) {
|
||||
throw new AppException(ErrorCodes::ERR_NOT_FOUND_001, 'این پزشک به کلینیک متصل نیست', 404);
|
||||
}
|
||||
|
||||
return $doctor;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user