Skip to content
Snippets Groups Projects
Commit d28ab22d authored by Camille Simiand's avatar Camille Simiand
Browse files

Merge branch...

Merge branch 'tuleap-142-when-editing-email-address-user-should-confirm-it-with-email-validation' into 'main'

tuleap-142-when-editing-email-address-user-should-confirm-it-with-email-validation

See merge request !69
parents dd76f01b dc3bc680
No related branches found
No related tags found
1 merge request!69tuleap-142-when-editing-email-address-user-should-confirm-it-with-email-validation
Pipeline #944 passed
Showing
with 333 additions and 42 deletions
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20220307154836 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE `pending_email_address` (id INT AUTO_INCREMENT NOT NULL, user INT NOT NULL, email VARCHAR(255) NOT NULL, INDEX IDX_621FD0118D93D649 (user), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE `pending_email_address` ADD CONSTRAINT FK_621FD0118D93D649 FOREIGN KEY (user) REFERENCES `user` (id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE `pending_email_address`');
$this->addSql('ALTER TABLE capsule CHANGE nom nom VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE link link VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE edition_link edition_link VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE password password VARCHAR(50) NOT NULL COLLATE `utf8_unicode_ci`');
$this->addSql('ALTER TABLE `group` CHANGE name name VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`');
$this->addSql('ALTER TABLE invitation_editeur_capsule CHANGE email email VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`');
$this->addSql('ALTER TABLE reset_password_request CHANGE selector selector VARCHAR(20) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE hashed_token hashed_token VARCHAR(100) NOT NULL COLLATE `utf8_unicode_ci`');
$this->addSql('ALTER TABLE `user` CHANGE email email VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE email_canonical email_canonical VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE name name VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE firstname firstname VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE username username VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE username_canonical username_canonical VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE roles roles LONGTEXT NOT NULL COLLATE `utf8_unicode_ci` COMMENT \'(DC2Type:json)\', CHANGE password password VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE salt salt VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`');
}
}
...@@ -278,9 +278,6 @@ class CapsuleEditorController extends AbstractController ...@@ -278,9 +278,6 @@ class CapsuleEditorController extends AbstractController
int $capsule_id, int $capsule_id,
Request $request Request $request
): Response { ): Response {
$form = $this->createForm(RemoveEditorFormType::class);
$form->handleRequest($request);
$capsule = $this->capsule_repository->findOneBy(['id' => $capsule_id]); $capsule = $this->capsule_repository->findOneBy(['id' => $capsule_id]);
if (! $capsule instanceof Capsule) { if (! $capsule instanceof Capsule) {
throw new \Exception('The retrieved capsule is not an instance of Capsule.'); throw new \Exception('The retrieved capsule is not an instance of Capsule.');
...@@ -289,6 +286,9 @@ class CapsuleEditorController extends AbstractController ...@@ -289,6 +286,9 @@ class CapsuleEditorController extends AbstractController
$pending_editor_invitation = $this->capsule_pending_editor_invitation_repository $pending_editor_invitation = $this->capsule_pending_editor_invitation_repository
->findOneBy(['id' => $pending_editor_invitation_id]); ->findOneBy(['id' => $pending_editor_invitation_id]);
$form = $this->createForm(RemoveEditorFormType::class);
$form->handleRequest($request);
if (! $pending_editor_invitation instanceof PendingEditorInvitation) { if (! $pending_editor_invitation instanceof PendingEditorInvitation) {
$this->addFlash( $this->addFlash(
'warning', 'warning',
......
...@@ -69,7 +69,7 @@ class RegistrationController extends AbstractController ...@@ -69,7 +69,7 @@ class RegistrationController extends AbstractController
} }
return $this->renderForm('registration/register.html.twig', [ return $this->renderForm('registration/register.html.twig', [
'registrationForm' => $form, 'registrationForm' => $form
]); ]);
} }
...@@ -92,7 +92,7 @@ class RegistrationController extends AbstractController ...@@ -92,7 +92,7 @@ class RegistrationController extends AbstractController
try { try {
$this->email_verifier->handleEmailConfirmation($request, $user); $this->email_verifier->handleEmailConfirmation($request, $user);
} catch (VerifyEmailExceptionInterface $exception) { } catch (VerifyEmailExceptionInterface $exception) {
$this->addFlash('verify_email_error', $exception->getReason()); $this->addFlash('error', $exception->getReason());
return $this->redirectToRoute('app_register'); return $this->redirectToRoute('app_register');
} }
......
...@@ -43,7 +43,7 @@ class ResetPasswordController extends AbstractController ...@@ -43,7 +43,7 @@ class ResetPasswordController extends AbstractController
} }
return $this->renderForm('reset_password/request.html.twig', [ return $this->renderForm('reset_password/request.html.twig', [
'requestForm' => $form, 'requestForm' => $form
]); ]);
} }
...@@ -118,7 +118,7 @@ class ResetPasswordController extends AbstractController ...@@ -118,7 +118,7 @@ class ResetPasswordController extends AbstractController
} }
return $this->renderForm('reset_password/reset.html.twig', [ return $this->renderForm('reset_password/reset.html.twig', [
'resetForm' => $form, 'resetForm' => $form
]); ]);
} }
......
...@@ -2,13 +2,18 @@ ...@@ -2,13 +2,18 @@
namespace App\Controller; namespace App\Controller;
use App\Entity\PendingEmailAddress;
use App\Entity\User; use App\Entity\User;
use App\Form\EditPasswordFormType; use App\Form\EditPasswordFormType;
use App\Form\EditUserProfileFormType; use App\Form\EditUserProfileFormType;
use App\Repository\PendingEmailAddressRepository;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
...@@ -17,7 +22,8 @@ class UserController extends AbstractController ...@@ -17,7 +22,8 @@ class UserController extends AbstractController
{ {
public function __construct( public function __construct(
private EntityManagerInterface $entity_manager, private EntityManagerInterface $entity_manager,
private TranslatorInterface $translator private TranslatorInterface $translator,
private PendingEmailAddressRepository $pending_email_address_repository
) { ) {
} }
...@@ -36,26 +42,65 @@ class UserController extends AbstractController ...@@ -36,26 +42,65 @@ class UserController extends AbstractController
} }
#[Route('/edit_profile', name:'edit_profile')] #[Route('/edit_profile', name:'edit_profile')]
public function editProfile(Request $request): Response public function editProfile(
{ Request $request,
MailerInterface $mailer
): Response {
$current_user = $this->getUser(); $current_user = $this->getUser();
if (! $current_user instanceof User) { if (! $current_user instanceof User) {
return $this->redirectToRoute('app_logout'); return $this->redirectToRoute('app_logout');
} }
$form = $this->createForm(EditUserProfileFormType::class, $current_user); $last_pending_email_address = $this->pending_email_address_repository->findOneBy(
['user' => $current_user->getId()]
);
if ($last_pending_email_address !== null) {
$this->entity_manager->remove($last_pending_email_address);
}
$form->setData($current_user); $form = $this->createForm(
EditUserProfileFormType::class,
$current_user,
['current_email_address' => $current_user->getEmail()]
);
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
if ($current_user->getEmail() !== $form->get('email')->getData()) {
$pending_email_address = new PendingEmailAddress();
$pending_email_address->setEmail($form->get('email')->getData());
$pending_email_address->setUser($current_user);
$this->entity_manager->persist($pending_email_address);
$this->entity_manager->flush();
$email = (new TemplatedEmail())
->to(new Address($pending_email_address->getEmail()))
->subject($this->translator->trans('user.edit.email.title'))
->htmlTemplate('user/update_email.html.twig')
->context([
'expiration_date' => new \DateTime('+1 day')
]);
$mailer->send($email);
$this->addFlash(
'warning',
$this->translator->trans('user.profile.updated.warning', [
'new_email_address' => $form->get('email')->getData()
])
);
return $this->render('user/edit_email_address.html.twig', [
'new_email_address' => $form->get('email')->getData()
]);
}
$this->entity_manager->persist($current_user); $this->entity_manager->persist($current_user);
$this->entity_manager->flush(); $this->entity_manager->flush();
$this->addFlash( $this->addFlash(
'profile_updated_success', 'success',
$this->translator->trans('user.profile.updated_success') $this->translator->trans('user.profile.updated.success')
); );
return $this->redirectToRoute('show_profile'); return $this->redirectToRoute('show_profile');
...@@ -69,7 +114,7 @@ class UserController extends AbstractController ...@@ -69,7 +114,7 @@ class UserController extends AbstractController
#[Route('/edit_password', name:'edit_password')] #[Route('/edit_password', name:'edit_password')]
public function editPassword( public function editPassword(
Request $request, Request $request,
UserPasswordHasherInterface $user_password_hasher, UserPasswordHasherInterface $user_password_hasher
): Response { ): Response {
$form = $this->createForm(EditPasswordFormType::class); $form = $this->createForm(EditPasswordFormType::class);
$form->handleRequest($request); $form->handleRequest($request);
...@@ -98,4 +143,33 @@ class UserController extends AbstractController ...@@ -98,4 +143,33 @@ class UserController extends AbstractController
'editPasswordForm' => $form 'editPasswordForm' => $form
]); ]);
} }
#[Route('/edit/email', name:'verify_new_email_address')]
public function verifyNewEmailAddress(): Response
{
$current_user = $this->getUser();
if (! $current_user instanceof User) {
return $this->redirectToRoute('app_logout');
}
$pending_email_address = $this->pending_email_address_repository->findOneBy(['user' => $current_user->getId()]);
if (! $pending_email_address instanceof PendingEmailAddress) {
throw new \Exception('Pending email address not found');
}
$current_user->setEmail($pending_email_address->getEmail());
$this->entity_manager->persist($current_user);
$this->entity_manager->remove($pending_email_address);
$this->entity_manager->flush();
$this->addFlash(
'success',
$this->translator->trans(
'user.edit.email.success',
['new_email_address' => $pending_email_address->getEmail()]
)
);
return $this->redirectToRoute('show_profile');
}
} }
<?php
namespace App\Entity;
use App\Repository\PendingEmailAddressRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass:PendingEmailAddressRepository::class)]
#[ORM\Table(name:'`pending_email_address`')]
#[UniqueEntity(fields: ['user', 'email'], message: 'pending_email_address.email.unique', errorPath: 'email')]
class PendingEmailAddress
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type:'integer')]
private int $id;
#[ORM\ManyToOne(targetEntity:User::class)]
#[ORM\JoinColumn(name:'user', referencedColumnName:'id', nullable:false)]
private User $user;
#[Assert\Email(message: 'email.valid')]
#[ORM\Column(type:'string', length:255)]
private string $email;
public function getUser(): User
{
return $this->user;
}
public function setUser(User $user): void
{
$this->user = $user;
}
public function getEmail(): string
{
return $this->email;
}
public function setEmail(string $email): void
{
$this->email = $email;
}
}
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
namespace App\Form; namespace App\Form;
use App\Entity\User; use App\Entity\User;
use App\Repository\PendingEmailAddressRepository;
use App\Repository\UserRepository;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType; use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType; use Symfony\Component\Form\Extension\Core\Type\PasswordType;
...@@ -12,11 +14,27 @@ use Symfony\Component\Form\FormBuilderInterface; ...@@ -12,11 +14,27 @@ use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Validator\Constraints\UserPassword; use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
class EditUserProfileFormType extends AbstractType class EditUserProfileFormType extends AbstractType
{ {
private UserRepository $user_repository;
private PendingEmailAddressRepository $pending_email_address_repository;
public function __construct(
UserRepository $user_repository,
PendingEmailAddressRepository $pending_email_address_repository
) {
$this->user_repository = $user_repository;
$this->pending_email_address_repository = $pending_email_address_repository;
}
public function buildForm(FormBuilderInterface $builder, array $options): void public function buildForm(FormBuilderInterface $builder, array $options): void
{ {
$user_repository = $this->user_repository;
$pending_email_address_repository = $this->pending_email_address_repository;
$builder $builder
->add( ->add(
'firstName', 'firstName',
...@@ -40,9 +58,36 @@ class EditUserProfileFormType extends AbstractType ...@@ -40,9 +58,36 @@ class EditUserProfileFormType extends AbstractType
'email', 'email',
EmailType::class, EmailType::class,
[ [
'constraints' => [new NotBlank(['message' => 'email.not_blank'])], 'data' => $options['current_email_address'],
'constraints' => [
new NotBlank(['message' => 'email.not_blank']),
new Assert\Email(),
new Assert\Callback(
['callback' => static function (
string $value,
ExecutionContextInterface $context
) use (
$options,
$user_repository,
$pending_email_address_repository
) {
if (
$value !== $options['current_email_address'] &&
($user_repository->emailExists($value) ||
$pending_email_address_repository->emailIsReserved($value))
) {
$context
->buildViolation(message: 'user.email.unique')
->addViolation()
;
}
}
]
)
],
'label' => 'general.email', 'label' => 'general.email',
'empty_data' => '' 'empty_data' => '',
'mapped' => false
] ]
) )
->add( ->add(
...@@ -70,6 +115,9 @@ class EditUserProfileFormType extends AbstractType ...@@ -70,6 +115,9 @@ class EditUserProfileFormType extends AbstractType
{ {
$resolver->setDefaults([ $resolver->setDefaults([
'data_class' => User::class, 'data_class' => User::class,
'current_email_address' => '',
'users_emails' => [],
'pending_emails' => []
]); ]);
} }
} }
<?php
namespace App\Repository;
use App\Entity\PendingEmailAddress;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method PendingEmailAddress|null find($id, $lockMode = null, $lockVersion = null)
* @method PendingEmailAddress|null findOneBy(array $criteria, array $orderBy = null)
* @method PendingEmailAddress[] findAll()
* @method PendingEmailAddress[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
* @template PendingEmailAddress of object
*/
class PendingEmailAddressRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, PendingEmailAddress::class);
}
public function findOneByEmail(string $value): ?User
{
return $this->createQueryBuilder('u')
->andWhere('u.email = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
public function emailIsReserved(string $email): bool
{
return $this->createQueryBuilder('p')
->andWhere('p.email = :email')
->setParameter('email', $email)
->getQuery()
->getOneOrNullResult() !== null;
}
}
...@@ -4,8 +4,6 @@ namespace App\Repository; ...@@ -4,8 +4,6 @@ namespace App\Repository;
use App\Entity\User; use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Exception\DatabaseObjectNotFoundException;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
...@@ -72,4 +70,13 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader ...@@ -72,4 +70,13 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader
->getQuery() ->getQuery()
->getResult(); ->getResult();
} }
public function emailExists(string $email): bool
{
return $this->createQueryBuilder('r')
->andWhere('r.email = :email')
->setParameter('email', $email)
->getQuery()
->getOneOrNullResult() !== null;
}
} }
...@@ -27,13 +27,13 @@ class EmailVerifier ...@@ -27,13 +27,13 @@ class EmailVerifier
} }
public function sendEmailConfirmation( public function sendEmailConfirmation(
string $verifyEmailRouteName, string $verify_email_route_name,
int $user_id, int $user_id,
string $email_address, string $email_address,
TemplatedEmail $email TemplatedEmail $email
): void { ): void {
$signatureComponents = $this->verifyEmailHelper->generateSignature( $signatureComponents = $this->verifyEmailHelper->generateSignature(
$verifyEmailRouteName, $verify_email_route_name,
(string) $user_id, (string) $user_id,
$email_address, $email_address,
['id' => $user_id] ['id' => $user_id]
......
...@@ -18,13 +18,13 @@ ...@@ -18,13 +18,13 @@
</div> </div>
{% for flashWarning in app.flashes('warning') %} {% for flashWarning in app.flashes('warning') %}
<div class="text-center alert alert-warning col-5 mx-auto my-5 mt-2" role="alert"> <div class="text-center alert alert-warning col-11 col-md-10 col-lg-9 col-xl-8 mx-auto my-5 mt-2" role="alert">
{{ flashWarning }} {{ flashWarning }}
</div> </div>
{% endfor %} {% endfor %}
{% for flashSuccess in app.flashes('success') %} {% for flashSuccess in app.flashes('success') %}
<div class="text-center alert alert-success col-5 mx-auto my-5 mt-2" role="alert"> <div class="text-center alert alert-success col-11 col-md-10 col-lg-9 col-xl-8 mx-auto my-5 mt-2" role="alert">
{{ flashSuccess }} {{ flashSuccess }}
</div> </div>
{% endfor %} {% endfor %}
......
...@@ -18,13 +18,13 @@ ...@@ -18,13 +18,13 @@
</div> </div>
{% for flashWarning in app.flashes('warning') %} {% for flashWarning in app.flashes('warning') %}
<div class="text-center alert alert-warning col-5 mx-auto my-5 mt-2" role="alert"> <div class="text-center alert alert-warning col-11 col-md-10 col-lg-9 col-xl-8 mx-auto my-5 mt-2" role="alert">
{{ flashWarning }} {{ flashWarning }}
</div> </div>
{% endfor %} {% endfor %}
{% for flashSuccess in app.flashes('success') %} {% for flashSuccess in app.flashes('success') %}
<div class="text-center alert alert-success col-5 mx-auto my-5 mt-2" role="alert"> <div class="text-center alert alert-success col-11 col-md-10 col-lg-9 col-xl-8 mx-auto my-5 mt-2" role="alert">
{{ flashSuccess }} {{ flashSuccess }}
</div> </div>
{% endfor %} {% endfor %}
......
...@@ -17,13 +17,13 @@ ...@@ -17,13 +17,13 @@
</div> </div>
{% for flashWarning in app.flashes('warning') %} {% for flashWarning in app.flashes('warning') %}
<div class="text-center alert alert-warning col-5 mx-auto my-5 mt-2" role="alert"> <div class="text-center alert alert-warning col-11 col-md-10 col-lg-9 col-xl-8 mx-auto my-5 mt-2" role="alert">
{{ flashWarning }} {{ flashWarning }}
</div> </div>
{% endfor %} {% endfor %}
{% for flashSuccess in app.flashes('success') %} {% for flashSuccess in app.flashes('success') %}
<div class="text-center alert alert-success col-5 mx-auto my-5 mt-2" role="alert"> <div class="text-center alert alert-success col-11 col-md-10 col-lg-9 col-xl-8 mx-auto my-5 mt-2" role="alert">
{{ flashSuccess }} {{ flashSuccess }}
</div> </div>
{% endfor %} {% endfor %}
......
...@@ -34,13 +34,13 @@ ...@@ -34,13 +34,13 @@
</div> </div>
{% for flashWarning in app.flashes('warning') %} {% for flashWarning in app.flashes('warning') %}
<div class="text-center alert alert-warning col-5 mx-auto my-5" role="alert"> <div class="text-center alert alert-warning col-11 col-md-10 col-lg-9 col-xl-8 mx-auto my-5" role="alert">
{{ flashWarning }} {{ flashWarning }}
</div> </div>
{% endfor %} {% endfor %}
{% for flashSuccess in app.flashes('success') %} {% for flashSuccess in app.flashes('success') %}
<div class="text-center alert alert-success col-5 mx-auto my-5" role="alert"> <div class="text-center alert alert-success col-11 col-md-10 col-lg-9 col-xl-8 mx-auto my-5" role="alert">
{{ flashSuccess }} {{ flashSuccess }}
</div> </div>
{% endfor %} {% endfor %}
......
{% extends 'layout.html.twig' %} {% extends 'layout.html.twig' %}
{% block body %} {% block body %}
<iframe src="{{ url }}" <iframe src="{{ url }}"
style="width:100%;height:100%;top:0;left:0;position:absolute" style="width:100%;height:100%;top:0;left:0;position:absolute"
{# width="1200"
height="600" #}
frameborder="0" frameborder="0"
webkitallowfullscreen webkitallowfullscreen
mozallowfullscreen mozallowfullscreen
allowfullscreen> allowfullscreen>
</iframe> </iframe>
{% endblock %} {% endblock %}
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
{% block body %} {% block body %}
<div class="mt-4"> <div class="mt-4">
{% for flashError in app.flashes('verify_email_error') %} {% for flashError in app.flashes('error') %}
<div class="alert alert-danger col-6 mx-auto my-5 h1" role="alert">{{ flashError }}</div> <div class="alert alert-danger col-11 col-md-10 col-lg-9 col-xl-8 mx-auto my-5 h1" role="alert">
{{ flashError }}
</div>
{% endfor %} {% endfor %}
{{ form_start(registrationForm, {'attr': {novalidate: 'novalidate', 'class': 'd-flex flex-column justify-content-center'}}) }} {{ form_start(registrationForm, {'attr': {novalidate: 'novalidate', 'class': 'd-flex flex-column justify-content-center'}}) }}
......
{% extends 'layout.html.twig' %}
{% block title %}
{{ 'user.edit_email_address'|trans }}
{% endblock %}
{% block body %}
<div class="row gx-0">
<div class="row-title-box">
<h3 class="row-title">
{{ 'user.edit_email_address'|trans }}
</h3>
</div>
</div>
{% for flashWarning in app.flashes('warning') %}
<div class="text-center alert alert-warning col-11 col-md-10 col-lg-9 col-xl-8 mx-auto my-5" role="alert">
{{ flashWarning }}
</div>
{% endfor %}
{% endblock %}
\ No newline at end of file
...@@ -23,5 +23,4 @@ ...@@ -23,5 +23,4 @@
{{ form_row(editUserProfileForm.update, {'row_attr': {'class' : 'form-group d-flex flex-column m-auto mb-4 col-2'}}) }} {{ form_row(editUserProfileForm.update, {'row_attr': {'class' : 'form-group d-flex flex-column m-auto mb-4 col-2'}}) }}
{{ form_end(editUserProfileForm) }} {{ form_end(editUserProfileForm) }}
</div> </div>
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -13,12 +13,18 @@ ...@@ -13,12 +13,18 @@
</div> </div>
</div> </div>
{% for flashSuccess in app.flashes('profile_updated_success') %} {% for flashSuccess in app.flashes('success') %}
<div class="text-center alert alert-success col-5 mx-auto my-5" role="alert"> <div class="text-center alert alert-success col-11 col-md-10 col-lg-9 col-xl-8 mx-auto mt-0 mb-4" role="alert">
{{ flashSuccess }} {{ flashSuccess }}
</div> </div>
{% endfor %} {% endfor %}
{% for flashWarning in app.flashes('warning') %}
<div class="text-center alert alert-warning col-11 col-md-10 col-lg-9 col-xl-8 mx-auto mt-0 mb-4" role="alert">
{{ flashWarning }}
</div>
{% endfor %}
<div class="d-flex flex-column flex-md-row justify-content-center align-items-center"> <div class="d-flex flex-column flex-md-row justify-content-center align-items-center">
<div class="profile-block d-flex flex-row ps-3 ps-md-5 pe-3 pe-md-5 pt-4 pb-3 fw-normal me-0 me-md-5"> <div class="profile-block d-flex flex-row ps-3 ps-md-5 pe-3 pe-md-5 pt-4 pb-3 fw-normal me-0 me-md-5">
<div class="pe-3 pe-md-4 text-nowrap"> <div class="pe-3 pe-md-4 text-nowrap">
......
<h1>
{{ 'user.edit.email.title'|trans }}
</h1>
<p>
{{ 'user.edit.email.text'|trans }}:
<br><br>
<a href="{{ url('verify_new_email_address') }}">
{{ 'user.edit.email.confirm_email'|trans }}
</a>
</p>
<p>
{{ 'general.greeting'|trans }}
</p>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment