diff --git a/.idea/php.xml b/.idea/php.xml index 3bc3bf6..91ab0f3 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -145,6 +145,9 @@ + + + diff --git a/.idea/sortir.iml b/.idea/sortir.iml index c0db0d2..0fa7baa 100644 --- a/.idea/sortir.iml +++ b/.idea/sortir.iml @@ -137,6 +137,9 @@ + + + diff --git a/composer.json b/composer.json index d81dbac..5493b47 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ "doctrine/doctrine-bundle": "^2.13", "doctrine/doctrine-migrations-bundle": "^3.3", "doctrine/orm": "^3.3", + "fzaninotto/faker": "^1.5", "phpdocumentor/reflection-docblock": "^5.6", "phpstan/phpdoc-parser": "^2.0", "symfony/asset": "6.4.*", @@ -98,6 +99,7 @@ } }, "require-dev": { + "doctrine/doctrine-fixtures-bundle": "*", "phpunit/phpunit": "^9.5", "symfony/browser-kit": "6.4.*", "symfony/css-selector": "6.4.*", diff --git a/composer.lock b/composer.lock index 8ce70f1..bf2178f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "12d1d380814a0606ceb716bdf895138d", + "content-hash": "1fd68014d63c789294bcc54a5c6d1c50", "packages": [ { "name": "composer/semver", @@ -1380,6 +1380,63 @@ ], "time": "2023-10-06T06:47:41+00:00" }, + { + "name": "fzaninotto/faker", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "d0190b156bcca848d401fb80f31f504f37141c8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/d0190b156bcca848d401fb80f31f504f37141c8d", + "reference": "d0190b156bcca848d401fb80f31f504f37141c8d", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "suggest": { + "ext-intl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "support": { + "issues": "https://github.com/fzaninotto/Faker/issues", + "source": "https://github.com/fzaninotto/Faker/tree/master" + }, + "abandoned": true, + "time": "2015-05-29T06:29:14+00:00" + }, { "name": "monolog/monolog", "version": "3.8.0", @@ -7768,6 +7825,179 @@ } ], "packages-dev": [ + { + "name": "doctrine/data-fixtures", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/data-fixtures.git", + "reference": "d2ff5046b263868baf6e9b06cf4918f60096c0d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/d2ff5046b263868baf6e9b06cf4918f60096c0d0", + "reference": "d2ff5046b263868baf6e9b06cf4918f60096c0d0", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^0.5.3 || ^1.0", + "doctrine/persistence": "^2.0 || ^3.0", + "php": "^7.4 || ^8.0", + "symfony/polyfill-php80": "^1" + }, + "conflict": { + "doctrine/dbal": "<3.5 || >=5", + "doctrine/orm": "<2.14 || >=4", + "doctrine/phpcr-odm": "<1.3.0" + }, + "require-dev": { + "doctrine/annotations": "^1.12 || ^2", + "doctrine/coding-standard": "^12", + "doctrine/dbal": "^3.5 || ^4", + "doctrine/mongodb-odm": "^1.3.0 || ^2.0.0", + "doctrine/orm": "^2.14 || ^3", + "ext-sqlite3": "*", + "fig/log-test": "^1", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.6.13 || ^10.4.2", + "psr/log": "^1.1 || ^2 || ^3", + "symfony/cache": "^5.4 || ^6.3 || ^7", + "symfony/var-exporter": "^5.4 || ^6.3 || ^7" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "For using MongoDB ODM 1.3 with PHP 7 (deprecated)", + "doctrine/mongodb-odm": "For loading MongoDB ODM fixtures", + "doctrine/orm": "For loading ORM fixtures", + "doctrine/phpcr-odm": "For loading PHPCR ODM fixtures" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\DataFixtures\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Data Fixtures for all Doctrine Object Managers", + "homepage": "https://www.doctrine-project.org", + "keywords": [ + "database" + ], + "support": { + "issues": "https://github.com/doctrine/data-fixtures/issues", + "source": "https://github.com/doctrine/data-fixtures/tree/1.8.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdata-fixtures", + "type": "tidelift" + } + ], + "time": "2024-11-04T22:36:12+00:00" + }, + { + "name": "doctrine/doctrine-fixtures-bundle", + "version": "3.6.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineFixturesBundle.git", + "reference": "f44a224e27573b79140197a44e68484c45fb24da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/f44a224e27573b79140197a44e68484c45fb24da", + "reference": "f44a224e27573b79140197a44e68484c45fb24da", + "shasum": "" + }, + "require": { + "doctrine/data-fixtures": "^1.3", + "doctrine/doctrine-bundle": "^2.2", + "doctrine/orm": "^2.14.0 || ^3.0", + "doctrine/persistence": "^2.4|^3.0", + "php": "^7.4 || ^8.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/doctrine-bridge": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0" + }, + "conflict": { + "doctrine/dbal": "< 3" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10.39", + "phpunit/phpunit": "^9.6.13", + "symfony/phpunit-bridge": "^6.3.6", + "vimeo/psalm": "^5.15" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\FixturesBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Doctrine Project", + "homepage": "https://www.doctrine-project.org" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DoctrineFixturesBundle", + "homepage": "https://www.doctrine-project.org", + "keywords": [ + "Fixture", + "persistence" + ], + "support": { + "issues": "https://github.com/doctrine/DoctrineFixturesBundle/issues", + "source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/3.6.2" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-fixtures-bundle", + "type": "tidelift" + } + ], + "time": "2024-11-13T07:41:29+00:00" + }, { "name": "masterminds/html5", "version": "2.9.0", diff --git a/config/bundles.php b/config/bundles.php index 2476b22..f9466c1 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -14,4 +14,6 @@ return [ Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true], SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle::class => ['all' => true], + Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], + Symfony\UX\Turbo\TurboBundle::class => ['all' => true], ]; diff --git a/migrations/Version20241120092127.php b/migrations/Version20241120095413.php similarity index 92% rename from migrations/Version20241120092127.php rename to migrations/Version20241120095413.php index 5d982b8..86bddab 100644 --- a/migrations/Version20241120092127.php +++ b/migrations/Version20241120095413.php @@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20241120092127 extends AbstractMigration +final class Version20241120095413 extends AbstractMigration { public function getDescription(): string { diff --git a/public/upload/image/profile/avatar-de-profil-673db25730c0c.png b/public/upload/image/profile/avatar-de-profil-673db25730c0c.png new file mode 100644 index 0000000..b4972ce Binary files /dev/null and b/public/upload/image/profile/avatar-de-profil-673db25730c0c.png differ diff --git a/public/upload/image/profile/avatar-de-profil-673db8d59264d.png b/public/upload/image/profile/avatar-de-profil-673db8d59264d.png new file mode 100644 index 0000000..b4972ce Binary files /dev/null and b/public/upload/image/profile/avatar-de-profil-673db8d59264d.png differ diff --git a/public/upload/image/profile/default.png b/public/upload/image/profile/default.png new file mode 100644 index 0000000..b2a9827 Binary files /dev/null and b/public/upload/image/profile/default.png differ diff --git a/src/Controller/ProfileController.php b/src/Controller/ProfileController.php index 78e1d38..314b439 100644 --- a/src/Controller/ProfileController.php +++ b/src/Controller/ProfileController.php @@ -3,6 +3,7 @@ namespace App\Controller; use App\Entity\Participant; +use App\Form\ProfileFormType; use App\Service\FileUploader; use App\Form\RegistrationFormType; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -20,7 +21,7 @@ class ProfileController extends AbstractController $this->profileRepo = $profileRepo; } #[Route('/profile/{uuid}', name: 'profile_view', methods: ['GET'])] - public function viewProfile(string $uuid, ParticipantRepository $profileRepo): Response + public function viewProfile(string $uuid, ParticipantRepository $profileRepo, Request $request): Response { $currentProfile = $profileRepo->findOneBy(['idParticipant' => $uuid]); return $this->render('profile/view.html.twig', [ @@ -37,7 +38,7 @@ class ProfileController extends AbstractController $this->addFlash('error', "Vous ne pouvez pas modifier un profil qui n'est pas le votre"); return $this->redirectToRoute('profile_view',['uuid' => $profile->getIdParticipant()]); } - $form = $this->createForm(RegistrationFormType::class, $profile); + $form = $this->createForm(ProfileFormType::class, $profile); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $imageFile = $form->get('image')->getData(); @@ -47,7 +48,34 @@ class ProfileController extends AbstractController $imageFilename = $this->fileUploader->upload($imageFile); $profile->setFileName($imageFilename); } else { - $profile->setFileName(''); + $profile->setFileName(null); + } + } + if ($form->has('newPassword') && $form->has('confirmPassword')) { + if ($form->get('newPassword')->getData() !== $form->get('confirmPassword')->getData()) { + $this->addFlash('error', "Les mots de passe ne correspondent pas"); + return $this->render('profile/edit.html.twig', [ + 'formProfile' => $form, + ]); + } + $profile->setPassword($form->get('newPassword')->getData()); + } + if ($form->has('pseudo')) { + $alreadyExists = $this->profileRepo->findOneBy(['pseudo' => $profile->getPseudo()]); + if ($alreadyExists && $alreadyExists !== $profile) { + $this->addFlash('error', "Ce pseudo existe déjà"); + return $this->render('profile/edit.html.twig', [ + 'formProfile' => $form, + ]); + } + } + if ($form->has('email')) { + $alreadyExists = $this->profileRepo->findOneBy(['email' => $profile->getEmail()]); + if ($alreadyExists && $alreadyExists !== $profile) { + $this->addFlash('error', "Cet email existe déjà"); + return $this->render('profile/edit.html.twig', [ + 'formProfile' => $form, + ]); } } $profileToUpdate = $this->profileRepo->update($profile); @@ -61,7 +89,7 @@ class ProfileController extends AbstractController 'formProfile' => $form, ]); } catch(\Exception $e) { - $formProfile = $this->createForm(RegistrationFormType::class, $profile); + $formProfile = $this->createForm(ProfileFormType::class, $profile); $this->addFlash('error', $e->getMessage()); return $this->render('profile/edit.html.twig', ['formProfile' => $formProfile]); } diff --git a/src/DataFixtures/UserFixtures.php b/src/DataFixtures/UserFixtures.php index 7205a72..ccbfa3f 100644 --- a/src/DataFixtures/UserFixtures.php +++ b/src/DataFixtures/UserFixtures.php @@ -9,7 +9,11 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; class UserFixtures extends Fixture { - public function load(ObjectManager $manager, UserPasswordHasherInterface $userPasswordHasher): void + private UserPasswordHasherInterface $userPasswordHasher; + public function __construct(UserPasswordHasherInterface $userPasswordHasher){ + $this->userPasswordHasher = $userPasswordHasher; + } + public function load(ObjectManager $manager): void { $olivier = new Participant(); $olivier->setPrenom('Olivier'); @@ -20,7 +24,7 @@ class UserFixtures extends Fixture $olivier->setRoles(['ROLE_USER', 'ROLE_ADMIN']); $olivier->setAdministrateur(true); $olivier->setActif(false); - $olivier->setPassword($userPasswordHasher->hashPassword($olivier, 'test-44')); + $olivier->setPassword($this->userPasswordHasher->hashPassword($olivier, 'test-44')); $manager->persist($olivier); $johan = new Participant(); @@ -32,7 +36,7 @@ class UserFixtures extends Fixture $johan->setRoles(['ROLE_USER', 'ROLE_ADMIN']); $johan->setAdministrateur(true); $johan->setActif(false); - $johan->setPassword($userPasswordHasher->hashPassword($johan, 'test-44')); + $johan->setPassword($this->userPasswordHasher->hashPassword($johan, 'test-44')); $manager->persist($johan); $marvin = new Participant(); @@ -44,7 +48,7 @@ class UserFixtures extends Fixture $marvin->setRoles(['ROLE_USER', 'ROLE_ADMIN']); $marvin->setAdministrateur(true); $marvin->setActif(false); - $marvin->setPassword($userPasswordHasher->hashPassword($marvin, 'test-44')); + $marvin->setPassword($this->userPasswordHasher->hashPassword($marvin, 'test-44')); $manager->persist($marvin); $manager->flush(); diff --git a/src/Form/ProfileFormType.php b/src/Form/ProfileFormType.php new file mode 100644 index 0000000..8442049 --- /dev/null +++ b/src/Form/ProfileFormType.php @@ -0,0 +1,154 @@ +add('nom', TextType::class, [ + 'label' => 'Nom', + 'label_attr' => ['class' => 'text-gray-700 font-bold'], + 'attr' => [ + 'class' => 'w-full mb-4 px-4 py-2 border-2 border-gray-300 rounded-lg text-center focus:outline-none focus:border-blue-500', + 'placeholder' => 'Nom', + ], + ]) + ->add('prenom', TextType::class, [ + 'label' => 'Prénom', + 'label_attr' => ['class' => 'text-gray-700 font-bold'], + 'attr' => [ + 'class' => 'w-full mb-4 px-4 py-2 border-2 border-gray-300 rounded-lg text-center focus:outline-none focus:border-blue-500', + 'placeholder' => 'Prénom', + ], + ]) + ->add('pseudo', TextType::class, [ + 'label' => 'Pseudo', + 'label_attr' => ['class' => 'text-gray-700 font-bold'], + 'attr' => [ + 'class' => 'w-full mb-4 px-4 py-2 border-2 border-gray-300 rounded-lg text-center focus:outline-none focus:border-blue-500', + 'placeholder' => 'Pseudo', + ], + ]) + ->add('email', EmailType::class, [ + 'label' => 'Email', + 'label_attr' => ['class' => 'text-gray-700 font-bold'], + 'attr' => [ + 'class' => 'w-full mb-4 px-4 py-2 border-2 border-gray-300 rounded-lg text-center focus:outline-none focus:border-blue-500', + 'placeholder' => 'Adresse e-mail', + ], + 'constraints' => [ + new NotBlank([ + 'message' => 'Please enter an email address', + ]), + ], + ]) + ->add('telephone', TextType::class, [ + 'label' => 'Numéro de téléphone', + 'label_attr' => ['class' => 'text-gray-700 font-bold'], + 'attr' => [ + 'class' => 'w-full text-center mb-4 px-4 py-2 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-blue-500', + 'placeholder' => 'Numéro de téléphone', + ], + ]) + ->add('newPassword', PasswordType::class, [ + 'mapped' => false, + 'label' => 'Nouveau mot de passe', + 'label_attr' => ['class' => 'text-gray-700 font-bold'], + 'attr' => [ + 'autocomplete' => 'new-password', + 'class' => 'w-full text-center mb-4 px-4 py-2 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-blue-500', + 'placeholder' => 'Nouveau mot de passe', + ], + 'constraints' => [ + new NotBlank([ + 'message' => 'Please enter a password', + ]), + new Length([ + 'min' => 6, + 'minMessage' => 'Your password should be at least {{ limit }} characters', + 'max' => 4096, + ]), + ], + ]) + ->add('confirmPassword', PasswordType::class, [ + 'mapped' => false, + 'label' => 'Confirmer mot de passe', + 'label_attr' => ['class' => 'text-gray-700 font-bold'], + 'attr' => [ + 'autocomplete' => 'new-password', + 'class' => 'w-full text-center mb-4 px-4 py-2 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-blue-500', + 'placeholder' => 'Confirmer mot de passe', + ], + 'constraints' => [ + new NotBlank([ + 'message' => 'Please enter a password', + ]), + new Length([ + 'min' => 6, + 'minMessage' => 'Your password should be at least {{ limit }} characters', + 'max' => 4096, + ]), + ], + ]) + ->add('image', FileType::class, [ + 'label' => 'Image', + 'mapped' => false, + 'required' => false, + 'attr' => [ + 'class' => 'w-full mb-4 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-blue-500', + ], + 'label_attr' => ['class' => 'text-gray-700 font-bold'], + 'constraints' => [ + new File([ + 'maxSize' => '1024k', + 'mimeTypes' => [ + 'image/png', + 'image/jpeg', + ], + 'mimeTypesMessage' => 'Please upload a valid image', + ]) + ], + ]) + ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + $profile = $event->getData(); + if ($profile && $profile->getFileName()) { + $form = $event->getForm(); + $form->add('deleteImage', CheckboxType::class, [ + 'required' => false, + 'mapped' => false, + 'label' => 'Supprimer l\'image', + 'attr' => [ + 'class' => 'w-4 h-4 mb-4 border-gray-300 rounded mx-2', + ], 'label_attr' => ['class' => 'text-gray-700 font-bold px-4'] + ]); + } + }) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => Participant::class, + ]); + } +} diff --git a/symfony.lock b/symfony.lock index 8310ae4..b711fb6 100644 --- a/symfony.lock +++ b/symfony.lock @@ -13,6 +13,18 @@ "./src/Repository/.gitignore" ] }, + "doctrine/doctrine-fixtures-bundle": { + "version": "3.6", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.0", + "ref": "1f5514cfa15b947298df4d771e694e578d4c204d" + }, + "files": [ + "./src/DataFixtures/AppFixtures.php" + ] + }, "doctrine/doctrine-migrations-bundle": { "version": "3.3", "recipe": { @@ -260,6 +272,15 @@ "./config/packages/uid.yaml" ] }, + "symfony/ux-turbo": { + "version": "2.21", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.19", + "ref": "9dd2778a116b6e5e01e5e1582d03d5a9e82630de" + } + }, "symfony/validator": { "version": "6.4", "recipe": { diff --git a/templates/main/header.html.twig b/templates/main/header.html.twig index be9b74e..64e0336 100644 --- a/templates/main/header.html.twig +++ b/templates/main/header.html.twig @@ -27,8 +27,9 @@ {% if app.user %}
  • Mon profile
  • {% endif %} -
  • ToDo
  • -
  • À propos
  • + {% if app.user and ('ROLE_ADMIN' in app.user.roles) %} +
  • Administration
  • + {% endif %} {% if app.user %}
  • Se déconnecter
  • {% else %} diff --git a/templates/profile/edit.html.twig b/templates/profile/edit.html.twig index 251d262..f545505 100644 --- a/templates/profile/edit.html.twig +++ b/templates/profile/edit.html.twig @@ -9,13 +9,39 @@ {% endblock %} {% block content %} -
    -
    +
    +

    Modifier votre profile

    {{ form_start(formProfile) }} - {{ form_widget(formProfile) }} - {% if formProfile.vars.data.imageFilename != null %} - + {{ form_row(formProfile.pseudo) }} +
    +
    + {{ form_row(formProfile.nom) }} +
    +
    + {{ form_row(formProfile.prenom) }} +
    +
    +
    +
    + {{ form_row(formProfile.email) }} +
    +
    + {{ form_row(formProfile.telephone) }} +
    +
    +
    +
    + {{ form_row(formProfile.newPassword) }} +
    +
    + {{ form_row(formProfile.confirmPassword) }} +
    +
    + {{ form_row(formProfile.image) }} + {% if formProfile.vars.data.fileName != null %} + {{ form_row(formProfile.deleteImage) }} + image de profile {% endif %} {{ form_end(formProfile) }} diff --git a/templates/profile/view.html.twig b/templates/profile/view.html.twig index dec7138..142ced9 100644 --- a/templates/profile/view.html.twig +++ b/templates/profile/view.html.twig @@ -9,15 +9,15 @@ {% endblock %} {% block content %} -
    -
    -
    -
    -
    - -
    +
    +
    +
    +
    +
    +
    +

    {{ profile.prenom }} {{ profile.nom }}