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 %} + diff --git a/templates/tech/profile/index.html.twig b/templates/tech/profile/index.html.twig new file mode 100644 index 0000000..a3f4971 --- /dev/null +++ b/templates/tech/profile/index.html.twig @@ -0,0 +1,39 @@ +{% extends 'layout/site.html.twig' %} + +{% block title %}Profile{% endblock %} + +{% block body %} +

Profile

+ +
+
+
+
Change Email
+
+

Current email: {{ user.email }}

+ {{ form_start(emailForm) }} + {{ form_row(emailForm.email) }} + {{ form_row(emailForm.currentPassword) }} +
+ +
+ {{ form_end(emailForm) }} +
+
+
+
+
+
Change Password
+
+ {{ form_start(passwordForm) }} + {{ form_row(passwordForm.currentPassword) }} + {{ form_row(passwordForm.plainPassword) }} +
+ +
+ {{ form_end(passwordForm) }} +
+
+
+
+{% endblock %} diff --git a/translations/messages.en.yaml b/translations/messages.en.yaml index 0fe2631..14bd9a3 100644 --- a/translations/messages.en.yaml +++ b/translations/messages.en.yaml @@ -3,6 +3,7 @@ site.name: EscapePage nav.home: Home nav.game: Game nav.admin: Admin +nav.profile: Profile nav.login: Login nav.register: Register nav.logout: Logout diff --git a/translations/messages.nl.yaml b/translations/messages.nl.yaml index ff772f2..f2c6108 100644 --- a/translations/messages.nl.yaml +++ b/translations/messages.nl.yaml @@ -3,6 +3,7 @@ site.name: EscapePage nav.home: Start nav.game: Spel nav.admin: Beheer +nav.profile: Profiel nav.login: Inloggen nav.register: Registreren nav.logout: Uitloggen