Read User information

This commit is contained in:
Charles 2025-07-16 15:12:45 +02:00
parent 10a8eb2255
commit 4a2f9d9547
18 changed files with 445 additions and 155 deletions

View File

@ -141,7 +141,6 @@
<path value="$PROJECT_DIR$/vendor/defuse/php-encryption" />
<path value="$PROJECT_DIR$/vendor/symfony/ux-turbo" />
<path value="$PROJECT_DIR$/vendor/symfony/stimulus-bundle" />
<path value="$PROJECT_DIR$/vendor/doctrine/cache" />
<path value="$PROJECT_DIR$/vendor/symfony/type-info" />
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
<path value="$PROJECT_DIR$/vendor/symfony/console" />

View File

@ -0,0 +1 @@
<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 464a208 208 0 1 1 0-416a208 208 0 1 1 0 416m0-464a256 256 0 1 0 0 512a256 256 0 1 0 0-512m120.9 294.6c4.5-4.2 7.1-10.1 7.1-16.3c0-12.3-10-22.3-22.3-22.3H304v-96c0-17.7-14.3-32-32-32h-32c-17.7 0-32 14.3-32 32v96h-57.7c-12.3 0-22.3 10-22.3 22.3c0 6.2 2.6 12.1 7.1 16.3l107.1 99.9c3.8 3.5 8.7 5.5 13.8 5.5s10.1-2 13.8-5.5z"/></svg>

After

Width:  |  Height:  |  Size: 425 B

View File

@ -0,0 +1 @@
<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 48a208 208 0 1 1 0 416a208 208 0 1 1 0-416m0 464a256 256 0 1 0 0-512a256 256 0 1 0 0 512M151.2 217.4c-4.6 4.2-7.2 10.1-7.2 16.4c0 12.3 10 22.3 22.3 22.3H208v96c0 17.7 14.3 32 32 32h32c17.7 0 32-14.3 32-32v-96h41.7c12.3 0 22.3-10 22.3-22.3c0-6.2-2.6-12.1-7.2-16.4l-91-84c-3.8-3.5-8.7-5.4-13.9-5.4s-10.1 1.9-13.9 5.4l-91 84z"/></svg>

After

Width:  |  Height:  |  Size: 428 B

View File

@ -0,0 +1 @@
<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M406.5 399.6c-19.1-46.7-65-79.6-118.5-79.6h-64c-53.5 0-99.4 32.9-118.5 79.6C69.9 362.2 48 311.7 48 256c0-114.9 93.1-208 208-208s208 93.1 208 208c0 55.7-21.9 106.2-57.5 143.6m-40.1 32.7c-32 20.1-69.8 31.7-110.4 31.7s-78.4-11.6-110.5-31.7c7.3-36.7 39.7-64.3 78.5-64.3h64c38.8 0 71.2 27.6 78.5 64.3zM256 512a256 256 0 1 0 0-512a256 256 0 1 0 0 512m0-272a40 40 0 1 1 0-80a40 40 0 1 1 0 80m-88-40a88 88 0 1 0 176 0a88 88 0 1 0-176 0"/></svg>

After

Width:  |  Height:  |  Size: 528 B

View File

@ -0,0 +1 @@
<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M288 80c-65.2 0-118.8 29.6-159.9 67.7C89.6 183.5 63 226 49.4 256C63 286 89.6 328.5 128 364.3c41.2 38.1 94.8 67.7 160 67.7s118.8-29.6 159.9-67.7C486.4 328.5 513 286 526.6 256c-13.6-30-40.2-72.5-78.6-108.3C406.8 109.6 353.2 80 288 80M95.4 112.6C142.5 68.8 207.2 32 288 32s145.5 36.8 192.6 80.6c46.8 43.5 78.1 95.4 93 131.1c3.3 7.9 3.3 16.7 0 24.6c-14.9 35.7-46.2 87.7-93 131.1C433.5 443.2 368.8 480 288 480s-145.5-36.8-192.6-80.6C48.6 356 17.3 304 2.5 268.3c-3.3-7.9-3.3-16.7 0-24.6C17.3 208 48.6 156 95.4 112.6M288 336c44.2 0 80-35.8 80-80s-35.8-80-80-80h-2c1.3 5.1 2 10.5 2 16c0 35.3-28.7 64-64 64c-5.5 0-10.9-.7-16-2v2c0 44.2 35.8 80 80 80m0-208a128 128 0 1 1 0 256a128 128 0 1 1 0-256"/></svg>

After

Width:  |  Height:  |  Size: 787 B

View File

@ -1,3 +1,13 @@
/*variable*/
:root{
--primary-blue-light : #086572;
--primary-blue-dark : #094754;
--black-font: #1D1E1C;
--delete : #E42E31;
--disable : #A3A3A3;
--check : #80F20E;
}
html {
margin: 0;
padding: 0;
@ -77,4 +87,30 @@ body {
font-family: "Nunito", sans-serif;
font-weight: 400;
border-top: 1px solid rgba(0, 0, 0, 0.06);
}
.btn-primary{
background: var(--primary-blue-light);
color : #FFFFFF;
border: var(--primary-blue-dark);
border-radius: 1rem;
}
.btn-primary:hover{
background: var(--primary-blue-dark);
color : #FFFFFF;
border: var(--primary-blue-light);
}
.btn-danger{
background: var(--delete);
color : #FFFFFF;
border: var(--delete);
border-radius: 1rem;
}
.color-primary{
color: var(--primary-blue-light);
}
.color-primary-dark{
color: var(--primary-blue-dark);
}

110
composer.lock generated
View File

@ -154,99 +154,6 @@
},
"time": "2023-06-19T06:10:36+00:00"
},
{
"name": "doctrine/cache",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "1ca8f21980e770095a31456042471a57bc4c68fb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb",
"reference": "1ca8f21980e770095a31456042471a57bc4c68fb",
"shasum": ""
},
"require": {
"php": "~7.1 || ^8.0"
},
"conflict": {
"doctrine/common": ">2.2,<2.4"
},
"require-dev": {
"cache/integration-tests": "dev-master",
"doctrine/coding-standard": "^9",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"psr/cache": "^1.0 || ^2.0 || ^3.0",
"symfony/cache": "^4.4 || ^5.4 || ^6",
"symfony/var-exporter": "^4.4 || ^5.4 || ^6"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.",
"homepage": "https://www.doctrine-project.org/projects/cache.html",
"keywords": [
"abstraction",
"apcu",
"cache",
"caching",
"couchdb",
"memcached",
"php",
"redis",
"xcache"
],
"support": {
"issues": "https://github.com/doctrine/cache/issues",
"source": "https://github.com/doctrine/cache/tree/2.2.0"
},
"funding": [
{
"url": "https://www.doctrine-project.org/sponsorship.html",
"type": "custom"
},
{
"url": "https://www.patreon.com/phpdoctrine",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache",
"type": "tidelift"
}
],
"time": "2022-05-20T20:07:39+00:00"
},
{
"name": "doctrine/collections",
"version": "2.3.0",
@ -335,28 +242,31 @@
},
{
"name": "doctrine/dbal",
"version": "3.9.5",
"version": "3.10.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "4a4e2eed3134036ee36a147ee0dac037dfa17868"
"reference": "1cf840d696373ea0d58ad0a8875c0fadcfc67214"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/4a4e2eed3134036ee36a147ee0dac037dfa17868",
"reference": "4a4e2eed3134036ee36a147ee0dac037dfa17868",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/1cf840d696373ea0d58ad0a8875c0fadcfc67214",
"reference": "1cf840d696373ea0d58ad0a8875c0fadcfc67214",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2",
"doctrine/cache": "^1.11|^2.0",
"doctrine/deprecations": "^0.5.3|^1",
"doctrine/event-manager": "^1|^2",
"php": "^7.4 || ^8.0",
"psr/cache": "^1|^2|^3",
"psr/log": "^1|^2|^3"
},
"conflict": {
"doctrine/cache": "< 1.11"
},
"require-dev": {
"doctrine/cache": "^1.11|^2.0",
"doctrine/coding-standard": "13.0.0",
"fig/log-test": "^1",
"jetbrains/phpstorm-stubs": "2023.1",
@ -426,7 +336,7 @@
],
"support": {
"issues": "https://github.com/doctrine/dbal/issues",
"source": "https://github.com/doctrine/dbal/tree/3.9.5"
"source": "https://github.com/doctrine/dbal/tree/3.10.0"
},
"funding": [
{
@ -442,7 +352,7 @@
"type": "tidelift"
}
],
"time": "2025-06-15T22:40:05+00:00"
"time": "2025-07-10T21:11:04+00:00"
},
{
"name": "doctrine/deprecations",

View File

@ -11,8 +11,10 @@ security:
property: email
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
ROLE_SUDALYS: ROLE_USER
ROLE_ADMIN: ROLE_USER
ROLE_SUDALYS_ADMIN: [ROLE_SUDALYS, ROLE_ALLOWED_TO_SWITCH, ROLE_ADMIN]
firewalls:
dev:

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250716130850 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace App\Controller;
use App\Entity\User;
use App\Entity\UsersOrganizations;
use App\Service\UserOrganizationService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
#[Route(path: '/user', name: 'user_')]
class UserController extends AbstractController
{
public function __construct(private readonly UserOrganizationService $userOrganizationService)
{
}
#[Route('/dashboard', name: 'dashboard')]
public function index(EntityManagerInterface $entityManager): Response
{
if ($this->isGranted('ROLE_SUDALYS_ADMIN')) {
$users = $entityManager->getRepository(User::class)->getAllActiveUsers();
} else {
$users = 'Not Super Admin';
}
return $this->render('user/index.html.twig', [
'users' => $users,
'controller_name' => 'IndexController',
]);
}
#[Route('/{id}', name: 'view')]
public function userProfile(Request $request, EntityManagerInterface $entityManager): Response
{
if ($this->isGranted('ROLE_SUDALYS_ADMIN')) {
$userId = $request->attributes->get('id');
$user = $entityManager->getRepository(User::class)->find($userId);
$userOrganizations = $this->userOrganizationService->getUserOrganizations($user);
}
return $this->render('user/profile.html.twig', [
'user' => $user,
'userOrganizations' => $userOrganizations,
]);
}
}

View File

@ -33,28 +33,13 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader
$this->getEntityManager()->flush();
}
// /**
// * @return User[] Returns an array of User objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('u')
// ->andWhere('u.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('u.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?User
// {
// return $this->createQueryBuilder('u')
// ->andWhere('u.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
public function getAllActiveUsers(): array{
$queryBuilder = $this->createQueryBuilder('u')
->select('u.surname', 'u.email', 'u.id', 'u.isActive', 'u.name', 'u.pictureUrl')
// Remove this line: ->from(User::class, 'u')
->where('u.isActive = :isActive') // Also fixed the concatenation
->orderBy('u.surname', 'ASC');
$queryBuilder->setParameter('isActive', true);
return $queryBuilder->getQuery()->getResult();
}
}

View File

@ -6,9 +6,7 @@ use App\Entity\UsersOrganizations;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<UsersOrganizations>
*/
class UsersOrganizationsRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
@ -16,28 +14,18 @@ class UsersOrganizationsRepository extends ServiceEntityRepository
parent::__construct($registry, UsersOrganizations::class);
}
// /**
// * @return UsersOrganizations[] Returns an array of UsersOrganizations objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('u')
// ->andWhere('u.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('u.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
public function findAllDistinctOrganizationsByUserId(int $userId): array
{
return $this->createQueryBuilder('uo')
->select('DISTINCT uo')
->leftJoin('uo.organization', 'o')
->leftJoin('uo.role', 'r')
->addSelect('o', 'r')
->where('uo.users = :userId', 'uo.isActive = :isActive')
->setParameter('userId', $userId)
->setParameter('isActive', true)
->getQuery()
->getResult();
}
// public function findOneBySomeField($value): ?UsersOrganizations
// {
// return $this->createQueryBuilder('u')
// ->andWhere('u.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@ -0,0 +1,103 @@
<?php
namespace App\Service;
use App\Entity\Roles;
use App\Entity\User;
use App\Entity\UsersOrganizations;
use Doctrine\ORM\EntityManagerInterface;
readonly class UserOrganizationService
{
public function __construct(private readonly EntityManagerInterface $entityManager) {}
/**
* Returns all organizations the given user belongs to,
* including the unique roles and apps the user has in each organization.
*
* @param User $user The user whose organizations are being fetched
* @return array<array{organization:object, roles:Roles[], apps:object[]}>
*/
public function getUserOrganizations(User $user): array
{
$userOrganizations = $this->entityManager
->getRepository(UsersOrganizations::class)
->findAllDistinctOrganizationsByUserId($user->getId());
$organizations = [];
foreach ($userOrganizations as $uo) {
$orgId = $uo->getOrganization()->getId();
// Initialize the organization entry if it doesn't exist
$organizations[$orgId] = $organizations[$orgId] ?? $this->createEmptyOrganizationBucket($uo);
// Aggregate roles & apps
$this->addRole($organizations[$orgId]['roles'], $uo->getRole());
$this->addApps($organizations[$orgId]['apps'], $uo->getApps());
}
$this->normalizeAppsIndexes($organizations);
return array_values($organizations);
}
/**
* Build the initial array structure for a fresh organization entry.
*
* @param UsersOrganizations $link
* @return array{organization:object, roles:Roles[], apps:array<int,object>}
*/
private function createEmptyOrganizationBucket(UsersOrganizations $link): array
{
return [
'organization' => $link->getOrganization(),
'roles' => [],
'apps' => [],
];
}
/**
* Add a Role entity to the roles array only if it is not already present (by ID).
*
* @param Roles[] &$roles
* @param Roles|null $role
*/
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;
}
/**
* Merge one or many apps into the apps map, keeping only one entry per id.
*
* @param array<int,object> &$apps
* @param iterable $appsToAdd Collection returned by $userOrganizations->getApps()
*/
private function addApps(array &$apps, iterable $appsToAdd): void
{
foreach ($appsToAdd as $app) {
$apps[$app->getId()] = $apps[$app->getId()] ?? $app;
}
}
/**
* Convert apps from associative maps (keyed by id) to plain indexed arrays,
* so the final output is clean JSON-able.
*
* @param array &$organizations
*/
private function normalizeAppsIndexes(array &$organizations): void
{
foreach ($organizations as &$org) {
$org['apps'] = array_values($org['apps']);
}
}
}

View File

@ -22,11 +22,14 @@
</ul>
</div>
</li>
{# if user is Super Admin#}
{% if is_granted('ROLE_SUDALYS_ADMIN') %}
<li class="nav-item">
<a class="nav-link" href="#">
<a class="nav-link" href="{{ path('user_dashboard') }}">
<i class="icon-grid menu-icon">{{ ux_icon('bi:menu-up', {height: '15px', width: '15px'}) }}</i>
<span class="menu-title">Menu 2</span>
<span class="menu-title">Users</span>
</a>
</li>
{% endif %}
</ul>
</nav>

View File

@ -0,0 +1,15 @@
{% block body %}
<div class="card">
<div class="card-title shadow-sm p-3">
<h2>{{ user.surname|capitalize }} {{ user.name|capitalize }}</h2>
</div>
<div class="card-body">
<p> <b>Email: </b>{{ user.email }}</p>
<p><b>Dernière connection: </b>{{ user.lastConnection|date('d/m/Y') }} à {{ user.lastConnection|date('H:m:s') }} </p>
<p><b>Compte crée le: </b>{{ user.createdAt|date('d/m/Y') }}</p>
<p><b>Numéro de téléphone: </b>{{ user.phoneNumber ? user.phoneNumber : 'Non renseigné' }}</p>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,85 @@
{% block body %}
<div class="card col-4 mt-3 me-3 user-org-card" style="cursor:pointer;" data-bs-toggle="collapse"
data-bs-target="#org-details-{{ organization.id }}" aria-expanded="false"
aria-controls="org-details-{{ organization.id }}">
<div class="card-title shadow-sm p-3 d-flex ">
<h2 class=" pe-2">{{ organization.name|capitalize }}</h2>
<i class="pt-2" id="arrow-icon-{{ organization.id }}">
{{ ux_icon('fa6-regular:circle-down', {height: '25px', width: '25px'}) }}
</i>
</div>
{# Information principale sur l'utilisateur dans l'organisation#}
<div class="card-body">
{# Affichage du plus haut role #}
<p><b>Role:</b>
{% if roles|length > 0 %}
{% set firstRole = roles[0] %}
{% if firstRole.name == "ROLE ADMIN SUDALYS" or firstRole.name == "ROLE ADMIN" %}
<span class="badge bg-danger">{{ firstRole.name|capitalize }}</span>
{% elseif firstRole.name == "ROLE USER" %}
<span class="badge bg-primary">{{ firstRole.name|capitalize }}</span>
{% else %}
<span class="badge bg-success">{{ firstRole.name|capitalize }}</span>
{% endif %}
{% else %}
Aucun rôle
{% endif %}
</p>
{# Affichage des applications dont l'utilisateur à accès #}
<div class="d-flex">
{% if apps is not empty %}
{% for app in apps %}
<div class="col">
{{ app.name }}
<img src="{{ asset(app.logoUrl) }}" alt="Logo {{ app.name }}" class="img-fluid ms-2" style="height: 20px; width: 20px;">
</div>
{% endfor %}
{% else %}
Aucune application associée.
{% endif %}
</div>
</div>
{# Détails supplémentaires sur l'organisation #}
<div class="collapse card-body border-top" id="org-details-{{ organization.id }}">
{% if roles|length > 1 %}
<p><b>Autres rôles:</b>
{% for role in roles|slice(1) %}
{% if role.name == "ROLE ADMIN SUDALYS" or role.name == "ROLE ADMIN" %}
<span class="badge bg-danger">{{ role.name|capitalize }}</span>
{% elseif role.name == "ROLE USER" %}
<span class="badge bg-primary">{{ role.name|capitalize }}</span>
{% else %}
<span class="badge bg-success">{{ role.name|capitalize }}</span>
{% endif %}
{% if not loop.last %} - {% endif %}
{% endfor %}
</p>
{% endif %}
<p><b>Membre depuis:</b> {{ organization.createdAt|date('d/m/Y') }}</p>
</div>
</div>
{% endblock %}
{% block javascript %}
<script>
document.addEventListener('DOMContentLoaded', function() {
var collapseEl = document.getElementById('org-details-{{ organization.id }}');
var arrowEl = document.getElementById('arrow-icon-{{ organization.id }}');
if (collapseEl && arrowEl) {
collapseEl.addEventListener('show.bs.collapse', function () {
arrowEl.innerHTML = `{{ ux_icon('fa6-regular:circle-up', {height: '25px', width: '25px'})|e('js') }}`;
});
collapseEl.addEventListener('hide.bs.collapse', function () {
arrowEl.innerHTML = `{{ ux_icon('fa6-regular:circle-down', {height: '25px', width: '25px'})|e('js') }}`;
});
}
});
</script>
{% endblock %}

View File

@ -0,0 +1,48 @@
{% extends 'base.html.twig' %}
{% block title %}User Profile{% endblock %}
{% block body %}
<div class="w-100 h-100 p-5 m-auto ">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>Gestion Utilisateurs</h1>
<a href="#" class="btn btn-primary">Ajouter un utilisateur</a>
</div>
<table class="table align-middle shadow">
<thead class="table-light shadow-sm">
<tr>
<th>Picture</th>
<th>Surname</th>
<th>Name</th>
<th>Email</th>
<th>Visualiser</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td></td>
<td>{{ user.surname }}</td>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
<td>
<a href="{{ path('user_view', {'id': user.id}) }}" class="p-3 align-middle">
<i class="icon-grid menu-icon color-primary">
{{ ux_icon('fa6-regular:eye', {height: '30px', width: '30px'}) }}
</a>
</td>
</tr>
{% endfor %}
{% if users|length == 0 %}
<tr>
<td colspan="5" class="text-center">Aucun utilisateur trouvé.</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends 'base.html.twig' %}
{% block body %}
<div class="col-md-10 m-auto p-5">
<div class="col d-flex justify-content-between align-items-center ">
<h1 class="mb-4">Gestion Utilisateur</h1>
<a href="#" class="btn btn-danger">Désactiver</a>
</div>
{% include 'elements/userInformation.html.twig' %}
<h1 class="mt-5 mb-4">Organisations</h1>
<div class="row">
{% if userOrganizations is empty %}
<div class="col-md-10 m-auto p-auto">
<h3>Aucune organisation associée à cet utilisateur.</h3>
</div>
{% else %}
{% for organization in userOrganizations %}
{% include 'elements/userOrganizationInformation.html.twig'
with {'organization': organization.organization, 'roles': organization.roles, 'apps': organization.apps} %}
{% endfor %}
{% endif %}
</div>
</div>
{% endblock %}
{% block title %}
{% endblock %}