From 5e25f5ee492e3e57249719a6adcb21fb86eca32a Mon Sep 17 00:00:00 2001
From: Eric WAGNER <eric.wagner@etu.unistra.fr>
Date: Sat, 1 Apr 2023 13:48:07 +0200
Subject: [PATCH] =?UTF-8?q?Projet=20termin=C3=A9=20avant=20d=C3=A9poloieme?=
 =?UTF-8?q?nt?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 config/packages/security.yaml           | 16 ++++-
 src/Controller/LoginFormController.php  | 43 ++++++++++++++
 src/Security/LoginFormAuthenticator.php | 58 +++++++++++++++++++
 templates/cart/index.html.twig          | 77 ++++++++++---------------
 templates/category/show.html.twig       | 22 +++----
 templates/clothes/index.html.twig       | 63 ++++++++++----------
 templates/ecurie/index.html.twig        |  2 -
 templates/ecurie/show.html.twig         | 52 +++++++++--------
 templates/home.html.twig                |  4 +-
 templates/layouts/_header.html.twig     | 28 +++++----
 templates/security/login.html.twig      | 42 ++++++++++++++
 11 files changed, 281 insertions(+), 126 deletions(-)
 create mode 100644 src/Controller/LoginFormController.php
 create mode 100644 src/Security/LoginFormAuthenticator.php
 create mode 100644 templates/security/login.html.twig

diff --git a/config/packages/security.yaml b/config/packages/security.yaml
index 5f130df..7b32bea 100644
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -17,6 +17,11 @@ security:
         main:
             lazy: true
             provider: app_user_provider
+            custom_authenticator: App\Security\LoginFormAuthenticator
+            logout:
+                path: app_logout
+                # where to redirect after logout
+                target: home
 
             # activate different ways to authenticate
             # https://symfony.com/doc/current/security.html#the-firewall
@@ -27,8 +32,15 @@ security:
     # 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 }
+      # restreint l'accès à la création de châteaux aux admin
+      - { path: '^/clothes/new', roles: ROLE_ADMIN }
+      - { path: '^/cayegory/new', roles: ROLE_ADMIN }
+      - { path: '^/ecurie/new', roles: ROLE_ADMIN }
+
+      # restreint l'accès à l'édition de châteaux aux admin
+      - { path: '^/clothes/\d+/edit', roles: ROLE_ADMIN }
+      - { path: '^/cayegory/\d+/edit', roles: ROLE_ADMIN }
+      - { path: '^/ecurie/\d+/edit', roles: ROLE_ADMIN }
 
 when@test:
     security:
diff --git a/src/Controller/LoginFormController.php b/src/Controller/LoginFormController.php
new file mode 100644
index 0000000..7880f2b
--- /dev/null
+++ b/src/Controller/LoginFormController.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Controller;
+
+use App\Entity\Category;
+use App\Form\CategoryType;
+use App\Repository\CategoryRepository;
+
+use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Routing\Annotation\Route;
+use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
+
+class LoginFormController extends AbstractController
+{
+    #[Route(path: '/login', name: 'app_login')]
+    public function login(AuthenticationUtils $authenticationUtils): Response
+    {
+        // if ($this->getUser()) {
+        //     return $this->redirectToRoute('target_path');
+        // }
+        
+        $categoryRepository = $this->getDoctrine()
+                                 ->getRepository(Category::class);   
+
+        // get the login error if there is one
+        $error = $authenticationUtils->getLastAuthenticationError();
+        // last username entered by the user
+        $lastUsername = $authenticationUtils->getLastUsername();
+
+        return $this->render('security/login.html.twig', [
+            'last_username' => $lastUsername,
+            'error' => $error,
+            'categories' => $categoryRepository->findAll(),
+        ]);
+    }
+
+    #[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.');
+    }
+}
diff --git a/src/Security/LoginFormAuthenticator.php b/src/Security/LoginFormAuthenticator.php
new file mode 100644
index 0000000..a5fb5d1
--- /dev/null
+++ b/src/Security/LoginFormAuthenticator.php
@@ -0,0 +1,58 @@
+<?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\Core\Security;
+use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
+use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
+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\Util\TargetPathTrait;
+
+class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
+{
+    use TargetPathTrait;
+
+    public const LOGIN_ROUTE = 'app_login';
+
+    public function __construct(private UrlGeneratorInterface $urlGenerator)
+    {
+    }
+
+    public function authenticate(Request $request): Passport
+    {
+        $username = $request->request->get('username', '');
+
+        $request->getSession()->set(Security::LAST_USERNAME, $username);
+
+        return new Passport(
+            new UserBadge($username),
+            new PasswordCredentials($request->request->get('password', '')),
+            [
+                new CsrfTokenBadge('authenticate', $request->request->get('_csrf_token')),
+            ]
+        );
+    }
+
+    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('home'));
+        // throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
+    }
+
+    protected function getLoginUrl(Request $request): string
+    {
+        return $this->urlGenerator->generate(self::LOGIN_ROUTE);
+    }
+}
diff --git a/templates/cart/index.html.twig b/templates/cart/index.html.twig
index 7bb4f85..d0646e5 100644
--- a/templates/cart/index.html.twig
+++ b/templates/cart/index.html.twig
@@ -3,51 +3,38 @@
 {% block title %}Votre Panier{% endblock %}
 
 {% block body %}
-    <table>
-        <thead>
-            <tr>
-                <td>
-                    Clothes
-                </td>
-                <td>
-                    Price
-                </td>
-                <td>
-                    Quantite
-                </td>
-                <td>
-                    Total
-                </td>
-                <td>
-                    Actions
-                </td>
-            </tr>
-        </thead>
-        <tbody>
+    <div class="my-6">
+        <h1 class="text-6xl text-center">Total <span class="text-[#00AA00]">{{total}} €</span></h1>
+    </div>
+
+    <div class="flex justify-center">
+        <ul class="max-w-[80%] flex flex-wrap">
             {% for element in dataPanier %}
-                <tr>
-                    <td>{{element.clothes.name}}</td>
-                    <td>{{element.clothes.price}} €</td>
-                    <td>{{element.quantite}}</td>
-                    <td>{{element.quantite * element.clothes.price}} €</td>
-                    <td>
-                        <a href="{{ path('app_cart_add', {id: element.clothes.id}) }}"><i class="bi bi-cart-plus"></i></a>
-                        <a href="{{ path('app_cart_remove', {id: element.clothes.id}) }}"><i class="bi bi-cart-dash"></i></a>
-                        <a href="{{ path('app_cart_delete', {id: element.clothes.id}) }}"><i class="bi bi-cart-x"></i></a>
-                    </td>
-                </tr>
-            {% else %}
-                <tr>
-                    <td colspan="5" class="text-center">Votre Panier est vide</td>
-                </tr>
+                <li class=" border-b-2 min-h-[710px] max-h-[710px] my-4">
+                    <article class="flex flex-col justify-center">
+                        <img src="{{ element.clothes.picture }}" alt="{{ element.clothes.name }}" class="h-[500px] w-[500px]">
+                        <div class="p-5 w-full">
+                            <div class="flex flex-row justify-between">
+                                <h3 class="text-[#CC0000] font-bold">{{ element.clothes.price }} €</h3>
+                                <h3 class="text-[#0000AA] font-bold">x{{element.quantite}}</h3>
+                                <h3 class="text-[#00AA00] font-bold">{{element.quantite * element.clothes.price}} €</h3>
+                            </div>
+                            <p class="min-h-[50px] max-h-[50px]">{{ element.clothes.name }}</p>
+                            <div class="flex flex-row justify-center items-center gap-8">
+                                <div class="min-w-[50px] min-h-[50px] p-2 bg-[#00AA00] rounded-full text-[#EEEEEE] font-bold text-2xl text-center">
+                                    <a href="{{ path('app_cart_add', {id: element.clothes.id}) }}"><i class="bi bi-cart-plus"></i></a>
+                                </div>
+                                <div class="min-w-[50px] min-h-[50px] p-2 bg-[#0000AA] rounded-full text-[#EEEEEE] font-bold text-2xl text-center">
+                                    <a href="{{ path('app_cart_remove', {id: element.clothes.id}) }}"><i class="bi bi-cart-dash"></i></a>
+                                </div>
+                                <div class="min-w-[50px] min-h-[50px] p-2 bg-[#AA0000] rounded-full text-[#EEEEEE] font-bold text-2xl text-center">
+                                    <a href="{{ path('app_cart_delete', {id: element.clothes.id}) }}"><i class="bi bi-cart-x"></i></a>
+                                </div>
+                            </div>
+                        </div>
+                    </article>
+                </li>
             {% endfor %}
-        </tbody>
-        <tfoot>
-            <tr>
-                <td colspan="3">Total</td>
-                <td>{{ total }} €</td>
-                <td></td>
-            </tr>
-        </tfoot>
-    </table>
+        </ul>
+    </div>
 {% endblock %}
\ No newline at end of file
diff --git a/templates/category/show.html.twig b/templates/category/show.html.twig
index d1c49da..ee9a4f4 100644
--- a/templates/category/show.html.twig
+++ b/templates/category/show.html.twig
@@ -8,27 +8,29 @@
     <div class="flex justify-center">
         <ul class="max-w-[80%] flex flex-wrap">
             {% for clothes in category.clothes %}
-                <li class="max-w-[33%] border-b-2">
+                <li class="max-w-[33%] border-b-2 min-h-[710px] max-h-[710px]">
                     <article class="flex flex-col justify-center">
-                        <img src="{{ clothes.picture }}" alt="{{ clothes.name }}">
+                        <img src="{{ clothes.picture }}" alt="{{ clothes.name }}" class="h-[500px] w-[500px]">
                         <div class="p-5 w-full">
                             <h3 class="text-[#CC0000] font-bold">{{ clothes.price }} €</h3>
-                            <p>{{ clothes.name }}</p>
+                            <p class="min-h-[50px] max-h-[50px]">{{ clothes.name }}</p>
                             <a href="{{ path('app_cart_add', {id: clothes.id}) }}" class="">
-                                <div class="w-full text-center p-3 bg-[#06e100] rounded-xl text-[#111111] font-bold my-5 hover:text-[#EEEEEE]">
+                                <div class="w-full text-center p-3 bg-[#06e100] rounded-xl text-[#111111] font-bold mt-5 hover:text-[#EEEEEE]">
                                     <i class="bi bi-cart-plus"></i> Ajouter au Panier
                                 </div>
                             </a>
+                            {% if is_granted('ROLE_ADMIN') %}
+                                <div class="flex flex-row justify-center">
+                                    <form method="post" action="{{ path('app_clothes_delete', {'id': clothes.id}) }}" onsubmit="return confirm('Êtes vous sûr de vouloir supprimer ce Vêtement ?');">
+                                        <input type="hidden" name="_token" value="{{ csrf_token('delete' ~ clothes.id) }}">
+                                        <button class="btn w-fit text-[#AA0000]"><i class="bi bi-trash-fill text-sm"></i></button>
+                                    </form>
+                                </div>
+                            {% endif %}
                         </div>
                     </article>
                 </li>
             {% endfor %}
         </ul>
     </div>
-
-    <a href="{{ path('app_category_index') }}">back to list</a>
-
-    <a href="{{ path('app_category_edit', {'id': category.id}) }}">edit</a>
-
-    {{ include('category/_delete_form.html.twig') }}
 {% endblock %}
diff --git a/templates/clothes/index.html.twig b/templates/clothes/index.html.twig
index b557909..7110557 100644
--- a/templates/clothes/index.html.twig
+++ b/templates/clothes/index.html.twig
@@ -3,37 +3,36 @@
 {% block title %}Clothes index{% endblock %}
 
 {% block body %}
-    <h1>Clothes index</h1>
+    <div class="my-6">
+        <h1 class="text-6xl text-center">Tous les Vêtements</h1>
+    </div>
 
-    <table class="table">
-        <thead>
-            <tr>
-                <th>Id</th>
-                <th>Name</th>
-                <th>Picture</th>
-                <th>Price</th>
-                <th>actions</th>
-            </tr>
-        </thead>
-        <tbody>
-        {% for clothes in clothes %}
-            <tr>
-                <td>{{ clothes.id }}</td>
-                <td>{{ clothes.name }}</td>
-                <td><img src="{{ clothes.picture }}" alt=""></td>
-                <td>{{ clothes.price }}</td>
-                <td>
-                    <a href="{{ path('app_clothes_show', {'id': clothes.id}) }}">show</a>
-                    <a href="{{ path('app_clothes_edit', {'id': clothes.id}) }}">edit</a>
-                </td>
-            </tr>
-        {% else %}
-            <tr>
-                <td colspan="5">no records found</td>
-            </tr>
-        {% endfor %}
-        </tbody>
-    </table>
-
-    <a href="{{ path('app_clothes_new') }}">Create new</a>
+    <div class="flex justify-center">
+        <ul class="max-w-[80%] flex flex-wrap">
+            {% for clothe in clothes %}
+                <li class="max-w-[33%] border-b-2 min-h-[710px] max-h-[710px]">
+                    <article class="flex flex-col justify-center">
+                        <img src="{{ clothe.picture }}" alt="{{ clothe.name }}" class="h-[500px] w-[500px]">
+                        <div class="p-5 w-full">
+                            <h3 class="text-[#CC0000] font-bold">{{ clothe.price }} €</h3>
+                            <p class="min-h-[50px] max-h-[50px]">{{ clothe.name }}</p>
+                            <a href="{{ path('app_cart_add', {id: clothe.id}) }}" class="">
+                                <div class="w-full text-center p-3 bg-[#06e100] rounded-xl text-[#111111] font-bold mt-5 hover:text-[#EEEEEE]">
+                                    <i class="bi bi-cart-plus"></i> Ajouter au Panier
+                                </div>
+                            </a>
+                            {% if is_granted('ROLE_ADMIN') %}
+                                <div class="flex flex-row justify-center">
+                                    <form method="post" action="{{ path('app_clothes_delete', {'id': clothe.id}) }}" onsubmit="return confirm('Êtes vous sûr de vouloir supprimer ce Vêtement ?');">
+                                        <input type="hidden" name="_token" value="{{ csrf_token('delete' ~ clothe.id) }}">
+                                        <button class="btn w-fit text-[#AA0000]"><i class="bi bi-trash-fill text-sm"></i></button>
+                                    </form>
+                                </div>
+                            {% endif %}
+                        </div>
+                    </article>
+                </li>
+            {% endfor %}
+        </ul>
+    </div>
 {% endblock %}
diff --git a/templates/ecurie/index.html.twig b/templates/ecurie/index.html.twig
index aa2020b..9dd78af 100644
--- a/templates/ecurie/index.html.twig
+++ b/templates/ecurie/index.html.twig
@@ -16,6 +16,4 @@
         {% endfor %}
     </ul>
 </div>
-
-    <a href="{{ path('app_ecurie_new') }}">Create new</a>
 {% endblock %}
diff --git a/templates/ecurie/show.html.twig b/templates/ecurie/show.html.twig
index 779341e..f688173 100644
--- a/templates/ecurie/show.html.twig
+++ b/templates/ecurie/show.html.twig
@@ -3,28 +3,34 @@
 {% block title %}Ecurie{% endblock %}
 
 {% block body %}
-    <h1>Ecurie</h1>
+<h1 class="text-3xl capitalize px-[5rem]">{{ ecurie.name }}</h1>
 
-    <table class="table">
-        <tbody>
-            <tr>
-                <th>Id</th>
-                <td>{{ ecurie.id }}</td>
-            </tr>
-            <tr>
-                <th>Name</th>
-                <td>{{ ecurie.name }}</td>
-            </tr>
-            <tr>
-                <th>Picture</th>
-                <td>{{ ecurie.picture }}</td>
-            </tr>
-        </tbody>
-    </table>
-
-    <a href="{{ path('app_ecurie_index') }}">back to list</a>
-
-    <a href="{{ path('app_ecurie_edit', {'id': ecurie.id}) }}">edit</a>
-
-    {{ include('ecurie/_delete_form.html.twig') }}
+    <div class="flex justify-center">
+        <ul class="max-w-[80%] flex flex-wrap">
+            {% for clothes in ecurie.clothes %}
+                <li class="max-w-[33%] border-b-2 min-h-[710px] max-h-[710px]">
+                    <article class="flex flex-col justify-center">
+                        <img src="{{ clothes.picture }}" alt="{{ clothes.name }}" class="h-[500px] w-[500px]">
+                        <div class="p-5 w-full">
+                            <h3 class="text-[#CC0000] font-bold">{{ clothes.price }} €</h3>
+                            <p class="min-h-[50px] max-h-[50px]">{{ clothes.name }}</p>
+                            <a href="{{ path('app_cart_add', {id: clothes.id}) }}" class="">
+                                <div class="w-full text-center p-3 bg-[#06e100] rounded-xl text-[#111111] font-bold mt-5 hover:text-[#EEEEEE]">
+                                    <i class="bi bi-cart-plus"></i> Ajouter au Panier
+                                </div>
+                            </a>
+                            {% if is_granted('ROLE_ADMIN') %}
+                                <div class="flex flex-row justify-center">
+                                    <form method="post" action="{{ path('app_clothes_delete', {'id': clothes.id}) }}" onsubmit="return confirm('Êtes vous sûr de vouloir supprimer ce Vêtement ?');">
+                                        <input type="hidden" name="_token" value="{{ csrf_token('delete' ~ clothes.id) }}">
+                                        <button class="btn w-fit text-[#AA0000]"><i class="bi bi-trash-fill text-sm"></i></button>
+                                    </form>
+                                </div>
+                            {% endif %}
+                        </div>
+                    </article>
+                </li>
+            {% endfor %}
+        </ul>
+    </div>
 {% endblock %}
diff --git a/templates/home.html.twig b/templates/home.html.twig
index 61bbec7..df7748d 100644
--- a/templates/home.html.twig
+++ b/templates/home.html.twig
@@ -12,7 +12,7 @@
             {% endfor %}
         </ul>
     </div>
-    <a href="">
-        <img src="{{ asset('img/DT_A_spot_2023_Teamwear_FR.avif') }}" alt="">
+    <a href="{{ path('app_clothes_index') }}">
+        <img src="{{ asset('img/DT_A_spot_2023_Teamwear_FR.avif') }}" alt="" class="w-full">
     </a>
 {% endblock %}
\ No newline at end of file
diff --git a/templates/layouts/_header.html.twig b/templates/layouts/_header.html.twig
index 6a0fd0c..54b2039 100644
--- a/templates/layouts/_header.html.twig
+++ b/templates/layouts/_header.html.twig
@@ -5,20 +5,28 @@
         </a>
     </div>
     <div class="flex flex-row justify-end gap-5">
-        <ul class="flex-flex-row justify-end items-center h-[40px]">
+        <ul class="flex flex-row justify-end items-center h-[40px]">
             <li class="flex items-center h-[40px] pl-[7px] pr-[5px] text-[#EEEEEE]">
-                <a href="" class="hover:underline">Mon Compte</a>
+                {% if app.user %}
+                    <a href="{{ path('app_logout') }}" class="hover:underline">{{ app.user.username }}</a>
+                {% else %}
+                    <a href="{{ path('app_login') }}" class="hover:underline">Connexion</a>
+                {% endif %}
             </li>
+            {% if is_granted('ROLE_ADMIN') %}
+                <li class="flex items-center h-[40px] pl-[7px] pr-[5px] text-[#EEEEEE]">
+                    <a href="{{ path('app_clothes_new') }}">Ajouter des Vêtements</a>
+                </li>
+                <li class="flex items-center h-[40px] pl-[7px] pr-[5px] text-[#EEEEEE]">
+                    <a href="{{ path('app_category_new') }}">Ajouter une Catégorie</a>
+                </li>
+            {% endif %}
         </ul>
-        <div class="w-[60px] h-[40px] bg-[#e10600] text-center pt-[0.5rem] pb-[0.4375rem] text-[#EEEEEE] hover:text-[#e10600] hover:bg-[#EEEEEE]" role="complementary">
-            <a href="/cart" 
-                data-trk-id="cart-icon" 
-                data-talos="linkCartIcon" 
-                {# class="{{ path('app_cart_show', {id: app.user.id}) }}"  #}
-                title="Vous avez 0 articles dans le panier. Le total est de 0,00&nbsp;€">
+        <a href="{{ path('app_cart_index') }}" class="h-fit">
+            <div class="w-[60px] h-[40px] bg-[#e10600] text-center pt-[0.5rem] pb-[0.4375rem] text-[#EEEEEE] hover:text-[#e10600] hover:bg-[#EEEEEE]" role="complementary">
                 <i class="bi bi-cart-fill"></i>
-            </a>
-        </div>
+            </div>
+        </a>
     </div>
 </header>
 <nav>
diff --git a/templates/security/login.html.twig b/templates/security/login.html.twig
new file mode 100644
index 0000000..6c19154
--- /dev/null
+++ b/templates/security/login.html.twig
@@ -0,0 +1,42 @@
+{% extends 'base.html.twig' %}
+
+{% block title %}Log in!{% endblock %}
+
+{% block body %}
+<form method="post">
+    {% if error %}
+        <div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
+    {% endif %}
+
+    {% if app.user %}
+        <div class="mb-3">
+            You are logged in as {{ app.user.userIdentifier }}, <a href="{{ path('app_logout') }}">Logout</a>
+        </div>
+    {% endif %}
+
+    <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
+    <label for="inputUsername">Username</label>
+    <input type="text" value="{{ last_username }}" name="username" id="inputUsername" class="form-control" autocomplete="username" required autofocus>
+    <label for="inputPassword">Password</label>
+    <input type="password" name="password" id="inputPassword" class="form-control" autocomplete="current-password" required>
+
+    <input type="hidden" name="_csrf_token"
+           value="{{ csrf_token('authenticate') }}"
+    >
+
+    {#
+        Uncomment this section and add a remember_me option below your firewall to activate remember me functionality.
+        See https://symfony.com/doc/current/security/remember_me.html
+
+        <div class="checkbox mb-3">
+            <label>
+                <input type="checkbox" name="_remember_me"> Remember me
+            </label>
+        </div>
+    #}
+
+    <button class="btn btn-lg btn-primary" type="submit">
+        Sign in
+    </button>
+</form>
+{% endblock %}
-- 
GitLab