Compare commits

..

7 Commits

25 changed files with 436 additions and 96 deletions

86
.gitignore vendored
View File

@ -1,25 +1,69 @@
###> symfony/framework-bundle ###
/.env.local
/.env.local.php
/.env.*.local
/config/secrets/prod/prod.decrypt.private.php
/public/bundles/
/var/
# Symfony & PHP
/vendor/
###< symfony/framework-bundle ###
###> phpunit/phpunit ###
/var/
/.env.local
.env.*.local
.env.test
.env.test.local
/phpunit.xml
.phpunit.result.cache
###< phpunit/phpunit ###
/phpunit.xml.dist
/.phpunit.result.cache
###> symfony/phpunit-bridge ###
.phpunit.result.cache
/phpunit.xml
###< symfony/phpunit-bridge ###
# Cache & logs
/var/cache/
/var/log/
/var/data/
###> symfony/asset-mapper ###
/public/assets/
/assets/vendor/
###< symfony/asset-mapper ###
# IDEs
/.idea/
/*.sublime-project
/*.sublime-workspace
/.vscode/
/*.code-workspace
# OS files
.DS_Store
Thumbs.db
# Composer
/composer.lock
# Symfony Encore / Webpack / Assets
/node_modules/
/public/build/
/public/bundles/
/assets/build/
# PHPUnit
.phpunit.result.cache
.phpunit.cache/
# Coverage reports
coverage/
# PHPMD, PHP-CS-Fixer, PHPStan, Psalm
.php_cs.cache
.php-cs-fixer.cache
phpstan-result.cache
psalm.xml
psalm.cache
# Docker
/docker-compose.override.yml
.docker/
# Misc
*.log
*.cache
*.swp
*.bak
*.tmp
*.orig
# Database
*.sqlite
*.sqlite3
/data/*.sqlite
# Translations
/translations/*.catalogue.php

View File

@ -3,6 +3,7 @@
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="App\" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="App\Tests\" />
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/cache" />

View File

@ -1,3 +1,7 @@
body {
background: url("../image/fond.png") center center / cover no-repeat !important;
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

22
assets/vendor/installed.php vendored Normal file
View File

@ -0,0 +1,22 @@
<?php return array (
'@hotwired/stimulus' =>
array (
'version' => '3.2.2',
'dependencies' =>
array (
),
'extraFiles' =>
array (
),
),
'@hotwired/turbo' =>
array (
'version' => '7.3.0',
'dependencies' =>
array (
),
'extraFiles' =>
array (
),
),
);

View File

@ -35,6 +35,7 @@
"symfony/property-info": "7.1.*",
"symfony/runtime": "7.1.*",
"symfony/security-bundle": "7.1.*",
"symfony/security-csrf": "7.1.*",
"symfony/serializer": "7.1.*",
"symfony/stimulus-bundle": "^2.20",
"symfony/string": "7.1.*",

38
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "e99a99b4ca2d6b58821cb711cb543c93",
"content-hash": "69565ad2398a468ae94c92c449ee3c20",
"packages": [
{
"name": "composer/semver",
@ -3466,16 +3466,16 @@
},
{
"name": "symfony/form",
"version": "v7.1.5",
"version": "v7.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/form.git",
"reference": "6b8b53ad6d42f14b158c896163b96ff260d78222"
"reference": "7a48dda96fe16711fc042df38ca1a7dd4d9d6387"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/form/zipball/6b8b53ad6d42f14b158c896163b96ff260d78222",
"reference": "6b8b53ad6d42f14b158c896163b96ff260d78222",
"url": "https://api.github.com/repos/symfony/form/zipball/7a48dda96fe16711fc042df38ca1a7dd4d9d6387",
"reference": "7a48dda96fe16711fc042df38ca1a7dd4d9d6387",
"shasum": ""
},
"require": {
@ -3543,7 +3543,7 @@
"description": "Allows to easily create, process and reuse HTML forms",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/form/tree/v7.1.5"
"source": "https://github.com/symfony/form/tree/v7.1.6"
},
"funding": [
{
@ -3559,7 +3559,7 @@
"type": "tidelift"
}
],
"time": "2024-09-20T08:28:38+00:00"
"time": "2024-10-09T08:46:59+00:00"
},
{
"name": "symfony/framework-bundle",
@ -5648,16 +5648,16 @@
},
{
"name": "symfony/security-bundle",
"version": "v7.1.4",
"version": "v7.1.11",
"source": {
"type": "git",
"url": "https://github.com/symfony/security-bundle.git",
"reference": "5e10107856ff64d477c61fed7bcbb8a16125ea01"
"reference": "4012dbc0884fc7cbf555615a5aaa16f7c0d3f222"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/security-bundle/zipball/5e10107856ff64d477c61fed7bcbb8a16125ea01",
"reference": "5e10107856ff64d477c61fed7bcbb8a16125ea01",
"url": "https://api.github.com/repos/symfony/security-bundle/zipball/4012dbc0884fc7cbf555615a5aaa16f7c0d3f222",
"reference": "4012dbc0884fc7cbf555615a5aaa16f7c0d3f222",
"shasum": ""
},
"require": {
@ -5734,7 +5734,7 @@
"description": "Provides a tight integration of the Security component into the Symfony full-stack framework",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/security-bundle/tree/v7.1.4"
"source": "https://github.com/symfony/security-bundle/tree/v7.1.11"
},
"funding": [
{
@ -5750,7 +5750,7 @@
"type": "tidelift"
}
],
"time": "2024-08-20T11:38:55+00:00"
"time": "2024-12-31T17:57:35+00:00"
},
{
"name": "symfony/security-core",
@ -5840,16 +5840,16 @@
},
{
"name": "symfony/security-csrf",
"version": "v7.1.1",
"version": "v7.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/security-csrf.git",
"reference": "27cd1bce9d7f3457a152a6ca9790712d6954dd21"
"reference": "23b460d3447fd61970e0ed5ec7a0301296a17f06"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/security-csrf/zipball/27cd1bce9d7f3457a152a6ca9790712d6954dd21",
"reference": "27cd1bce9d7f3457a152a6ca9790712d6954dd21",
"url": "https://api.github.com/repos/symfony/security-csrf/zipball/23b460d3447fd61970e0ed5ec7a0301296a17f06",
"reference": "23b460d3447fd61970e0ed5ec7a0301296a17f06",
"shasum": ""
},
"require": {
@ -5888,7 +5888,7 @@
"description": "Symfony Security Component - CSRF Library",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/security-csrf/tree/v7.1.1"
"source": "https://github.com/symfony/security-csrf/tree/v7.1.6"
},
"funding": [
{
@ -5904,7 +5904,7 @@
"type": "tidelift"
}
],
"time": "2024-05-31T14:57:53+00:00"
"time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/security-http",

View File

@ -1,44 +1,59 @@
security:
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\Utilisateur
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\Utilisateur
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
form_login:
login_path: app_login
check_path: app_login
enable_csrf: true
csrf_token_id: authenticate
logout:
path: app_logout
target: app_login
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/profile, roles: ROLE_USER }
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/secretaire, roles: ROLE_SECRETAIRE }
- { path: ^/chauffagiste, roles: ROLE_CHAUFFAGISTE }
when@test:
security:
password_hashers:
# By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon
security:
password_hashers:
# By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon

View File

@ -0,0 +1,71 @@
<?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 Version20250410150126 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
$this->addSql('CREATE SEQUENCE fault_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE intervention_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE skill_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE stock_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE utilisateur_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE vehicle_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE fault (id INT NOT NULL, wording VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE intervention (id INT NOT NULL, wording VARCHAR(255) NOT NULL, timestamp TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, description VARCHAR(255) NOT NULL, address VARCHAR(255) NOT NULL, status VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE skill (id INT NOT NULL, wording VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE stock (id INT NOT NULL, wording VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, quantity VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE utilisateur (id INT NOT NULL, email VARCHAR(180) NOT NULL, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, birth_date DATE NOT NULL, phone VARCHAR(255) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON utilisateur (email)');
$this->addSql('CREATE TABLE vehicle (id INT NOT NULL, license_plate VARCHAR(255) NOT NULL, brand VARCHAR(255) NOT NULL, model VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE messenger_messages (id BIGSERIAL NOT NULL, body TEXT NOT NULL, headers TEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, available_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, delivered_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0 ON messenger_messages (queue_name)');
$this->addSql('CREATE INDEX IDX_75EA56E0E3BD61CE ON messenger_messages (available_at)');
$this->addSql('CREATE INDEX IDX_75EA56E016BA31DB ON messenger_messages (delivered_at)');
$this->addSql('COMMENT ON COLUMN messenger_messages.created_at IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('COMMENT ON COLUMN messenger_messages.available_at IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('COMMENT ON COLUMN messenger_messages.delivered_at IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('CREATE OR REPLACE FUNCTION notify_messenger_messages() RETURNS TRIGGER AS $$
BEGIN
PERFORM pg_notify(\'messenger_messages\', NEW.queue_name::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;');
$this->addSql('DROP TRIGGER IF EXISTS notify_trigger ON messenger_messages;');
$this->addSql('CREATE TRIGGER notify_trigger AFTER INSERT OR UPDATE ON messenger_messages FOR EACH ROW EXECUTE PROCEDURE notify_messenger_messages();');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('DROP SEQUENCE fault_id_seq CASCADE');
$this->addSql('DROP SEQUENCE intervention_id_seq CASCADE');
$this->addSql('DROP SEQUENCE skill_id_seq CASCADE');
$this->addSql('DROP SEQUENCE stock_id_seq CASCADE');
$this->addSql('DROP SEQUENCE utilisateur_id_seq CASCADE');
$this->addSql('DROP SEQUENCE vehicle_id_seq CASCADE');
$this->addSql('DROP TABLE fault');
$this->addSql('DROP TABLE intervention');
$this->addSql('DROP TABLE skill');
$this->addSql('DROP TABLE stock');
$this->addSql('DROP TABLE utilisateur');
$this->addSql('DROP TABLE vehicle');
$this->addSql('DROP TABLE messenger_messages');
}
}

View File

@ -9,7 +9,7 @@ use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class AuthenticationController extends AbstractController
{
#[Route(path: '/', name: '_login')]
#[Route(path: '/', name: 'app_login')]
public function login(AuthenticationUtils $authenticationUtils): Response
{
// get the login error if there is one
@ -24,7 +24,7 @@ class AuthenticationController extends AbstractController
]);
}
#[Route(path: '/logout', name: '_logout')]
#[Route(path: '/logout', name: 'app_logout')]
public function logout(): void
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');

View File

@ -15,4 +15,17 @@ class CalendrierController extends AbstractController
'controller_name' => 'CalendrierController',
]);
}
#[Route('/calendrier/secretaire', name: 'calendrier_index_secretaire')]
public function indexSecretaire(): Response
{
return $this->render('calendrier/indexSecretaire.html.twig');
}
#[Route('/calendrier/chauffagiste', name: 'calendrier_index_chauffagiste')]
public function indexChauffagiste(): Response
{
return $this->render('calendrier/indexChauffagiste.html.twig');
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class DashboardController extends AbstractController
{
#[Route('/admin/dashboard', name: 'admin_dashboard')]
public function admin(): Response
{
return $this->render('dashboard/admin.html.twig');
}
#[Route('/secretaire/dashboard', name: 'secretaire_dashboard')]
public function secretaire(): Response
{
return $this->render('dashboard/secretaire.html.twig');
}
#[Route('/chauffagiste/dashboard', name: 'chauffagiste_dashboard')]
public function chauffagiste(): Response
{
return $this->render('dashboard/chauffagiste.html.twig');
}
}

View File

@ -17,7 +17,7 @@ final class FaultController extends AbstractController
#[Route(name: 'app_fault_index', methods: ['GET'])]
public function index(FaultRepository $faultRepository): Response
{
return $this->render('fault/index.html.twig', [
return $this->render('fault/admin.html.twig', [
'faults' => $faultRepository->findAll(),
]);
}

View File

@ -17,7 +17,7 @@ final class InterventionController extends AbstractController
#[Route(name: 'app_intervention_index', methods: ['GET'])]
public function index(InterventionRepository $interventionRepository): Response
{
return $this->render('intervention/index.html.twig', [
return $this->render('intervention/admin.html.twig', [
'interventions' => $interventionRepository->findAll(),
]);
}

View File

@ -17,7 +17,7 @@ final class SkillController extends AbstractController
#[Route(name: 'app_skill_index', methods: ['GET'])]
public function index(SkillRepository $skillRepository): Response
{
return $this->render('skill/index.html.twig', [
return $this->render('skill/admin.html.twig', [
'skills' => $skillRepository->findAll(),
]);
}

View File

@ -17,7 +17,7 @@ final class StockController extends AbstractController
#[Route(name: 'app_stock_index', methods: ['GET'])]
public function index(StockRepository $stockRepository): Response
{
return $this->render('stock/index.html.twig', [
return $this->render('stock/admin.html.twig', [
'stocks' => $stockRepository->findAll(),
]);
}

View File

@ -17,7 +17,7 @@ final class UserController extends AbstractController
#[Route(name: 'app_user_index', methods: ['GET'])]
public function index(UserRepository $userRepository): Response
{
return $this->render('user/index.html.twig', [
return $this->render('user/admin.html.twig', [
'users' => $userRepository->findAll(),
]);
}

View File

@ -17,7 +17,7 @@ final class VehicleController extends AbstractController
#[Route(name: 'app_vehicle_index', methods: ['GET'])]
public function index(VehicleRepository $vehicleRepository): Response
{
return $this->render('vehicle/index.html.twig', [
return $this->render('vehicle/admin.html.twig', [
'vehicles' => $vehicleRepository->findAll(),
]);
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Security;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface
{
private RouterInterface $router;
public function __construct(RouterInterface $router)
{
$this->router = $router;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token): RedirectResponse
{
$user = $token->getUser();
$roles = $user->getRoles();
return match (true) {
in_array('ROLE_ADMIN', $roles) => new RedirectResponse($this->router->generate('admin_dashboard')),
in_array('ROLE_SECRETAIRE', $roles) => new RedirectResponse($this->router->generate('secretaire_dashboard')),
in_array('ROLE_CHAUFFAGISTE', $roles) => new RedirectResponse($this->router->generate('chauffagiste_dashboard')),
default => new RedirectResponse($this->router->generate('_login')),
};
}
}

View File

@ -2,16 +2,53 @@
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
{% block stylesheets %}
{% endblock %}
{% block javascripts %}
{% block importmap %}{{ importmap('app') }}{% endblock %}
{% endblock %}
<title>{% block title %}Mon App Symfony{% endblock %}</title>
{% block stylesheets %}{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
{% if app.user %}
<div class="user-info">
Connecté en tant que {{ app.user.email }} |
Rôles :
{% for role in app.user.roles %}
{{ role }}{% if not loop.last %}, {% endif %}
{% endfor %}
</div>
<nav>
<ul>
{% if is_granted('ROLE_ADMIN') %}
<li><a href="{{ path('admin_dashboard') }}">Dashboard Admin</a></li>
<li><a href="{{ path('app_user_new') }}">Créer un utilisateur</a></li>
<li><a href="{{ path('app_calendrier') }}">Tous les plannings</a></li>
<li><a href="{{ path('app_stock_index') }}">Gérer les stocks</a></li>
<li><a href="{{ path('app_vehicle_index') }}">Gérer les véhicules</a></li>
{% endif %}
{% if is_granted('ROLE_SECRETAIRE') %}
<li><a href="{{ path('secretaire_dashboard') }}">Dashboard Secrétaire</a></li>
<li><a href="{{ path('user_new') }}">Créer un chauffagiste</a></li>
<li><a href="{{ path('calendrier_index_secretaire') }}">Plannings chauffagistes</a></li>
<li><a href="{{ path('stock_index') }}">Gérer les stocks</a></li>
<li><a href="{{ path('vehicle_index') }}">Gérer les véhicules</a></li>
{% endif %}
{% if is_granted('ROLE_CHAUFFAGISTE') %}
<li><a href="{{ path('chauffagiste_dashboard') }}">Dashboard Chauffagiste</a></li>
<li><a href="{{ path('calendrier_index_chauffagiste') }}">Mon planning</a></li>
<li><a href="{{ path('intervention_index') }}">Mes interventions</a></li>
<li><a href="{{ path('stock_index') }}">Pièces détachées</a></li>
{% endif %}
<li><a href="{{ path('_logout') }}">Déconnexion</a></li>
</ul>
</nav>
{% endif %}
<div class="content">
{% block body %}{% endblock %}
</div>
{% block javascripts %}{% endblock %}
</body>
</html>

View File

@ -0,0 +1,7 @@
{% extends 'base.html.twig' %}
{% block body %}
<h1>Bienvenue Admin</h1>
<p>Tu as tous les droits ici !</p>
{% endblock %}

View File

@ -0,0 +1,7 @@
{% extends 'base.html.twig' %}
{% block body %}
<h1>Bienvenue chauffagiste</h1>
<p>Vas travailler</p>
{% endblock %}

View File

@ -0,0 +1,7 @@
{% extends 'base.html.twig' %}
{% block body %}
<h1>Bienvenue Secretaire</h1>
<p>Fais ce que tu veux</p>
{% endblock %}

View File

@ -24,7 +24,8 @@
<img class="logoProfile" src="{{ asset('styles/image/profile.png') }}" alt="Logo Profil">
<img class="logoPassword" src="{{ asset('styles/image/password.png') }}" alt="Logo Password">
<form method="post">
<form method="post" action="{{ path('_login') }}">
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}