From 773084b6aa402de6c805c9e4b1b05a6f2cae7552 Mon Sep 17 00:00:00 2001 From: Jesse Rushlow Date: Fri, 29 Jan 2021 11:00:43 -0500 Subject: [PATCH 1/5] [ResetPassword] add api platform support --- src/Maker/MakeResetPassword.php | 13 +++++ tests/Maker/MakeResetPasswordTest.php | 75 +++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/src/Maker/MakeResetPassword.php b/src/Maker/MakeResetPassword.php index 011b422eb..888d739a3 100644 --- a/src/Maker/MakeResetPassword.php +++ b/src/Maker/MakeResetPassword.php @@ -55,6 +55,7 @@ class MakeResetPassword extends AbstractMaker private $fileManager; private $doctrineHelper; private $entityClassGenerator; + private $generateApi = false; public function __construct(FileManager $fileManager, DoctrineHelper $doctrineHelper, EntityClassGenerator $entityClassGenerator) { @@ -172,6 +173,11 @@ public function interact(InputInterface $input, ConsoleStyle $io, Command $comma [Validator::class, 'notBlank'] ) ); + + $this->generateApi = $io->confirm('Do you want to implement API based Password Resets?', false); + + //@TODO Check if API Platform is installed, if true - continue, if false - alert user composer require api-platform + // @TODO May make more sense to ask this at the top and fail if yes and api platform is not installed. } public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator) @@ -265,6 +271,13 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen 'reset_password/reset.html.twig', 'resetPassword/twig_reset.tpl.php' ); + + if ($this->generateApi) { + // @TODO - Create DTO + // @TODO - Create Data Transformer + // @TODO - Create Data Persister + // @TODO - Add API DocBlocks to Entity + } $generator->writeChanges(); diff --git a/tests/Maker/MakeResetPasswordTest.php b/tests/Maker/MakeResetPasswordTest.php index 518b2c330..d91815335 100644 --- a/tests/Maker/MakeResetPasswordTest.php +++ b/tests/Maker/MakeResetPasswordTest.php @@ -28,6 +28,7 @@ public function getTestDetails() 'app_home', 'jr@rushlow.dev', 'SymfonyCasts', + false, // No Api ]) ->setRequiredPhpVersion(70200) ->addExtraDependencies('security-bundle') @@ -74,6 +75,7 @@ function (string $output, string $directory) { 'app_home', 'jr@rushlow.dev', 'SymfonyCasts', + false, // No Api ]) ->setRequiredPhpVersion(70200) ->addExtraDependencies('security-bundle') @@ -101,6 +103,7 @@ function (string $output, string $directory) { 'app_home', 'jr@rushlow.dev', 'SymfonyCasts', + false, // No Api ]) ->setRequiredPhpVersion(70200) ->addExtraDependencies('security-bundle') @@ -132,6 +135,7 @@ function (string $output, string $directory) { 'app_home', 'jr@rushlow.dev', 'SymfonyCasts', + false, // No Api ]) ->setRequiredPhpVersion(70200) ->addExtraDependencies('doctrine') @@ -153,6 +157,7 @@ function (string $output, string $directory) { 'app_home', 'jr@rushlow.dev', 'SymfonyCasts', + false, // No Api ]) ->setRequiredPhpVersion(70200) ->addExtraDependencies('security-bundle') @@ -180,5 +185,75 @@ function (string $output, string $directory) { } ), ]; + + yield 'reset_password_api' => [MakerTestDetails::createTest( + $this->getMakerInstance(MakeResetPassword::class), + [ + 'App\Entity\User', + 'emailAddress', + 'setMyPassword', + 'app_home', + 'jr@rushlow.dev', + 'SymfonyCasts', + true, // Generate API Objects + ]) + ->setRequiredPhpVersion(70200) + ->addExtraDependencies('api-platform') + ->addExtraDependencies('security-bundle') + ->addExtraDependencies('twig') + ->setFixtureFilesPath(__DIR__.'/../fixtures/MakeResetPasswordApiFixtures') + ->assert( + function (string $output, string $directory) { + $this->markTestIncomplete('NOT YET IMPLEMENTED'); + + $this->assertStringContainsString('Success', $output); + + $fs = new Filesystem(); + + $generatedFiles = [ + 'src/DataPersister/ResetPasswordDataPersister.php', + 'src/DataTransformer/ResetPasswordInputDateTransformer.php', + 'src/Dto/ResetPasswordInput', + ]; + + foreach ($generatedFiles as $file) { + $this->assertTrue($fs->exists(sprintf('%s/%s', $directory, $file))); + } + + // check ResetPasswordDto + $contentResetPasswordInput = file_get_contents($directory.'/src/Dto/ResetPasswordInput.php'); + $this->assertStringContainsString('@Groups({"reset-password:write"})', $contentResetPasswordInput); + $this->assertStringContainsString('public ?string $email = null;', $contentResetPasswordInput); + + // check ResetPasswordInputDataTransformer + $contentResetPasswordDataTransformer = file_get_contents($directory.'/src/DataTransformer/ResetPasswordInputDataTransformer.php'); + + // check ResetPasswordDataPersister + $contentResetPasswordRequestFormType = file_get_contents($directory.'/src/DataPersister/ResetPasswordDataPersister.php'); + } + ), + ]; + + yield 'reset_password_api_functional_test' => [MakerTestDetails::createTest( + $this->getMakerInstance(MakeResetPassword::class), + [ + 'App\Entity\User', + 'app_home', + 'jr@rushlow.dev', + 'SymfonyCasts', + true, // Generate API Objects + ]) + ->setRequiredPhpVersion(70200) + ->addExtraDependencies('api-platform') + ->addExtraDependencies('doctrine') + ->addExtraDependencies('doctrine/annotations') + ->addExtraDependencies('mailer') + ->addExtraDependencies('security-bundle') + ->addExtraDependencies('symfony/form') + ->addExtraDependencies('symfony/validator') + ->addExtraDependencies('twig') + ->setFixtureFilesPath(__DIR__.'/../fixtures/MakeResetPasswordApiFunctionalTest'), + ]; } + } From 9b1742453c1894b3b5b7a02d7ec8b4db8d0e2fbf Mon Sep 17 00:00:00 2001 From: Jesse Rushlow Date: Fri, 29 Jan 2021 18:14:17 -0500 Subject: [PATCH 2/5] WIP - draft templates to be generated --- .../ResetPasswordDataPersister.tpl.php | 57 +++++++++++++++++++ .../resetPassword/ResetPasswordInput.tpl.php | 16 ++++++ .../ResetPasswordInputDataTransformer.tpl.php | 24 ++++++++ 3 files changed, 97 insertions(+) create mode 100644 src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php create mode 100644 src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php create mode 100644 src/Resources/skeleton/resetPassword/ResetPasswordInputDataTransformer.tpl.php diff --git a/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php b/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php new file mode 100644 index 000000000..c52a1e76f --- /dev/null +++ b/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php @@ -0,0 +1,57 @@ +decoratedDataPersister = $decoratedDataPersister; + $this->userRepository = $userRepository; + $this->resetPasswordHelper = $resetPasswordHelper; + $this->messageBus = $messageBus; + } + + public function supports($data, array $context = []): bool + { + return $data instanceof ResetPasswordInput; + } + + /** + * @param ResetPasswordInput $data + */ + public function persist($data, array $context = []): void + { + $user = $this->userRepository->findOneBy(['email' => $data->email]); + + if (!$user instanceof User) { + return; + } + + $token = $this->resetPasswordHelper->generateResetToken($user); + + /** @psalm-suppress PossiblyNullArgument */ + $this->messageBus->dispatch(new SendResetPasswordMessage($user->getEmail(), $token)); + + return; + } + + public function remove($data, array $context = []): void + { + $this->decoratedDataPersister->remove($data); + } +} diff --git a/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php b/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php new file mode 100644 index 000000000..6f253a497 --- /dev/null +++ b/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php @@ -0,0 +1,16 @@ + Date: Sat, 30 Jan 2021 11:09:20 -0500 Subject: [PATCH 3/5] generate templates --- src/Maker/MakeResetPassword.php | 37 ++++++-- .../ResetPasswordDataPersister.tpl.php | 7 +- .../resetPassword/ResetPasswordInput.tpl.php | 6 +- .../ResetPasswordInputDataTransformer.tpl.php | 6 +- tests/Maker/MakeResetPasswordTest.php | 86 +++++++++---------- .../config/packages/security.yml | 3 + .../MakeResetPasswordApi/src/Entity/User.php | 38 ++++++++ 7 files changed, 123 insertions(+), 60 deletions(-) create mode 100644 tests/fixtures/MakeResetPasswordApi/config/packages/security.yml create mode 100644 tests/fixtures/MakeResetPasswordApi/src/Entity/User.php diff --git a/src/Maker/MakeResetPassword.php b/src/Maker/MakeResetPassword.php index 888d739a3..5fbc93401 100644 --- a/src/Maker/MakeResetPassword.php +++ b/src/Maker/MakeResetPassword.php @@ -271,12 +271,39 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen 'reset_password/reset.html.twig', 'resetPassword/twig_reset.tpl.php' ); - + if ($this->generateApi) { - // @TODO - Create DTO - // @TODO - Create Data Transformer - // @TODO - Create Data Persister - // @TODO - Add API DocBlocks to Entity + $dtoClassNameDetails = $generator->createClassNameDetails( + 'ResetPasswordInput', + 'Dto\\' + ); + + $generator->generateClass( + $dtoClassNameDetails->getFullName(), + 'resetPassword/ResetPasswordInput.tpl.php' + ); + + $dataTransformerClassNameDetails = $generator->createClassNameDetails( + 'ResetPasswordInputDataTransformer', + 'DataTransformer\\' + ); + + $generator->generateClass( + $dataTransformerClassNameDetails->getFullName(), + 'resetPassword/ResetPasswordInputDataTransformer.tpl.php', + ); + + $dataPersisterClassNameDetails = $generator->createClassNameDetails( + 'ResetPasswordDataPersister', + 'DataPersister\\' + ); + + $generator->generateClass( + $dataPersisterClassNameDetails->getFullName(), + 'resetPassword/ResetPasswordDataPersister.tpl.php' + ); + +// @TODO - Add API DocBlocks to Entity } $generator->writeChanges(); diff --git a/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php b/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php index c52a1e76f..b62d53a7a 100644 --- a/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php +++ b/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php @@ -1,6 +1,6 @@ - -namespace App\DataPersister; +namespace ; use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface; use ApiPlatform\Core\DataPersister\DataPersisterInterface; @@ -11,7 +11,7 @@ use Symfony\Component\Messenger\MessageBusInterface; use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface; -class ResetPasswordDataPersister implements ContextAwareDataPersisterInterface +class implements ContextAwareDataPersisterInterface { private DataPersisterInterface $decoratedDataPersister; private UserRepository $userRepository; @@ -44,7 +44,6 @@ public function persist($data, array $context = []): void $token = $this->resetPasswordHelper->generateResetToken($user); - /** @psalm-suppress PossiblyNullArgument */ $this->messageBus->dispatch(new SendResetPasswordMessage($user->getEmail(), $token)); return; diff --git a/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php b/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php index 6f253a497..defd97fed 100644 --- a/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php +++ b/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php @@ -1,11 +1,11 @@ - -namespace App\Dto; +namespace ; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; -class ResetPasswordInput +class { /** * @Groups({"reset-password:write"}) diff --git a/src/Resources/skeleton/resetPassword/ResetPasswordInputDataTransformer.tpl.php b/src/Resources/skeleton/resetPassword/ResetPasswordInputDataTransformer.tpl.php index bc6af6396..7438fde15 100644 --- a/src/Resources/skeleton/resetPassword/ResetPasswordInputDataTransformer.tpl.php +++ b/src/Resources/skeleton/resetPassword/ResetPasswordInputDataTransformer.tpl.php @@ -1,12 +1,12 @@ - -namespace App\DataTransformer; +namespace ; use ApiPlatform\Core\DataTransformer\DataTransformerInterface; use App\Dto\ResetPasswordInput; use App\Entity\ResetPasswordRequest; -class ResetPasswordInputDataTransformer implements DataTransformerInterface +class implements DataTransformerInterface { public function transform($object, string $to, array $context = []): object { diff --git a/tests/Maker/MakeResetPasswordTest.php b/tests/Maker/MakeResetPasswordTest.php index d91815335..784557d93 100644 --- a/tests/Maker/MakeResetPasswordTest.php +++ b/tests/Maker/MakeResetPasswordTest.php @@ -24,11 +24,11 @@ public function getTestDetails() yield 'reset_password_replaces_flex_config' => [MakerTestDetails::createTest( $this->getMakerInstance(MakeResetPassword::class), [ - 'App\Entity\User', - 'app_home', - 'jr@rushlow.dev', - 'SymfonyCasts', - false, // No Api + 'App\Entity\User', // User Entity + 'app_home', // Redirect route after successful reset + 'jr@rushlow.dev', // Email from address + 'SymfonyCasts', // Email from name + 'n', // Generate API templates ]) ->setRequiredPhpVersion(70200) ->addExtraDependencies('security-bundle') @@ -71,11 +71,11 @@ function (string $output, string $directory) { yield 'reset_password_custom_config' => [MakerTestDetails::createTest( $this->getMakerInstance(MakeResetPassword::class), [ - 'App\Entity\User', - 'app_home', - 'jr@rushlow.dev', - 'SymfonyCasts', - false, // No Api + 'App\Entity\User', // User Entity + 'app_home', // Redirect route after successful reset + 'jr@rushlow.dev', // Email from address + 'SymfonyCasts', // Email from name + 'n', // Generate API templates ]) ->setRequiredPhpVersion(70200) ->addExtraDependencies('security-bundle') @@ -99,11 +99,11 @@ function (string $output, string $directory) { yield 'reset_password_amends_config' => [MakerTestDetails::createTest( $this->getMakerInstance(MakeResetPassword::class), [ - 'App\Entity\User', - 'app_home', - 'jr@rushlow.dev', - 'SymfonyCasts', - false, // No Api + 'App\Entity\User', // User Entity + 'app_home', // Redirect route after successful reset + 'jr@rushlow.dev', // Email from address + 'SymfonyCasts', // Email from name + 'n', // Generate API templates ]) ->setRequiredPhpVersion(70200) ->addExtraDependencies('security-bundle') @@ -131,11 +131,11 @@ function (string $output, string $directory) { yield 'reset_password_functional_test' => [MakerTestDetails::createTest( $this->getMakerInstance(MakeResetPassword::class), [ - 'App\Entity\User', - 'app_home', - 'jr@rushlow.dev', - 'SymfonyCasts', - false, // No Api + 'App\Entity\User', // User Entity + 'app_home', // Redirect route after successful reset + 'jr@rushlow.dev', // Email from address + 'SymfonyCasts', // Email from name + 'n', // Generate API templates ]) ->setRequiredPhpVersion(70200) ->addExtraDependencies('doctrine') @@ -151,13 +151,13 @@ function (string $output, string $directory) { yield 'reset_password_custom_user' => [MakerTestDetails::createTest( $this->getMakerInstance(MakeResetPassword::class), [ - 'App\Entity\UserCustom', - 'emailAddress', - 'setMyPassword', - 'app_home', - 'jr@rushlow.dev', - 'SymfonyCasts', - false, // No Api + 'App\Entity\UserCustom', // User Entity + 'emailAddress', // Email property + 'setMyPassword', // Email setter + 'app_home', // Redirect route after successful reset + 'jr@rushlow.dev', // Email from address + 'SymfonyCasts', // Email from name + 'n', // Generate API Templates ]) ->setRequiredPhpVersion(70200) ->addExtraDependencies('security-bundle') @@ -189,22 +189,19 @@ function (string $output, string $directory) { yield 'reset_password_api' => [MakerTestDetails::createTest( $this->getMakerInstance(MakeResetPassword::class), [ - 'App\Entity\User', - 'emailAddress', - 'setMyPassword', - 'app_home', - 'jr@rushlow.dev', - 'SymfonyCasts', - true, // Generate API Objects + 'App\Entity\User', // User Entity + 'app_home', // Redirect route after successful reset + 'jr@rushlow.dev', // Email from address + 'SymfonyCasts', // Email from name + 'y', // Generate API templates ]) ->setRequiredPhpVersion(70200) - ->addExtraDependencies('api-platform') + ->addExtraDependencies('api') ->addExtraDependencies('security-bundle') ->addExtraDependencies('twig') - ->setFixtureFilesPath(__DIR__.'/../fixtures/MakeResetPasswordApiFixtures') + ->setFixtureFilesPath(__DIR__.'/../fixtures/MakeResetPasswordApi') ->assert( function (string $output, string $directory) { - $this->markTestIncomplete('NOT YET IMPLEMENTED'); $this->assertStringContainsString('Success', $output); @@ -212,8 +209,8 @@ function (string $output, string $directory) { $generatedFiles = [ 'src/DataPersister/ResetPasswordDataPersister.php', - 'src/DataTransformer/ResetPasswordInputDateTransformer.php', - 'src/Dto/ResetPasswordInput', + 'src/DataTransformer/ResetPasswordInputDataTransformer.php', + 'src/Dto/ResetPasswordInput.php', ]; foreach ($generatedFiles as $file) { @@ -237,11 +234,11 @@ function (string $output, string $directory) { yield 'reset_password_api_functional_test' => [MakerTestDetails::createTest( $this->getMakerInstance(MakeResetPassword::class), [ - 'App\Entity\User', - 'app_home', - 'jr@rushlow.dev', - 'SymfonyCasts', - true, // Generate API Objects + 'App\Entity\User', // User Entity + 'app_home', // Redirect route after successful reset + 'jr@rushlow.dev', // Email from address + 'SymfonyCasts', // Email from name + 'y', // Generate API templates ]) ->setRequiredPhpVersion(70200) ->addExtraDependencies('api-platform') @@ -255,5 +252,4 @@ function (string $output, string $directory) { ->setFixtureFilesPath(__DIR__.'/../fixtures/MakeResetPasswordApiFunctionalTest'), ]; } - } diff --git a/tests/fixtures/MakeResetPasswordApi/config/packages/security.yml b/tests/fixtures/MakeResetPasswordApi/config/packages/security.yml new file mode 100644 index 000000000..0cdc923bd --- /dev/null +++ b/tests/fixtures/MakeResetPasswordApi/config/packages/security.yml @@ -0,0 +1,3 @@ +security: + encoders: + App\Entity\User: bcrypt diff --git a/tests/fixtures/MakeResetPasswordApi/src/Entity/User.php b/tests/fixtures/MakeResetPasswordApi/src/Entity/User.php new file mode 100644 index 000000000..98fcf97e9 --- /dev/null +++ b/tests/fixtures/MakeResetPasswordApi/src/Entity/User.php @@ -0,0 +1,38 @@ + Date: Sat, 30 Jan 2021 18:47:27 -0500 Subject: [PATCH 4/5] use template vars --- src/Maker/MakeResetPassword.php | 28 ++++++++++++++++++- .../ResetPasswordDataPersister.tpl.php | 27 ++++++++++-------- .../resetPassword/ResetPasswordInput.tpl.php | 2 +- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/Maker/MakeResetPassword.php b/src/Maker/MakeResetPassword.php index 5fbc93401..e67382a4c 100644 --- a/src/Maker/MakeResetPassword.php +++ b/src/Maker/MakeResetPassword.php @@ -188,6 +188,26 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen 'Entity\\' ); + $userDoctrineDetails = $this->doctrineHelper->createDoctrineDetails($userClassNameDetails->getFullName()); + + $userRepoVars = [ + 'repository_full_class_name' => 'Doctrine\ORM\EntityManagerInterface', + 'repository_class_name' => 'EntityManagerInterface', + 'repository_property_var' => 'manager', + 'repository_var' => '$manager', + ]; + + if (null !== $userDoctrineDetails && null !== ($userRepository = $userDoctrineDetails->getRepositoryClass())) { + $userRepoClassDetails = $generator->createClassNameDetails('\\'.$userRepository, 'Repository\\', 'Repository'); + + $userRepoVars = [ + 'repository_full_class_name' => $userRepoClassDetails->getFullName(), + 'repository_class_name' => $userRepoClassDetails->getShortName(), + 'repository_property_var' => lcfirst($userRepoClassDetails->getShortName()), + 'repository_var' => sprintf('$%s', lcfirst($userRepoClassDetails->getShortName())), + ]; + } + $controllerClassNameDetails = $generator->createClassNameDetails( 'ResetPasswordController', 'Controller\\' @@ -300,7 +320,13 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen $generator->generateClass( $dataPersisterClassNameDetails->getFullName(), - 'resetPassword/ResetPasswordDataPersister.tpl.php' + 'resetPassword/ResetPasswordDataPersister.tpl.php', + array_merge([ + 'user_full_class_name' => $userClassNameDetails->getFullName(), + 'user_class_name' => $userClassNameDetails->getShortName(), + ], + $userRepoVars + ) ); // @TODO - Add API DocBlocks to Entity diff --git a/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php b/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php index b62d53a7a..a61c2eb6e 100644 --- a/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php +++ b/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php @@ -5,23 +5,23 @@ use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface; use ApiPlatform\Core\DataPersister\DataPersisterInterface; use App\Dto\ResetPasswordInput; -use App\Entity\User; +use ; use App\Message\SendResetPasswordMessage; -use App\Repository\UserRepository; +use ; use Symfony\Component\Messenger\MessageBusInterface; use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface; class implements ContextAwareDataPersisterInterface { - private DataPersisterInterface $decoratedDataPersister; - private UserRepository $userRepository; - private ResetPasswordHelperInterface $resetPasswordHelper; - private MessageBusInterface $messageBus; + private $decoratedDataPersister; + private ; + private $resetPasswordHelper; + private $messageBus; - public function __construct(DataPersisterInterface $decoratedDataPersister, UserRepository $userRepository, ResetPasswordHelperInterface $resetPasswordHelper, MessageBusInterface $messageBus) + public function __construct(DataPersisterInterface $decoratedDataPersister, , ResetPasswordHelperInterface $resetPasswordHelper, MessageBusInterface $messageBus) { $this->decoratedDataPersister = $decoratedDataPersister; - $this->userRepository = $userRepository; + $this-> = ; $this->resetPasswordHelper = $resetPasswordHelper; $this->messageBus = $messageBus; } @@ -36,9 +36,14 @@ public function supports($data, array $context = []): bool */ public function persist($data, array $context = []): void { - $user = $this->userRepository->findOneBy(['email' => $data->email]); - - if (!$user instanceof User) { + + $repository = $this->->getRepository(::class); + $user = $repository->findOneBy(['email' => $data->email]); + + $user = $this->->findOneBy(['email' => $data->email]); + + + if (!$user instanceof ) { return; } diff --git a/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php b/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php index defd97fed..127c652c0 100644 --- a/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php +++ b/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php @@ -12,5 +12,5 @@ class * @Assert\NotBlank * @Assert\Email() */ - public ?string $email = null; + public $email = null; } From afb75b0ce52e657cf02d7e3e03ee458d45af4460 Mon Sep 17 00:00:00 2001 From: Jesse Rushlow Date: Sun, 31 Jan 2021 15:36:07 -0500 Subject: [PATCH 5/5] refactor templates --- .../ResetPasswordDataPersister.tpl.php | 71 ++++++++++++++++--- .../resetPassword/ResetPasswordInput.tpl.php | 20 ++++-- 2 files changed, 78 insertions(+), 13 deletions(-) diff --git a/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php b/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php index a61c2eb6e..835574128 100644 --- a/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php +++ b/src/Resources/skeleton/resetPassword/ResetPasswordDataPersister.tpl.php @@ -3,38 +3,72 @@ namespace ; use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface; -use ApiPlatform\Core\DataPersister\DataPersisterInterface; use App\Dto\ResetPasswordInput; use ; use App\Message\SendResetPasswordMessage; use ; use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface; class implements ContextAwareDataPersisterInterface { - private $decoratedDataPersister; private ; private $resetPasswordHelper; private $messageBus; + private $userPasswordEncoder; - public function __construct(DataPersisterInterface $decoratedDataPersister, , ResetPasswordHelperInterface $resetPasswordHelper, MessageBusInterface $messageBus) + public function __construct( , ResetPasswordHelperInterface $resetPasswordHelper, MessageBusInterface $messageBus, UserPasswordEncoderInterface $userPasswordEncoder) { - $this->decoratedDataPersister = $decoratedDataPersister; $this-> = ; $this->resetPasswordHelper = $resetPasswordHelper; $this->messageBus = $messageBus; + $this->userPasswordEncoder = $userPasswordEncoder; } public function supports($data, array $context = []): bool { - return $data instanceof ResetPasswordInput; + if (!$data instanceof ResetPasswordInput) { + return false; + } + + if (isset($context['collection_operation_name']) && 'post' === $context['collection_operation_name']) { + return true; + } + + if (isset($context['item_operation_name']) && 'put' === $context['item_operation_name']) { + return true; + } + + return false; } /** * @param ResetPasswordInput $data */ public function persist($data, array $context = []): void + { + if (isset($context['collection_operation_name']) && 'post' === $context['collection_operation_name']) { + $this->generateRequest($data->email); + + return; + } + + if (isset($context['item_operation_name']) && 'put' === $context['item_operation_name']) { + if (!$context['previous_data'] instanceof ) { + return; + } + + $this->changePassword($context['previous_data'], $data->plainTextPassword); + } + } + + public function remove($data, array $context = []): void + { + throw new \RuntimeException('Operation not supported.'); + } + + private function generateRequest(string $email): void { $repository = $this->->getRepository(::class); @@ -50,12 +84,31 @@ public function persist($data, array $context = []): void $token = $this->resetPasswordHelper->generateResetToken($user); $this->messageBus->dispatch(new SendResetPasswordMessage($user->getEmail(), $token)); - - return; } - public function remove($data, array $context = []): void + private function changePassword( $previousUser, string $plainTextPassword): void { - $this->decoratedDataPersister->remove($data); + $userId = $previousUser->getId(); + + + $repository = $this->->getRepository(::class); + $user = $repository->find($userId); + + $user = $this->->find($userId); + + + if (null === $user) { + return; + } + + $encoded = $this->userPasswordEncoder->encodePassword($user, $plainTextPassword); + + + $user->setPassword($encoded); + + $repository->flush(); + + $this->->upgradePassword($user, $encoded); + } } diff --git a/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php b/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php index 127c652c0..3764af176 100644 --- a/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php +++ b/src/Resources/skeleton/resetPassword/ResetPasswordInput.tpl.php @@ -8,9 +8,21 @@ class { /** - * @Groups({"reset-password:write"}) - * @Assert\NotBlank - * @Assert\Email() - */ + * @Assert\NotBlank(groups={"postValidation"}) + * @Assert\Email(groups={"postValidation"}) + * @Groups({"reset-password:post"}) + */ public $email = null; + + /** + * @Assert\NotBlank(groups={"putValidation"}) + * @Groups({"reset-password:put"}) + */ + public $token = null; + + /** + * @Assert\NotBlank(groups={"putValidation"}) + * @Groups({"reset-password:put"}) + */ + public $plainTextPassword = null; }