fix: allow sending more invite in case of expirations (#745)
This commit is contained in:
parent
06a76374bc
commit
030eb6c805
7 changed files with 88 additions and 2 deletions
|
|
@ -18,6 +18,7 @@ use App\Form\Type\User\ChangePasswordFormType;
|
||||||
use App\Form\Type\User\EditProfileFormType;
|
use App\Form\Type\User\EditProfileFormType;
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
use App\Validator\Constraints\User\MembershipPaid;
|
use App\Validator\Constraints\User\MembershipPaid;
|
||||||
|
use App\Validator\Constraints\User\UniqueUser;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
|
@ -44,7 +45,8 @@ use function Symfony\Component\String\u;
|
||||||
#[ORM\Index(columns: ['lost_password_token'])]
|
#[ORM\Index(columns: ['lost_password_token'])]
|
||||||
#[ORM\Table(name: '`user`')] // we also need escaping here
|
#[ORM\Table(name: '`user`')] // we also need escaping here
|
||||||
#[ORM\EntityListeners([UserListener::class])]
|
#[ORM\EntityListeners([UserListener::class])]
|
||||||
#[UniqueEntity('email', groups: [AccountCreateStep1FormType::class, ChangeLoginFormType::class, 'Default'])]
|
#[UniqueUser(groups: [AccountCreateStep1FormType::class, ChangeLoginFormType::class])]
|
||||||
|
#[UniqueEntity('email', groups: ['Default'])]
|
||||||
#[MembershipPaid]
|
#[MembershipPaid]
|
||||||
class User implements UserInterface, PasswordAuthenticatedUserInterface, ImageInterface, EquatableInterface
|
class User implements UserInterface, PasswordAuthenticatedUserInterface, ImageInterface, EquatableInterface
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,9 @@ final class CreateGroupInvitationMessageHandler
|
||||||
$user = $this->userManager->getStep1User($message->email);
|
$user = $this->userManager->getStep1User($message->email);
|
||||||
$this->userManager->save($user, true);
|
$this->userManager->save($user, true);
|
||||||
$isNewUser = true;
|
$isNewUser = true;
|
||||||
|
} elseif (!$user->isEmailConfirmed()) {
|
||||||
|
$this->userManager->refreshConfirmationToken($user);
|
||||||
|
$isNewUser = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now create the invitation to the group.
|
// now create the invitation to the group.
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ use App\Entity\User;
|
||||||
use App\Mailer\AppMailer;
|
use App\Mailer\AppMailer;
|
||||||
use App\Mailer\Email\Security\CreateAccountStep1Email;
|
use App\Mailer\Email\Security\CreateAccountStep1Email;
|
||||||
use App\Message\Command\Security\AccountCreateStep1Command;
|
use App\Message\Command\Security\AccountCreateStep1Command;
|
||||||
|
use App\Repository\UserRepository;
|
||||||
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
||||||
|
|
||||||
#[AsMessageHandler]
|
#[AsMessageHandler]
|
||||||
|
|
@ -20,6 +21,7 @@ final class AccountCreateStep1CommandHandler
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly UserManager $userManager,
|
private readonly UserManager $userManager,
|
||||||
private readonly AppMailer $appMailer,
|
private readonly AppMailer $appMailer,
|
||||||
|
private readonly UserRepository $userRepository,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,6 +33,17 @@ final class AccountCreateStep1CommandHandler
|
||||||
*/
|
*/
|
||||||
public function __invoke(AccountCreateStep1Command $message): void
|
public function __invoke(AccountCreateStep1Command $message): void
|
||||||
{
|
{
|
||||||
|
$existingUser = $this->userRepository->findOneByEmail($message->email);
|
||||||
|
if ($existingUser instanceof User) {
|
||||||
|
if (!$existingUser->isEmailConfirmed()) {
|
||||||
|
$this->userManager->refreshConfirmationToken($existingUser);
|
||||||
|
$this->userManager->save($existingUser, true);
|
||||||
|
$this->appMailer->send(CreateAccountStep1Email::class, ['user' => $existingUser]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$user = new User();
|
$user = new User();
|
||||||
$user->setEmail($message->email);
|
$user->setEmail($message->email);
|
||||||
$this->userManager->refreshConfirmationToken($user);
|
$this->userManager->refreshConfirmationToken($user);
|
||||||
|
|
|
||||||
18
src/Validator/Constraints/User/UniqueUser.php
Normal file
18
src/Validator/Constraints/User/UniqueUser.php
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Validator\Constraints\User;
|
||||||
|
|
||||||
|
use Symfony\Component\Validator\Constraint;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_CLASS)]
|
||||||
|
final class UniqueUser extends Constraint
|
||||||
|
{
|
||||||
|
public string $message = 'validator.user.unique.message';
|
||||||
|
|
||||||
|
public function getTargets(): string
|
||||||
|
{
|
||||||
|
return self::CLASS_CONSTRAINT;
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/Validator/Constraints/User/UniqueUserValidator.php
Normal file
45
src/Validator/Constraints/User/UniqueUserValidator.php
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Validator\Constraints\User;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Repository\UserRepository;
|
||||||
|
use Symfony\Component\Validator\Constraint;
|
||||||
|
use Symfony\Component\Validator\ConstraintValidator;
|
||||||
|
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||||
|
use Symfony\Component\Validator\Exception\UnexpectedValueException;
|
||||||
|
|
||||||
|
final class UniqueUserValidator extends ConstraintValidator
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly UserRepository $userRepository,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validate(mixed $value, Constraint $constraint): void
|
||||||
|
{
|
||||||
|
if (!$constraint instanceof UniqueUser) {
|
||||||
|
throw new UnexpectedTypeException($constraint, UniqueUser::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$value instanceof User) {
|
||||||
|
throw new UnexpectedValueException($value, User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
$existingUser = $this->userRepository->findOneByEmail($value->getEmail());
|
||||||
|
|
||||||
|
if (null === $existingUser) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$existingUser->isEmailConfirmed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->context->buildViolation($constraint->message)
|
||||||
|
->atPath('email')
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ final class TestReference
|
||||||
// common
|
// common
|
||||||
public const UUID_404 = '1ed7a2a8-0a77-6dbc-a404-040404040404'; // valid UUID for 404 pages
|
public const UUID_404 = '1ed7a2a8-0a77-6dbc-a404-040404040404'; // valid UUID for 404 pages
|
||||||
public const VALIDATION_ERROR_BLANK = 'This value should not be blank';
|
public const VALIDATION_ERROR_BLANK = 'This value should not be blank';
|
||||||
public const VALIDATION_ERROR_ALREADY_USED = 'This value is already used';
|
public const VALIDATION_ERROR_ALREADY_USED = 'validator.user.unique.message';
|
||||||
|
|
||||||
// EasyAdmin
|
// EasyAdmin
|
||||||
public const ADMIN_URL = '/admin?crudAction=%s&crudControllerFqcn=%s';
|
public const ADMIN_URL = '/admin?crudAction=%s&crudControllerFqcn=%s';
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,11 @@
|
||||||
<target>Veuillez remplir ce champ</target>
|
<target>Veuillez remplir ce champ</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|
||||||
|
<trans-unit id="abcdef" resname="validator.user.unique.message">
|
||||||
|
<source>validator.user.unique.message</source>
|
||||||
|
<target>Cette valeur est déjà utilisée.</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue