From 49a7acb331761bf96e7aa0f2fe759a8e1af645c2 Mon Sep 17 00:00:00 2001 From: user <user@imta.fr> Date: Wed, 26 Mar 2025 04:13:07 +0100 Subject: [PATCH] correction previous commit --- config/packages/framework.yaml | 3 ++ config/packages/security.yaml | 19 +++------ init.sql | 27 ++++++++++++ src/Controller/HomeController.php | 1 - src/Controller/PurchaseProofController.php | 2 + src/Controller/RegistrationController.php | 3 ++ src/Controller/UserController.php | 26 +++++++++++- src/Entity/Item.php | 2 +- src/Entity/PurchaseProof.php | 7 ++-- src/Entity/User.php | 10 +++-- src/Form/RegistrationFormType.php | 9 +++- templates/base.html.twig | 6 +++ templates/home/index.html.twig | 31 +++++++++++++- templates/registration/register.html.twig | 10 ++++- templates/user/purchase_proofs.html.twig | 48 ++++++++++++++++++++++ 15 files changed, 177 insertions(+), 27 deletions(-) create mode 100644 init.sql create mode 100644 templates/user/purchase_proofs.html.twig diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index 7e1ee1f1..8f51215d 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -5,6 +5,7 @@ framework: # Note that the session will be started ONLY if you read or write from it. session: true + #esi: true #fragments: true @@ -13,3 +14,5 @@ when@test: test: true session: storage_factory_id: session.storage.factory.mock_file + + diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 6910e77d..eaa62189 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -25,19 +25,12 @@ security: secret: '%kernel.secret%' access_control: - # Allow access to /login and / without being authenticated - - { path: ^/login, allow_if: "1" } - - { path: ^/register, allow_if: "1" } - - { path: ^/$, allow_if: "1" } - - # Allow users who are admins to access the /admin path - - { path: ^/admin, allow_if: "user and user.isAdmin() == true" } - - # Allow users who are not locked to access other pages - - { path: ^/.*, allow_if: "user and user.isLocked() != true" } - - - + - { path: ^/login, allow_if: "1" } + - { path: ^/register, allow_if: "1" } + - { path: ^/$, allow_if: "1" } # Page d'accueil accessible à tous + - { path: ^/admin, allow_if: "user and user.isAdmin() == true" } + - { path: ^/, allow_if: "user" } + when@test: security: password_hashers: diff --git a/init.sql b/init.sql new file mode 100644 index 00000000..72ab8036 --- /dev/null +++ b/init.sql @@ -0,0 +1,27 @@ +-- Start transaction +START TRANSACTION; + +-- Insert users (one admin and one non-admin) +INSERT INTO `user` (`id`, `email`, `first_name`, `last_name`, `password`, `is_locked`, `is_admin`, `image`) VALUES +(1, 'admin@example.com', 'Admin', 'User', '$2y$10$adminpasswordhash', 0, 1, NULL), -- Admin user +(2, 'user@example.com', 'Regular', 'User', '$2y$10$userpasswordhash', 0, 0, NULL); -- Non-admin user + +-- Insert wishlists (one for each user) +INSERT INTO `wishlist` (`id`, `name`, `deadline`, `is_disabled`, `owner_id`) VALUES +(1, 'Admin Wishlist', '2025-12-31 23:59:59', 0, 1), -- Admin's wishlist +(2, 'User Wishlist', '2025-12-31 23:59:59', 0, 2); -- Non-admin's wishlist + +-- Insert items (linked to wishlists) +INSERT INTO `item` (`id`, `wishlist_id`, `title`, `description`, `url`, `image`, `price`) VALUES +(1, 1, 'Admin Item 1', 'Description for Admin Item 1', 'https://example.com/admin-item-1', NULL, 100.00), -- Item for admin's wishlist +(2, 1, 'Admin Item 2', 'Description for Admin Item 2', 'https://example.com/admin-item-2', NULL, 200.00), -- Item for admin's wishlist +(3, 2, 'User Item 1', 'Description for User Item 1', 'https://example.com/user-item-1', NULL, 50.00), -- Item for useVALUESr's wishlist +(4, 2, 'User Item 2', 'Description for User Item 2', 'https://example.com/user-item-2', NULL, 75.00); -- Item for user's wishlist + +-- Insert purchase proofs (linked to items) +INSERT INTO `purchase_proof` (`id`, `item_id`, `buyer_id`, `congrats_text`, `image_path`) VALUES +(1, 1, 1, 'Congrats on purchasing Admin Item 1!', '/path/to/admin-item-1-proof.png'), -- Proof for admin's item, buyer is user with ID 2 +(2, 3, 1, 'Congrats on purchasing User Item 1!', '/path/to/user-item-1-proof.png'); -- Proof for user's item, buyer is user with ID 1 + +-- Commit transaction +COMMIT; \ No newline at end of file diff --git a/src/Controller/HomeController.php b/src/Controller/HomeController.php index c5ec3000..af3ddc1e 100644 --- a/src/Controller/HomeController.php +++ b/src/Controller/HomeController.php @@ -33,7 +33,6 @@ class HomeController extends AbstractController $links['My Wishlists'] = $this->generateUrl('app_wishlist_index'); $links['Profile'] = $this->generateUrl('user_profile'); $links['Logout'] = $this->generateUrl('logout'); - dump($user->getId()); $links['See my purchase proofs'] = $this->generateUrl('user_purchase_proofs'); diff --git a/src/Controller/PurchaseProofController.php b/src/Controller/PurchaseProofController.php index b31218ca..935dc5f3 100644 --- a/src/Controller/PurchaseProofController.php +++ b/src/Controller/PurchaseProofController.php @@ -47,4 +47,6 @@ class PurchaseProofController extends AbstractController 'item' => $item, ]); } + + } diff --git a/src/Controller/RegistrationController.php b/src/Controller/RegistrationController.php index 84f8c732..d2259d0b 100644 --- a/src/Controller/RegistrationController.php +++ b/src/Controller/RegistrationController.php @@ -32,6 +32,9 @@ class RegistrationController extends AbstractController // Rediriger vers la page de connexion return $this->redirectToRoute('login'); } + else { + // Si le formulaire n'est pas valide, les erreurs seront disponibles dans la vue + } return $this->render('registration/register.html.twig', [ 'registrationForm' => $form->createView(), diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index f8088efc..411f3e04 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -9,6 +9,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\HttpFoundation\Request; +use App\Repository\PurchaseProofRepository; use App\Form\UserType; @@ -103,4 +104,27 @@ final class UserController extends AbstractController 'form' => $form->createView(), ]); } -} + + #[Route('/user/purchase-proofs', name: 'user_purchase_proofs')] + public function listPurchaseProofs(PurchaseProofRepository $purchaseProofRepository): Response + { + $user = $this->getUser(); + if (!$user) { + throw $this->createAccessDeniedException('You must be logged in to access this page.'); + } + + $purchaseProofs = $purchaseProofRepository->createQueryBuilder('pp') + ->join('pp.item', 'i') + ->join('i.wishlist', 'w') + ->where('w.owner = :user') + ->setParameter('user', $user) + ->getQuery() + ->getResult(); + + return $this->render('user/purchase_proofs.html.twig', [ + 'purchaseProofs' => $purchaseProofs, + ]); + } + + +} \ No newline at end of file diff --git a/src/Entity/Item.php b/src/Entity/Item.php index 1412642c..3ebfe22e 100644 --- a/src/Entity/Item.php +++ b/src/Entity/Item.php @@ -39,7 +39,7 @@ class Item #[ORM\Column] private ?float $price = null; - #[ORM\OneToOne(mappedBy: 'item', cascade: ['persist', 'remove'])] + #[ORM\OneToOne(mappedBy: 'item', targetEntity: PurchaseProof::class, cascade: ['persist', 'remove'])] private ?PurchaseProof $purchaseProof = null; #[ORM\ManyToOne(inversedBy: 'items')] diff --git a/src/Entity/PurchaseProof.php b/src/Entity/PurchaseProof.php index cbaf858b..3667d913 100644 --- a/src/Entity/PurchaseProof.php +++ b/src/Entity/PurchaseProof.php @@ -19,12 +19,13 @@ class PurchaseProof #[ORM\Column(length: 255)] private ?string $imagePath = null; - #[ORM\OneToOne(inversedBy: "purchaseProof", cascade: ["persist", "remove"])] + #[ORM\OneToOne(inversedBy: 'purchaseProof', cascade: ['persist', 'remove'])] #[ORM\JoinColumn(nullable: false)] private ?Item $item = null; - #[ORM\Column] - private ?int $item_id = null; // Explicit item_id column + #[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'purchaseProofs')] + #[ORM\JoinColumn(nullable: false)] + private ?User $buyer = null; public function getId(): ?int { diff --git a/src/Entity/User.php b/src/Entity/User.php index 406c8d52..8a0a1ed2 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -32,7 +32,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface #[ORM\Id] #[ORM\GeneratedValue] - #[ORM\Column] + #[ORM\Column(type: 'integer')] private ?int $id = null; #[ORM\Column(length: 255, unique: true)] @@ -59,8 +59,12 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface #[ORM\OneToMany(mappedBy: 'owner', targetEntity: Wishlist::class)] private Collection $wishlists; - #[ORM\OneToMany(mappedBy: 'invitedUser', targetEntity: Item::class)] - private Collection $invitations; + // #[ORM\OneToMany(mappedBy: 'invitedUser', targetEntity: Item::class)] + // private Collection $invitations; + + + #[ORM\OneToMany(mappedBy: 'buyer', targetEntity: PurchaseProof::class, cascade: ['persist', 'remove'])] + private Collection $purchaseProofs; public function __construct() { diff --git a/src/Form/RegistrationFormType.php b/src/Form/RegistrationFormType.php index 89c463ad..663fb6b8 100644 --- a/src/Form/RegistrationFormType.php +++ b/src/Form/RegistrationFormType.php @@ -40,8 +40,13 @@ class RegistrationFormType extends AbstractType ->add('password', PasswordType::class, [ 'label' => 'Mot de passe', 'constraints' => [ - new NotBlank(), - new Length(['min' => 6]), + new NotBlank([ + 'message' => 'Le mot de passe ne peut pas être vide.', + ]), + new Length([ + 'min' => 6, + 'minMessage' => 'Veuillez choisir un mot de passe contenant au moins {{ limit }} caractères.', + ]), ], ]) ->add('image', FileType::class, [ diff --git a/templates/base.html.twig b/templates/base.html.twig index 213ebaff..6e00c3f7 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -31,4 +31,10 @@ {% block body %}{% endblock %} </body> + + <footer> + <div style="text-align: center; margin-top: 20px;"> + <a href="{{ path('homepage') }}" class="btn btn-primary">Retour à la page d'accueil</a> + </div> +</footer> </html> diff --git a/templates/home/index.html.twig b/templates/home/index.html.twig index 3e984d35..dcadb785 100644 --- a/templates/home/index.html.twig +++ b/templates/home/index.html.twig @@ -1,6 +1,33 @@ -{% extends 'base.html.twig' %} +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"> + <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 rel="stylesheet" href="{{ asset('css/style.css') }}"> + {% block stylesheets %} + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"> + <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet"> + <link href="{{ asset('css/style.css') }}" rel="stylesheet"> + {% endblock %} + + {% block javascripts %} + {% block importmap %}{{ importmap('app') }} + {% endblock %} + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/js/all.min.js"></script> + {% endblock %} + </head> + <body> + {% for label, messages in app.flashes %} + {% for message in messages %} + <div class="alert alert-{{ label }} alert-dismissible fade show" role="alert"> + {{ message }} + <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> + </div> + {% endfor %} + {% endfor %} + -{% block title %}Homepage{% endblock %} {% block body %} <style> diff --git a/templates/registration/register.html.twig b/templates/registration/register.html.twig index 1f9833da..674cedbe 100644 --- a/templates/registration/register.html.twig +++ b/templates/registration/register.html.twig @@ -10,7 +10,15 @@ {{ form_row(registrationForm.firstName) }} {{ form_row(registrationForm.lastName) }} {{ form_row(registrationForm.email) }} - {{ form_row(registrationForm.password) }} + + + {{ form_label(registrationForm.password) }} + {{ form_widget(registrationForm.password) }} + {% for error in registrationForm.password.vars.errors %} + <div class="text-danger">{{ error.message }}</div> + {% endfor %} + + {{ form_row(registrationForm.image) }} <button type="submit" class="btn btn-primary">S'inscrire</button> {{ form_end(registrationForm) }} diff --git a/templates/user/purchase_proofs.html.twig b/templates/user/purchase_proofs.html.twig new file mode 100644 index 00000000..f27b7e2f --- /dev/null +++ b/templates/user/purchase_proofs.html.twig @@ -0,0 +1,48 @@ +{% extends 'base.html.twig' %} + +{% block title %}Purchase Proofs{% endblock %} + +{% block body %} + <header> + <div class="user-icon"></div> + <h1><a href="#">Purchase Proof Management</a></h1> + <input type="text" placeholder="Search…" class="search-bar"> + </header> + + <main> + <div class="container"> + <section class="form-section"> + <h1>Purchase Proofs</h1> + + <table class="table"> + <thead> + <tr> + <th>Id</th> + <th>Congrats Text</th> + <th>Image Path</th> + <th>Actions</th> + </tr> + </thead> + <tbody> + {% for proof in purchaseProofs %} + <tr> + <td>{{ proof.id }}</td> + <td>{{ proof.congratsText }}</td> + <td> + <img src="{{ asset(proof.imagePath) }}" alt="Proof Image" style="max-width: 100px;"> + </td> + <td> + <a href="{{ path('app_purchase_proof', { 'id': proof.id }) }}">View</a> + </td> + </tr> + {% else %} + <tr> + <td colspan="4">No purchase proofs found.</td> + </tr> + {% endfor %} + </tbody> + </table> + </section> + </div> + </main> +{% endblock %} \ No newline at end of file -- GitLab