diff --git a/src/Tech/Controller/ProfileController.php b/src/Tech/Controller/ProfileController.php new file mode 100644 index 0000000..ca8e37a --- /dev/null +++ b/src/Tech/Controller/ProfileController.php @@ -0,0 +1,105 @@ +getUser(); + if (!$user instanceof User) { + throw $this->createAccessDeniedException(); + } + + $passwordForm = $this->createForm(ProfileChangePasswordFormType::class); + $passwordForm->handleRequest($request); + + if ($passwordForm->isSubmitted() && $passwordForm->isValid()) { + $currentPassword = (string) $passwordForm->get('currentPassword')->getData(); + + if (!$this->passwordHasher->isPasswordValid($user, $currentPassword)) { + $passwordForm->get('currentPassword')->addError(new FormError('Incorrect password.')); + } else { + $plainPassword = (string) $passwordForm->get('plainPassword')->getData(); + $user->setPassword($this->passwordHasher->hashPassword($user, $plainPassword)); + $this->entityManager->flush(); + + $this->addFlash('success', 'Your password has been updated.'); + + return $this->redirectToRoute('app_profile'); + } + } + + $emailForm = $this->createForm(ProfileChangeEmailFormType::class, ['email' => $user->getEmail()]); + $emailForm->handleRequest($request); + + if ($emailForm->isSubmitted() && $emailForm->isValid()) { + $currentPassword = (string) $emailForm->get('currentPassword')->getData(); + + if (!$this->passwordHasher->isPasswordValid($user, $currentPassword)) { + $emailForm->get('currentPassword')->addError(new FormError('Incorrect password.')); + } else { + $newEmail = (string) $emailForm->get('email')->getData(); + + if ($newEmail === $user->getEmail()) { + $this->addFlash('info', 'That is already your email address.'); + return $this->redirectToRoute('app_profile'); + } + + $existing = $this->userRepository->findOneBy(['email' => $newEmail]); + if ($existing) { + $emailForm->get('email')->addError(new FormError('This email address is already in use.')); + } else { + $user->setEmail($newEmail); + $user->setIsVerified(false); + $this->entityManager->flush(); + + $this->emailVerifier->sendEmailConfirmation('app_verify_email', $user, + (new TemplatedEmail()) + ->from($this->getParameter('mailer_from')) + ->to($newEmail) + ->subject('Please confirm your new email address') + ->htmlTemplate('tech/registration/confirmation_email.html.twig') + ); + + $this->addFlash('success', 'Your email address has been updated. You must verify it (check your inbox) before you can log in again.'); + + return $this->redirectToRoute('app_profile'); + } + } + } + + return $this->render('tech/profile/index.html.twig', [ + 'user' => $user, + 'passwordForm' => $passwordForm, + 'emailForm' => $emailForm, + ]); + } +} diff --git a/src/Tech/Form/ProfileChangeEmailFormType.php b/src/Tech/Form/ProfileChangeEmailFormType.php new file mode 100644 index 0000000..0547e97 --- /dev/null +++ b/src/Tech/Form/ProfileChangeEmailFormType.php @@ -0,0 +1,36 @@ +add('email', EmailType::class, [ + 'label' => 'New email address', + 'constraints' => [new NotBlank(), new Email()], + ]) + ->add('currentPassword', PasswordType::class, [ + 'label' => 'Current password', + 'attr' => ['autocomplete' => 'current-password'], + 'constraints' => [ + new NotBlank(message: 'Please enter your current password'), + ], + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([]); + } +} diff --git a/src/Tech/Form/ProfileChangePasswordFormType.php b/src/Tech/Form/ProfileChangePasswordFormType.php new file mode 100644 index 0000000..80ade6a --- /dev/null +++ b/src/Tech/Form/ProfileChangePasswordFormType.php @@ -0,0 +1,59 @@ +add('currentPassword', PasswordType::class, [ + 'label' => 'Current password', + 'attr' => ['autocomplete' => 'current-password'], + 'constraints' => [ + new NotBlank(message: 'Please enter your current password'), + ], + ]) + ->add('plainPassword', RepeatedType::class, [ + 'type' => PasswordType::class, + 'options' => [ + 'attr' => [ + 'autocomplete' => 'new-password', + ], + ], + 'first_options' => [ + 'constraints' => [ + new NotBlank(message: 'Please enter a password'), + new Length( + min: 12, + minMessage: 'Your password should be at least {{ limit }} characters', + max: 4096, + ), + new PasswordStrength(), + new NotCompromisedPassword(), + ], + 'label' => 'New password', + ], + 'second_options' => [ + 'label' => 'Repeat new password', + ], + 'invalid_message' => 'The password fields must match.', + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([]); + } +} diff --git a/templates/layout/site.html.twig b/templates/layout/site.html.twig index 3cd9b0b..2fc06a0 100644 --- a/templates/layout/site.html.twig +++ b/templates/layout/site.html.twig @@ -26,6 +26,9 @@ {{ 'nav.admin'|trans }} {% endif %} +
Current email: {{ user.email }}
+ {{ form_start(emailForm) }} + {{ form_row(emailForm.email) }} + {{ form_row(emailForm.currentPassword) }} +