diff --git a/src/Controller/OrganizationController.php b/src/Controller/OrganizationController.php index d8f5843..7ecb5e4 100644 --- a/src/Controller/OrganizationController.php +++ b/src/Controller/OrganizationController.php @@ -182,7 +182,7 @@ class OrganizationController extends AbstractController #[Route(path: '/view/{id}', name: 'show', methods: ['GET'])] public function view($id): Response { - $this->denyAccessUnlessGranted('ROLE_ADMIN'); + $this->denyAccessUnlessGranted('ROLE_USER'); $organization = $this->organizationsRepository->find($id); $actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier()); if (!$organization) { @@ -304,7 +304,7 @@ class OrganizationController extends AbstractController #[Route(path: '/data', name: 'data', methods: ['GET'])] public function data(Request $request): JsonResponse { - $this->denyAccessUnlessGranted('ROLE_ADMIN'); + $this->denyAccessUnlessGranted('ROLE_USER'); $page = max(1, (int)$request->query->get('page', 1)); diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index 5466b30..e65cac7 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -369,21 +369,22 @@ class UserController extends AbstractController #[Route('/organization/activateStatus/{id}', name: 'activate_organization', methods: ['GET', 'POST'])] public function activateStatusOrganization(int $id, Request $request): JsonResponse { - $this->denyAccessUnlessGranted('ROLE_ADMIN'); + $this->denyAccessUnlessGranted('ROLE_USER'); $actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier()); try { - if ($this->userService->hasAccessTo($actingUser, true)) { + $user = $this->userRepository->find($id); + if (!$user) { + $this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId()); + throw $this->createNotFoundException(self::NOT_FOUND); + } + if ($this->userService->isAdminOfUser($user)) { $orgId = $request->get('organizationId'); $org = $this->organizationRepository->find($orgId); if (!$org) { $this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getId()); throw $this->createNotFoundException(self::NOT_FOUND); } - $user = $this->userRepository->find($id); - if (!$user) { - $this->loggerService->logEntityNotFound('User', ['id' => $id], $actingUser->getId()); - throw $this->createNotFoundException(self::NOT_FOUND); - } + $uo = $this->uoRepository->findOneBy(['users' => $user, 'organization' => $org]); if (!$uo) { diff --git a/src/Repository/UsersOrganizationsRepository.php b/src/Repository/UsersOrganizationsRepository.php index c15ce1c..fef5e87 100644 --- a/src/Repository/UsersOrganizationsRepository.php +++ b/src/Repository/UsersOrganizationsRepository.php @@ -19,121 +19,32 @@ class UsersOrganizationsRepository extends ServiceEntityRepository } /** - * Returns active user-organization mappings with joined User and Organization. - * Only active and non-deleted users and organizations are included. - * - * @return UsersOrganizations[] + * Checks if an acting user has administrative rights over a target user + * based on shared organizational memberships. */ - public function findUsersWithOrganization(array $organizationIds = null): array + public function isUserAdminOfTarget(User $actingUser, User $targetUser, $adminRole): bool { - $qb = $this->createQueryBuilder('uo') - ->addSelect('u', 'o') - ->leftJoin('uo.users', 'u') - ->leftJoin('uo.organization', 'o') - ->andWhere('u.isActive = :uActive') - ->andWhere('u.isDeleted = :uDeleted') - ->andWhere('o.isActive = :oActive') - ->andWhere('o.isDeleted = :oDeleted') - ->orderBy('o.name', 'ASC') - ->addOrderBy('u.surname', 'ASC') - ->setParameter('uActive', true) - ->setParameter('uDeleted', false) - ->setParameter('oActive', true) - ->setParameter('oDeleted', false); - if (!empty($organizationIds)) { - $qb->andWhere('o.id IN (:orgIds)') - ->setParameter('orgIds', $organizationIds); - } + $qb = $this->createQueryBuilder('uo_acting'); - return $qb->getQuery()->getResult(); - } - - /** - * Same as above, filtered by a list of organization IDs. - * - * @param int[] $organizationIds - * @return UsersOrganizations[] - */ - public function findActiveWithUserAndOrganizationByOrganizationIds(array $organizationIds): array - { - if (empty($organizationIds)) { - return []; - } - - $qb = $this->createQueryBuilder('uo') - ->addSelect('u', 'o') - ->leftJoin('uo.users', 'u') - ->leftJoin('uo.organization', 'o') - ->where('uo.isActive = :uoActive') - ->andWhere('u.isActive = :uActive') - ->andWhere('u.isDeleted = :uDeleted') - ->andWhere('o.isActive = :oActive') - ->andWhere('o.isDeleted = :oDeleted') - ->andWhere('o.id IN (:orgIds)') - ->orderBy('o.name', 'ASC') - ->addOrderBy('u.surname', 'ASC') - ->setParameter('uoActive', true) - ->setParameter('uActive', true) - ->setParameter('uDeleted', false) - ->setParameter('oActive', true) - ->setParameter('oDeleted', false) - ->setParameter('orgIds', $organizationIds); - - return $qb->getQuery()->getResult(); - } - - /** - * Find 10 newest Users in an Organization. - * - * @param Organizations $organization - * @return User[] - */ - public function findNewestUO(Organizations $organization): array - { - $qb = $this->createQueryBuilder('uo') - ->select('uo', 'u') - ->leftJoin('uo.users', 'u') - ->where('uo.organization = :org') - ->andWhere('uo.isActive = :uoActive') - ->andWhere('u.isActive = :uActive') - ->andWhere('u.isDeleted = :uDeleted') - ->orderBy('u.createdAt', 'DESC') - ->setMaxResults(10) - ->setParameter('org', $organization) - ->setParameter('uoActive', true) - ->setParameter('uActive', true) - ->setParameter('uDeleted', false); - - return $qb->getQuery()->getResult(); - } - - /** - * Find all the admins of an Organization. - * limited to 10 results. - * - * @param Organizations $organization - * @return User[] - */ - public function findAdminsInOrganization(Organizations $organization): array - { - $qb = $this->createQueryBuilder('uo') - ->select('uo', 'u') - ->leftJoin('uo.users', 'u') - ->leftJoin('uo.userOrganizatonApps', 'uoa') - ->leftJoin('uoa.role', 'r') - ->where('uo.organization = :org') - ->andWhere('uo.isActive = :uoActive') - ->andWhere('u.isActive = :uActive') - ->andWhere('u.isDeleted = :uDeleted') - ->andWhere('r.name = :roleAdmin') - ->orderBy('u.surname', 'ASC') - ->setMaxResults(10) - ->setParameter('org', $organization) - ->setParameter('uoActive', true) - ->setParameter('uActive', true) - ->setParameter('uDeleted', false) - ->setParameter('roleAdmin', 'ADMIN'); - - return $qb->getQuery()->getResult(); + return (bool) $qb + ->select('COUNT(uo_acting.id)') + // We join the same table again to find the target user in the same organization + ->innerJoin( + UsersOrganizations::class, + 'uo_target', + 'WITH', + 'uo_target.organization = uo_acting.organization' + ) + ->where('uo_acting.users = :actingUser') + ->andWhere('uo_acting.role = :role') + ->andWhere('uo_acting.isActive = true') + ->andWhere('uo_target.users = :targetUser') + ->andWhere('uo_target.statut = :status') + ->setParameter('actingUser', $actingUser) + ->setParameter('targetUser', $targetUser) + ->setParameter('role', $adminRole) + ->setParameter('status', 'ACCEPTED') + ->getQuery() + ->getSingleScalarResult() > 0; } } diff --git a/src/Service/UserService.php b/src/Service/UserService.php index 241fc3c..b630af9 100644 --- a/src/Service/UserService.php +++ b/src/Service/UserService.php @@ -134,21 +134,23 @@ class UserService */ public function isAdminOfUser(User $user): bool { - $actingUser = $this->getUserByIdentifier($this->security->getUser()->getUserIdentifier()); - $roleAdmin = $this->rolesRepository->findOneBy(['name' => 'ADMIN']); - $adminUOs = $this->entityManager->getRepository(UsersOrganizations::class)->findBy([ - 'users' => $actingUser, - 'isActive' => true, - 'role'=> $roleAdmin]); - $userOrganizations = $this->entityManager->getRepository(UsersOrganizations::class)->findBy(['users' => $user, 'statut' => 'ACCEPTED', 'isActive' => true]); - if ($userOrganizations) { - foreach ($userOrganizations as $uo) { - if (in_array($uo, $adminUOs, true)) { - return true; - } - } + $actingUser = $this->security->getUser(); + + if (!$actingUser instanceof User) { + return false; } - return false; + + // Reuse the cached/fetched role + $adminRole = $this->rolesRepository->findOneBy(['name' => 'ADMIN']); + + if (!$adminRole) { + return false; + } + + // Call the optimized repository method + return $this->entityManager + ->getRepository(UsersOrganizations::class) + ->isUserAdminOfTarget($actingUser, $user, $adminRole); } /** @@ -161,7 +163,7 @@ class UserService */ public function isAdminOfOrganization(Organizations $organizations): bool { - $actingUser = $this->getUserByIdentifier($this->security->getUser()->getUserIdentifier()); + $actingUser =$this->security->getUser(); $roleAdmin = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'ADMIN']); $uoAdmin = $this->entityManager->getRepository(UsersOrganizations::class)->findOneBy(['users' => $actingUser, 'organization' => $organizations,