diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index f6bc9be..0eeeb75 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -88,8 +88,8 @@ class UserController extends AbstractController $this->addFlash('danger', "L'utilisateur demandé n'existe pas."); throw $this->createNotFoundException(self::NOT_FOUND); } - //if hasAccessTo is false, turn to true and denie access - if (!$this->userService->isAdminOfUser($user)) { + //if hasAccessTo is false, turn to true and deny access + if (!$this->userService->isAdminOfUser($user) && !$this->isGranted('ROLE_ADMIN')) { $this->loggerService->logAccessDenied($actingUser->getUserIdentifier()); $this->addFlash('danger', "Vous n'avez pas accès à cette information."); throw new AccessDeniedHttpException (self::ACCESS_DENIED); @@ -555,9 +555,15 @@ class UserController extends AbstractController public function dataNew(Request $request): JsonResponse { $actingUser = $this->getUser(); - if ($this->userService->hasAccessTo($actingUser, true) && $this->isGranted("ROLE_USER")) { - $orgId = $request->query->get('orgId'); - $uos = $this->uoRepository->findBy(['organization' => $orgId, 'statut' => ["ACCEPTED", "INVITED"]], + $orgId = $request->query->get('orgId'); + $org = $this->organizationRepository->find($orgId); + if (!$org) { + $this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getUserIdentifier()); + throw $this->createNotFoundException(self::NOT_FOUND); + } + if ($this->userService->isAdminOfOrganization($org) || $this->isGranted("ROLE_ADMIN")) { + + $uos = $this->uoRepository->findBy(['organization' => $org, 'statut' => ["ACCEPTED", "INVITED"]], orderBy: ['createdAt' => 'DESC'], limit: 5); @@ -591,9 +597,14 @@ class UserController extends AbstractController public function dataAdmin(Request $request): JsonResponse { $actingUser = $this->getUser(); - if ($this->userService->hasAccessTo($actingUser, true) && $this->isGranted("ROLE_USER")) { - $orgId = $request->query->get('orgId'); - $uos = $this->uoRepository->findBy(['organization' => $orgId]); + $orgId = $request->query->get('orgId'); + $org = $this->organizationRepository->find($orgId); + if (!$org) { + $this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getUserIdentifier()); + throw $this->createNotFoundException(self::NOT_FOUND); + } + if ($this->userService->isAdminOfOrganization($org) || $this->isGranted("ROLE_ADMIN")) { + $uos = $this->uoRepository->findBy(['organization' => $org]); $roleAdmin = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'ADMIN']); $users = []; foreach ($uos as $uo) { @@ -632,58 +643,36 @@ class UserController extends AbstractController public function dataUserOrganization(Request $request): JsonResponse { $actingUser = $this->getUser(); + $orgId = $request->query->get('orgId'); - if ($this->userService->hasAccessTo($actingUser, true) && $this->isGranted("ROLE_USER")) { - $orgId = $request->query->get('orgId'); - $page = max(1, (int)$request->query->get('page', 1)); - $size = max(1, (int)$request->query->get('size', 10)); - - $filters = $request->query->all('filter') ?? []; - - $repo = $this->uoRepository; - - // Base query - $qb = $repo->createQueryBuilder('uo') - ->join('uo.users', 'u') - ->where('uo.organization = :orgId') - ->setParameter('orgId', $orgId); - - // Apply filters - if (!empty($filters['name'])) { - $qb->andWhere('u.surname LIKE :name') - ->setParameter('name', '%' . $filters['name'] . '%'); - } - if (!empty($filters['prenom'])) { - $qb->andWhere('u.name LIKE :prenom') - ->setParameter('prenom', '%' . $filters['prenom'] . '%'); - } - if (!empty($filters['email'])) { - $qb->andWhere('u.email LIKE :email') - ->setParameter('email', '%' . $filters['email'] . '%'); - } - - $countQb = clone $qb; - $total = (int)$countQb->select('COUNT(uo.id)')->getQuery()->getSingleScalarResult(); - - $qb->orderBy('uo.isActive', 'DESC') - ->addOrderBy('CASE WHEN uo.statut = :invited THEN 0 ELSE 1 END', 'ASC') - ->setParameter('invited', 'INVITED'); - - $offset = ($page - 1) * $size; - $rows = $qb->setFirstResult($offset)->setMaxResults($size)->getQuery()->getResult(); - $data = $this->userService->formatStatutForOrganizations($rows); - - $lastPage = (int)ceil($total / $size); - - return $this->json([ - 'data' => $data, - 'last_page' => $lastPage, - 'total' => $total, - ]); + $org = $this->organizationRepository->find($orgId); + if (!$org) { + $this->loggerService->logEntityNotFound('Organization', ['id' => $orgId], $actingUser->getUserIdentifier()); + throw $this->createNotFoundException(self::NOT_FOUND); } - throw $this->createAccessDeniedException(self::ACCESS_DENIED); + // Security Check + if (!$this->isGranted("ROLE_ADMIN") && !$this->userService->isAdminOfOrganization($org)) { + throw $this->createAccessDeniedException(self::ACCESS_DENIED); + } + // Params extraction + $page = max(1, $request->query->getInt('page', 1)); + $size = max(1, $request->query->getInt('size', 10)); + $filters = $request->query->all('filter') ?? []; + + // Get paginated results from Repository + $paginator = $this->uoRepository->findByOrganizationWithFilters($org, $page, $size, $filters); + $total = count($paginator); + + // Format the data using your existing service method + $data = $this->userService->formatStatutForOrganizations(iterator_to_array($paginator)); + + return $this->json([ + 'data' => $data, + 'last_page' => (int)ceil($total / $size), + 'total' => $total, + ]); } #[Route(path: '/organization/resend-invitation/{userId}', name: 'resend_invitation', methods: ['POST'])] diff --git a/src/Repository/UsersOrganizationsRepository.php b/src/Repository/UsersOrganizationsRepository.php index fef5e87..47d066e 100644 --- a/src/Repository/UsersOrganizationsRepository.php +++ b/src/Repository/UsersOrganizationsRepository.php @@ -6,8 +6,10 @@ use App\Entity\Organizations; use App\Entity\User; use App\Entity\UsersOrganizations; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\ORM\Tools\Pagination\Paginator; use Doctrine\Persistence\ManagerRegistry; + /** * @extends ServiceEntityRepository */ @@ -47,4 +49,36 @@ class UsersOrganizationsRepository extends ServiceEntityRepository ->getQuery() ->getSingleScalarResult() > 0; } + + public function findByOrganizationWithFilters(Organizations $org, int $page, int $size, array $filters = []): Paginator + { + $qb = $this->createQueryBuilder('uo') + ->innerJoin('uo.users', 'u') + ->where('uo.organization = :org') + ->setParameter('org', $org); + + // Apply filters + if (!empty($filters['name'])) { + $qb->andWhere('u.surname LIKE :name') + ->setParameter('name', '%' . $filters['name'] . '%'); + } + if (!empty($filters['prenom'])) { + $qb->andWhere('u.name LIKE :prenom') + ->setParameter('prenom', '%' . $filters['prenom'] . '%'); + } + if (!empty($filters['email'])) { + $qb->andWhere('u.email LIKE :email') + ->setParameter('email', '%' . $filters['email'] . '%'); + } + + // Apply complex sorting + $qb->orderBy('uo.isActive', 'DESC') + ->addOrderBy("CASE WHEN uo.statut = 'INVITED' THEN 0 ELSE 1 END", 'ASC'); + + // Pagination + $qb->setFirstResult(($page - 1) * $size) + ->setMaxResults($size); + + return new Paginator($qb); + } } diff --git a/src/Service/LoggerService.php b/src/Service/LoggerService.php index a610708..f7167b4 100644 --- a/src/Service/LoggerService.php +++ b/src/Service/LoggerService.php @@ -23,7 +23,7 @@ readonly class LoggerService // User Management Logs - public function logUserCreated(int $userId, int $actingUserId): void + public function logUserCreated(int $userId, int|string $actingUserId): void { $this->userManagementLogger->notice("New user created: $userId", [ 'target_user_id' => $userId, @@ -34,7 +34,7 @@ readonly class LoggerService } // Organization Management Logs - public function logUserOrganizationLinkCreated(int $userId, int $orgId, int $actingUserId, ?int $uoId): void + public function logUserOrganizationLinkCreated(int $userId, int $orgId, int|string $actingUserId, ?int $uoId): void { $this->organizationManagementLogger->notice('User-Organization link created', [ 'target_user_id' => $userId, @@ -46,7 +46,7 @@ readonly class LoggerService ]); } - public function logExistingUserAddedToOrg(int $userId, int $orgId, int $actingUserId, int $uoId): void + public function logExistingUserAddedToOrg(int $userId, int $orgId, int|string $actingUserId, int $uoId): void { $this->organizationManagementLogger->notice('Existing user added to organization', [ 'target_user_id' => $userId, @@ -87,7 +87,7 @@ readonly class LoggerService ])); } - public function logSuperAdmin(int $userId, int $actingUserId, string $message, ?int $orgId = null): void + public function logSuperAdmin(int $userId, int|string $actingUserId, string $message, ?int $orgId = null): void { $this->adminActionsLogger->notice($message, [ 'target_user_id' => $userId, @@ -116,7 +116,7 @@ readonly class LoggerService } // Security Logs - public function logAccessDenied(?int $actingUserId): void + public function logAccessDenied(int|string $actingUserId): void { $this->securityLogger->warning('Access denied', [ 'acting_user_id' => $actingUserId, @@ -133,7 +133,7 @@ readonly class LoggerService } - public function logUserAction(int $targetId, int $actingUserId, string $message): void + public function logUserAction(int $targetId, int|string $actingUserId, string $message): void { $this->userManagementLogger->notice($message, [ 'target_user_id'=> $targetId, @@ -143,7 +143,7 @@ readonly class LoggerService ]); } - public function logAdminAction(int $targetId, int $actingUserId, int $organizationId, string $message): void + public function logAdminAction(int $targetId, int|string $actingUserId, int $organizationId, string $message): void { $this->adminActionsLogger->notice($message, [ 'target_id' => $targetId, @@ -154,7 +154,7 @@ readonly class LoggerService ]); } - public function logEntityNotFound(string $entityType, array $criteria, ?int $actingUserId): void + public function logEntityNotFound(string $entityType, array $criteria, int|string $actingUserId): void { $this->errorLogger->error('Entity not found', array_merge($criteria, [ 'entity_type' => $entityType, @@ -192,7 +192,7 @@ readonly class LoggerService ]); } - public function logOrganizationInformation(int $organizationId, int $actingUserId, string $message): void + public function logOrganizationInformation(int $organizationId, int|string $actingUserId, string $message): void { $this->organizationManagementLogger->info($message, [ 'organization_id' => $organizationId, @@ -202,7 +202,7 @@ readonly class LoggerService ]); } - public function logRoleEntityAssignment(int $userId, int $organizationId, int $roleId, int $actingUserId, string $message): void + public function logRoleEntityAssignment(int $userId, int $organizationId, int $roleId, int|string $actingUserId, string $message): void { $this->accessControlLogger->info($message, [ 'target_user_id' => $userId, @@ -252,7 +252,7 @@ readonly class LoggerService ])); } - public function logApplicationInformation(string $string, array $array, int $actingUser) + public function logApplicationInformation(string $string, array $array, int|string $actingUser) { $this->accessControlLogger->info($string, array_merge($array, [ 'acting_user_id' => $actingUser, diff --git a/src/Service/UserService.php b/src/Service/UserService.php index b630af9..2ea60c0 100644 --- a/src/Service/UserService.php +++ b/src/Service/UserService.php @@ -147,7 +147,6 @@ class UserService return false; } - // Call the optimized repository method return $this->entityManager ->getRepository(UsersOrganizations::class) ->isUserAdminOfTarget($actingUser, $user, $adminRole);