From f0be849a2c8c956fad97319019ee4bb3e86983ef Mon Sep 17 00:00:00 2001
From: pfleu <pierre.fleutot@audemarspiguet.com>
Date: Mon, 2 Dec 2024 11:34:31 +0100
Subject: [PATCH] =?UTF-8?q?Ajout=20formulaire=20User=20pour=20modifier=20l?=
 =?UTF-8?q?e=20r=C3=B4le=20et=20le=20pseudo?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 config/packages/security.yaml        |   2 +-
 src/Controller/AppUserController.php |  27 +++++++
 src/Entity/User.php                  |  11 +++
 src/Form/UserType.php                | 115 +++++++++++++++++++++++++++
 templates/user/index.html.twig       |   6 +-
 5 files changed, 159 insertions(+), 2 deletions(-)
 create mode 100644 src/Form/UserType.php

diff --git a/config/packages/security.yaml b/config/packages/security.yaml
index a7a4e9c..fb717d5 100644
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -26,7 +26,7 @@ security:
         api_token:
             pattern: ^/api/token$
             security: false
-        api:
+        api: # Pour permettre à l'utilisateur connecté sur Balex (avec rôle admin) d'utiliser le swagger sans token, on commente tout le pare-feu "api"
             pattern: ^/api(?!/doc$) # Accepts routes under /api except /api/doc (pour api/doc, on utilisera donc le firewall "main" ce qui permettra d'accéder au swagger quand on est authentifié via Session PHP avec le role Admin
             security: true
             stateless: true # Pas d'authentification, pas de session utilisateur (mais le compte user est vérifié via le token)
diff --git a/src/Controller/AppUserController.php b/src/Controller/AppUserController.php
index c0a4336..53785dd 100644
--- a/src/Controller/AppUserController.php
+++ b/src/Controller/AppUserController.php
@@ -6,6 +6,7 @@ use App\Entity\Entry;
 use App\Entity\User;
 use App\Form\UserAddFriendType;
 use App\Form\UserProfileFormType;
+use App\Form\UserType;
 use App\Repository\UserRepository;
 use Doctrine\Persistence\ManagerRegistry;
 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@@ -87,6 +88,32 @@ class AppUserController extends AbstractController
         ]);
     }
 
+    /**
+     * @Route("/{id}/edit", name="user_edit", methods={"GET","POST"})
+     * @IsGranted("ROLE_ADMIN")
+     */
+    public function edit(Request $request, User $appUser): Response
+    {
+        $form = $this->createForm(UserType::class, $appUser, [
+            'action' => $this->generateUrl('user_edit', ['id' => $appUser->getId()])
+        ]);
+        $form->handleRequest($request);
+
+        if ($form->isSubmitted() && $form->isValid()) {
+
+            $this->doctrine->getManager()->flush();
+            $this->addFlash('success',$this->translator->trans("L'utilisateur a été modifié."));
+
+            return $this->render('closeModalAndReload.html.twig');
+        }
+
+        return $this->render('genericModalForm.html.twig', [
+            'title' => $this->translator->trans("Modifier l'utilisateur") . ': ' . $appUser,
+            'user' => $appUser,
+            'form' => $form->createView(),
+        ]);
+    }
+
     /**
      * @Route("/{id}/edit-activation", name="app_user_toggle_activation")
      */
diff --git a/src/Entity/User.php b/src/Entity/User.php
index 3953b6f..128c399 100644
--- a/src/Entity/User.php
+++ b/src/Entity/User.php
@@ -35,6 +35,12 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
         'C2' => 'C2',
     ];
 
+    const EDIT_ROLES = [
+        'ROLE_USER'         => 'Student',
+        'ROLE_TEACHER'      => 'Teacher',
+        'ROLE_ADMIN'        => 'Admin',
+    ];
+
     const ROLES = [
         'ROLE_USER'         => 'Student',
         'ROLE_TEACHER'      => 'Teacher',
@@ -395,12 +401,17 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
         $this->successes->add($success);
     }
 
+    // Si on a que le ROLE_USER (student), on le retourne, sinon on le supprime de la liste (car on ne peut avoir qu'un rôle à la fois et on veut afficher le plus haut)
     public function getFormattedRoles()
     {
         $result = [];
         foreach ($this->getRoles() as $role) {
             $result[] = self::ROLES[$role];
         }
+        if (count($result) > 1) {
+            $result = array_diff($result, [self::ROLES['ROLE_USER']]);
+        }
+
         return $result;
     }
 
diff --git a/src/Form/UserType.php b/src/Form/UserType.php
new file mode 100644
index 0000000..ce31d1c
--- /dev/null
+++ b/src/Form/UserType.php
@@ -0,0 +1,115 @@
+<?php
+
+namespace App\Form;
+
+use App\Entity\Company;
+use App\Entity\Department;
+use App\Entity\Project;
+use Doctrine\ORM\EntityRepository;
+use Symfony\Component\Form\CallbackTransformer;
+use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
+use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
+use Symfony\Component\Security\Core\Security;
+use Symfony\Component\Validator\Constraints\Email;
+use Symfony\Component\Validator\Constraints\NotBlank;
+use App\Entity\User;
+use Symfony\Bridge\Doctrine\Form\Type\EntityType;
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
+use Symfony\Component\Form\Extension\Core\Type\PasswordType;
+use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\Form\FormError;
+use Symfony\Component\Form\FormEvent;
+use Symfony\Component\Form\FormEvents;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+
+class UserType extends AbstractType
+{
+    private $security;
+
+    public function __construct(Security $security)
+    {
+        $this->security = $security;
+    }
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $stringToArrayTransformer = new CallbackTransformer(
+            function ($listAsArray) {
+                // transform the array to a string
+
+                // On supprime le ROLE_USER
+                $filtered = [];
+                foreach ($listAsArray as $item) {
+                    if ($item != "ROLE_USER" && $item != "ROLE_SUPER_ADMIN") {
+                        $filtered[] = $item;
+                    }
+                }
+
+                if ($filtered) {
+                    return implode("\r\n", $filtered);
+                } else {
+                    return '';
+                }
+            },
+            function ($listAsString) {
+                // transform the string back to an array
+                if (empty($listAsString)) {
+                    return array();
+                } else {
+                    $resultArray = explode("\r\n", $listAsString);
+                    return array_filter($resultArray, function($value) { return $value !== ''; });
+                }
+            }
+        );
+
+
+        $rolesChoices = array_flip(User::EDIT_ROLES);
+
+        $user = $builder->getData();
+
+        $builder
+            ->add('pseudo', null, ['label' => "Pseudo"])
+            ;
+
+        if ($user !== $this->security->getUser()) {
+            $builder
+                ->add('roles', ChoiceType::class, [
+                    'label' => 'Rôle',
+                    'choices' => $rolesChoices,
+                    'constraints' => [new NotBlank(['message' => 'Veuillez indiquer un rôle.'])]
+                ]);
+            $builder->get('roles')->addModelTransformer($stringToArrayTransformer);
+        }
+
+        $builder
+            ->add('submit', SubmitType::class, array(
+                'label' => 'Enregistrer',
+                'attr' => ['class' => 'btn-primary']
+            ))
+        ;
+
+//        if ($this->security->isGranted('CAN_EDIT_ROLES_USER', $builder->getData())) {
+//            $builder
+//                ->add('disabled', null, ['label' => "Désactiver l'utilisateur"]);
+//        }
+
+
+
+//        $builder->get('languages')->addModelTransformer($stringToArrayTransformer);
+    }
+
+    public function configureOptions(OptionsResolver $resolver)
+    {
+        $resolver->setDefaults([
+            'data_class' => User::class,
+            'attr' => [
+                'data-ajax-form' => '',
+                'data-ajax-form-target' => '#bootstrap-modal .modal-content',
+                'novalidate' => 'novalidate',
+            ],
+        ]);
+    }
+}
diff --git a/templates/user/index.html.twig b/templates/user/index.html.twig
index ad7a5ac..adfd5c1 100644
--- a/templates/user/index.html.twig
+++ b/templates/user/index.html.twig
@@ -1,6 +1,7 @@
 {% extends 'base.html.twig' %}
 
 {% block title %}{{ "Utilisateurs"|trans }}{% endblock %}
+{% block container %}container-fluid {% endblock %}
 
 {% block body %}
 
@@ -17,6 +18,7 @@
                             <tr>
                                 <th>Pseudo</th>
                                 <th>Email</th>
+                                <th>Rôle</th>
                                 <th>Gamification</th>
                                 <th>{{ "Stats persos"|trans }}</th>
                                 <th>{{"Partage données"|trans}}<br>{{ "autres utilisateurs"|trans }}</th>
@@ -33,6 +35,7 @@
                                 <tr class="{{ not user.enabled ? 'text-muted fst-italic' }}">
                                     <td>{{ user.pseudo }}</td>
                                     <td>{{ user.email }}</td>
+                                    <td>{{ user.formattedRoles|join(', ') }}</td>
                                     <td>{{ user.activeGamification  ? '<i class="bi bi-check text-success"></i>' : '<i class="bi bi-x text-danger"></i>' }}</td>
                                     <td>{{ user.activePersonalStats  ? '<i class="bi bi-check text-success"></i>' : '<i class="bi bi-x text-danger"></i>' }}</td>
                                     <td>{{ user.shareDataWithOtherUsers  ? '<i class="bi bi-check text-success"></i>' : '<i class="bi bi-x text-danger"></i>' }}</td>
@@ -47,7 +50,8 @@
                                             <a href="{{ path('app_user_toggle_activation', {'id': user.id}) }}" class="btn btn-secondary btn-xs">{{ "Activer"|trans }}</a>
                                         {% endif %}
                                     </td>
-                                    <td>
+                                    <td class="text-nowrap">
+                                        <a href="#" data-url="{{ path('user_edit', {'id': user.id}) }}" class="btn btn-secondary btn-xs modal-form"><i class="fa fa-pencil"></i></a>
                                         <a data-confirm="{{ "Confirmer la suppression ?"|trans }}" data-bs-toggle="modal" data-bs-target="#confirm-dialog"
                                            data-href="{{ path('app_user_delete', {id: user.id}) }}" class="btn btn-xs btn-danger"><i class="bi-x-circle"></i></a>
                                     </td>
-- 
GitLab