From 05d8ca049954b2f332868b83c848e7b65977d181 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 28 Jul 2025 15:19:59 +0200 Subject: [PATCH] organization dashboard User management --- src/Controller/OrganizationController.php | 32 +++++++- .../UsersOrganizationsRepository.php | 78 +++++++++++++++++++ src/Service/OrganizationsService.php | 28 +++++++ templates/organization/show.html.twig | 31 +++++++- templates/user/userList.html.twig | 15 ++-- templates/user/userListSmall.html.twig | 39 ++++++++++ 6 files changed, 212 insertions(+), 11 deletions(-) create mode 100644 src/Service/OrganizationsService.php create mode 100644 templates/user/userListSmall.html.twig diff --git a/src/Controller/OrganizationController.php b/src/Controller/OrganizationController.php index 9bb7fd5..3c27b4a 100644 --- a/src/Controller/OrganizationController.php +++ b/src/Controller/OrganizationController.php @@ -3,6 +3,7 @@ namespace App\Controller; use App\Entity\UsersOrganizations; +use App\Service\OrganizationsService; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Routing\Attribute\Route; @@ -16,7 +17,8 @@ class OrganizationController extends AbstractController private const NOT_FOUND = 'Entity not found'; private const ACCESS_DENIED = 'Access denied'; - public function __construct(private readonly EntityManagerInterface $entityManager) + public function __construct(private readonly EntityManagerInterface $entityManager, + private readonly OrganizationsService $organizationsService) { } @@ -48,14 +50,40 @@ class OrganizationController extends AbstractController #[Route(path: '/{id}', name: 'show', methods: ['GET'])] public function show(int $id): Response { - $organization = $this->entityManager->getRepository(Organizations::class)->find($id); + if (!$this->isGranted('ROLE_ADMIN')) { + $user = $this->getUser(); + if (!$user) { + return $this->redirectToRoute('app_login'); + } + $userIdentifier = $user->getUserIdentifier(); + $organization = $this->entityManager->getRepository(UsersOrganizations::class)->findOneBy([ + 'userEmail' => $userIdentifier, + 'organization' => $id, + 'roleName' => 'ADMIN' + ]); + + if (!$organization) { + throw $this->createNotFoundException(self::ACCESS_DENIED); + } + } + $organization = $this->entityManager->getRepository(Organizations::class)->find($id); if (!$organization) { throw $this->createNotFoundException(self::NOT_FOUND); } + $newUsers = $this->entityManager->getRepository(UsersOrganizations::class)->getLastNewActiveUsersByOrganization($organization); + $adminUsers = $this->entityManager->getRepository(UsersOrganizations::class)->getAdminUsersByOrganization($organization); +// reusing the method to avoid code duplication even though it returns an array of UsersOrganizations + $org = $this->entityManager->getRepository(UsersOrganizations::class)->findActiveUsersByOrganizations([$organization]); + + + return $this->render('organization/show.html.twig', [ 'organization' => $organization, + 'adminUsers' => $adminUsers, + 'newUsers' => $newUsers, + 'org' => $org[0], ]); } diff --git a/src/Repository/UsersOrganizationsRepository.php b/src/Repository/UsersOrganizationsRepository.php index f00e572..72583b7 100644 --- a/src/Repository/UsersOrganizationsRepository.php +++ b/src/Repository/UsersOrganizationsRepository.php @@ -193,4 +193,82 @@ class UsersOrganizationsRepository extends ServiceEntityRepository } return $userToOrgs; } + + /** + * Get the last 10 new active users for a specific organization. + * Users are ordered by creation date (most recent first). + * + * @param Organizations $organization + * @return array + */ + public function getLastNewActiveUsersByOrganization(Organizations $organization): array + { + $results = $this->createQueryBuilder('uo') + ->select('u.id', 'u.surname', 'u.name', 'u.email', 'u.pictureUrl', 'u.isActive', 'uo.createdAt') + ->innerJoin('uo.users', 'u') + ->innerJoin('uo.organization', 'o') + ->where('uo.isActive = :isActive') + ->andWhere('u.isActive = :userIsActive') + ->andWhere('o.isActive = :orgIsActive') + ->andWhere('uo.organization = :organization') + ->setParameter('isActive', true) + ->setParameter('userIsActive', true) + ->setParameter('orgIsActive', true) + ->setParameter('organization', $organization) + ->orderBy('uo.createdAt', 'DESC') + ->setMaxResults(10) + ->getQuery() + ->getResult(); + + // Remove duplicates by user ID (in case user has multiple roles) + $uniqueUsers = []; + foreach ($results as $result) { + $userId = $result['id']; + if (!isset($uniqueUsers[$userId])) { + $uniqueUsers[$userId] = $result; + } + } + + return array_values($uniqueUsers); + } + + /** + * Get all active admin users for a specific organization. + * Returns users who have the 'ADMIN' role in the given organization. + * + * @param Organizations $organization + * @return array + */ + public function getAdminUsersByOrganization(Organizations $organization): array + { + $results = $this->createQueryBuilder('uo') + ->select('u.id', 'u.surname', 'u.name', 'u.email', 'u.pictureUrl', 'u.isActive') + ->innerJoin('uo.users', 'u') + ->innerJoin('uo.organization', 'o') + ->innerJoin('uo.role', 'r') + ->where('uo.isActive = :isActive') + ->andWhere('u.isActive = :userIsActive') + ->andWhere('o.isActive = :orgIsActive') + ->andWhere('uo.organization = :organization') + ->andWhere('r.name = :roleName') + ->setParameter('isActive', true) + ->setParameter('userIsActive', true) + ->setParameter('orgIsActive', true) + ->setParameter('organization', $organization) + ->setParameter('roleName', 'ADMIN') + ->orderBy('u.surname', 'ASC') + ->getQuery() + ->getResult(); + + // Remove duplicates by user ID (in case user has multiple admin-related roles) + $uniqueUsers = []; + foreach ($results as $result) { + $userId = $result['id']; + if (!isset($uniqueUsers[$userId])) { + $uniqueUsers[$userId] = $result; + } + } + + return array_values($uniqueUsers); + } } diff --git a/src/Service/OrganizationsService.php b/src/Service/OrganizationsService.php new file mode 100644 index 0000000..8bb69d6 --- /dev/null +++ b/src/Service/OrganizationsService.php @@ -0,0 +1,28 @@ +entityManager->getRepository(Roles::class)->findBy(['name' => 'ADMIN']); + return $this->entityManager->getRepository(UsersOrganizations::class)->findBy(['organization'=>$organization, + 'role' => $roleAdmin, + 'isActive' => true]); + } + + public function getNewUsers(Organizations $organization): array{ + return $this->entityManager->getRepository(UsersOrganizations::class)->findBy(['organization'=>$organization, + 'isActive' => true]); + } + +} \ No newline at end of file diff --git a/templates/organization/show.html.twig b/templates/organization/show.html.twig index 90bf331..6713e19 100644 --- a/templates/organization/show.html.twig +++ b/templates/organization/show.html.twig @@ -1,10 +1,33 @@ {% extends 'base.html.twig' %} {% block body %} - +
+
+

{{ organization.name|title }} - Dashboard

+ {% if is_granted("ROLE_SUER_ADMIN") %} + {# Désactiver #} + {% endif %} +
+
+
+ {% include 'user/userListSmall.html.twig' with { + title: 'Nouveaux utilisateurs', + users: newUsers, + empty_message: 'Aucun nouvel utilisateur trouvé.' + } %} +
+
+ {% include 'user/userListSmall.html.twig' with { + title: 'Administrateurs', + users: adminUsers, + empty_message: 'Aucun administrateur trouvé.' + } %} +
+
+ {% include 'user/userList.html.twig' with { + title: 'Mes utilisateurs', + } %} +
{% endblock %} -{% block title %} - {{ organization.name|title }} - Dashboard -{% endblock %} diff --git a/templates/user/userList.html.twig b/templates/user/userList.html.twig index e936f42..2752bfa 100644 --- a/templates/user/userList.html.twig +++ b/templates/user/userList.html.twig @@ -1,5 +1,8 @@ {% block body %} + {% if title is defined %} +

{{ title }}

+ {% endif %} @@ -7,10 +10,16 @@ +{# #} + {% if org.users|length == 0 %} + + + + {% endif %} {% for user in org.users %} {% endfor %} - {% if org.users|length == 0 %} - - - - {% endif %} +
Surname Name EmailStatutVisualiser
Aucun utilisateur trouvé.
@@ -29,11 +38,7 @@
Aucun utilisateur trouvé.
{% endblock %} \ No newline at end of file diff --git a/templates/user/userListSmall.html.twig b/templates/user/userListSmall.html.twig new file mode 100644 index 0000000..1549478 --- /dev/null +++ b/templates/user/userListSmall.html.twig @@ -0,0 +1,39 @@ +
+
+

{{ title }}

+
+
+ + + + + + + + + + {% if users|length == 0 %} + + + + {% else %} + {% for user in users %} + + + + + + {% endfor %} + {% endif %} + +
PictureEmailVisualiser
{{ empty_message }}
+ {% if user.pictureUrl %} + User profile pic + {% endif %} + {{ user.email }} + + {{ ux_icon('fa6-regular:eye', {height: '30px', width: '30px'}) }} + +
+
+
\ No newline at end of file