/!\A REGLER : Impossible de charger le form pour Update un User dans la section Compte/!\

ajout des Roles + access denied, remplacement du Modal Compte par une vu et un controlleur appeler en AJAX directement dans Index, mise en place du Update pour les utilisateurs, optimisation de certaine partis
This commit is contained in:
bethoulevj 2024-11-07 19:01:46 +01:00
parent b98318b79f
commit eaeabed512
11 changed files with 684 additions and 427 deletions

814
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -29,10 +29,14 @@ security:
role_hierarchy:
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
access_control: access_control:
# - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } # - { path: ^/, roles: ROLE_USER }
- { path: ^/login, roles: PUBLIC_ACCESS }
- { path: ^/logout, roles: ROLE_USER } - { path: ^/logout, roles: ROLE_USER }
- { path: ^/index, roles: ROLE_USER } - { path: ^/index, roles: ROLE_ADMIN }
- { path: ^/user, roles: ROLE_ADMIN } - { path: ^/user, roles: ROLE_ADMIN }
#when@test: #when@test:

View File

@ -1,18 +0,0 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class AccesDeniedController extends AbstractController
{
#[Route('/acces/denied', name: 'app_acces_denied')]
public function index(): Response
{
return $this->render('acces_denied/index.html.twig', [
'controller_name' => 'AccesDeniedController',
]);
}
}

View File

@ -28,4 +28,11 @@ class LoginController extends AbstractController
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.'); throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
} }
#[Route('/access/denied', name: 'app_access_denied')]
public function denied(): Response
{
return $this->render('access_denied/index.html.twig', [
'controller_name' => 'AccessDeniedController',
]);
}
} }

View File

@ -3,6 +3,7 @@
namespace App\Controller; namespace App\Controller;
use App\Entity\Utilisateurs; use App\Entity\Utilisateurs;
use App\Form\UpdateUserType;
use App\Repository\UtilisateursRepository; use App\Repository\UtilisateursRepository;
use App\Form\AddUserFormType; use App\Form\AddUserFormType;
use App\Security\LoginAuthenticator; use App\Security\LoginAuthenticator;
@ -48,6 +49,32 @@ class UserController extends AbstractController
]); ]);
} }
#[Route('/user/update/{id}', name: 'update-user')]
public function update(Request $request, UserPasswordHasherInterface $userPasswordHasher, Security $security, EntityManagerInterface $entityManager, int $id): Response
{
$user = $this->utilisateursRepository->find($id);
$form = $this->createForm(UpdateUserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var string $plainPassword */
$plainPassword = $form->get('Password')->getData();
// encode the plain password
$user->setPassword($userPasswordHasher->hashPassword($user, $plainPassword));
$entityManager->persist($user);
$entityManager->flush();
return $this->redirectToRoute('app_index');
}
return $this->render('gestion_user/index.html.twig', [
'form' => $form,
]);
}
#[Route('/user/list', name: 'list_user')] #[Route('/user/list', name: 'list_user')]
public function list(): Response public function list(): Response
{ {
@ -57,4 +84,10 @@ class UserController extends AbstractController
'utilisateurs' => $utilisateur 'utilisateurs' => $utilisateur
]); ]);
} }
#[Route('/gestion-user', name: 'gestion_user', methods: ['GET'])]
public function index(): Response
{
return $this->render('gestion_user/index.html.twig');
}
} }

View File

@ -0,0 +1,57 @@
<?php
namespace App\Form;
use App\Entity\Reservations;
use App\Entity\Tables;
use App\Entity\Utilisateurs;
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\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
class UpdateUserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('UserIdentifier', EmailType::class, )
->add('Password', PasswordType::class, [
// instead of being set onto the object directly,
// this is read and encoded in the controller
'mapped' => false,
'attr' => ['autocomplete' => 'new-password'],
'constraints' => [
new NotBlank([
'message' => 'Entrer un mot de passe',
]),
],
])
->add('Nom')
->add('Prenom')
->add('Roles', ChoiceType::class, [
'choices' => [
'Admin' => 'ROLE_ADMIN',
'User' => 'ROLE_USER',
],
'expanded' => true,
'multiple' => true,
'data' => $options['data']->getRoles(),
])
->add('Modifier', SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Utilisateurs::class,
]);
}
}

View File

@ -56,7 +56,7 @@ class LoginAuthenticator extends AbstractLoginFormAuthenticator
public function start(Request $request, ?AuthenticationException $authException = null): RedirectResponse public function start(Request $request, ?AuthenticationException $authException = null): RedirectResponse
{ {
return new RedirectResponse($this->urlGenerator->generate('app_acces_denied')); return new RedirectResponse($this->urlGenerator->generate('app_access_denied'));
} }
protected function getLoginUrl(Request $request): string protected function getLoginUrl(Request $request): string

View File

@ -7,6 +7,9 @@
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Qwitcher+Grypen:wght@400;700&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Qwitcher+Grypen:wght@400;700&display=swap" rel="stylesheet">
{# bootstrap#}
{# <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">#}
{% block stylesheets %} {% block stylesheets %}
{% endblock %} {% endblock %}
@ -16,5 +19,8 @@
</head> </head>
<body> <body>
{% block body %}{% endblock %} {% block body %}{% endblock %}
{# bootstrap#}
{# <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>#}
{# <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script> </body>#}
</body> </body>
</html> </html>

View File

@ -0,0 +1,113 @@
{% extends 'base.html.twig' %}
{% block title %}Gestion User{% endblock %}
{% block body %}
<style>
body {
width: 100%;
height: 100%;
}
/* Style pour chaque élément d'information de l'utilisateur */
.user-info-item {
display: flex;
padding: 10px 0;
border-bottom: 1px solid #e0e0e0;
}
/* Dernier élément sans bordure */
.user-info-item:last-child {
border-bottom: none;
}
/* Style pour le label de chaque information (Nom, Prénom, etc.) */
.user-info-label {
font-weight: bold;
color: #333;
width: 7%;
}
/* Style pour la valeur de chaque information (la donnée de l'utilisateur) */
.user-info-value {
color: #555;
text-align: left;
width: 65%;
word-wrap: break-word; /* Gère les débordements */
}
.password {
display: flex;
flex-direction: column;
width: 100%;
text-align: left;
}
/* Ajout d'un style pour rendre responsive */
@media (max-width: 600px) {
#InformationUser {
padding: 15px;
}
.user-info-item {
flex-direction: column;
padding: 8px 0;
}
.user-info-label, .user-info-value {
width: 100%;
}
}
</style>
<p>Test</p>
{# {{ form_start(form) }}#}
{# <div> #}
{# {{ form_row(form.UserIdentifier) }}#}
{# {{ form_row(form.Password) }}#}
{# {{ form_row(form.Nom) }}#}
{# {{ form_row(form.Prenom) }}#}
{# {{ form_row(form.Roles) }}#}
{# </div>#}
{# {{ form_end(form) }}#}
{# <form id="UpdateUser" action="{{ path('update-user', { 'id': app.user.id }) }}" method="post">#}
{# <div id="InformationUser">#}
{# <div class="user-info-item">#}
{# <span class="user-info-label">Nom :</span>#}
{# <span class="user-info-value">{{ app.user.nom }}</span>#}
{# <input type="text" id="nom" name="nom" value="{{ app.user.nom }}" class="user-info-input">#}
{# </div>#}
{# <div class="user-info-item">#}
{# <span class="user-info-label">Prénom :</span>#}
{# <span class="user-info-value">{{ app.user.prenom }}</span>#}
{# <input type="text" id="prenom" name="prenom" value="{{ app.user.prenom }}" class="user-info-input">#}
{# </div>#}
{# <div class="user-info-item">#}
{# <span class="user-info-label">Email :</span>#}
{# <span class="user-info-value">{{ app.user.userIdentifier }}</span>#}
{# <input type="text" id="email" name="email" value="{{ app.user.userIdentifier }}" class="user-info-input">#}
{# </div>#}
{# <div class="user-info-item">#}
{# <div id="passwordConfirmDiv" class="password-confirm-div">#}
{# <label for="confirm_password" class="user-info-label">Confirmer ou modifier le mot de passe :</label>#}
{# <input type="password" id="confirm_password" name="confirm_password" class="user-info-input" placeholder="Mot de passe">#}
{# </div>#}
{# </div>#}
{# <div class="user-info-item">#}
{# <span class="user-info-label">Roles :</span>#}
{# <span class="user-info-value">{{ app.user.getRolesAsString() }}</span>#}
{# <input type="checkbox" id="roles" name="roles" value="{{ app.user.getRolesAsString() }}" class="user-info-input" readonly>#}
{# </div>#}
{# <div class="btn">#}
{# <button type="submit" class="submit-button">Mettre à jour</button>#}
{# </div>#}
{# </div>#}
{# </form>#}
{% endblock %}

View File

@ -14,7 +14,19 @@
{% endblock %} {% endblock %}
{% block body %} {% block body %}
<style></style> <style>
#container_gestion_user {
background-color: white;
margin-left: 20%; /* Centrage vertical */
margin-top: 5%;
padding: 20px;
border: 1px solid black;
width: 75%; /* Largeur du contenu de la modal */
height: 100%; /* Hauteur du contenu de la modal */
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2);
display: none;
}
</style>
<!-- Top Bar --> <!-- Top Bar -->
<div class="top-bar"> <div class="top-bar">
@ -64,11 +76,10 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="Information-perso"> <div class="Information-perso">
<div class="btn-info-compte icon-container"> <div class="btn-info-compte icon-container">
<i class="icon-medium"> {{ ux_icon('ph:user-circle-fill') }}</i> <i class="icon-medium"> {{ ux_icon('ph:user-circle-fill') }}</i>
<span data-modal="compteModal">Compte</span> <span>Compte</span>
</div> </div>
<div class="btn-info-exit icon-container"> <div class="btn-info-exit icon-container">
<a href="{{ path('app_logout') }}" class="icon-medium"> <a href="{{ path('app_logout') }}" class="icon-medium">
@ -78,6 +89,42 @@
</div> </div>
</div> </div>
<div id="container_gestion_user">
<!-- Contenu par défaut, ou vous pouvez laisser vide -->
</div>
<script>
document.querySelector('.btn-info-compte').addEventListener('click', function(event) {
event.preventDefault();
const contentContainer = document.getElementById('container-gestion-user');
// Vérifie si le contenu est déjà affiché
if (container_gestion_user.style.display === 'block') {
// Masquer la section "Compte" si elle est déjà affichée
container_gestion_user.style.display = 'none';
container_gestion_user.innerHTML = ''; // On efface le contenu pour éviter la réutilisation
} else {
// Afficher le conteneur et charger le contenu via AJAX
fetch('/gestion-user')
.then(response => {
if (!response.ok) {
throw new Error('Erreur de chargement de la section Compte');
}
return response.text();
})
.then(html => {
// Insérer le HTML dans le conteneur et l'afficher
container_gestion_user.innerHTML = html;
container_gestion_user.style.display = 'block';
})
.catch(error => {
console.error('Erreur:', error);
});
}
});
</script>
<!-- Include modals --> <!-- Include modals -->
{% include 'Modals/gestionUtilisateurModal.html.twig' %} {% include 'Modals/gestionUtilisateurModal.html.twig' %}
{% include 'Modals/gestionTableModal.html.twig' %} {% include 'Modals/gestionTableModal.html.twig' %}