From a3f993b8589ce79725d449fb4d37cba4572ec1b0 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 29 Jul 2025 15:55:55 +0200 Subject: [PATCH] organizations user information --- assets/styles/app.css | 2 +- src/Controller/OrganizationController.php | 7 +- src/Controller/UserController.php | 7 +- .../UsersOrganizationsRepository.php | 105 +-------------- src/Service/UserOrganizationService.php | 126 +++++++++++++++++- src/Service/UserService.php | 26 ++++ templates/organization/activity.html.twig | 25 +++- templates/organization/show.html.twig | 68 +++++----- templates/user/index.html.twig | 5 +- templates/user/userInformation.html.twig | 2 +- templates/user/userList.html.twig | 106 ++++++++------- templates/user/userListSmall.html.twig | 74 +++++----- 12 files changed, 320 insertions(+), 233 deletions(-) diff --git a/assets/styles/app.css b/assets/styles/app.css index 42a7c59..565a11f 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -69,7 +69,7 @@ body { } .content-wrapper { - background: #F5F7FF; + background: #EEF0FD; width: 100%; -webkit-flex-grow: 1; flex-grow: 1; diff --git a/src/Controller/OrganizationController.php b/src/Controller/OrganizationController.php index 3c27b4a..53a35ac 100644 --- a/src/Controller/OrganizationController.php +++ b/src/Controller/OrganizationController.php @@ -4,6 +4,7 @@ namespace App\Controller; use App\Entity\UsersOrganizations; use App\Service\OrganizationsService; +use App\Service\UserOrganizationService; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Routing\Attribute\Route; @@ -18,7 +19,8 @@ class OrganizationController extends AbstractController private const ACCESS_DENIED = 'Access denied'; public function __construct(private readonly EntityManagerInterface $entityManager, - private readonly OrganizationsService $organizationsService) + private readonly OrganizationsService $organizationsService, + private readonly UserOrganizationService $usersOrganizationService) { } @@ -75,7 +77,8 @@ class OrganizationController extends AbstractController $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]); + $org = $this->usersOrganizationService->findActiveUsersByOrganizations([$organization]); + diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index 450580b..2f8c5b1 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -36,8 +36,8 @@ class UserController extends AbstractController public function index(EntityManagerInterface $entityManager): Response { if ($this->isGranted('ROLE_SUPER_ADMIN')) { - $usersByOrganization = $entityManager->getRepository(UsersOrganizations::class)->getActiveUsersGroupedByOrganization(); - + $usersByOrganization = $this->userOrganizationService->getActiveUsersGroupedByOrganization(); +// dd($usersByOrganization); } else{ $user = $this->getUser(); if (!$user) { @@ -49,8 +49,7 @@ class UserController extends AbstractController // if user is not admin in any organization, throw access denied throw $this->createNotFoundException(self::ACCESS_DENIED); } - $usersByOrganization = $this->entityManager->getRepository(UsersOrganizations::class) - ->findActiveUsersByOrganizations($organizations); + $usersByOrganization = $this->userOrganizationService->findActiveUsersByOrganizations($organizations); } return $this->render('user/index.html.twig', [ 'usersByOrganization' => $usersByOrganization, diff --git a/src/Repository/UsersOrganizationsRepository.php b/src/Repository/UsersOrganizationsRepository.php index 72583b7..a72cf62 100644 --- a/src/Repository/UsersOrganizationsRepository.php +++ b/src/Repository/UsersOrganizationsRepository.php @@ -65,90 +65,8 @@ class UsersOrganizationsRepository extends ServiceEntityRepository return array_map(fn($uo) => $uo->getOrganization(), $results); } - /** - * Get all active users grouped by organization. - * Users with no organization are grouped under 'autre'. - * - * @return array - */ - public function getActiveUsersGroupedByOrganization(): array - { - $users = $this->getEntityManager()->getRepository(User::class)->getAllActiveUsers(); - $userOrgs = $this->getAllActiveUserOrganizationLinks(); - $userToOrgs = $this->mapUserToOrganizations($userOrgs); - $orgs = []; - foreach ($users as $user) { - $userId = $user['id']; - if (isset($userToOrgs[$userId])) { - foreach ($userToOrgs[$userId] as $orgInfo) { - $orgId = $orgInfo['organization_id']; - if (!isset($orgs[$orgId])) { - $orgs[$orgId] = [ - 'organization_id' => $orgId, - 'organization_name' => $orgInfo['organization_name'], - 'users' => [], - ]; - } - $orgs[$orgId]['users'][$userId] = $user; - } - } else { - if (!isset($orgs['autre'])) { - $orgs['autre'] = [ - 'organization_id' => null, - 'organization_name' => 'autre', - 'users' => [], - ]; - } - $orgs['autre']['users'][$userId] = $user; - } - } - - // Convert users arrays to indexed arrays - foreach ($orgs as &$org) { - $org['users'] = array_values($org['users']); - } - - return array_values($orgs); - } - - /** - * Get all active users for each organization in the given array. - * - * @param Organizations[] $organizations - * @return array - */ - public function findActiveUsersByOrganizations(array $organizations): array - { - if (empty($organizations)) { - return []; - } - - $userOrgs = $this->getAllActiveUserOrganizationLinks($organizations); - - $usersByOrg = []; - foreach ($userOrgs as $uo) { - $org = $uo->getOrganization(); - $orgId = $org->getId(); - if (!isset($usersByOrg[$orgId])) { - $usersByOrg[$orgId] = [ - 'organization_id' => $orgId, - 'organization_name' => $org->getName(), - 'users' => [], - ]; - } - $userId = $uo->getUsers()->getId(); - $usersByOrg[$orgId]['users'][$userId] = $uo->getUsers(); - } - - // Convert users arrays to indexed arrays - foreach ($usersByOrg as &$org) { - $org['users'] = array_values($org['users']); - } - - return array_values($usersByOrg); - } /** * Helper: Get all active UsersOrganizations links, optionally filtered by organizations. @@ -156,7 +74,7 @@ class UsersOrganizationsRepository extends ServiceEntityRepository * @param Organizations[]|null $organizations * @return UsersOrganizations[] */ - private function getAllActiveUserOrganizationLinks(array $organizations = null): array + public function getAllActiveUserOrganizationLinks(array $organizations = null): array { $qb = $this->createQueryBuilder('uo') ->innerJoin('uo.organization', 'o') @@ -172,27 +90,6 @@ class UsersOrganizationsRepository extends ServiceEntityRepository return $qb->getQuery()->getResult(); } - /** - * Helper: Map userId to their organizations (id and name), avoiding duplicates. - * - * @param UsersOrganizations[] $userOrgs - * @return array - */ - private function mapUserToOrganizations(array $userOrgs): array - { - $userToOrgs = []; - foreach ($userOrgs as $uo) { - $userId = $uo->getUsers()->getId(); - $org = $uo->getOrganization(); - $orgId = $org->getId(); - $orgName = $org->getName(); - $userToOrgs[$userId][$orgId] = [ - 'organization_id' => $orgId, - 'organization_name' => $orgName, - ]; - } - return $userToOrgs; - } /** * Get the last 10 new active users for a specific organization. diff --git a/src/Service/UserOrganizationService.php b/src/Service/UserOrganizationService.php index 9e2bb5d..dd4f9d7 100644 --- a/src/Service/UserOrganizationService.php +++ b/src/Service/UserOrganizationService.php @@ -6,6 +6,7 @@ use App\Entity\Apps; use App\Entity\Organizations; use App\Entity\Roles; use App\Entity\User; +use App\Service\UserService; use App\Entity\UsersOrganizations; use Doctrine\ORM\EntityManagerInterface; @@ -20,7 +21,8 @@ readonly class UserOrganizationService * * @param EntityManagerInterface $entityManager Le gestionnaire d'entités Doctrine */ - public function __construct(private readonly EntityManagerInterface $entityManager) + public function __construct(private readonly EntityManagerInterface $entityManager, + private readonly UserService $userService) { } @@ -335,4 +337,126 @@ readonly class UserOrganizationService } $this->entityManager->flush(); } + + /** + * Get all active users grouped by organization. + * Users with no organization are grouped under 'autre'. + * + * @return array + */ + public function getActiveUsersGroupedByOrganization(): array + { + $users = $this->entityManager->getRepository(User::class)->getAllActiveUsers(); + $userOrgs = $this->entityManager->getRepository(UsersOrganizations::class)->getAllActiveUserOrganizationLinks(); + + $userToOrgs = $this->mapUserToOrganizations($userOrgs); + + $orgs = []; + foreach ($users as $user) { + $userId = $user['id']; + if (isset($userToOrgs[$userId])) { + foreach ($userToOrgs[$userId] as $orgInfo) { + $orgId = $orgInfo['organization_id']; + if (!isset($orgs[$orgId])) { + $orgs[$orgId] = [ + 'organization_id' => $orgId, + 'organization_name' => $orgInfo['organization_name'], + 'users' => [], + ]; + } +// $orgs[$orgId]['users'][$userId] = $user; + $orgs[$orgId]['users'][$userId] = [ + 'users' => $user, + 'is_connected' => $this->userService->isUserConnected($user['email']) + ]; + } + } else { + if (!isset($orgs['autre'])) { + $orgs['autre'] = [ + 'organization_id' => null, + 'organization_name' => 'autre', + 'users' => [], + ]; + } + $orgs['autre']['users'][$userId] = [ + 'users' => $user, + 'is_connected' => $this->userService->isUserConnected($user['email']) + ]; + } + } + + // Convert users arrays to indexed arrays + foreach ($orgs as &$org) { + $org['users'] = array_values($org['users']); + } + + return array_values($orgs); + } + + /** + * Get all active users for each organization in the given array. + * + * @param Organizations[] $organizations + * @return array + */ + public function findActiveUsersByOrganizations(array $organizations): array + { + if (empty($organizations)) { + return []; + } + + $userOrgs = $this->entityManager->getRepository(UsersOrganizations::class)->getAllActiveUserOrganizationLinks($organizations); + + $usersByOrg = []; + foreach ($userOrgs as $uo) { + $org = $uo->getOrganization(); + $orgId = $org->getId(); + if (!isset($usersByOrg[$orgId])) { + $usersByOrg[$orgId] = [ + 'organization_id' => $orgId, + 'organization_name' => $org->getName(), + 'users' => [], + ]; + } + + $user = $uo->getUsers(); + $userId = $user->getId(); + + // Add connection status to user data + $usersByOrg[$orgId]['users'][$userId] = [ + 'users' => $user, + 'is_connected' => $this->userService->isUserConnected($user->getUserIdentifier()) + ]; + } + + // Convert users arrays to indexed arrays + foreach ($usersByOrg as &$org) { + $org['users'] = array_values($org['users']); + } + + return array_values($usersByOrg); + } + + /** + * Helper: Map userId to their organizations (id and name), avoiding duplicates. + * + * @param UsersOrganizations[] $userOrgs + * @return array + */ + private function mapUserToOrganizations(array $userOrgs): array + { + $userToOrgs = []; + foreach ($userOrgs as $uo) { + $userId = $uo->getUsers()->getId(); + $org = $uo->getOrganization(); + $orgId = $org->getId(); + $orgName = $org->getName(); + $userToOrgs[$userId][$orgId] = [ + 'organization_id' => $orgId, + 'organization_name' => $orgName, + ]; + } + return $userToOrgs; + } + } diff --git a/src/Service/UserService.php b/src/Service/UserService.php index 61eaf5a..41577c5 100644 --- a/src/Service/UserService.php +++ b/src/Service/UserService.php @@ -8,6 +8,7 @@ use App\Entity\Roles; use App\Entity\User; use App\Entity\UsersOrganizations; use Doctrine\ORM\EntityManagerInterface; +use League\Bundle\OAuth2ServerBundle\Model\AccessToken; class UserService { @@ -59,4 +60,29 @@ class UserService 'roleId' => $roleAdmin[0]->getId()])); } + + /** + * Check if the user is currently connected. + * This method check if the user is currently connected to one of the applications. + * + * @param String $userIdentifier + * @return bool + */ + public function isUserConnected(string $userIdentifier): bool + { + $now = new \DateTimeImmutable('now', new \DateTimeZone('Europe/Paris')); + $tokens = $this->entityManager->getRepository(AccessToken::class)->findBy([ + 'userIdentifier' => $userIdentifier, + 'revoked' => false + ]); + + foreach ($tokens as $token) { + // Assuming $token->getExpiry() returns a DateTimeInterface + if ($token->getExpiry() > $now) { + return true; + } + } + + return false; + } } diff --git a/templates/organization/activity.html.twig b/templates/organization/activity.html.twig index 60ad84d..81ea905 100644 --- a/templates/organization/activity.html.twig +++ b/templates/organization/activity.html.twig @@ -1,8 +1,10 @@ {% block body %} -

{{ title }}

-
+
+
+

{{ title }}

+
{# {% if activities|length == 0 %}#} {#

Aucune activité récente.

#} @@ -10,11 +12,24 @@
    {# {% for activity in activities %}#}
  • -{# {{ activity.timestamp|date('Y-m-d H:i') }} - #} -{# {{ activity.user.name }} a {{ activity.action }} sur {{ activity.targetType }}: #} -{# {{ activity.targetName }}#}

    5 mins ago

  • +
  • +

    5 mins ago

    +
  • +
  • +

    5 mins ago

    +
  • +
  • +

    5 mins ago

    +
  • +
  • +

    5 mins ago

    +
  • +
  • +

    5 mins ago

    +
  • + {# {% endfor %}#}
{# {% endif %}#} diff --git a/templates/organization/show.html.twig b/templates/organization/show.html.twig index 9939c02..e234945 100644 --- a/templates/organization/show.html.twig +++ b/templates/organization/show.html.twig @@ -8,39 +8,45 @@ {# Désactiver #} {% endif %}
-
-
- {% include 'user/userListSmall.html.twig' with { - title: 'Nouveaux utilisateurs', - users: newUsers, - empty_message: 'Aucun nouvel utilisateur trouvé.' - } %} +{# USER ROW#} +
+
+
+
+ {% 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', + } %} +
-
- {% include 'user/userListSmall.html.twig' with { - title: 'Administrateurs', - users: adminUsers, - empty_message: 'Aucun administrateur trouvé.' - } %} -
-
- {% include 'user/userList.html.twig' with { - title: 'Mes utilisateurs', - } %} -{#
#} -{#
#} -{# {% include 'user/userList.html.twig' with {#} -{# title: 'Mes utilisateurs',#} -{# } %}#} -{#
#} -{#
#} -{# {% include 'organization/activity.html.twig' with {#} -{# title: 'Activités récentes',#} -{# empty_message: 'Aucune activité récente.'#} -{# } %}#} -{#
#} -{#
#} +
+ {% include 'organization/activity.html.twig' with { + title: 'Activités récentes', + empty_message: 'Aucune activité récente.' + } %} +
+ +
+ +{# APPLICATION ROW#} +
+ +
{% endblock %} diff --git a/templates/user/index.html.twig b/templates/user/index.html.twig index e72325e..2015b4b 100644 --- a/templates/user/index.html.twig +++ b/templates/user/index.html.twig @@ -10,8 +10,9 @@
{% for org in usersByOrganization %} -

{{ org.organization_name|title }}

- {% include 'user/userList.html.twig' %} + {% include 'user/userList.html.twig' with { + title: org.organization_name|capitalize + } %} {% endfor %}
{% endblock %} \ No newline at end of file diff --git a/templates/user/userInformation.html.twig b/templates/user/userInformation.html.twig index 228e6ba..71c4355 100644 --- a/templates/user/userInformation.html.twig +++ b/templates/user/userInformation.html.twig @@ -1,6 +1,6 @@ {% block body %} -
+

{{ user.surname|capitalize }} {{ user.name|capitalize }}

Modifier diff --git a/templates/user/userList.html.twig b/templates/user/userList.html.twig index 810f66b..c91924a 100644 --- a/templates/user/userList.html.twig +++ b/templates/user/userList.html.twig @@ -1,52 +1,62 @@ {% block body %} - {% if title is defined %} -

{{ title }}

- {% endif %} - - - - - - - - - - - - - {% if org.users|length == 0 %} - - - - {% endif %} - {% for user in org.users %} - - - - - -{# #} - - - - {% endfor %} +
-
-
PictureSurnameNameEmailStatutVisualiser
Aucun utilisateur trouvé.
- {% if user.pictureUrl %} - User profile pic - {% endif %} - {{ user.surname }}{{ user.name }}{{ user.email }}#} -{# {% if user.isActive %}#} -{# Actif#} -{# {% else %}#} -{# Inactif#} -{# {% endif %}#} -{# Actif - - - {{ ux_icon('fa6-regular:eye', {height: '30px', width: '30px'}) }} - -
+ {% if title is defined %} +
+

{{ title }}

+ +
+ {% endif %} +
+ + + + + + + + + + + + + + {% if org.users|length == 0 %} + + + + {% endif %} + {% for user in org.users %} + + + + + + + + + {% endfor %} + + +
PictureSurnameNameEmailStatutVisualiser
Aucun utilisateur trouvé.
+ {% if user.users.pictureUrl %} + User profile pic + {% endif %} + {{ user.users.surname }}{{ user.users.name }}{{ user.users.email }} + {% if user.is_connected %} + Actif + {% else %} + Inactif + {% endif %} + + + + {{ ux_icon('fa6-regular:eye', {height: '30px', width: '30px'}) }} + +
+
+
{% endblock %} \ No newline at end of file diff --git a/templates/user/userListSmall.html.twig b/templates/user/userListSmall.html.twig index 7d5ee00..1a6ce77 100644 --- a/templates/user/userListSmall.html.twig +++ b/templates/user/userListSmall.html.twig @@ -1,39 +1,45 @@ -
-
-

{{ title }}

-
-
- - - - - - - - - - {% if users|length == 0 %} +{% block body %} + +
+
+

{{ title }}

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