472 lines
16 KiB
PHP
472 lines
16 KiB
PHP
<?php
|
|
|
|
namespace App\Service;
|
|
|
|
use App\Entity\Actions;
|
|
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;
|
|
|
|
/**
|
|
* Service pour la gestion des organisations d'utilisateurs.
|
|
* Fournit des méthodes pour récupérer, modifier et désactiver les rôles et applications d'un utilisateur dans une organisation.
|
|
*/
|
|
readonly class UserOrganizationService
|
|
{
|
|
/**
|
|
* Constructeur du service UserOrganizationService.
|
|
*
|
|
* @param EntityManagerInterface $entityManager Le gestionnaire d'entités Doctrine
|
|
*/
|
|
public function __construct(private readonly EntityManagerInterface $entityManager,
|
|
private readonly UserService $userService)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Récupère toutes les organisations auxquelles appartient l'utilisateur donné,
|
|
* incluant les rôles et applications uniques de l'utilisateur dans chaque organisation.
|
|
*
|
|
* @param User $user L'utilisateur concerné
|
|
* @param int|null $organizationsId ID optionnel pour filtrer par organisation
|
|
* @return array<array{organization:object, roles:Roles[], apps:object[], uoId:int}>
|
|
*/
|
|
public function getUserOrganizations(User $user, int $organizationsId = null): array
|
|
{
|
|
$userOrganizations = $this->entityManager
|
|
->getRepository(UsersOrganizations::class)
|
|
->findAllDistinctOrganizationsByUserId($user->getId());
|
|
$organizations = [];
|
|
|
|
foreach ($userOrganizations as $uo) {
|
|
$orgId = $uo->getOrganization()->getId();
|
|
|
|
// Si $organizationsId est fourni, ignorer les autres organisations
|
|
if ($organizationsId !== null && $orgId !== $organizationsId) {
|
|
continue;
|
|
}
|
|
|
|
// Initialiser l'entrée de l'organisation si elle n'existe pas
|
|
$organizations[$orgId] = $organizations[$orgId] ?? $this->createEmptyOrganizationBucket($uo);
|
|
$organizations[$orgId]['uoId'] = $uo->getId();
|
|
|
|
// Agréger les rôles et applications
|
|
$this->addRole($organizations[$orgId]['roles'], $uo->getRole());
|
|
$this->addApps($organizations[$orgId]['apps'], $uo->getApps());
|
|
}
|
|
|
|
// Ordonner les rôles : Super Admin, Admin, puis les autres
|
|
foreach ($organizations as &$org) {
|
|
$org['roles'] = $this->sortRoles($org['roles']);
|
|
}
|
|
unset($org);
|
|
|
|
$this->normalizeAppsIndexes($organizations);
|
|
|
|
return array_values($organizations);
|
|
}
|
|
|
|
/**
|
|
* Trie les rôles pour que Super Admin et Admin soient en premier, puis les autres.
|
|
*
|
|
* @param Roles[] $roles
|
|
* @return Roles[]
|
|
*/
|
|
private function sortRoles(array $roles): array
|
|
{
|
|
usort($roles, function ($a, $b) {
|
|
$priority = [
|
|
'SUPER_ADMIN' => 0,
|
|
'ADMIN' => 1
|
|
];
|
|
$aName = strtoupper($a->getName());
|
|
$bName = strtoupper($b->getName());
|
|
$aPriority = $priority[$aName] ?? 2;
|
|
$bPriority = $priority[$bName] ?? 2;
|
|
if ($aPriority === $bPriority) {
|
|
return strcmp($aName, $bName);
|
|
}
|
|
return $aPriority <=> $bPriority;
|
|
});
|
|
return $roles;
|
|
}
|
|
|
|
/**
|
|
* Initialise la structure de données pour une organisation.
|
|
*
|
|
* @param UsersOrganizations $link Lien utilisateur-organisation
|
|
* @return array{organization:object, roles:Roles[], apps:array<int,object>}
|
|
*/
|
|
private function createEmptyOrganizationBucket(UsersOrganizations $link): array
|
|
{
|
|
return [
|
|
'organization' => $link->getOrganization(),
|
|
'roles' => [],
|
|
'apps' => [],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Ajoute un rôle à la liste si non déjà présent (par ID).
|
|
*
|
|
* @param Roles[] &$roles Liste des rôles
|
|
* @param Roles|null $role Rôle à ajouter
|
|
* @return void
|
|
*/
|
|
private function addRole(array &$roles, ?Roles $role): void
|
|
{
|
|
if ($role === null) {
|
|
return;
|
|
}
|
|
foreach ($roles as $existingRole) {
|
|
if ($existingRole->getId() === $role->getId()) {
|
|
return; // Already present
|
|
}
|
|
}
|
|
$roles[] = $role;
|
|
}
|
|
|
|
/**
|
|
* Fusionne une ou plusieurs applications dans le tableau associatif, une entrée par ID.
|
|
*
|
|
* @param array<int,object> &$apps Tableau des applications
|
|
* @param iterable $appsToAdd Applications à ajouter
|
|
* @return void
|
|
*/
|
|
private function addApps(array &$apps, iterable $appsToAdd): void
|
|
{
|
|
foreach ($appsToAdd as $app) {
|
|
$apps[$app->getId()] = $apps[$app->getId()] ?? $app;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Normalise le tableau des applications pour le rendre indexé (JSON-friendly).
|
|
*
|
|
* @param array &$organizations Tableau des organisations
|
|
* @return void
|
|
*/
|
|
private function normalizeAppsIndexes(array &$organizations): void
|
|
{
|
|
foreach ($organizations as &$org) {
|
|
$org['apps'] = array_values($org['apps']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Définit les rôles d'un utilisateur dans une organisation, en s'assurant que le rôle USER est toujours présent.
|
|
* Désactive tous les rôles si USER n'est pas sélectionné.
|
|
*
|
|
* @param User $user L'utilisateur
|
|
* @param Organizations $organization L'organisation
|
|
* @param array $selectedRoles Tableau des IDs de rôles sélectionnés
|
|
* @return void
|
|
* @throws \RuntimeException Si le rôle USER n'est pas trouvé
|
|
*/
|
|
public function setUserOrganizations(User $user, Organizations $organization, array $selectedRoles): void
|
|
{
|
|
$repo = $this->entityManager->getRepository(UsersOrganizations::class);
|
|
$roleRepo = $this->entityManager->getRepository(Roles::class);
|
|
$userRole = $roleRepo->findOneBy(['name' => 'USER']);
|
|
if (!$userRole) {
|
|
throw new \RuntimeException('USER role not found');
|
|
}
|
|
if (!in_array($userRole->getId(), $selectedRoles)) {
|
|
$this->deactivateAllUserRoles($user, $organization);
|
|
return;
|
|
}
|
|
$currentUserOrgs = $repo->findBy([
|
|
'users' => $user,
|
|
'organization' => $organization
|
|
]);
|
|
$currentRolesMap = $this->mapUserOrgRoles($currentUserOrgs);
|
|
$selectedRoles = $this->ensureUserRolePresent($selectedRoles, $userRole->getId());
|
|
$this->addOrUpdateRoles($selectedRoles, $currentRolesMap, $roleRepo, $user, $organization);
|
|
$this->deactivateUnselectedRoles($currentRolesMap);
|
|
$this->entityManager->flush();
|
|
}
|
|
|
|
/**
|
|
* Met à jour les applications associées à l'utilisateur dans une organisation.
|
|
*
|
|
* @param User $user L'utilisateur
|
|
* @param Organizations $organization L'organisation
|
|
* @param array $selectedApps Tableau des IDs d'applications sélectionnées
|
|
* @return void
|
|
*/
|
|
public function setUserOrganizationsApps(User $user, Organizations $organization, array $selectedApps): void
|
|
{
|
|
$roleUser = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'USER']);
|
|
$uoEntity = $this->entityManager
|
|
->getRepository(UsersOrganizations::class)
|
|
->findOneBy(['users' => $user, 'organization' => $organization, 'role' => $roleUser]);
|
|
if (!$uoEntity) {
|
|
return;
|
|
}
|
|
$this->removeUnselectedApps($uoEntity, $selectedApps);
|
|
$this->addSelectedApps($uoEntity, $selectedApps);
|
|
$this->entityManager->persist($uoEntity);
|
|
$this->entityManager->flush();
|
|
}
|
|
|
|
/**
|
|
* Crée une map des rôles actuels de l'utilisateur dans l'organisation.
|
|
* @param array $currentUserOrgs
|
|
* @return array
|
|
*/
|
|
private function mapUserOrgRoles(array $currentUserOrgs): array
|
|
{
|
|
$map = [];
|
|
foreach ($currentUserOrgs as $uo) {
|
|
$map[$uo->getRole()->getId()] = $uo;
|
|
}
|
|
return $map;
|
|
}
|
|
|
|
/**
|
|
* S'assure que le rôle USER est présent dans la sélection si nécessaire.
|
|
* @param array $selectedRoles
|
|
* @param int $userRoleId
|
|
* @return array
|
|
*/
|
|
private function ensureUserRolePresent(array $selectedRoles, int $userRoleId): array
|
|
{
|
|
$hasNonUserRole = false;
|
|
foreach ($selectedRoles as $roleId) {
|
|
if ($roleId !== $userRoleId) {
|
|
$hasNonUserRole = true;
|
|
break;
|
|
}
|
|
}
|
|
if ($hasNonUserRole && !in_array($userRoleId, $selectedRoles)) {
|
|
$selectedRoles[] = $userRoleId;
|
|
}
|
|
return $selectedRoles;
|
|
}
|
|
|
|
/**
|
|
* Ajoute ou réactive les rôles sélectionnés pour l'utilisateur dans l'organisation.
|
|
* @param array $selectedRoles
|
|
* @param array $currentRolesMap
|
|
* @param $roleRepo
|
|
* @param User $user
|
|
* @param Organizations $organization
|
|
*/
|
|
private function addOrUpdateRoles(array $selectedRoles, array &$currentRolesMap, $roleRepo, User $user, Organizations $organization): void
|
|
{
|
|
foreach ($selectedRoles as $roleId) {
|
|
if (!isset($currentRolesMap[$roleId])) {
|
|
$roleEntity = $roleRepo->find($roleId);
|
|
if ($roleEntity) {
|
|
$newUserOrganization = new UsersOrganizations();
|
|
$newUserOrganization->setUsers($user);
|
|
$newUserOrganization->setRole($roleEntity);
|
|
$newUserOrganization->setOrganization($organization);
|
|
$newUserOrganization->setIsActive(true);
|
|
$this->entityManager->persist($newUserOrganization);
|
|
}
|
|
} else {
|
|
$currentRolesMap[$roleId]->setIsActive(true);
|
|
$this->entityManager->persist($currentRolesMap[$roleId]);
|
|
}
|
|
unset($currentRolesMap[$roleId]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Désactive les rôles non sélectionnés pour l'utilisateur dans l'organisation.
|
|
* @param array $currentRolesMap
|
|
*/
|
|
private function deactivateUnselectedRoles(array $currentRolesMap): void
|
|
{
|
|
foreach ($currentRolesMap as $uo) {
|
|
$uo->setIsActive(false);
|
|
$this->entityManager->persist($uo);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retire les applications non sélectionnées de l'utilisateur dans l'organisation.
|
|
* @param UsersOrganizations $uoEntity
|
|
* @param array $selectedApps
|
|
*/
|
|
private function removeUnselectedApps(UsersOrganizations $uoEntity, array $selectedApps): void
|
|
{
|
|
foreach ($uoEntity->getApps()->toArray() as $existingApp) {
|
|
if (!in_array($existingApp->getId(), $selectedApps)) {
|
|
$uoEntity->removeApp($existingApp);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ajoute les applications sélectionnées à l'utilisateur dans l'organisation.
|
|
* @param UsersOrganizations $uoEntity
|
|
* @param array $selectedApps
|
|
*/
|
|
private function addSelectedApps(UsersOrganizations $uoEntity, array $selectedApps): void
|
|
{
|
|
foreach ($selectedApps as $appId) {
|
|
$appEntity = $this->entityManager->getRepository(Apps::class)->find($appId);
|
|
if ($appEntity && !$uoEntity->getApps()->contains($appEntity)) {
|
|
$uoEntity->addApp($appEntity);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Désactive tous les rôles d'un utilisateur dans une organisation.
|
|
*
|
|
* @param User $user L'utilisateur
|
|
* @param Organizations $organization L'organisation
|
|
* @return void
|
|
*/
|
|
public function deactivateAllUserRoles(User $user, Organizations $organization): void
|
|
{
|
|
$repo = $this->entityManager->getRepository(UsersOrganizations::class);
|
|
$userOrganizations = $repo->findBy([
|
|
'users' => $user,
|
|
'organization' => $organization
|
|
]);
|
|
foreach ($userOrganizations as $uo) {
|
|
$uo->setIsActive(false);
|
|
//Log action
|
|
$action = new Actions();
|
|
$action->setActionType("Désactivation role" );
|
|
$action->setDescription("Désactivation du rôle " . $uo->getRole()->getName() . " pour l'utilisateur " . $user->getUserIdentifier() . " dans l'organisation " . $organization->getName());
|
|
$action->setOrganization($organization);
|
|
$action->setUsers($user);
|
|
$this->entityManager->persist($uo);
|
|
}
|
|
$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;
|
|
}
|
|
|
|
|
|
|
|
}
|