feat: gestion des remarques chauffagistes + refacto sécurité
- Ajout du champ 'Remarque' dans l'entité Intervention
- Création d'un formulaire RemarqueType dédié
- Ajout d'une route /intervention/{id}/remarque accessible uniquement au chauffagiste assigné
- Mise en place d'un contrôleur sécurisé pour ajouter une remarque
- Création de la vue intervention/remarque.html.twig
- Affichage conditionnel du bouton 'Ajouter une remarque' dans show.html.twig
- Séparation stricte des rôles : seuls les chauffagistes peuvent ajouter leur remarque
- Mise à jour de tous les contrôleurs avec denyUnlessAdminOrSecretaire() pour clarifier les accès
- Redirection des dashboards et calendriers selon rôle (admin, secrétaire, chauffagiste)
✅ Prochaine étape : liaison compétences ↔ pannes ou gestion des stocks associés
This commit is contained in:
parent
5cdf38794a
commit
8580911c1a
4
.idea/dataSources.xml
generated
4
.idea/dataSources.xml
generated
@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
<data-source source="LOCAL" name="hegreetconfort@localhost" uuid="21423ae4-3232-4641-affb-06399f70655a">
|
<data-source source="LOCAL" name="@localhost" uuid="21423ae4-3232-4641-affb-06399f70655a">
|
||||||
<driver-ref>postgresql</driver-ref>
|
<driver-ref>postgresql</driver-ref>
|
||||||
<synchronize>true</synchronize>
|
<synchronize>true</synchronize>
|
||||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||||
<jdbc-url>jdbc:postgresql://localhost:5432/hegreetconfort</jdbc-url>
|
<jdbc-url>jdbc:postgresql://localhost:5433/</jdbc-url>
|
||||||
<working-dir>$ProjectFileDir$</working-dir>
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
</data-source>
|
</data-source>
|
||||||
</component>
|
</component>
|
||||||
|
10
README.md
10
README.md
@ -29,7 +29,7 @@ Cette application permet de gérer les interventions, les utilisateurs (chauffag
|
|||||||
```
|
```
|
||||||
2. Installez les dépendances avec Composer :
|
2. Installez les dépendances avec Composer :
|
||||||
```bash
|
```bash
|
||||||
cd chauffagiste-app
|
cd HegreEtConfort
|
||||||
composer install
|
composer install
|
||||||
```
|
```
|
||||||
3. Créez la base de données :
|
3. Créez la base de données :
|
||||||
@ -40,7 +40,13 @@ Cette application permet de gérer les interventions, les utilisateurs (chauffag
|
|||||||
```bash
|
```bash
|
||||||
php bin/console doctrine:migrations:migrate
|
php bin/console doctrine:migrations:migrate
|
||||||
```
|
```
|
||||||
5. Lancez le serveur Symfony :
|
5. Exécuter cette insertion dans la console PostgreSQL pour créer votre premier utilisateur admin :
|
||||||
|
```bash
|
||||||
|
INSERT INTO "HegreEtConfort".public.utilisateur (id, email, first_name, last_name, birth_date, phone, roles, password)
|
||||||
|
VALUES (1000, 'admin@admin.admin', 'admin', 'admin', '2025-04-10', 'admin', '["ROLE_ADMIN"]', '$2y$13$4jqoZVgncgDJ6oPFDswZeeiVmt9TF2AC.xoBwyyrrbNl5Xz8r.50e');
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Lancez le serveur Symfony :
|
||||||
```bash
|
```bash
|
||||||
symfony server:start
|
symfony server:start
|
||||||
```
|
```
|
||||||
|
@ -3,25 +3,22 @@
|
|||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||||
|
|
||||||
class AuthenticationController extends AbstractController
|
class AuthenticationController extends AbstractController
|
||||||
{
|
{
|
||||||
#[Route(path: '/', name: 'app_login')]
|
#[Route(path: '/login', name: 'app_login')]
|
||||||
public function login(AuthenticationUtils $authenticationUtils): Response
|
public function login(AuthenticationUtils $authenticationUtils): Response
|
||||||
{
|
{
|
||||||
// Get the login error if there is one
|
// get the login error if there is one
|
||||||
$error = $authenticationUtils->getLastAuthenticationError();
|
$error = $authenticationUtils->getLastAuthenticationError();
|
||||||
|
// last username entered by the user
|
||||||
// Last username entered by the user
|
|
||||||
$lastUsername = $authenticationUtils->getLastUsername();
|
$lastUsername = $authenticationUtils->getLastUsername();
|
||||||
|
|
||||||
return $this->render('login/index.html.twig', [
|
return $this->render('authentication/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
|
||||||
'last_username' => $lastUsername,
|
|
||||||
'error' => $error,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route(path: '/logout', name: 'app_logout')]
|
#[Route(path: '/logout', name: 'app_logout')]
|
||||||
|
@ -4,28 +4,26 @@ namespace App\Controller;
|
|||||||
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
#[Route('/dashboard')]
|
||||||
class DashboardController extends AbstractController
|
class DashboardController extends AbstractController
|
||||||
{
|
{
|
||||||
#[Route('/admin/dashboard', name: 'admin_dashboard')]
|
#[Route('/', name: 'dashboard')]
|
||||||
public function admin(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('ROLE_ADMIN');
|
if ($this->isGranted('ROLE_ADMIN')) {
|
||||||
return $this->render('dashboard/admin.html.twig');
|
return $this->render('admin.html.twig');
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/secretaire/dashboard', name: 'secretaire_dashboard')]
|
if ($this->isGranted('ROLE_SECRETAIRE')) {
|
||||||
public function secretaire(): Response
|
return $this->render('secretaire.html.twig');
|
||||||
{
|
|
||||||
$this->denyAccessUnlessGranted('ROLE_SECRETAIRE');
|
|
||||||
return $this->render('dashboard/secretaire.html.twig');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/chauffagiste/dashboard', name: 'chauffagiste_dashboard')]
|
if ($this->isGranted('ROLE_CHAUFFAGISTE')) {
|
||||||
public function chauffagiste(): Response
|
return $this->render('chauffagiste.html.twig');
|
||||||
{
|
}
|
||||||
$this->denyAccessUnlessGranted('ROLE_CHAUFFAGISTE');
|
|
||||||
return $this->render('dashboard/chauffagiste.html.twig');
|
throw $this->createAccessDeniedException('Vous ne pouvez pas accéder à ce tableau de bord.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,45 +9,36 @@ use Doctrine\ORM\EntityManagerInterface;
|
|||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
#[Route('/fault')]
|
#[Route('/fault')]
|
||||||
final class FaultController extends AbstractController
|
class FaultController extends AbstractController
|
||||||
{
|
{
|
||||||
#[Route(name: 'app_fault_index', methods: ['GET'])]
|
#[Route('/', name: 'app_fault_index', methods: ['GET'])]
|
||||||
public function index(FaultRepository $faultRepository): Response
|
public function index(FaultRepository $faultRepository): Response
|
||||||
{
|
{
|
||||||
// Filtrage des pannes : un chauffagiste ne peut voir que ses pannes
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
$faults = $this->isGranted('ROLE_CHAUFFAGISTE')
|
|
||||||
? $faultRepository->findByUser($this->getUser()) // Filtre les pannes par utilisateur
|
|
||||||
: $faultRepository->findAll(); // Admins voient toutes les pannes
|
|
||||||
|
|
||||||
return $this->render('fault/index.html.twig', [
|
return $this->render('fault/index.html.twig', [
|
||||||
'faults' => $faults,
|
'faults' => $faultRepository->findAll(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/new', name: 'app_fault_new', methods: ['GET', 'POST'])]
|
#[Route('/new', name: 'app_fault_new', methods: ['GET', 'POST'])]
|
||||||
public function new(Request $request, EntityManagerInterface $entityManager): Response
|
public function new(Request $request, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
|
|
||||||
$fault = new Fault();
|
$fault = new Fault();
|
||||||
$form = $this->createForm(FaultType::class, $fault);
|
$form = $this->createForm(FaultType::class, $fault);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
// Associe la panne à un chauffagiste si c'est un chauffagiste
|
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE')) {
|
|
||||||
$fault->setUser($this->getUser());
|
|
||||||
}
|
|
||||||
|
|
||||||
$entityManager->persist($fault);
|
$entityManager->persist($fault);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
return $this->redirectToRoute('app_fault_index');
|
||||||
return $this->redirectToRoute('app_fault_index', [], Response::HTTP_SEE_OTHER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('fault/new.html.twig', [
|
return $this->render('fault/new.html.twig', [
|
||||||
'fault' => $fault,
|
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -55,11 +46,7 @@ final class FaultController extends AbstractController
|
|||||||
#[Route('/{id}', name: 'app_fault_show', methods: ['GET'])]
|
#[Route('/{id}', name: 'app_fault_show', methods: ['GET'])]
|
||||||
public function show(Fault $fault): Response
|
public function show(Fault $fault): Response
|
||||||
{
|
{
|
||||||
// Un chauffagiste ne peut voir que ses pannes
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $fault->getUser() !== $this->getUser()) {
|
|
||||||
throw $this->createAccessDeniedException('Vous ne pouvez pas voir cette panne.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render('fault/show.html.twig', [
|
return $this->render('fault/show.html.twig', [
|
||||||
'fault' => $fault,
|
'fault' => $fault,
|
||||||
]);
|
]);
|
||||||
@ -68,39 +55,39 @@ final class FaultController extends AbstractController
|
|||||||
#[Route('/{id}/edit', name: 'app_fault_edit', methods: ['GET', 'POST'])]
|
#[Route('/{id}/edit', name: 'app_fault_edit', methods: ['GET', 'POST'])]
|
||||||
public function edit(Request $request, Fault $fault, EntityManagerInterface $entityManager): Response
|
public function edit(Request $request, Fault $fault, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
// Un chauffagiste ne peut modifier que ses propres pannes
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $fault->getUser() !== $this->getUser()) {
|
|
||||||
throw $this->createAccessDeniedException('Vous ne pouvez pas modifier cette panne.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$form = $this->createForm(FaultType::class, $fault);
|
$form = $this->createForm(FaultType::class, $fault);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
return $this->redirectToRoute('app_fault_index');
|
||||||
return $this->redirectToRoute('app_fault_index', [], Response::HTTP_SEE_OTHER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('fault/edit.html.twig', [
|
return $this->render('fault/edit.html.twig', [
|
||||||
'fault' => $fault,
|
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
|
'fault' => $fault,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/{id}', name: 'app_fault_delete', methods: ['POST'])]
|
#[Route('/{id}', name: 'app_fault_delete', methods: ['POST'])]
|
||||||
public function delete(Request $request, Fault $fault, EntityManagerInterface $entityManager): Response
|
public function delete(Request $request, Fault $fault, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
// Un chauffagiste ne peut supprimer que ses propres pannes
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $fault->getUser() !== $this->getUser()) {
|
|
||||||
throw $this->createAccessDeniedException('Vous ne pouvez pas supprimer cette panne.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->isCsrfTokenValid('delete'.$fault->getId(), $request->get('csrf_token'))) {
|
if ($this->isCsrfTokenValid('delete'.$fault->getId(), $request->request->get('_token'))) {
|
||||||
$entityManager->remove($fault);
|
$entityManager->remove($fault);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->redirectToRoute('app_fault_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_fault_index');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function denyUnlessAdminOrSecretaire(): void
|
||||||
|
{
|
||||||
|
if (!$this->isGranted('ROLE_ADMIN') && !$this->isGranted('ROLE_SECRETAIRE')) {
|
||||||
|
throw $this->createAccessDeniedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,51 +7,39 @@ use App\Form\InterventionType;
|
|||||||
use App\Repository\InterventionRepository;
|
use App\Repository\InterventionRepository;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
#[Route('/intervention')]
|
#[Route('/intervention')]
|
||||||
final class InterventionController extends AbstractController
|
class InterventionController extends AbstractController
|
||||||
{
|
{
|
||||||
#[Route(name: 'app_intervention_index', methods: ['GET'])]
|
#[Route('/', name: 'app_intervention_index', methods: ['GET'])]
|
||||||
public function index(InterventionRepository $interventionRepository): Response
|
public function index(InterventionRepository $interventionRepository): Response
|
||||||
{
|
{
|
||||||
// Vérifier si l'utilisateur est un chauffagiste, pour filtrer ses interventions
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE')) {
|
|
||||||
$interventions = $interventionRepository->findByUser($this->getUser()); // On filtre par utilisateur connecté
|
|
||||||
} else {
|
|
||||||
// Les autres rôles (admin) peuvent voir toutes les interventions
|
|
||||||
$interventions = $interventionRepository->findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render('intervention/index.html.twig', [
|
return $this->render('intervention/index.html.twig', [
|
||||||
'interventions' => $interventions,
|
'interventions' => $interventionRepository->findAll(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/new', name: 'app_intervention_new', methods: ['GET', 'POST'])]
|
#[Route('/new', name: 'app_intervention_new', methods: ['GET', 'POST'])]
|
||||||
public function new(Request $request, EntityManagerInterface $entityManager): Response
|
public function new(Request $request, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
|
|
||||||
$intervention = new Intervention();
|
$intervention = new Intervention();
|
||||||
$form = $this->createForm(InterventionType::class, $intervention);
|
$form = $this->createForm(InterventionType::class, $intervention);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
// Si l'utilisateur est un chauffagiste, on associe l'intervention à lui
|
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE')) {
|
|
||||||
$intervention->setUser($this->getUser());
|
|
||||||
}
|
|
||||||
|
|
||||||
$entityManager->persist($intervention);
|
$entityManager->persist($intervention);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
|
||||||
return $this->redirectToRoute('app_intervention_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_intervention_index');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('intervention/new.html.twig', [
|
return $this->render('intervention/new.html.twig', [
|
||||||
'intervention' => $intervention,
|
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -59,11 +47,7 @@ final class InterventionController extends AbstractController
|
|||||||
#[Route('/{id}', name: 'app_intervention_show', methods: ['GET'])]
|
#[Route('/{id}', name: 'app_intervention_show', methods: ['GET'])]
|
||||||
public function show(Intervention $intervention): Response
|
public function show(Intervention $intervention): Response
|
||||||
{
|
{
|
||||||
// Vérifier si l'utilisateur peut voir cette intervention (chauffagiste ne voit que ses interventions)
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $intervention->getUser() !== $this->getUser()) {
|
|
||||||
throw $this->createAccessDeniedException('Vous ne pouvez pas voir cette intervention.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render('intervention/show.html.twig', [
|
return $this->render('intervention/show.html.twig', [
|
||||||
'intervention' => $intervention,
|
'intervention' => $intervention,
|
||||||
]);
|
]);
|
||||||
@ -72,10 +56,7 @@ final class InterventionController extends AbstractController
|
|||||||
#[Route('/{id}/edit', name: 'app_intervention_edit', methods: ['GET', 'POST'])]
|
#[Route('/{id}/edit', name: 'app_intervention_edit', methods: ['GET', 'POST'])]
|
||||||
public function edit(Request $request, Intervention $intervention, EntityManagerInterface $entityManager): Response
|
public function edit(Request $request, Intervention $intervention, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
// Vérification de sécurité : un chauffagiste ne peut modifier que ses propres interventions
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $intervention->getUser() !== $this->getUser()) {
|
|
||||||
throw $this->createAccessDeniedException('Vous ne pouvez pas modifier cette intervention.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$form = $this->createForm(InterventionType::class, $intervention);
|
$form = $this->createForm(InterventionType::class, $intervention);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
@ -83,49 +64,57 @@ final class InterventionController extends AbstractController
|
|||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
|
||||||
return $this->redirectToRoute('app_intervention_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_intervention_index');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('intervention/edit.html.twig', [
|
return $this->render('intervention/edit.html.twig', [
|
||||||
'intervention' => $intervention,
|
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
|
'intervention' => $intervention,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/{id}', name: 'app_intervention_delete', methods: ['POST'])]
|
#[Route('/{id}', name: 'app_intervention_delete', methods: ['POST'])]
|
||||||
public function delete(Request $request, Intervention $intervention, EntityManagerInterface $entityManager): Response
|
public function delete(Request $request, Intervention $intervention, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
// Vérification de sécurité : un chauffagiste ne peut supprimer que ses propres interventions
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $intervention->getUser() !== $this->getUser()) {
|
|
||||||
throw $this->createAccessDeniedException('Vous ne pouvez pas supprimer cette intervention.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->isCsrfTokenValid('delete'.$intervention->getId(), $request->get('csrf_token'))) {
|
if ($this->isCsrfTokenValid('delete' . $intervention->getId(), $request->request->get('_token'))) {
|
||||||
$entityManager->remove($intervention);
|
$entityManager->remove($intervention);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->redirectToRoute('app_intervention_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_intervention_index');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('/{id}/remarque', name: 'app_intervention_remarque', methods: ['GET', 'POST'])]
|
||||||
|
public function ajouterRemarque(Request $request, Intervention $intervention, EntityManagerInterface $entityManager): Response
|
||||||
#[Route('/api/interventions', name: 'api_interventions')]
|
|
||||||
public function apiInterventions(InterventionRepository $repo): JsonResponse
|
|
||||||
{
|
{
|
||||||
$interventions = $repo->findAll();
|
// Vérifie que l'utilisateur est le chauffagiste assigné à l'intervention
|
||||||
|
$user = $this->getUser();
|
||||||
$events = [];
|
if (!$this->isGranted('ROLE_CHAUFFAGISTE') || $intervention->getUser() !== $user) {
|
||||||
|
throw $this->createAccessDeniedException("Vous ne pouvez modifier que vos propres interventions.");
|
||||||
foreach ($interventions as $intervention) {
|
|
||||||
$events[] = [
|
|
||||||
'id' => $intervention->getId(),
|
|
||||||
'title' => $intervention->getWording(), // ou getTitre() selon ton entité
|
|
||||||
'start' => $intervention->getDate()->format('Y-m-d\TH:i:s'),
|
|
||||||
// ajoute 'end' si tu veux une durée
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->json($events);
|
$form = $this->createForm(RemarqueType::class, $intervention);
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$entityManager->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', 'Remarque ajoutée avec succès.');
|
||||||
|
return $this->redirectToRoute('app_intervention_show', ['id' => $intervention->getId()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('intervention/remarque.html.twig', [
|
||||||
|
'form' => $form,
|
||||||
|
'intervention' => $intervention,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function denyUnlessAdminOrSecretaire(): void
|
||||||
|
{
|
||||||
|
if (!$this->isGranted('ROLE_ADMIN') && !$this->isGranted('ROLE_SECRETAIRE')) {
|
||||||
|
throw $this->createAccessDeniedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,16 +9,16 @@ use Doctrine\ORM\EntityManagerInterface;
|
|||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
#[Route('/skill')]
|
#[Route('/skill')]
|
||||||
final class SkillController extends AbstractController
|
class SkillController extends AbstractController
|
||||||
{
|
{
|
||||||
#[Route(name: 'app_skill_index', methods: ['GET'])]
|
#[Route('/', name: 'app_skill_index', methods: ['GET'])]
|
||||||
public function index(SkillRepository $skillRepository): Response
|
public function index(SkillRepository $skillRepository): Response
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('ROLE_ADMIN');
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
return $this->render('skill/admin.html.twig', [
|
return $this->render('skill/index.html.twig', [
|
||||||
'skills' => $skillRepository->findAll(),
|
'skills' => $skillRepository->findAll(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -26,7 +26,8 @@ final class SkillController extends AbstractController
|
|||||||
#[Route('/new', name: 'app_skill_new', methods: ['GET', 'POST'])]
|
#[Route('/new', name: 'app_skill_new', methods: ['GET', 'POST'])]
|
||||||
public function new(Request $request, EntityManagerInterface $entityManager): Response
|
public function new(Request $request, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('ROLE_ADMIN');
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
|
|
||||||
$skill = new Skill();
|
$skill = new Skill();
|
||||||
$form = $this->createForm(SkillType::class, $skill);
|
$form = $this->createForm(SkillType::class, $skill);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
@ -35,11 +36,10 @@ final class SkillController extends AbstractController
|
|||||||
$entityManager->persist($skill);
|
$entityManager->persist($skill);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
|
||||||
return $this->redirectToRoute('app_skill_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_skill_index');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('skill/new.html.twig', [
|
return $this->render('skill/new.html.twig', [
|
||||||
'skill' => $skill,
|
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -47,6 +47,7 @@ final class SkillController extends AbstractController
|
|||||||
#[Route('/{id}', name: 'app_skill_show', methods: ['GET'])]
|
#[Route('/{id}', name: 'app_skill_show', methods: ['GET'])]
|
||||||
public function show(Skill $skill): Response
|
public function show(Skill $skill): Response
|
||||||
{
|
{
|
||||||
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
return $this->render('skill/show.html.twig', [
|
return $this->render('skill/show.html.twig', [
|
||||||
'skill' => $skill,
|
'skill' => $skill,
|
||||||
]);
|
]);
|
||||||
@ -55,31 +56,40 @@ final class SkillController extends AbstractController
|
|||||||
#[Route('/{id}/edit', name: 'app_skill_edit', methods: ['GET', 'POST'])]
|
#[Route('/{id}/edit', name: 'app_skill_edit', methods: ['GET', 'POST'])]
|
||||||
public function edit(Request $request, Skill $skill, EntityManagerInterface $entityManager): Response
|
public function edit(Request $request, Skill $skill, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('ROLE_ADMIN');
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
|
|
||||||
$form = $this->createForm(SkillType::class, $skill);
|
$form = $this->createForm(SkillType::class, $skill);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
|
||||||
return $this->redirectToRoute('app_skill_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_skill_index');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('skill/edit.html.twig', [
|
return $this->render('skill/edit.html.twig', [
|
||||||
'skill' => $skill,
|
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
|
'skill' => $skill,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/{id}', name: 'app_skill_delete', methods: ['POST'])]
|
#[Route('/{id}', name: 'app_skill_delete', methods: ['POST'])]
|
||||||
public function delete(Request $request, Skill $skill, EntityManagerInterface $entityManager): Response
|
public function delete(Request $request, Skill $skill, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('ROLE_ADMIN');
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
if ($this->isCsrfTokenValid('delete'.$skill->getId(), $request->get('csrf_token'))) {
|
|
||||||
|
if ($this->isCsrfTokenValid('delete' . $skill->getId(), $request->request->get('_token'))) {
|
||||||
$entityManager->remove($skill);
|
$entityManager->remove($skill);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->redirectToRoute('app_skill_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_skill_index');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function denyUnlessAdminOrSecretaire(): void
|
||||||
|
{
|
||||||
|
if (!$this->isGranted('ROLE_ADMIN') && !$this->isGranted('ROLE_SECRETAIRE')) {
|
||||||
|
throw $this->createAccessDeniedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,14 +9,15 @@ use Doctrine\ORM\EntityManagerInterface;
|
|||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
#[Route('/stock')]
|
#[Route('/stock')]
|
||||||
final class StockController extends AbstractController
|
class StockController extends AbstractController
|
||||||
{
|
{
|
||||||
#[Route(name: 'app_stock_index', methods: ['GET'])]
|
#[Route('/', name: 'app_stock_index', methods: ['GET'])]
|
||||||
public function index(StockRepository $stockRepository): Response
|
public function index(StockRepository $stockRepository): Response
|
||||||
{
|
{
|
||||||
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
return $this->render('stock/index.html.twig', [
|
return $this->render('stock/index.html.twig', [
|
||||||
'stocks' => $stockRepository->findAll(),
|
'stocks' => $stockRepository->findAll(),
|
||||||
]);
|
]);
|
||||||
@ -25,6 +26,8 @@ final class StockController extends AbstractController
|
|||||||
#[Route('/new', name: 'app_stock_new', methods: ['GET', 'POST'])]
|
#[Route('/new', name: 'app_stock_new', methods: ['GET', 'POST'])]
|
||||||
public function new(Request $request, EntityManagerInterface $entityManager): Response
|
public function new(Request $request, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
|
|
||||||
$stock = new Stock();
|
$stock = new Stock();
|
||||||
$form = $this->createForm(StockType::class, $stock);
|
$form = $this->createForm(StockType::class, $stock);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
@ -33,11 +36,10 @@ final class StockController extends AbstractController
|
|||||||
$entityManager->persist($stock);
|
$entityManager->persist($stock);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
|
||||||
return $this->redirectToRoute('app_stock_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_stock_index');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('stock/new.html.twig', [
|
return $this->render('stock/new.html.twig', [
|
||||||
'stock' => $stock,
|
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -45,6 +47,7 @@ final class StockController extends AbstractController
|
|||||||
#[Route('/{id}', name: 'app_stock_show', methods: ['GET'])]
|
#[Route('/{id}', name: 'app_stock_show', methods: ['GET'])]
|
||||||
public function show(Stock $stock): Response
|
public function show(Stock $stock): Response
|
||||||
{
|
{
|
||||||
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
return $this->render('stock/show.html.twig', [
|
return $this->render('stock/show.html.twig', [
|
||||||
'stock' => $stock,
|
'stock' => $stock,
|
||||||
]);
|
]);
|
||||||
@ -53,10 +56,7 @@ final class StockController extends AbstractController
|
|||||||
#[Route('/{id}/edit', name: 'app_stock_edit', methods: ['GET', 'POST'])]
|
#[Route('/{id}/edit', name: 'app_stock_edit', methods: ['GET', 'POST'])]
|
||||||
public function edit(Request $request, Stock $stock, EntityManagerInterface $entityManager): Response
|
public function edit(Request $request, Stock $stock, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
// Si un chauffagiste essaie de modifier un stock d'admin
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE')) {
|
|
||||||
throw $this->createAccessDeniedException('Vous ne pouvez pas modifier ce stock.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$form = $this->createForm(StockType::class, $stock);
|
$form = $this->createForm(StockType::class, $stock);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
@ -64,23 +64,32 @@ final class StockController extends AbstractController
|
|||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
|
||||||
return $this->redirectToRoute('app_stock_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_stock_index');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('stock/edit.html.twig', [
|
return $this->render('stock/edit.html.twig', [
|
||||||
'stock' => $stock,
|
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
|
'stock' => $stock,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/{id}', name: 'app_stock_delete', methods: ['POST'])]
|
#[Route('/{id}', name: 'app_stock_delete', methods: ['POST'])]
|
||||||
public function delete(Request $request, Stock $stock, EntityManagerInterface $entityManager): Response
|
public function delete(Request $request, Stock $stock, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
if ($this->isCsrfTokenValid('delete'.$stock->getId(), $request->get('csrf_token'))) {
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
|
|
||||||
|
if ($this->isCsrfTokenValid('delete' . $stock->getId(), $request->request->get('_token'))) {
|
||||||
$entityManager->remove($stock);
|
$entityManager->remove($stock);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->redirectToRoute('app_stock_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_stock_index');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function denyUnlessAdminOrSecretaire(): void
|
||||||
|
{
|
||||||
|
if (!$this->isGranted('ROLE_ADMIN') && !$this->isGranted('ROLE_SECRETAIRE')) {
|
||||||
|
throw $this->createAccessDeniedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ use Symfony\Component\HttpFoundation\Request;
|
|||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
final class UserController extends AbstractController
|
final class UserController extends AbstractController
|
||||||
{
|
{
|
||||||
@ -89,27 +90,19 @@ final class UserController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Route pour supprimer un utilisateur spécifique
|
// Route pour supprimer un utilisateur spécifique
|
||||||
|
#[IsGranted('ROLE_ADMIN', 'ROLE_SECRETAIRE')]
|
||||||
#[Route('/user/{id}', name: 'app_user_delete', methods: ['POST'])]
|
#[Route('/user/{id}', name: 'app_user_delete', methods: ['POST'])]
|
||||||
public function delete(Request $request, Utilisateur $user, EntityManagerInterface $entityManager): Response
|
public function delete(Request $request, Utilisateur $utilisateur): Response
|
||||||
{
|
{
|
||||||
// Si l'utilisateur est un secrétaire et qu'il essaie de supprimer un autre secrétaire
|
if ($this->isCsrfTokenValid('delete' . $utilisateur->getId(), $request->request->get('_token'))) {
|
||||||
if ($this->isGranted('ROLE_SECRETAIRE') && $user->hasRole('ROLE_SECRETAIRE')) {
|
$this->entityManager->remove($utilisateur);
|
||||||
throw $this->createAccessDeniedException('Vous ne pouvez pas supprimer un autre secrétaire ou un administrateur.');
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', 'Utilisateur supprimé avec succès.');
|
||||||
|
} else {
|
||||||
|
$this->addFlash('error', 'Token CSRF invalide.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si l'utilisateur est un chauffagiste et qu'il essaie de supprimer un admin
|
return $this->redirectToRoute('app_user_index');
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE') && ($user->hasRole('ROLE_SECRETAIRE') || $user->hasRole('ROLE_CHAUFFAGISTE'))) {
|
|
||||||
throw $this->createAccessDeniedException('Vous ne pouvez pas supprimer un utilisateur.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// On s'assure que seul un admin peut supprimer un autre admin
|
|
||||||
$this->denyAccessUnlessGranted("ROLE_ADMIN");
|
|
||||||
|
|
||||||
if ($this->isCsrfTokenValid('delete' . $user->getId(), $request->get('csrf_token'))) {
|
|
||||||
$entityManager->remove($user);
|
|
||||||
$entityManager->flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->redirectToRoute('app_user_index', [], Response::HTTP_SEE_OTHER);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,45 +9,36 @@ use Doctrine\ORM\EntityManagerInterface;
|
|||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
#[Route('/vehicle')]
|
#[Route('/vehicle')]
|
||||||
final class VehicleController extends AbstractController
|
class VehicleController extends AbstractController
|
||||||
{
|
{
|
||||||
#[Route(name: 'app_vehicle_index', methods: ['GET'])]
|
#[Route('/', name: 'app_vehicle_index', methods: ['GET'])]
|
||||||
public function index(VehicleRepository $vehicleRepository): Response
|
public function index(VehicleRepository $vehicleRepository): Response
|
||||||
{
|
{
|
||||||
// Admin peut voir tous les véhicules, chauffagiste ne peut voir que ses véhicules
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
$vehicles = $this->isGranted('ROLE_CHAUFFAGISTE')
|
|
||||||
? $vehicleRepository->findByUser($this->getUser()) // Filtre les véhicules par utilisateur
|
|
||||||
: $vehicleRepository->findAll(); // Les admins voient tout
|
|
||||||
|
|
||||||
return $this->render('vehicle/index.html.twig', [
|
return $this->render('vehicle/index.html.twig', [
|
||||||
'vehicles' => $vehicles,
|
'vehicles' => $vehicleRepository->findAll(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/new', name: 'app_vehicle_new', methods: ['GET', 'POST'])]
|
#[Route('/new', name: 'app_vehicle_new', methods: ['GET', 'POST'])]
|
||||||
public function new(Request $request, EntityManagerInterface $entityManager): Response
|
public function new(Request $request, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
|
|
||||||
$vehicle = new Vehicle();
|
$vehicle = new Vehicle();
|
||||||
$form = $this->createForm(VehicleType::class, $vehicle);
|
$form = $this->createForm(VehicleType::class, $vehicle);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
// Si l'utilisateur est un chauffagiste, on associe le véhicule à lui
|
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE')) {
|
|
||||||
$vehicle->setUser($this->getUser());
|
|
||||||
}
|
|
||||||
|
|
||||||
$entityManager->persist($vehicle);
|
$entityManager->persist($vehicle);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
return $this->redirectToRoute('app_vehicle_index');
|
||||||
return $this->redirectToRoute('app_vehicle_index', [], Response::HTTP_SEE_OTHER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('vehicle/new.html.twig', [
|
return $this->render('vehicle/new.html.twig', [
|
||||||
'vehicle' => $vehicle,
|
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -55,11 +46,7 @@ final class VehicleController extends AbstractController
|
|||||||
#[Route('/{id}', name: 'app_vehicle_show', methods: ['GET'])]
|
#[Route('/{id}', name: 'app_vehicle_show', methods: ['GET'])]
|
||||||
public function show(Vehicle $vehicle): Response
|
public function show(Vehicle $vehicle): Response
|
||||||
{
|
{
|
||||||
// Si l'utilisateur est un chauffagiste et essaie de voir un véhicule d'un autre chauffagiste, on bloque
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $vehicle->getUser() !== $this->getUser()) {
|
|
||||||
throw $this->createAccessDeniedException('Vous ne pouvez pas voir ce véhicule.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render('vehicle/show.html.twig', [
|
return $this->render('vehicle/show.html.twig', [
|
||||||
'vehicle' => $vehicle,
|
'vehicle' => $vehicle,
|
||||||
]);
|
]);
|
||||||
@ -68,39 +55,39 @@ final class VehicleController extends AbstractController
|
|||||||
#[Route('/{id}/edit', name: 'app_vehicle_edit', methods: ['GET', 'POST'])]
|
#[Route('/{id}/edit', name: 'app_vehicle_edit', methods: ['GET', 'POST'])]
|
||||||
public function edit(Request $request, Vehicle $vehicle, EntityManagerInterface $entityManager): Response
|
public function edit(Request $request, Vehicle $vehicle, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
// Vérifier si un chauffagiste essaie de modifier un véhicule d'un autre chauffagiste
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $vehicle->getUser() !== $this->getUser()) {
|
|
||||||
throw $this->createAccessDeniedException('Vous ne pouvez pas modifier ce véhicule.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$form = $this->createForm(VehicleType::class, $vehicle);
|
$form = $this->createForm(VehicleType::class, $vehicle);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
return $this->redirectToRoute('app_vehicle_index');
|
||||||
return $this->redirectToRoute('app_vehicle_index', [], Response::HTTP_SEE_OTHER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('vehicle/edit.html.twig', [
|
return $this->render('vehicle/edit.html.twig', [
|
||||||
'vehicle' => $vehicle,
|
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
|
'vehicle' => $vehicle,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/{id}', name: 'app_vehicle_delete', methods: ['POST'])]
|
#[Route('/{id}', name: 'app_vehicle_delete', methods: ['POST'])]
|
||||||
public function delete(Request $request, Vehicle $vehicle, EntityManagerInterface $entityManager): Response
|
public function delete(Request $request, Vehicle $vehicle, EntityManagerInterface $entityManager): Response
|
||||||
{
|
{
|
||||||
// Vérification de sécurité : un chauffagiste ne peut supprimer un véhicule d'un autre chauffagiste
|
$this->denyUnlessAdminOrSecretaire();
|
||||||
if ($this->isGranted('ROLE_CHAUFFAGISTE') && $vehicle->getUser() !== $this->getUser()) {
|
|
||||||
throw $this->createAccessDeniedException('Vous ne pouvez pas supprimer ce véhicule.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->isCsrfTokenValid('delete'.$vehicle->getId(), $request->get('csrf_token'))) {
|
if ($this->isCsrfTokenValid('delete' . $vehicle->getId(), $request->request->get('_token'))) {
|
||||||
$entityManager->remove($vehicle);
|
$entityManager->remove($vehicle);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->redirectToRoute('app_vehicle_index', [], Response::HTTP_SEE_OTHER);
|
return $this->redirectToRoute('app_vehicle_index');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function denyUnlessAdminOrSecretaire(): void
|
||||||
|
{
|
||||||
|
if (!$this->isGranted('ROLE_ADMIN') && !$this->isGranted('ROLE_SECRETAIRE')) {
|
||||||
|
throw $this->createAccessDeniedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,6 +202,9 @@ class Intervention
|
|||||||
#[ORM\Column(length: 255)]
|
#[ORM\Column(length: 255)]
|
||||||
private ?string $Status = null;
|
private ?string $Status = null;
|
||||||
|
|
||||||
|
#[ORM\Column(type: 'text', nullable: true)]
|
||||||
|
private ?string $Remarque = null;
|
||||||
|
|
||||||
#[ORM\ManyToOne(inversedBy: 'interventions')]
|
#[ORM\ManyToOne(inversedBy: 'interventions')]
|
||||||
#[ORM\JoinColumn(nullable: false)]
|
#[ORM\JoinColumn(nullable: false)]
|
||||||
private ?Utilisateur $user = null;
|
private ?Utilisateur $user = null;
|
||||||
@ -355,5 +358,15 @@ class Intervention
|
|||||||
{
|
{
|
||||||
return $this->Wording;
|
return $this->Wording;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRemarque(): ?string
|
||||||
|
{
|
||||||
|
return $this->Remarque;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRemarque(?string $Remarque): void
|
||||||
|
{
|
||||||
|
$this->Remarque = $Remarque;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
31
src/Form/RemarqueType.php
Normal file
31
src/Form/RemarqueType.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Form;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use App\Entity\Intervention;
|
||||||
|
|
||||||
|
class RemarqueType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('Remarque', TextareaType::class, [
|
||||||
|
'label' => 'Ajouter une remarque',
|
||||||
|
'attr' => [
|
||||||
|
'rows' => 5,
|
||||||
|
'placeholder' => 'Renseignez les observations de l’intervention…'
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => Intervention::class,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
18
templates/intervention/remarque.html.twig
Normal file
18
templates/intervention/remarque.html.twig
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}Ajouter une remarque{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<h1 class="mb-4">📝 Ajouter une remarque à l'intervention #{{ intervention.id }}</h1>
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
{{ form_widget(form) }}
|
||||||
|
<button class="btn btn-primary mt-3">Enregistrer la remarque</button>
|
||||||
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<a href="{{ path('app_intervention_show', {'id': intervention.id}) }}" class="btn btn-secondary">
|
||||||
|
← Retour à l'intervention
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -63,6 +63,11 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% if is_granted('ROLE_CHAUFFAGISTE') and intervention.user == app.user %}
|
||||||
|
<a href="{{ path('app_intervention_remarque', {'id': intervention.id}) }}" class="btn btn-outline-primary">
|
||||||
|
📝 Ajouter une remarque
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user