Merge pull request #26 from Apes-HDF/chore/sync-les-tilleuls
Chore/sync les tilleuls
This commit is contained in:
commit
462b59f41c
22 changed files with 176 additions and 147 deletions
|
|
@ -1 +1,6 @@
|
||||||
CVE-2025-30204
|
CVE-2025-30204
|
||||||
|
GHSA-c2pc-g5qf-rfrf
|
||||||
|
CVE-2024-8176
|
||||||
|
CVE-2024-55549
|
||||||
|
CVE-2025-24855
|
||||||
|
CVE-2025-59530
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,6 @@ App\Entity\User:
|
||||||
name: 'APES compte lieu'
|
name: 'APES compte lieu'
|
||||||
address: '@address_region_hauts_de_france'
|
address: '@address_region_hauts_de_france'
|
||||||
schedule: '9h30 - 17h30'
|
schedule: '9h30 - 17h30'
|
||||||
phoneNumber: null
|
|
||||||
createdAt: <date_create_immutable('+1 month')>
|
createdAt: <date_create_immutable('+1 month')>
|
||||||
|
|
||||||
# —— Users —————————————————————————————————————————————————————————————————
|
# —— Users —————————————————————————————————————————————————————————————————
|
||||||
|
|
@ -170,6 +169,7 @@ App\Entity\User:
|
||||||
firstname: <firstname()>
|
firstname: <firstname()>
|
||||||
lastname: <lastname()>
|
lastname: <lastname()>
|
||||||
address: null
|
address: null
|
||||||
|
phoneNumber: '+33600000000'
|
||||||
avatar: 'a9a9bf49-24e4-4b3e-bdbd-86808c32939e.jpg'
|
avatar: 'a9a9bf49-24e4-4b3e-bdbd-86808c32939e.jpg'
|
||||||
|
|
||||||
# user with an address and a preferred category set
|
# user with an address and a preferred category set
|
||||||
|
|
|
||||||
|
|
@ -342,7 +342,7 @@ abstract class AbstractUserCrudController extends AbstractCrudController impleme
|
||||||
->setFormType(PhoneNumberType::class)
|
->setFormType(PhoneNumberType::class)
|
||||||
->setFormTypeOptions([
|
->setFormTypeOptions([
|
||||||
'format' => PhoneNumberFormat::INTERNATIONAL,
|
'format' => PhoneNumberFormat::INTERNATIONAL,
|
||||||
'required' => false,
|
'required' => true,
|
||||||
])
|
])
|
||||||
->setHelp($i18prefix.'.field.phone.help')
|
->setHelp($i18prefix.'.field.phone.help')
|
||||||
;
|
;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use App\Controller\FlashTrait;
|
||||||
use App\Controller\i18nTrait;
|
use App\Controller\i18nTrait;
|
||||||
use App\Controller\User\MyAccountAction;
|
use App\Controller\User\MyAccountAction;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
|
use App\Enum\User\UserType;
|
||||||
use App\Exception\UserConfirmationTokenExpiredException;
|
use App\Exception\UserConfirmationTokenExpiredException;
|
||||||
use App\Exception\UserNotFoundException;
|
use App\Exception\UserNotFoundException;
|
||||||
use App\Form\Type\Security\AccountCreateStep1FormType;
|
use App\Form\Type\Security\AccountCreateStep1FormType;
|
||||||
|
|
@ -20,12 +21,15 @@ use App\MessageBus\CommandBus;
|
||||||
use App\MessageBus\QueryBus;
|
use App\MessageBus\QueryBus;
|
||||||
use App\MessageHandler\Command\Security\AccountCreateStep1CommandHandler;
|
use App\MessageHandler\Command\Security\AccountCreateStep1CommandHandler;
|
||||||
use App\Repository\ConfigurationRepository;
|
use App\Repository\ConfigurationRepository;
|
||||||
|
use libphonenumber\PhoneNumber;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Bundle\SecurityBundle\Security;
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
|
use Symfony\Component\Form\FormError;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Messenger\Exception\HandlerFailedException;
|
use Symfony\Component\Messenger\Exception\HandlerFailedException;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see AccountCreateActionStep1Test
|
* @see AccountCreateActionStep1Test
|
||||||
|
|
@ -43,6 +47,7 @@ final class AccountCreateController extends AbstractController
|
||||||
private readonly CommandBus $commandBus,
|
private readonly CommandBus $commandBus,
|
||||||
private readonly Security $security,
|
private readonly Security $security,
|
||||||
private readonly ConfigurationRepository $configurationRepository,
|
private readonly ConfigurationRepository $configurationRepository,
|
||||||
|
private readonly TranslatorInterface $translator,
|
||||||
) {
|
) {
|
||||||
$this->i18nPrefix = $this->getI18nPrefix();
|
$this->i18nPrefix = $this->getI18nPrefix();
|
||||||
}
|
}
|
||||||
|
|
@ -102,39 +107,55 @@ final class AccountCreateController extends AbstractController
|
||||||
$configuration = $this->configurationRepository->getInstanceConfigurationOrCreate();
|
$configuration = $this->configurationRepository->getInstanceConfigurationOrCreate();
|
||||||
// nominal case: user found and token not expired
|
// nominal case: user found and token not expired
|
||||||
$form = $this->createForm(AccountCreateStep2FormType::class, $user->setStep2Defaults())->handleRequest($request);
|
$form = $this->createForm(AccountCreateStep2FormType::class, $user->setStep2Defaults())->handleRequest($request);
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted()) {
|
||||||
/** @var User $user */
|
$phone = $form->get('phone')->getData() ?? '';
|
||||||
$user = $form->getData();
|
|
||||||
$this->commandBus->dispatch(new AccountCreateStep2Command($user));
|
|
||||||
$this->security->login($user); // auto-log the user
|
|
||||||
|
|
||||||
// If user has pending invitations then redirect them to the first group
|
if (!$phone instanceof PhoneNumber || $phone->getNationalNumber() === '') {
|
||||||
// found without doing the confirmation stuff, it must be done on the
|
$form->get('phone')->addError(
|
||||||
// page group.
|
new FormError($this->translator->trans('account_create.phone.empty.error', [], 'validators'))
|
||||||
$group = $user->getMyGroupsAsInvited()->first();
|
);
|
||||||
if ($group !== false) {
|
}
|
||||||
// If platform needs payment, redirect to payment
|
|
||||||
if ($configuration->getPaidMembership()) {
|
if ($phone instanceof PhoneNumber && \strlen($phone->getNationalNumber() ?? '') < 8) {
|
||||||
$successMessage = $this->i18nPrefix.'.step2.with_invitation.global_paid_membership.flash.success';
|
$form->get('phone')->addError(
|
||||||
|
new FormError($this->translator->trans('account_create.phone.short.error', [], 'validators'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ($form->isValid()) {
|
||||||
|
/** @var User $user */
|
||||||
|
$user = $form->getData();
|
||||||
|
$user->setType(UserType::USER);
|
||||||
|
$this->commandBus->dispatch(new AccountCreateStep2Command($user));
|
||||||
|
$this->security->login($user); // auto-log the user
|
||||||
|
|
||||||
|
// If user has pending invitations then redirect them to the first group
|
||||||
|
// found without doing the confirmation stuff, it must be done on the
|
||||||
|
// page group.
|
||||||
|
$group = $user->getMyGroupsAsInvited()->first();
|
||||||
|
if ($group !== false) {
|
||||||
|
// If platform needs payment, redirect to payment
|
||||||
|
if ($configuration->getPaidMembership()) {
|
||||||
|
$successMessage = $this->i18nPrefix.'.step2.with_invitation.global_paid_membership.flash.success';
|
||||||
|
$this->addFlashSuccess($successMessage);
|
||||||
|
|
||||||
|
return $this->redirectToRoute('redirect_to_payment');
|
||||||
|
}
|
||||||
|
$successMessage = $this->i18nPrefix.'.step2.with_invitation.flash.success';
|
||||||
$this->addFlashSuccess($successMessage);
|
$this->addFlashSuccess($successMessage);
|
||||||
|
|
||||||
return $this->redirectToRoute('redirect_to_payment');
|
return $this->redirectToRoute('app_group_show_logged', $group->getRoutingParameters());
|
||||||
}
|
}
|
||||||
$successMessage = $this->i18nPrefix.'.step2.with_invitation.flash.success';
|
|
||||||
|
if ($configuration->getPaidMembership()) {
|
||||||
|
$successMessage = $this->i18nPrefix.'.step2.global_paid_membership.flash.success';
|
||||||
|
} else {
|
||||||
|
$successMessage = $this->i18nPrefix.'.step2.flash.success';
|
||||||
|
}
|
||||||
|
// otherwise go to the address form
|
||||||
$this->addFlashSuccess($successMessage);
|
$this->addFlashSuccess($successMessage);
|
||||||
|
|
||||||
return $this->redirectToRoute('app_group_show_logged', $group->getRoutingParameters());
|
return $this->redirectToRoute(MyAccountAction::ROUTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($configuration->getPaidMembership()) {
|
|
||||||
$successMessage = $this->i18nPrefix.'.step2.global_paid_membership.flash.success';
|
|
||||||
} else {
|
|
||||||
$successMessage = $this->i18nPrefix.'.step2.flash.success';
|
|
||||||
}
|
|
||||||
// otherwise go to the address form
|
|
||||||
$this->addFlashSuccess($successMessage);
|
|
||||||
|
|
||||||
return $this->redirectToRoute(MyAccountAction::ROUTE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('pages/register/step2.html.twig', compact('form', 'user'));
|
return $this->render('pages/register/step2.html.twig', compact('form', 'user'));
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@ use App\Form\Type\User\EditProfileFormType;
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
use App\Tests\Functional\Controller\User\Account\EditProfileActionTest;
|
use App\Tests\Functional\Controller\User\Account\EditProfileActionTest;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use libphonenumber\PhoneNumber;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\Form\FormError;
|
||||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
@ -21,6 +23,7 @@ use Symfony\Component\Routing\Annotation\Route;
|
||||||
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
|
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
|
||||||
use Symfony\Component\Security\Http\Attribute\CurrentUser;
|
use Symfony\Component\Security\Http\Attribute\CurrentUser;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see EditProfileActionTest
|
* @see EditProfileActionTest
|
||||||
|
|
@ -34,6 +37,7 @@ final class EditProfileAction extends AbstractController
|
||||||
private readonly UserRepository $userRepository,
|
private readonly UserRepository $userRepository,
|
||||||
private readonly UserManager $userManager,
|
private readonly UserManager $userManager,
|
||||||
private readonly EntityManagerInterface $entityManager,
|
private readonly EntityManagerInterface $entityManager,
|
||||||
|
private readonly TranslatorInterface $translator,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,14 +49,30 @@ final class EditProfileAction extends AbstractController
|
||||||
public function __invoke(Request $request, #[CurrentUser] User $user): Response
|
public function __invoke(Request $request, #[CurrentUser] User $user): Response
|
||||||
{
|
{
|
||||||
$form = $this->createForm(EditProfileFormType::class, $user)->handleRequest($request);
|
$form = $this->createForm(EditProfileFormType::class, $user)->handleRequest($request);
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted()) {
|
||||||
/** @var UploadedFile|null $avatar */
|
$phone = $form->get('phone')->getData() ?? '';
|
||||||
$avatar = $form->get('avatar')->getData();
|
|
||||||
$this->userManager->upload($avatar, $user);
|
|
||||||
$this->userRepository->save($user, true);
|
|
||||||
$this->addFlashSuccess($this->getI18nPrefix().'.flash.success');
|
|
||||||
|
|
||||||
return $this->redirectToRoute(MyAccountAction::ROUTE);
|
if (!$phone instanceof PhoneNumber || $phone->getNationalNumber() === '') {
|
||||||
|
$form->get('phone')->addError(
|
||||||
|
new FormError($this->translator->trans('account_create.phone.empty.error', [], 'validators'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($phone instanceof PhoneNumber && \strlen($phone->getNationalNumber() ?? '') < 8) {
|
||||||
|
$form->get('phone')->addError(
|
||||||
|
new FormError($this->translator->trans('account_create.phone.short.error', [], 'validators'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($form->isValid()) {
|
||||||
|
/** @var UploadedFile|null $avatar */
|
||||||
|
$avatar = $form->get('avatar')->getData();
|
||||||
|
$this->userManager->upload($avatar, $user);
|
||||||
|
$this->userRepository->save($user, true);
|
||||||
|
$this->addFlashSuccess($this->getI18nPrefix().'.flash.success');
|
||||||
|
|
||||||
|
return $this->redirectToRoute(MyAccountAction::ROUTE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case of error, we must reload the original firstname (to display it in navbar)
|
// In case of error, we must reload the original firstname (to display it in navbar)
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,10 @@ declare(strict_types=1);
|
||||||
namespace App\Form\Type\Security;
|
namespace App\Form\Type\Security;
|
||||||
|
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Enum\User\UserType;
|
use libphonenumber\PhoneNumberFormat;
|
||||||
|
use Misd\PhoneNumberBundle\Form\Type\PhoneNumberType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\CallbackTransformer;
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
|
|
@ -27,19 +26,6 @@ final class AccountCreateStep2FormType extends AbstractType
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
->add('type', ChoiceType::class, [
|
|
||||||
'label' => 'account_create_action.account_type',
|
|
||||||
'label_attr' => ['class' => 'text-black fw-light'],
|
|
||||||
'choices' => UserType::getForFront(),
|
|
||||||
'choice_attr' => function () {
|
|
||||||
return [
|
|
||||||
'data-controller' => 'account',
|
|
||||||
'data-action' => 'click->account#choosenType',
|
|
||||||
];
|
|
||||||
},
|
|
||||||
'expanded' => true,
|
|
||||||
])
|
|
||||||
|
|
||||||
->add('firstname', TextType::class, [
|
->add('firstname', TextType::class, [
|
||||||
'label' => 'account_create_action.firsname',
|
'label' => 'account_create_action.firsname',
|
||||||
'label_attr' => ['class' => 'text-black fw-light required'],
|
'label_attr' => ['class' => 'text-black fw-light required'],
|
||||||
|
|
@ -60,14 +46,14 @@ final class AccountCreateStep2FormType extends AbstractType
|
||||||
'required' => false,
|
'required' => false,
|
||||||
])
|
])
|
||||||
|
|
||||||
->add('name', TextType::class, [
|
->add('phone', PhoneNumberType::class, [
|
||||||
'label' => 'account_create_action.name',
|
'label' => 'account_create_action.phone',
|
||||||
'label_attr' => ['class' => 'text-black fw-light required'],
|
'label_attr' => ['class' => 'text-black fs-6 fw-normal'],
|
||||||
'attr' => [
|
'widget' => PhoneNumberType::WIDGET_COUNTRY_CHOICE,
|
||||||
'class' => 'form-control-sm input-name',
|
'format' => PhoneNumberFormat::INTERNATIONAL,
|
||||||
'placeholder' => 'account_create_action.name.placeholder',
|
'country_display_emoji_flag' => true,
|
||||||
],
|
'preferred_country_choices' => ['FR'],
|
||||||
'required' => false,
|
'required' => true,
|
||||||
])
|
])
|
||||||
|
|
||||||
->add('plainPassword', RepeatedType::class, [
|
->add('plainPassword', RepeatedType::class, [
|
||||||
|
|
@ -118,15 +104,6 @@ final class AccountCreateStep2FormType extends AbstractType
|
||||||
'attr' => ['class' => 'btn btn-primary btn-sm'],
|
'attr' => ['class' => 'btn btn-primary btn-sm'],
|
||||||
])
|
])
|
||||||
;
|
;
|
||||||
|
|
||||||
$builder->get('type')->addModelTransformer(new CallbackTransformer(
|
|
||||||
function (?UserType $enumToString) {
|
|
||||||
return $enumToString === null ? '' : $enumToString->value;
|
|
||||||
},
|
|
||||||
function (string $stringToEnum) {
|
|
||||||
return UserType::from($stringToEnum);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver): void
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,9 @@ final class EditProfileFormType extends AbstractType
|
||||||
'label_attr' => ['class' => 'text-black fs-6 fw-normal'],
|
'label_attr' => ['class' => 'text-black fs-6 fw-normal'],
|
||||||
'format' => PhoneNumberFormat::INTERNATIONAL,
|
'format' => PhoneNumberFormat::INTERNATIONAL,
|
||||||
'widget' => PhoneNumberType::WIDGET_COUNTRY_CHOICE,
|
'widget' => PhoneNumberType::WIDGET_COUNTRY_CHOICE,
|
||||||
|
'country_display_emoji_flag' => true,
|
||||||
'preferred_country_choices' => ['FR'],
|
'preferred_country_choices' => ['FR'],
|
||||||
'required' => false,
|
'required' => true,
|
||||||
])
|
])
|
||||||
|
|
||||||
->add('smsNotifications', CheckboxType::class, [
|
->add('smsNotifications', CheckboxType::class, [
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ namespace App\Message\Command\Security;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Enum\User\UserType;
|
use App\Enum\User\UserType;
|
||||||
use App\MessageHandler\Command\Security\AccountCreateStep2CommandHandler;
|
use App\MessageHandler\Command\Security\AccountCreateStep2CommandHandler;
|
||||||
|
use libphonenumber\PhoneNumber;
|
||||||
use Symfony\Component\Uid\Uuid;
|
use Symfony\Component\Uid\Uuid;
|
||||||
use Webmozart\Assert\Assert;
|
use Webmozart\Assert\Assert;
|
||||||
|
|
||||||
|
|
@ -22,6 +23,7 @@ final class AccountCreateStep2Command
|
||||||
public ?string $firstname = null;
|
public ?string $firstname = null;
|
||||||
public ?string $name = null;
|
public ?string $name = null;
|
||||||
public string $plainPassword;
|
public string $plainPassword;
|
||||||
|
public PhoneNumber $phone;
|
||||||
|
|
||||||
public function __construct(User $user)
|
public function __construct(User $user)
|
||||||
{
|
{
|
||||||
|
|
@ -33,5 +35,7 @@ final class AccountCreateStep2Command
|
||||||
$this->name = $user->getName();
|
$this->name = $user->getName();
|
||||||
Assert::stringNotEmpty($user->getPlainPassword());
|
Assert::stringNotEmpty($user->getPlainPassword());
|
||||||
$this->plainPassword = $user->getPlainPassword();
|
$this->plainPassword = $user->getPlainPassword();
|
||||||
|
Assert::notNull($user->phone);
|
||||||
|
$this->phone = $user->phone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ use App\Entity\User;
|
||||||
use App\Enum\User\UserType;
|
use App\Enum\User\UserType;
|
||||||
use App\Message\Command\Security\AccountCreateStep2Command;
|
use App\Message\Command\Security\AccountCreateStep2Command;
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
|
use libphonenumber\PhoneNumberFormat;
|
||||||
|
use libphonenumber\PhoneNumberUtil;
|
||||||
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
||||||
use Webmozart\Assert\Assert;
|
use Webmozart\Assert\Assert;
|
||||||
|
|
||||||
|
|
@ -47,6 +49,11 @@ final class AccountCreateStep2CommandHandler
|
||||||
throw new \UnexpectedValueException('This hanlder can only create users or places.');
|
throw new \UnexpectedValueException('This hanlder can only create users or places.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$phoneObjectToString = PhoneNumberUtil::getInstance()->format(
|
||||||
|
$message->phone,
|
||||||
|
PhoneNumberFormat::E164
|
||||||
|
);
|
||||||
|
$user->setPhoneNumber($phoneObjectToString);
|
||||||
$this->userManager->updatePassword($user->setPlainPassword($message->plainPassword));
|
$this->userManager->updatePassword($user->setPlainPassword($message->plainPassword));
|
||||||
$this->userManager->finalizeAccountCreateStep2($user);
|
$this->userManager->finalizeAccountCreateStep2($user);
|
||||||
$this->userManager->save($user, true);
|
$this->userManager->save($user, true);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
{% set is_product_owner = product.owner == app.user %}
|
{% set is_product_owner = product.owner == app.user %}
|
||||||
|
|
||||||
<div class="bg-light rounded-2 p-3" data-controller="calendar" data-calendar-unavailabilities-value="{{ product.getUnavailabilities()|join(',') }}">
|
<div class="bg-light rounded-2 p-3" data-controller="calendar"
|
||||||
|
data-calendar-unavailabilities-value="{{ product.getUnavailabilities()|join(',') }}">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h5>{{ title }}</h5>
|
<h5>{{ title }}</h5>
|
||||||
|
|
@ -71,22 +72,36 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="d-grid col mt-3">
|
<div class="d-grid col mt-3">
|
||||||
<button class="btn border border-0 text-primary text-decoration-underline" data-action="click->calendar#resetDates" type="button">
|
<button class="btn border border-0 text-primary text-decoration-underline"
|
||||||
|
data-action="click->calendar#resetDates" type="button">
|
||||||
{{ 'templates.components.product.calendar.reset'|trans }}
|
{{ 'templates.components.product.calendar.reset'|trans }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{% if actionNeeded %}
|
{% if actionNeeded %}
|
||||||
<div class="d-grid col-12 mt-3">
|
<div class="d-grid col-12 mt-3">
|
||||||
{% if app.user is null or is_granted('borrow', product) %}
|
{% if app.user is null or is_granted('borrow', product) %}
|
||||||
<button
|
{% if app.user and app.user.address is null %}
|
||||||
id="service-request"
|
{% include 'components/product/_modal.html.twig' with {
|
||||||
class="btn btn-sm btn-primary"
|
menu_action: false,
|
||||||
data-path="{{ path('app_user_service_request_new', {id: product.id}) }}"
|
page_type: 'article',
|
||||||
data-action="click->calendar#serviceRequest"
|
button: 'templates.components.product.calendar.service_request'|trans,
|
||||||
disabled
|
title: 'templates.pages.account.index.no-address-title'|trans,
|
||||||
>
|
message: 'templates.pages.account.index.no-address-message'|trans({
|
||||||
{{ 'templates.components.product.calendar.service_request'|trans }}
|
'%product%': product.type.isObject ? 'objet' : 'service'
|
||||||
</button>
|
}),
|
||||||
|
action: 'templates.pages.account.product.list.no-address-add'|trans
|
||||||
|
} %}
|
||||||
|
{% else %}
|
||||||
|
<button
|
||||||
|
id="service-request"
|
||||||
|
class="btn btn-sm btn-primary"
|
||||||
|
data-path="{{ path('app_user_service_request_new', {id: product.id}) }}"
|
||||||
|
data-action="click->calendar#serviceRequest"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
{{ 'templates.components.product.calendar.service_request'|trans }}
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ form_widget(form.submit) }}
|
{{ form_widget(form.submit) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
{% if menu_action is defined and menu_action == true %}
|
{% if menu_action is defined and menu_action == true %}
|
||||||
<span class="text-decoration-none text-primary ms-2 position-relative pe-1 cursor-pointer"
|
<span class="text-decoration-none text-primary ms-2 position-relative pe-1 cursor-pointer"
|
||||||
data-bs-toggle="modal"
|
data-bs-toggle="modal"
|
||||||
data-bs-target="#modalAddAddress">{{ button }}</span>
|
data-bs-target="#modalAddAddress">{{ button }}</span>
|
||||||
|
{% elseif menu_action is defined and menu_action == false and page_type == 'article' %}
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-primary"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#modalAddAddress">
|
||||||
|
{{ button }}
|
||||||
|
</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="d-grid col-12 col-lg-4 mx-auto my-3 order-last">
|
<div class="d-grid col-12 col-lg-4 mx-auto my-3 order-last">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
|
|
@ -32,7 +39,7 @@
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="btn btn-outline-secondary"
|
class="btn btn-outline-secondary"
|
||||||
data-bs-dismiss="modal">
|
data-bs-dismiss="modal">
|
||||||
{{ (i18n_prefix ~ '.no-address-cancel')|trans }}
|
{{ 'templates.pages.account.product.list.no-address-cancel'|trans }}
|
||||||
</button>
|
</button>
|
||||||
<a href="{{ path('user_address_step1') }}"
|
<a href="{{ path('user_address_step1') }}"
|
||||||
class="btn btn-secondary">
|
class="btn btn-secondary">
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@
|
||||||
|
|
||||||
{{ form_start(form, {attr: {novalidate: true}}) }}
|
{{ form_start(form, {attr: {novalidate: true}}) }}
|
||||||
|
|
||||||
{{ form_row(form.type) }}
|
|
||||||
<div class="user-input mt-2">
|
<div class="user-input mt-2">
|
||||||
{{ form_label(form.firstname) }}
|
{{ form_label(form.firstname) }}
|
||||||
{{ form_widget(form.firstname) }}
|
{{ form_widget(form.firstname) }}
|
||||||
|
|
@ -40,10 +39,10 @@
|
||||||
{{ form_widget(form.lastname) }}
|
{{ form_widget(form.lastname) }}
|
||||||
{{ form_errors(form.lastname) }}
|
{{ form_errors(form.lastname) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="place-input mt-2">
|
<div class="phone-input mt-2">
|
||||||
{{ form_label(form.name) }}
|
{{ form_label(form.phone) }}
|
||||||
{{ form_widget(form.name) }}
|
{{ form_widget(form.phone) }}
|
||||||
{{ form_errors(form.name) }}
|
{{ form_errors(form.phone) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% include 'components/form/_password_visibility.html.twig' with {
|
{% include 'components/form/_password_visibility.html.twig' with {
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Tests\Functional\Controller\Security;
|
|
||||||
|
|
||||||
use App\Test\ContainerRepositoryTrait;
|
|
||||||
use App\Test\KernelTrait;
|
|
||||||
use App\Tests\TestReference;
|
|
||||||
use Hautelook\AliceBundle\PhpUnit\RefreshDatabaseTrait;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
|
||||||
use Symfony\Component\String\ByteString;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see AccountCreateController
|
|
||||||
*/
|
|
||||||
final class AccountCreateActionStep2PlaceTest extends WebTestCase
|
|
||||||
{
|
|
||||||
use ContainerRepositoryTrait;
|
|
||||||
use RefreshDatabaseTrait;
|
|
||||||
use KernelTrait;
|
|
||||||
|
|
||||||
private const ROUTE = '/fr/compte/creer-mon-compte-etape-2/';
|
|
||||||
|
|
||||||
public function testUserConfirmationTokenExpiredException(): void
|
|
||||||
{
|
|
||||||
$client = self::createClient();
|
|
||||||
$client->request('GET', self::ROUTE.TestReference::USER_13_CONFIRMATION_TOKEN);
|
|
||||||
self::assertResponseRedirects();
|
|
||||||
$client->followRedirect();
|
|
||||||
self::assertResponseIsSuccessful();
|
|
||||||
self::assertSelectorTextContains('body', 'app.controller.security.account_create_controller.step2.user_confirmation_token_expired.warning');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFormSubmitPlaceSuccess(): void
|
|
||||||
{
|
|
||||||
$client = self::createClient();
|
|
||||||
$crawler = $client->request('GET', self::ROUTE.TestReference::USER_12_CONFIRMATION_TOKEN);
|
|
||||||
$form = $crawler->selectButton('account_create_step2_form_submit')->form();
|
|
||||||
|
|
||||||
$password = ByteString::fromRandom(13);
|
|
||||||
$client->submit($form, [
|
|
||||||
$form->getName().'[type]' => 'place',
|
|
||||||
$form->getName().'[name]' => 'My Association',
|
|
||||||
$form->getName().'[plainPassword][first]' => $password,
|
|
||||||
$form->getName().'[plainPassword][second]' => $password,
|
|
||||||
$form->getName().'[gdpr]' => 1,
|
|
||||||
]);
|
|
||||||
self::assertResponseRedirects();
|
|
||||||
$client->followRedirect();
|
|
||||||
self::assertResponseIsSuccessful();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -33,11 +33,12 @@ final class AccountCreateActionStep2UserInvitationTest extends WebTestCase
|
||||||
|
|
||||||
$password = ByteString::fromRandom(13);
|
$password = ByteString::fromRandom(13);
|
||||||
$client->submit($form, [
|
$client->submit($form, [
|
||||||
$form->getName().'[type]' => 'user',
|
|
||||||
$form->getName().'[firstname]' => 'Foo',
|
$form->getName().'[firstname]' => 'Foo',
|
||||||
$form->getName().'[lastname]' => 'Bar',
|
$form->getName().'[lastname]' => 'Bar',
|
||||||
$form->getName().'[plainPassword][first]' => $password,
|
$form->getName().'[plainPassword][first]' => $password,
|
||||||
$form->getName().'[plainPassword][second]' => $password,
|
$form->getName().'[plainPassword][second]' => $password,
|
||||||
|
$form->getName().'[phone][country]' => 'FR',
|
||||||
|
$form->getName().'[phone][number]' => '602030405',
|
||||||
$form->getName().'[gdpr]' => 1,
|
$form->getName().'[gdpr]' => 1,
|
||||||
]);
|
]);
|
||||||
self::assertResponseRedirects();
|
self::assertResponseRedirects();
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,12 @@ final class AccountCreateActionStep2UserTest extends WebTestCase
|
||||||
|
|
||||||
$password = ByteString::fromRandom(13);
|
$password = ByteString::fromRandom(13);
|
||||||
$client->submit($form, [
|
$client->submit($form, [
|
||||||
$form->getName().'[type]' => 'user',
|
|
||||||
$form->getName().'[firstname]' => 'Foo',
|
$form->getName().'[firstname]' => 'Foo',
|
||||||
$form->getName().'[lastname]' => 'Bar',
|
$form->getName().'[lastname]' => 'Bar',
|
||||||
$form->getName().'[plainPassword][first]' => $password,
|
$form->getName().'[plainPassword][first]' => $password,
|
||||||
$form->getName().'[plainPassword][second]' => $password,
|
$form->getName().'[plainPassword][second]' => $password,
|
||||||
|
$form->getName().'[phone][country]' => 'FR',
|
||||||
|
$form->getName().'[phone][number]' => '602030405',
|
||||||
$form->getName().'[gdpr]' => 1,
|
$form->getName().'[gdpr]' => 1,
|
||||||
]);
|
]);
|
||||||
self::assertResponseRedirects();
|
self::assertResponseRedirects();
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ final class EditProfileActionTest extends WebTestCase
|
||||||
$form->getName().'[category]' => TestReference::CATEGORY_OBJECT_1,
|
$form->getName().'[category]' => TestReference::CATEGORY_OBJECT_1,
|
||||||
$form->getName().'[description]' => 'description test',
|
$form->getName().'[description]' => 'description test',
|
||||||
$form->getName().'[phone][country]' => 'FR',
|
$form->getName().'[phone][country]' => 'FR',
|
||||||
$form->getName().'[phone][number]' => '',
|
$form->getName().'[phone][number]' => '634563424',
|
||||||
$form->getName().'[smsNotifications]' => false,
|
$form->getName().'[smsNotifications]' => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ final class EditProfileActionTest extends WebTestCase
|
||||||
|
|
||||||
/** @var User $editedUser */
|
/** @var User $editedUser */
|
||||||
$editedUser = $repo->find(TestReference::USER_16);
|
$editedUser = $repo->find(TestReference::USER_16);
|
||||||
self::assertNull($editedUser->getPhoneNumber());
|
self::assertNotNull($editedUser->getPhoneNumber());
|
||||||
|
|
||||||
self::assertResponseRedirects();
|
self::assertResponseRedirects();
|
||||||
$client->followRedirect();
|
$client->followRedirect();
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ final class UserManagerTest extends KernelTestCase
|
||||||
|
|
||||||
$user = new User();
|
$user = new User();
|
||||||
$user->setEmail(ByteString::fromRandom(6)->toString().'@example.com');
|
$user->setEmail(ByteString::fromRandom(6)->toString().'@example.com');
|
||||||
|
$user->setPhoneNumber('+33600000000');
|
||||||
$user->setPassword('foo');
|
$user->setPassword('foo');
|
||||||
|
|
||||||
$userManager->save($user, true);
|
$userManager->save($user, true);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ use App\Message\Command\Security\AccountCreateStep2Command;
|
||||||
use App\MessageHandler\Command\Security\AccountCreateStep2CommandHandler;
|
use App\MessageHandler\Command\Security\AccountCreateStep2CommandHandler;
|
||||||
use App\Tests\TestReference;
|
use App\Tests\TestReference;
|
||||||
use Hautelook\AliceBundle\PhpUnit\RefreshDatabaseTrait;
|
use Hautelook\AliceBundle\PhpUnit\RefreshDatabaseTrait;
|
||||||
|
use libphonenumber\PhoneNumberUtil;
|
||||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
use Symfony\Component\Uid\Uuid;
|
use Symfony\Component\Uid\Uuid;
|
||||||
|
|
||||||
|
|
@ -25,11 +26,17 @@ final class AccountCreateStep2CommandHandlerTest extends KernelTestCase
|
||||||
|
|
||||||
$this->expectException(\UnexpectedValueException::class);
|
$this->expectException(\UnexpectedValueException::class);
|
||||||
$this->expectExceptionMessage('This hanlder can only create users or places');
|
$this->expectExceptionMessage('This hanlder can only create users or places');
|
||||||
|
|
||||||
$user = (new User())
|
$user = (new User())
|
||||||
->setId(Uuid::fromString(TestReference::USER_17))
|
->setId(Uuid::fromString(TestReference::USER_17))
|
||||||
->setType(UserType::ADMIN)
|
->setType(UserType::ADMIN)
|
||||||
->setPlainPassword('foo')
|
->setPlainPassword('foo')
|
||||||
;
|
;
|
||||||
|
|
||||||
|
$phoneUtil = PhoneNumberUtil::getInstance();
|
||||||
|
$phone = $phoneUtil->parse('+33602030405', 'FR');
|
||||||
|
$user->phone = $phone;
|
||||||
|
|
||||||
$message = new AccountCreateStep2Command($user);
|
$message = new AccountCreateStep2Command($user);
|
||||||
$handler($message);
|
$handler($message);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ final class UserRepositoryTest extends KernelTestCase
|
||||||
|
|
||||||
$user = new User();
|
$user = new User();
|
||||||
$user->setEmail(ByteString::fromRandom(6)->toString().'@example.com');
|
$user->setEmail(ByteString::fromRandom(6)->toString().'@example.com');
|
||||||
|
$user->setPhoneNumber('+33600000000');
|
||||||
$user->setPassword('foo');
|
$user->setPassword('foo');
|
||||||
$repo->save($user, true);
|
$repo->save($user, true);
|
||||||
$count = $repo->count([]);
|
$count = $repo->count([]);
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,11 @@
|
||||||
<target>8 caractères minimun</target>
|
<target>8 caractères minimun</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|
||||||
|
<trans-unit id="3Wd6Kp0" resname="account_create_action.phone">
|
||||||
|
<source>account_create_action.phone</source>
|
||||||
|
<target>Numéro de téléphone</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
<trans-unit id="m3UMrJf" resname="account_create_action.gdpr">
|
<trans-unit id="m3UMrJf" resname="account_create_action.gdpr">
|
||||||
<source>account_create_action.gdpr</source>
|
<source>account_create_action.gdpr</source>
|
||||||
<target>J’ai lu et j’accepte les <![CDATA[<a href="%link%" class="text-primary">Conditions Générales d'Utilisation</a>]]></target>
|
<target>J’ai lu et j’accepte les <![CDATA[<a href="%link%" class="text-primary">Conditions Générales d'Utilisation</a>]]></target>
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,16 @@
|
||||||
<target>Le nom du lieu est obligatoire</target>
|
<target>Le nom du lieu est obligatoire</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|
||||||
|
<trans-unit id="tY0WDru" resname="account_create.phone.empty.error">
|
||||||
|
<source>account_create.phone.empty.error</source>
|
||||||
|
<target>Le numéro de téléphone est obligatoire</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
|
<trans-unit id="tY0WDzu" resname="account_create.phone.short.error">
|
||||||
|
<source>account_create.phone.short.error</source>
|
||||||
|
<target>Veuillez indiquer un numéro de téléphone valide</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@
|
||||||
|
|
||||||
<trans-unit id="ftBMsiP" resname="templates.pages.account.index.no-address-message">
|
<trans-unit id="ftBMsiP" resname="templates.pages.account.index.no-address-message">
|
||||||
<source>templates.pages.account.index.no-address-message</source>
|
<source>templates.pages.account.index.no-address-message</source>
|
||||||
<target>Pour pouvoir créer un %product%, commencez par remplir votre adresse.</target>
|
<target>Pour pouvoir créer ou emprunter un %product%, commencez par remplir votre adresse.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|
||||||
<trans-unit id="e8xvcp6" resname="templates.pages.account.index.no-address-cancel">
|
<trans-unit id="e8xvcp6" resname="templates.pages.account.index.no-address-cancel">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue