Compare commits

...

8 Commits

Author SHA1 Message Date
eaeabed512 /!\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
2024-11-07 19:01:46 +01:00
b98318b79f Ajout et modification du nouvelle index.html fait dans realease/Index 2024-10-28 02:45:24 +01:00
975bc1e153 Modification Table : tabl -> table 2024-10-27 23:29:20 +01:00
f141abf1cc Mise en place des Roles
Modification Index pour tester les roles
Modification du form d'ajout d'un Utilisateur pour selectionner les roles au lieux de les saisir en texte
Mise en place d'une page d'accés refuser personnaliser
2024-10-26 01:50:10 +02:00
ca240ee372 Css sur l'ajout d'un User
Css sur le login
Mise en place du /Logout
Ajout de la liste User
2024-10-26 00:32:31 +02:00
fef9b0d56e Systeme de Login OK, nouvelle migration clean + migrations pour Utilisateurs/Mail:string -> Mail:json
Ajout d'un controlleur et form User pour ajouter un Utilisateurs dans la table avec le password Hash et le role au formet Array
Ajout de l'Authenticator pour verifier le Login
Nouveau Form pour le login, permet le login correctement
Changement des Vu pour Login, permet de POST le password et le mail correctement
Ajout d'un IndexController pour les tests
Changement du Utilisateurs.php (Table) pour mettre le Login correctement en place (Ajout du systele de login symfony, Mot_de_Passe -> Password, Mail -> UserIdentifier)
2024-10-25 19:15:26 +02:00
8213037f96 Merge remote-tracking branch 'origin/release/Login' into release/Login 2024-10-17 17:53:51 +02:00
9dfd212718 push de controller cuisinier /add /delete 2024-10-17 17:53:18 +02:00
41 changed files with 3255 additions and 519 deletions

View File

@ -7,6 +7,7 @@
"php": ">=8.2", "php": ">=8.2",
"ext-ctype": "*", "ext-ctype": "*",
"ext-iconv": "*", "ext-iconv": "*",
"amphp/http-client": "4.2.1",
"doctrine/dbal": "^3", "doctrine/dbal": "^3",
"doctrine/doctrine-bundle": "^2.13", "doctrine/doctrine-bundle": "^2.13",
"doctrine/doctrine-migrations-bundle": "^3.3", "doctrine/doctrine-migrations-bundle": "^3.3",
@ -38,6 +39,7 @@
"symfony/string": "7.1.*", "symfony/string": "7.1.*",
"symfony/translation": "7.1.*", "symfony/translation": "7.1.*",
"symfony/twig-bundle": "7.1.*", "symfony/twig-bundle": "7.1.*",
"symfony/ux-icons": "^2.21",
"symfony/ux-turbo": "^2.20", "symfony/ux-turbo": "^2.20",
"symfony/validator": "7.1.*", "symfony/validator": "7.1.*",
"symfony/web-link": "7.1.*", "symfony/web-link": "7.1.*",

2227
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -13,4 +13,5 @@ return [
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Symfony\UX\Icons\UXIconsBundle::class => ['all' => true],
]; ];

View File

@ -2,38 +2,52 @@ security:
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers: password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers: providers:
users_in_memory: { memory: null } app_user_provider:
entity:
class: App\Entity\Utilisateurs
property: Mail
firewalls: firewalls:
dev: dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/ pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false security: false
main: main:
lazy: true lazy: true
provider: users_in_memory provider: app_user_provider
form_login:
login_path: app_login
check_path: app_login
custom_authenticator: App\Security\LoginAuthenticator
entry_point: App\Security\LoginAuthenticator
# activate different ways to authenticate logout:
# https://symfony.com/doc/current/security.html#the-firewall path: app_logout
target: app_login
# 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
role_hierarchy:
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
access_control: access_control:
# - { path: ^/admin, roles: ROLE_ADMIN } # - { path: ^/, roles: ROLE_USER }
# - { path: ^/profile, roles: ROLE_USER } - { path: ^/login, roles: PUBLIC_ACCESS }
- { path: ^/logout, roles: ROLE_USER }
- { path: ^/index, roles: ROLE_ADMIN }
- { path: ^/user, roles: ROLE_ADMIN }
when@test: #when@test:
security: # security:
password_hashers: # password_hashers:
# By default, password hashers are resource intensive and take time. This is # # By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes # # important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following # # are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values. # # reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: # Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto # algorithm: auto
cost: 4 # Lowest possible value for bcrypt # cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon # time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon # memory_cost: 10 # Lowest possible value for argon

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace DoctrineMigrations; namespace DoctrineMigrations\Latest;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace DoctrineMigrations; namespace DoctrineMigrations\Latest;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace DoctrineMigrations; namespace DoctrineMigrations\Latest;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace DoctrineMigrations; namespace DoctrineMigrations\Latest;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace DoctrineMigrations; namespace DoctrineMigrations\Latest;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace DoctrineMigrations; namespace DoctrineMigrations\Latest;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace DoctrineMigrations; namespace DoctrineMigrations\Latest;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace DoctrineMigrations; namespace DoctrineMigrations\Latest;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace DoctrineMigrations; namespace DoctrineMigrations\Latest;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace DoctrineMigrations; namespace DoctrineMigrations\Latest;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration; use Doctrine\Migrations\AbstractMigration;

View File

@ -0,0 +1,140 @@
<?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 Version20241020235112 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 clients_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE commandes_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE details_commande_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE plats_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE reductions_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE reservations_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE statut_commandes_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE statut_tables_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE tables_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE utilisateurs_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE clients (id INT NOT NULL, prenom VARCHAR(255) NOT NULL, nom VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, telephone VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE clients_tables (clients_id INT NOT NULL, tables_id INT NOT NULL, PRIMARY KEY(clients_id, tables_id))');
$this->addSql('CREATE INDEX IDX_8190D6C6AB014612 ON clients_tables (clients_id)');
$this->addSql('CREATE INDEX IDX_8190D6C685405FD2 ON clients_tables (tables_id)');
$this->addSql('CREATE TABLE commandes (id INT NOT NULL, statut_commande_id INT DEFAULT NULL, date_heure TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, statut BOOLEAN NOT NULL, total DOUBLE PRECISION NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_35D4282CFB435DFD ON commandes (statut_commande_id)');
$this->addSql('CREATE TABLE commandes_clients (commandes_id INT NOT NULL, clients_id INT NOT NULL, PRIMARY KEY(commandes_id, clients_id))');
$this->addSql('CREATE INDEX IDX_C665A6248BF5C2E6 ON commandes_clients (commandes_id)');
$this->addSql('CREATE INDEX IDX_C665A624AB014612 ON commandes_clients (clients_id)');
$this->addSql('CREATE TABLE details_commande (id INT NOT NULL, commande_id INT DEFAULT NULL, quantite INT NOT NULL, prix_unitaire DOUBLE PRECISION NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_4BCD5F682EA2E54 ON details_commande (commande_id)');
$this->addSql('CREATE TABLE plats (id INT NOT NULL, reduction_id INT DEFAULT NULL, nom VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, prix DOUBLE PRECISION NOT NULL, categorie VARCHAR(255) NOT NULL, statut BOOLEAN NOT NULL, nb_de_commande INT NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_854A620AC03CB092 ON plats (reduction_id)');
$this->addSql('CREATE TABLE plats_commandes (plats_id INT NOT NULL, commandes_id INT NOT NULL, PRIMARY KEY(plats_id, commandes_id))');
$this->addSql('CREATE INDEX IDX_7F8CABAAAA14E1C8 ON plats_commandes (plats_id)');
$this->addSql('CREATE INDEX IDX_7F8CABAA8BF5C2E6 ON plats_commandes (commandes_id)');
$this->addSql('CREATE TABLE reductions (id INT NOT NULL, description VARCHAR(255) NOT NULL, prix DOUBLE PRECISION NOT NULL, pourcentage INT NOT NULL, montant_fixe VARCHAR(255) NOT NULL, date_debut TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, date_fin TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE reservations (id INT NOT NULL, tabl_id INT DEFAULT NULL, date_heure TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, nb_de_prsn INT NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_4DA2394DE1870D ON reservations (tabl_id)');
$this->addSql('CREATE TABLE statut_commandes (id INT NOT NULL, libelle VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE statut_tables (id INT NOT NULL, tabl_id INT DEFAULT NULL, libellé VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_33C8A3754DE1870D ON statut_tables (tabl_id)');
$this->addSql('CREATE TABLE tables (id INT NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE utilisateurs (id INT NOT NULL, nom VARCHAR(255) NOT NULL, prenom VARCHAR(255) NOT NULL, mail VARCHAR(255) NOT NULL, mot_de_passe VARCHAR(255) NOT NULL, role VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE utilisateurs_reservations (utilisateurs_id INT NOT NULL, reservations_id INT NOT NULL, PRIMARY KEY(utilisateurs_id, reservations_id))');
$this->addSql('CREATE INDEX IDX_995A78E71E969C5 ON utilisateurs_reservations (utilisateurs_id)');
$this->addSql('CREATE INDEX IDX_995A78E7D9A7F869 ON utilisateurs_reservations (reservations_id)');
$this->addSql('CREATE TABLE utilisateurs_tables (utilisateurs_id INT NOT NULL, tables_id INT NOT NULL, PRIMARY KEY(utilisateurs_id, tables_id))');
$this->addSql('CREATE INDEX IDX_A9A665291E969C5 ON utilisateurs_tables (utilisateurs_id)');
$this->addSql('CREATE INDEX IDX_A9A6652985405FD2 ON utilisateurs_tables (tables_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();');
$this->addSql('ALTER TABLE clients_tables ADD CONSTRAINT FK_8190D6C6AB014612 FOREIGN KEY (clients_id) REFERENCES clients (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE clients_tables ADD CONSTRAINT FK_8190D6C685405FD2 FOREIGN KEY (tables_id) REFERENCES tables (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE commandes ADD CONSTRAINT FK_35D4282CFB435DFD FOREIGN KEY (statut_commande_id) REFERENCES statut_commandes (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE commandes_clients ADD CONSTRAINT FK_C665A6248BF5C2E6 FOREIGN KEY (commandes_id) REFERENCES commandes (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE commandes_clients ADD CONSTRAINT FK_C665A624AB014612 FOREIGN KEY (clients_id) REFERENCES clients (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE details_commande ADD CONSTRAINT FK_4BCD5F682EA2E54 FOREIGN KEY (commande_id) REFERENCES commandes (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE plats ADD CONSTRAINT FK_854A620AC03CB092 FOREIGN KEY (reduction_id) REFERENCES reductions (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE plats_commandes ADD CONSTRAINT FK_7F8CABAAAA14E1C8 FOREIGN KEY (plats_id) REFERENCES plats (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE plats_commandes ADD CONSTRAINT FK_7F8CABAA8BF5C2E6 FOREIGN KEY (commandes_id) REFERENCES commandes (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE reservations ADD CONSTRAINT FK_4DA2394DE1870D FOREIGN KEY (tabl_id) REFERENCES tables (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE statut_tables ADD CONSTRAINT FK_33C8A3754DE1870D FOREIGN KEY (tabl_id) REFERENCES tables (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE utilisateurs_reservations ADD CONSTRAINT FK_995A78E71E969C5 FOREIGN KEY (utilisateurs_id) REFERENCES utilisateurs (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE utilisateurs_reservations ADD CONSTRAINT FK_995A78E7D9A7F869 FOREIGN KEY (reservations_id) REFERENCES reservations (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE utilisateurs_tables ADD CONSTRAINT FK_A9A665291E969C5 FOREIGN KEY (utilisateurs_id) REFERENCES utilisateurs (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE utilisateurs_tables ADD CONSTRAINT FK_A9A6652985405FD2 FOREIGN KEY (tables_id) REFERENCES tables (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP SEQUENCE clients_id_seq CASCADE');
$this->addSql('DROP SEQUENCE commandes_id_seq CASCADE');
$this->addSql('DROP SEQUENCE details_commande_id_seq CASCADE');
$this->addSql('DROP SEQUENCE plats_id_seq CASCADE');
$this->addSql('DROP SEQUENCE reductions_id_seq CASCADE');
$this->addSql('DROP SEQUENCE reservations_id_seq CASCADE');
$this->addSql('DROP SEQUENCE statut_commandes_id_seq CASCADE');
$this->addSql('DROP SEQUENCE statut_tables_id_seq CASCADE');
$this->addSql('DROP SEQUENCE tables_id_seq CASCADE');
$this->addSql('DROP SEQUENCE utilisateurs_id_seq CASCADE');
$this->addSql('ALTER TABLE clients_tables DROP CONSTRAINT FK_8190D6C6AB014612');
$this->addSql('ALTER TABLE clients_tables DROP CONSTRAINT FK_8190D6C685405FD2');
$this->addSql('ALTER TABLE commandes DROP CONSTRAINT FK_35D4282CFB435DFD');
$this->addSql('ALTER TABLE commandes_clients DROP CONSTRAINT FK_C665A6248BF5C2E6');
$this->addSql('ALTER TABLE commandes_clients DROP CONSTRAINT FK_C665A624AB014612');
$this->addSql('ALTER TABLE details_commande DROP CONSTRAINT FK_4BCD5F682EA2E54');
$this->addSql('ALTER TABLE plats DROP CONSTRAINT FK_854A620AC03CB092');
$this->addSql('ALTER TABLE plats_commandes DROP CONSTRAINT FK_7F8CABAAAA14E1C8');
$this->addSql('ALTER TABLE plats_commandes DROP CONSTRAINT FK_7F8CABAA8BF5C2E6');
$this->addSql('ALTER TABLE reservations DROP CONSTRAINT FK_4DA2394DE1870D');
$this->addSql('ALTER TABLE statut_tables DROP CONSTRAINT FK_33C8A3754DE1870D');
$this->addSql('ALTER TABLE utilisateurs_reservations DROP CONSTRAINT FK_995A78E71E969C5');
$this->addSql('ALTER TABLE utilisateurs_reservations DROP CONSTRAINT FK_995A78E7D9A7F869');
$this->addSql('ALTER TABLE utilisateurs_tables DROP CONSTRAINT FK_A9A665291E969C5');
$this->addSql('ALTER TABLE utilisateurs_tables DROP CONSTRAINT FK_A9A6652985405FD2');
$this->addSql('DROP TABLE clients');
$this->addSql('DROP TABLE clients_tables');
$this->addSql('DROP TABLE commandes');
$this->addSql('DROP TABLE commandes_clients');
$this->addSql('DROP TABLE details_commande');
$this->addSql('DROP TABLE plats');
$this->addSql('DROP TABLE plats_commandes');
$this->addSql('DROP TABLE reductions');
$this->addSql('DROP TABLE reservations');
$this->addSql('DROP TABLE statut_commandes');
$this->addSql('DROP TABLE statut_tables');
$this->addSql('DROP TABLE tables');
$this->addSql('DROP TABLE utilisateurs');
$this->addSql('DROP TABLE utilisateurs_reservations');
$this->addSql('DROP TABLE utilisateurs_tables');
$this->addSql('DROP TABLE messenger_messages');
}
}

View File

@ -0,0 +1,34 @@
<?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 Version20241024193330 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('ALTER TABLE utilisateurs ALTER role TYPE JSON USING role::json');
$this->addSql('COMMENT ON COLUMN utilisateurs.role IS NULL');
}
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('ALTER TABLE utilisateurs ALTER role TYPE TEXT');
$this->addSql('COMMENT ON COLUMN utilisateurs.role IS \'(DC2Type:array)\'');
}
}

152
public/css/modal.css Normal file
View File

@ -0,0 +1,152 @@
.top-bar {
background-color: #db5559;
width: calc(100% - 18%); /*Calcule la totalité de l'écran - le left-background */
height: 60px;
position: fixed;
top: 0;
left: 18%; /*Evite le chauvechement des 2 bars */
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
color: white;
font-size: 18px;
box-sizing: border-box; /* Inclut le padding dans la largeur totale */
}
.user-role {
background-color: white;
color: black;
padding: 10px 15px;
font-weight: bold;
overflow: hidden;
}
.left-background {
background-color: #db5559;
width: 18%;
height: 100%;
position: fixed;
top: 0;
left: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.index-title-page {
color: #FFFFFF;
font-size: 60px;
padding-bottom: 10px;
font-family: 'Brittany Signature', sans-serif;
}
ul {
list-style-type: none;
padding: 0;
}
li {
padding-bottom: 30px;
}
.btn-custom {
background-color: #FFFFFF;
color: black;
padding: 15px 40px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
display: inline-block;
border-right: 5px solid #db5559;
border-left: 5px solid #db5559;
}
.btn-custom:hover, .btn-info-compte:hover, .btn-info-exit:hover {
background-color: #f8b5b5;
color: #FFFFFF;
}
.icon-medium {
width: 25px;
height: 25px;
}
.icon-container {
display: flex;
align-items: center;
gap: 10px;
}
.Information-perso {
display: flex;
justify-content: space-between;
padding: 20px;
margin-top: auto;
}
.btn-info-compte, .btn-info-exit {
background-color: #FFFFFF;
color: black;
padding: 10px 20px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
border: 1px solid black;
}
.btn-info-compte {
width: 50%;
height: 30px;
}
.btn-info-exit {
width: 10%;
height: 30px;
}
/* Style pour la modal (cachée par défaut) */
.modal {
display: none; /* Masquée par défaut */
position: fixed;
z-index: 1; /* Au-dessus du contenu normal */
left: 18%; /* Commence juste après ton left-background */
top: 0;
width: 82%; /* Prend le reste de la largeur après le left-background */
height: 100%; /* Prend toute la hauteur de l'écran */
background-color: rgba(0, 0, 0, 0.4); /* Couleur d'arrière-plan avec transparence */
overflow: auto; /* Permet le défilement si le contenu dépasse */
}
/* Contenu de la modal */
.modal-content {
background-color: white;
margin: 5% auto; /* Centrage vertical */
padding: 20px;
border: 1px solid black;
width: 80%; /* Largeur du contenu de la modal */
height: 80%; /* Hauteur du contenu de la modal */
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2);
}
/* Bouton de fermeture */
.close {
color: black;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: red;
cursor: pointer;
}

38
public/js/modal.js Normal file
View File

@ -0,0 +1,38 @@
document.addEventListener('DOMContentLoaded', function() {
// Fonction pour ouvrir la modal
function openModal(modalId) {
const modal = document.getElementById(modalId);
if (modal) {
modal.style.display = "block";
}
}
// Fonction pour fermer la modal
function closeModal(modalId) {
const modal = document.getElementById(modalId);
if (modal) {
modal.style.display = "none";
}
}
// Ouvre les modals lorsqu'un bouton est cliqué
document.body.addEventListener('click', function(event) {
if (event.target.matches('span[data-modal]')) {
const modalId = event.target.getAttribute('data-modal');
openModal(modalId);
}
// Ferme la modal lorsqu'on clique sur le bouton de fermeture
if (event.target.matches('.close[data-modal]')) {
const modalId = event.target.getAttribute('data-modal');
closeModal(modalId);
}
// Ferme la modal lorsqu'on clique en dehors du contenu
document.querySelectorAll('.modal').forEach(modal => {
if (event.target === modal) {
modal.style.display = "none";
}
});
});
});

View File

@ -0,0 +1,46 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class CuisinierController extends AbstractController
{
#[Route('/cuisinier/ajouter', name: 'ajouter_cuisinier')]
public function ajouter(Request $request, EntityManagerInterface $entityManager): Response
{
$cuisinier = new Cuisinier();
$form = $this->createForm(CuisinierType::class, $cuisinier);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->persist($cuisinier);
$entityManager->flush();
$this->addFlash('success', 'Cuisinier ajouté avec succès !');
return $this->redirectToRoute('ajouter_cuisinier');
}
return $this->render('cuisinier/ajouter.html.twig', [
'form' => $form->createView(),
]);
}
#[Route('/cuisinier/supprimer/{id}', name: 'supprimer_cuisinier', methods: ['POST'])]
public function supprimer(int $id, EntityManagerInterface $entityManager): Response
{
$cuisinier = $entityManager->getRepository(Cuisinier::class)->find($id);
if (!$cuisinier) {
throw $this->createNotFoundException('Ce cuisinier n\'existe pas');
}
$entityManager->remove($cuisinier);
$entityManager->flush();
$this->addFlash('success', 'Cuisinier supprimé avec succès !');
return $this->redirectToRoute('ajouter_cuisinier');
}
}

View File

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

View File

@ -2,22 +2,37 @@
namespace App\Controller; namespace App\Controller;
use App\Form\LoginFormType;
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\Attribute\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class LoginController extends AbstractController class LoginController extends AbstractController
{ {
#[Route('/login', name: 'app_login')] #[Route('/login', name: 'app_login')]
public function index(Request $request): Response public function index(AuthenticationUtils $authenticationUtils): Response
{ {
$form = $this->createForm(LoginFormType::class); // get the login error if there is one
$form->handleRequest($request); $error = $authenticationUtils->getLastAuthenticationError();
return $this->render('login/login.html.twig',[ // last username entered by the user
'form' => $form->createView(), $lastUsername = $authenticationUtils->getLastUsername();
return $this->render('login/index.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}
#[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.');
}
#[Route('/access/denied', name: 'app_access_denied')]
public function denied(): Response
{
return $this->render('access_denied/index.html.twig', [
'controller_name' => 'AccessDeniedController',
]); ]);
} }
} }

View File

@ -0,0 +1,93 @@
<?php
namespace App\Controller;
use App\Entity\Utilisateurs;
use App\Form\UpdateUserType;
use App\Repository\UtilisateursRepository;
use App\Form\AddUserFormType;
use App\Security\LoginAuthenticator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
class UserController extends AbstractController
{
public function __construct(UtilisateursRepository $utilisateursRepository)
{
$this->utilisateursRepository = $utilisateursRepository;
}
#[Route('/user/add', name: 'add_user')]
public function register(Request $request, UserPasswordHasherInterface $userPasswordHasher, Security $security, EntityManagerInterface $entityManager): Response
{
$user = new Utilisateurs();
$form = $this->createForm(AddUserFormType::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();
// do anything else you need here, like send an email
return $security->login($user, LoginAuthenticator::class, 'main');
}
return $this->render('user/add.html.twig', [
'registrationForm' => $form,
]);
}
#[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')]
public function list(): Response
{
$utilisateur = $this->utilisateursRepository->findAll();
return $this->render('user/list.html.twig', [
'utilisateurs' => $utilisateur
]);
}
#[Route('/gestion-user', name: 'gestion_user', methods: ['GET'])]
public function index(): Response
{
return $this->render('gestion_user/index.html.twig');
}
}

View File

@ -30,8 +30,8 @@ class Clients
/** /**
* @var Collection<int, Tables> * @var Collection<int, Tables>
*/ */
#[ORM\ManyToMany(targetEntity: Tables::class, inversedBy: 'Tabl')] #[ORM\ManyToMany(targetEntity: Tables::class, inversedBy: 'Client')]
private Collection $Tabl; private Collection $table;
/** /**
* @var Collection<int, Commandes> * @var Collection<int, Commandes>
@ -41,7 +41,7 @@ class Clients
public function __construct() public function __construct()
{ {
$this->Tabl = new ArrayCollection(); $this->table = new ArrayCollection();
$this->commandes = new ArrayCollection(); $this->commandes = new ArrayCollection();
} }
@ -101,23 +101,23 @@ class Clients
/** /**
* @return Collection<int, Tables> * @return Collection<int, Tables>
*/ */
public function getTabl(): Collection public function getTable(): Collection
{ {
return $this->Tabl; return $this->table;
} }
public function addTabl(Tables $tabl): static public function addTable(Tables $table): static
{ {
if (!$this->Tabl->contains($tabl)) { if (!$this->table->contains($table)) {
$this->Tabl->add($tabl); $this->table->add($table);
} }
return $this; return $this;
} }
public function removeTabl(Tables $tabl): static public function removeTable(Tables $table): static
{ {
$this->Tabl->removeElement($tabl); $this->table->removeElement($table);
return $this; return $this;
} }

View File

@ -23,7 +23,7 @@ class Reservations
private ?int $Nb_de_prsn = null; private ?int $Nb_de_prsn = null;
#[ORM\ManyToOne(inversedBy: 'reservations')] #[ORM\ManyToOne(inversedBy: 'reservations')]
private ?Tables $Tabl = null; private ?Tables $Table = null;
/** /**
* @var Collection<int, Utilisateurs> * @var Collection<int, Utilisateurs>
@ -65,14 +65,14 @@ class Reservations
return $this; return $this;
} }
public function getTabl(): ?Tables public function getTable(): ?Tables
{ {
return $this->Tabl; return $this->Table;
} }
public function setTabl(?Tables $Tabl): static public function setTable(?Tables $Table): static
{ {
$this->Tabl = $Tabl; $this->Table = $Table;
return $this; return $this;
} }

View File

@ -17,7 +17,7 @@ class StatutTables
private ?string $Libellé = null; private ?string $Libellé = null;
#[ORM\ManyToOne(inversedBy: 'statutTables')] #[ORM\ManyToOne(inversedBy: 'statutTables')]
private ?Tables $Tabl = null; private ?Tables $Table = null;
public function getId(): ?int public function getId(): ?int
{ {
@ -36,14 +36,14 @@ class StatutTables
return $this; return $this;
} }
public function getTabl(): ?Tables public function getTable(): ?Tables
{ {
return $this->Tabl; return $this->Table;
} }
public function setTabl(?Tables $Tabl): static public function setTable(?Tables $Table): static
{ {
$this->Tabl = $Tabl; $this->Table = $Table;
return $this; return $this;
} }

View File

@ -18,25 +18,25 @@ class Tables
/** /**
* @var Collection<int, Clients> * @var Collection<int, Clients>
*/ */
#[ORM\ManyToMany(targetEntity: Clients::class, mappedBy: 'Tabl')] #[ORM\ManyToMany(targetEntity: Clients::class, mappedBy: 'table')]
private Collection $Clients; private Collection $Clients;
/** /**
* @var Collection<int, Reservations> * @var Collection<int, Reservations>
*/ */
#[ORM\OneToMany(targetEntity: Reservations::class, mappedBy: 'Tabl')] #[ORM\OneToMany(targetEntity: Reservations::class, mappedBy: 'Table')]
private Collection $reservations; private Collection $reservations;
/** /**
* @var Collection<int, StatutTables> * @var Collection<int, StatutTables>
*/ */
#[ORM\OneToMany(targetEntity: StatutTables::class, mappedBy: 'Tabl')] #[ORM\OneToMany(targetEntity: StatutTables::class, mappedBy: 'Table')]
private Collection $statutTables; private Collection $statutTables;
/** /**
* @var Collection<int, Utilisateurs> * @var Collection<int, Utilisateurs>
*/ */
#[ORM\ManyToMany(targetEntity: Utilisateurs::class, mappedBy: 'tabl')] #[ORM\ManyToMany(targetEntity: Utilisateurs::class, mappedBy: 'table')]
private Collection $utilisateurs; private Collection $utilisateurs;
public function __construct() public function __construct()
@ -60,20 +60,20 @@ class Tables
return $this->Clients; return $this->Clients;
} }
public function addClient(Clients $tabl): static public function addClient(Clients $table): static
{ {
if (!$this->Clients->contains($tabl)) { if (!$this->Clients->contains($table)) {
$this->Clients->add($tabl); $this->Clients->add($table);
$tabl->addTabl($this); $table->addTable($this);
} }
return $this; return $this;
} }
public function removeClient(Clients $tabl): static public function removeClient(Clients $table): static
{ {
if ($this->Clients->removeElement($tabl)) { if ($this->Clients->removeElement($table)) {
$tabl->removeTabl($this); $table->removeTable($this);
} }
return $this; return $this;
@ -91,7 +91,7 @@ class Tables
{ {
if (!$this->reservations->contains($reservation)) { if (!$this->reservations->contains($reservation)) {
$this->reservations->add($reservation); $this->reservations->add($reservation);
$reservation->setTabl($this); $reservation->setTable($this);
} }
return $this; return $this;
@ -101,8 +101,8 @@ class Tables
{ {
if ($this->reservations->removeElement($reservation)) { if ($this->reservations->removeElement($reservation)) {
// set the owning side to null (unless already changed) // set the owning side to null (unless already changed)
if ($reservation->getTabl() === $this) { if ($reservation->getTable() === $this) {
$reservation->setTabl(null); $reservation->setTable(null);
} }
} }
@ -121,7 +121,7 @@ class Tables
{ {
if (!$this->statutTables->contains($statutTable)) { if (!$this->statutTables->contains($statutTable)) {
$this->statutTables->add($statutTable); $this->statutTables->add($statutTable);
$statutTable->setTabl($this); $statutTable->setTable($this);
} }
return $this; return $this;
@ -131,8 +131,8 @@ class Tables
{ {
if ($this->statutTables->removeElement($statutTable)) { if ($this->statutTables->removeElement($statutTable)) {
// set the owning side to null (unless already changed) // set the owning side to null (unless already changed)
if ($statutTable->getTabl() === $this) { if ($statutTable->getTable() === $this) {
$statutTable->setTabl(null); $statutTable->setTable(null);
} }
} }
@ -151,7 +151,7 @@ class Tables
{ {
if (!$this->utilisateurs->contains($utilisateur)) { if (!$this->utilisateurs->contains($utilisateur)) {
$this->utilisateurs->add($utilisateur); $this->utilisateurs->add($utilisateur);
$utilisateur->addTabl($this); $utilisateur->addTable($this);
} }
return $this; return $this;
@ -160,7 +160,7 @@ class Tables
public function removeUtilisateur(Utilisateurs $utilisateur): static public function removeUtilisateur(Utilisateurs $utilisateur): static
{ {
if ($this->utilisateurs->removeElement($utilisateur)) { if ($this->utilisateurs->removeElement($utilisateur)) {
$utilisateur->removeTabl($this); $utilisateur->removeTable($this);
} }
return $this; return $this;

View File

@ -6,12 +6,14 @@ use App\Repository\UtilisateursRepository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
#[ORM\Entity(repositoryClass: UtilisateursRepository::class)] #[ORM\Entity(repositoryClass: UtilisateursRepository::class)]
class Utilisateurs class Utilisateurs implements UserInterface, PasswordAuthenticatedUserInterface
{ {
#[ORM\Id] #[ORM\Id]
#[ORM\GeneratedValue] #[ORM\GeneratedValue(strategy: 'SEQUENCE')]
#[ORM\Column] #[ORM\Column]
private ?int $id = null; private ?int $id = null;
@ -21,14 +23,14 @@ class Utilisateurs
#[ORM\Column(length: 255)] #[ORM\Column(length: 255)]
private ?string $Prenom = null; private ?string $Prenom = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255, unique: true)]
private ?string $Mail = null; private ?string $Mail = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255)]
private ?string $MotDePasse = null; private ?string $MotDePasse = null;
#[ORM\Column(length: 255)] #[ORM\Column(type: 'json', length: 255)]
private ?string $Role = null; private array $Role = [];
/** /**
* @var Collection<int, Reservations> * @var Collection<int, Reservations>
@ -40,12 +42,12 @@ class Utilisateurs
* @var Collection<int, Tables> * @var Collection<int, Tables>
*/ */
#[ORM\ManyToMany(targetEntity: Tables::class, inversedBy: 'utilisateurs')] #[ORM\ManyToMany(targetEntity: Tables::class, inversedBy: 'utilisateurs')]
private Collection $tabl; private Collection $table;
public function __construct() public function __construct()
{ {
$this->Reservation = new ArrayCollection(); $this->Reservation = new ArrayCollection();
$this->tabl = new ArrayCollection(); $this->table = new ArrayCollection();
} }
public function getId(): ?int public function getId(): ?int
@ -77,42 +79,57 @@ class Utilisateurs
return $this; return $this;
} }
public function getMail(): ?string public function getUserIdentifier(): string
{ {
return $this->Mail; return $this->Mail;
} }
public function setMail(string $Mail): static public function setUserIdentifier(string $userIdentifier): self
{ {
$this->Mail = $Mail; $this->Mail = $userIdentifier;
return $this; return $this;
} }
public function getMotDePasse(): ?string public function getPassword(): ?string
{ {
return $this->MotDePasse; return $this->MotDePasse;
} }
public function setMotDePasse(string $MotDePasse): static public function setPassword(string $MotDePasse): static
{ {
$this->MotDePasse = $MotDePasse; $this->MotDePasse = $MotDePasse;
return $this; return $this;
} }
public function getRole(): ?string public function getRoles(): array
{ {
return $this->Role; return $this->Role;
} }
public function setRole(string $Role): static public function getRolesAsString(): string
{
// Supprime le préfixe "ROLE_" et formate en majuscule seulement la première lettre
$roles = array_map(function($role) {
return ucfirst(strtolower(str_replace('ROLE_', '', $role)));
}, $this->Role);
return implode(', ', $roles);
}
public function setRoles(array $Role): self
{ {
$this->Role = $Role; $this->Role = $Role;
return $this; return $this;
} }
public function eraseCredentials(): void
{
// Méthode pour effacer les données sensibles (ex : plaintext password)
}
/** /**
* @return Collection<int, Reservations> * @return Collection<int, Reservations>
*/ */
@ -140,23 +157,23 @@ class Utilisateurs
/** /**
* @return Collection<int, Tables> * @return Collection<int, Tables>
*/ */
public function getTabl(): Collection public function getTable(): Collection
{ {
return $this->tabl; return $this->table;
} }
public function addTabl(Tables $tabl): static public function addTable(Tables $table): static
{ {
if (!$this->tabl->contains($tabl)) { if (!$this->table->contains($table)) {
$this->tabl->add($tabl); $this->table->add($table);
} }
return $this; return $this;
} }
public function removeTabl(Tables $tabl): static public function removeTable(Tables $table): static
{ {
$this->tabl->removeElement($tabl); $this->table->removeElement($table);
return $this; return $this;
} }

View File

@ -0,0 +1,59 @@
<?php
namespace App\Form;
use App\Entity\Utilisateurs;
use App\Entity\Tables;
use App\Entity\Clients;
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\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
class AddUserFormType 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,
])
->add('Enregistrer', SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Utilisateurs::class,
]);
}
}

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

@ -0,0 +1,66 @@
<?php
namespace App\Security;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\SecurityRequestAttributes;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
class LoginAuthenticator extends AbstractLoginFormAuthenticator
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'app_login';
public function __construct(private UrlGeneratorInterface $urlGenerator)
{
}
public function authenticate(Request $request): Passport
{
$mail = $request->getPayload()->getString('UserIdentifier');
$request->getSession()->set(SecurityRequestAttributes::LAST_USERNAME, $mail);
return new Passport(
new UserBadge($mail),
new PasswordCredentials($request->getPayload()->getString('Password')),
[
new CsrfTokenBadge('authenticate', $request->getPayload()->getString('_csrf_token')),
new RememberMeBadge(),
]
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
return new RedirectResponse($targetPath);
}
// For example:
return new RedirectResponse($this->urlGenerator->generate('app_index'));
}
public function start(Request $request, ?AuthenticationException $authException = null): RedirectResponse
{
return new RedirectResponse($this->urlGenerator->generate('app_access_denied'));
}
protected function getLoginUrl(Request $request): string
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}

View File

@ -248,6 +248,18 @@
"templates/base.html.twig" "templates/base.html.twig"
] ]
}, },
"symfony/ux-icons": {
"version": "2.21",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "2.17",
"ref": "803a3bbd5893f9584969ab8670290cdfb6a0a5b5"
},
"files": [
"./assets/icons/symfony.svg"
]
},
"symfony/ux-turbo": { "symfony/ux-turbo": {
"version": "v2.20.0" "version": "v2.20.0"
}, },

View File

@ -0,0 +1,58 @@
<div id="compteModal" class="modal" tabindex="-1" aria-labelledby="compteModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<span class="close" data-modal="compteModal">&times;</span>
<h2 class="modal-header" id="compteModalLabel">Gestion Compte</h2>
<div class="modal-body">
<!-- Contenu de la modal Gestion Utilisateur -->
<div id="InformationUser">
<div id="NomUser">
<span>Nom : {{ app.user.nom }}</span>
</div>
<div id="NomUser">
<span>Prenom : {{ app.user.prenom }}</span>
</div>
<div id="NomUser">
<span>Email : {{ app.user.userIdentifier }}</span>
</div>
<div id="NomUser">
<span>Roles : {{ app.user.getRolesAsString() }}</span>
</div>
<div class="btn-custom icon-container" data-bs-toggle="modal" data-bs-target="#modifModal">
<i class="icon-medium"> {{ ux_icon('fluent-emoji-high-contrast:ten-oclock') }}</i>
<span>Modifier</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Modal de Modification des Informations Utilisateur -->
<div id="modifModal" class="modal" tabindex="-1" aria-labelledby="modifModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modifModalLabel">Modifier Informations Utilisateur</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form>
<div class="mb-3">
<label for="newEmail" class="form-label">Nouvel Email</label>
<input type="email" class="form-control" id="newEmail" placeholder="Entrez votre nouvel email">
</div>
<div class="mb-3">
<label for="newNom" class="form-label">Nouveau Nom</label>
<input type="text" class="form-control" id="newNom" placeholder="Entrez votre nouveau nom">
</div>
<div class="mb-3">
<label for="newPrenom" class="form-label">Nouveau Prenom</label>
<input type="text" class="form-control" id="newPrenom" placeholder="Entrez votre nouveau prenom">
</div>
<button type="submit" class="btn btn-primary">Confirmer</button>
</form>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,8 @@
<div id="tableModal" class="modal">
<div class="modal-content">
<span class="close" data-modal="tableModal">&times;</span>
<h2>Gestion Table</h2>
<!-- Contenu de la modal Gestion Table -->
<p>Ajouter ici le formulaire ou les informations pour gérer les tables.</p>
</div>
</div>

View File

@ -0,0 +1,8 @@
<div id="userModal" class="modal">
<div class="modal-content">
<span class="close" data-modal="userModal">&times;</span>
<h2>Gestion Utilisateur</h2>
<!-- Contenu de la modal Gestion Utilisateur -->
<p>Ajouter ici le formulaire ou les informations pour gérer les utilisateurs.</p>
</div>
</div>

View File

@ -0,0 +1,28 @@
{% extends 'base.html.twig' %}
{% block title %}Accès Refusé{% endblock %}
{% block body %}
<style>
.container {
margin-top: 50px;
text-align: center;
background-color: orange;
}
h1 {
color: #dc3545;
}
.btn {
margin-top: 20px;
}
</style>
<div class="container">
<h1>Accès Refusé</h1>
<p>Vous n'avez pas les permissions nécessaires pour accéder à cette page.</p>
<a href="{{ path('app_login') }}" class="btn btn-primary">Ce connecter</a>
</div>
{% endblock %}

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

@ -0,0 +1,138 @@
{% extends 'base.html.twig' %}
{% block head %}
<head>
<meta charset="UTF-8">
<title>{% block title %}Index FestinHegre!{% 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>">
<link href="https://fonts.cdnfonts.com/css/brittany-signature" rel="stylesheet">
</head>
{% endblock %}
{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('css/modal.css') }}"> <!-- Ajout du fichier CSS -->
{% endblock %}
{% block body %}
<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 -->
<div class="top-bar">
<div>
Bonjour, {{ app.user.prenom }}
</div>
<div class="user-role">
Rôle : {{ app.user.getRolesAsString() }}
</div>
</div>
<!-- Left Menu -->
<div class="left-background">
<img class="LogoHegre" src="{{ asset('asset/image/LogoHegre.png') }}">
<div class="nav-bar">
<ul>
<li>
<div class="btn-custom icon-container">
<i class="icon-medium"> {{ ux_icon('grommet-icons:group') }}</i>
<span data-modal="userModal">Gérer Utilisateur</span>
</div>
</li>
<li>
<div class="btn-custom icon-container">
<i class="icon-medium"> {{ ux_icon('ic:outline-table-bar') }}</i>
<span data-modal="tableModal">Gérer Table</span>
</div>
</li>
<li>
<div class="btn-custom icon-container">
<i class="icon-medium"> {{ ux_icon('bx:food-menu') }}</i>
<span>Gestion Menu</span>
</div>
</li>
<li>
<div class="btn-custom icon-container">
<i class="icon-medium"> {{ ux_icon('lsicon:badge-promotion-outline') }}</i>
<span>Gestion Promotion</span>
</div>
</li>
<li>
<div class="btn-custom icon-container">
<i class="icon-medium"> {{ ux_icon('fluent-emoji-high-contrast:ten-oclock') }}</i>
<span>Voir tendances</span>
</div>
</li>
</ul>
</div>
<div class="Information-perso">
<div class="btn-info-compte icon-container">
<i class="icon-medium"> {{ ux_icon('ph:user-circle-fill') }}</i>
<span>Compte</span>
</div>
<div class="btn-info-exit icon-container">
<a href="{{ path('app_logout') }}" class="icon-medium">
{{ ux_icon('iconamoon:exit-bold') }}
</a>
</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/gestionUtilisateurModal.html.twig' %}
{% include 'Modals/gestionTableModal.html.twig' %}
{% include 'Modals/gestionCompteModal.html.twig' %}
{% include 'Modals/gestionUtilisateurModal.html.twig' %}
{% endblock %}
{% block javascripts %}
<script src="{{ asset('js/modal.js') }}"></script> <!-- Ajout du fichier JS -->
{% endblock %}

View File

@ -60,6 +60,7 @@
} }
.Title1 { .Title1 {
font-size: 60px;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
@ -101,22 +102,33 @@
<div class="Circle"> <div class="Circle">
<img src="asset/image/LogoHegre.png" class="Logo"> <img src="asset/image/LogoHegre.png" class="Logo">
<div class="Form"> <div class="Form">
{{ form_start(form) }} <form method="post">
<h1 class="Title1">Bienvenue !</h1> <h1 class="Title1">Bienvenue !</h1>
<div class="form-group"> <div class="form-group">
{{ form_label(form.email) }} <label for="UserIdentifier">Email:</label>
{{ form_widget(form.email, {'attr': {'class': 'form-control'}}) }} <input type="text" id="UserIdentifier" name="UserIdentifier" value="{{ last_username }}" required autofocus>
</div> </div>
<div class="form-group"> <div class="form-group">
{{ form_label(form.password) }} <label for="Password">Mot de passe:</label>
{{ form_widget(form.password, {'attr': {'class': 'form-control'}}) }} <input type="password" id="Password" name="Password" required>
</div> </div>
<input type="hidden" name="_csrf_token"
value="{{ csrf_token('authenticate') }}"
>
<div class="form-group"> <div class="form-group">
{{ form_widget(form.confirm, {'attr': {'class': 'btn btn-primary'}}) }} <button class="btn btn-lg btn-primary" type="submit">
</div> Connexion
{{ form_end(form) }} </button>
</div> </div>
<h1 class="Title2">Volaille en fête, Saveurs parfaites !</h1> <h1 class="Title2">Volaille en fête, Saveurs parfaites !</h1>
</form>
</div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,105 @@
{% extends 'base.html.twig' %}
{% block stylesheets %}
<style>
.form-container {
max-width: 500px;
margin: 0 auto;
padding: 20px;
background-color: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
font-family: sans-serif;
}
.form-container h1 {
text-align: center;
margin-bottom: 20px;
font-size: 24px;
}
.form-group {
margin-bottom: 15px;
}
.form-input {
display: flex;
justify-content: center;
margin-bottom: 20px;
width: 95%;
padding: 10px;
border: 1px solid #ced4da;
border-radius: 4px;
font-size: 16px;
}
.form-input:focus {
border-color: #007bff;
box-shadow: 0 0 5px rgba(0, 123, 255, 0.25);
outline: none;
}
.btn-container {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
.btn-save {
padding: 5px 10px;
text-decoration: none;
color: white;
background-color: #007bff;
border-radius: 5px;
font-weight: bold;
margin-top: 25px;
}
.btn-list {
padding: 5px 10px;
text-decoration: none;
color: white;
background-color: orange;
border-radius: 5px;
font-weight: bold;
}
</style>
{% endblock %}
{% block title %}Nouvelle Utilisateur{% endblock %}
{% block body %}
<div class="form-container">
<h1>Nouvelle Utilisateur ! ✅</h1>
{{ form_start(registrationForm) }}
{{ form_errors(registrationForm) }}
<div class="form-group">
{{ form_row(registrationForm.Nom, {'attr': {'class': 'form-input'}, 'label': 'Nom'}) }}
</div>
<div class="form-group">
{{ form_row(registrationForm.Prenom, {'attr': {'class': 'form-input'}, 'label': 'Prénom'}) }}
</div>
<div class="form-group">
{{ form_row(registrationForm.UserIdentifier, {'attr': {'class': 'form-input'}, 'label': 'Email'}) }}
</div>
<div class="form-group">
{{ form_row(registrationForm.Password, {'attr': {'class': 'form-input'}, 'label': 'Password'}) }}
</div>
<div class="form-group">
{{ form_row(registrationForm.Roles, {'attr': {'class': 'form-input'}, 'label': 'Roles'}) }}
</div>
<div class="btn-container">
{{ form_row(registrationForm.Enregistrer, {'attr': {'class': 'btn-save'}, 'label': 'Enregistrer'}) }}
</div>
{{ form_end(registrationForm) }}
<div class="btn-container">
<a href="{{ path('list_user') }}" class="btn-list btn-primary">Liste des Utilisateur</a>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,84 @@
{% extends 'base.html.twig' %}
{% block title %}Liste Utilisateur{% endblock %}
{% block body %}
<style>
.user-table {
width: 100%;
border-collapse: collapse;
font-family: sans-serif;
}
.user-table th,
.user-table td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
.user-table th {
background-color: #f2f2f2;
font-weight: bold;
}
.user-table tr:nth-child(even) {
background-color: #f9f9f9;
}
.user-table tr:hover {
background-color: #f1f1f1;
}
.btn-container {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
.btn {
padding: 5px 10px;
text-decoration: none;
color: white;
background-color: #007bff;
border-radius: 5px;
font-weight: bold;
margin-top: 25px;
}
</style>
<div class="example-wrapper">
<h1>Liste des Utilisateurs ! ✅</h1>
<table class="user-table">
<thead>
<tr>
<th>ID</th>
<th>Nom</th>
<th>Prenom</th>
<th>Mail</th>
<th>Roles</th>
</tr>
</thead>
<tbody>
{% for utilisateur in utilisateurs %}
<tr>
<td>{{ utilisateur.id }}</td>
<td>{{ utilisateur.nom }}</td>
<td>{{ utilisateur.prenom }}</td>
<td>{{ utilisateur.UserIdentifier }}</td>
<td>{{ utilisateur.roles|join }}</td>
</tr>
{% else %}
<tr>
<td colspan="5">Aucun utilisateur trouvé.</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="btn-container">
<a href="{{ path('add_user') }}" class="btn btn-primary">Ajouter un Utilisateur</a>
</div>
</div>
{% endblock %}