<?php
namespace Bidcoz\Bundle\FrontendBundle\Controller;
use Bidcoz\Bundle\CoreBundle\Constants;
use Bidcoz\Bundle\CoreBundle\Controller\CoreController;
use Bidcoz\Bundle\CoreBundle\Entity\Campaign;
use Bidcoz\Bundle\CoreBundle\Entity\Organization;
use Bidcoz\Bundle\CoreBundle\Entity\PaymentGateway\Account\Account;
use Bidcoz\Bundle\CoreBundle\Entity\Proxy\StripeCreditCardProxy;
use Bidcoz\Bundle\CoreBundle\Entity\User;
use Bidcoz\Bundle\CoreBundle\Form\Type\StripeCreditCardType;
use Bidcoz\Bundle\UserBundle\Event\BidcozFilterUserResponseEvent;
use Bidcoz\Bundle\UserBundle\Event\BidcozGetResponseUserEvent;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\FOSUserEvents;
use Karser\Recaptcha3Bundle\Form\Recaptcha3Type;
use Karser\Recaptcha3Bundle\Validator\Constraints\Recaptcha3;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/{orgSlug}", requirements={"orgSlug" = Constants::RESERVED_SLUG_REGEX})
*/
class CreateOrganizationController extends CoreController
{
# TODO: New authenticator behaves differently for @Security and @IsGranted
# Issue: "Symfony\Component\Security\Core\Exception\AccessDeniedException: No user token or you forgot to put your controller behind a firewall while using a @Security tag
# PR fixes this (still "Open"): https://github.com/sensiolabs/SensioFrameworkExtraBundle/pull/763
# Docs: https://symfony.com/doc/5.2/security/experimental_authenticators.html#enabling-the-system
# Notes: When PR gets merged, switch back to using the @Security tag: @Security("is_granted('VIEW', organization)")
/**
* @Route("/register", name="organization_register_user")
* @IsGranted("VIEW", subject="organization")
*/
public function organizationAction(Request $request, Organization $organization)
{
$userManager = $this->getUserManager();
$dispatcher = $this->getEventDispatcher();
$user = $userManager->createUser();
$user->setEnabled(true);
$event = new BidcozGetResponseUserEvent($user, $request);
$event->setOrganization($organization);
$dispatcher->dispatch($event, FOSUserEvents::REGISTRATION_INITIALIZE);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
$email = '';
$form = $this->getRegistrationFormFactory()->createForm();
$form->add('captcha', Recaptcha3Type::class, [
'constraints' => new Recaptcha3(),
'action_name' => 'organization_register_user',
]);
$form->setData($user);
$hasEmailAlreadyInUserError = false;
if ('POST' === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$event = new FormEvent($form, $request);
$dispatcher->dispatch($event, FOSUserEvents::REGISTRATION_SUCCESS);
$user->setLoggedIn();
$userManager->updateUser($user);
$contact = $this->getContactManager()->findOrCreateContact($organization, $user, true);
if (null === $response = $event->getResponse()) {
$url = $this->getRouter()->generate('organization_home', [
'orgSlug' => $organization->getSlug(),
]);
$response = new RedirectResponse($url);
}
$event = new BidcozFilterUserResponseEvent($user, $request, $response);
$event->setOrganization($organization);
$dispatcher->dispatch($event, FOSUserEvents::REGISTRATION_COMPLETED);
return $response;
} else {
// This is a hack
$emailForm = $form->get('email');
foreach ($emailForm->getErrors() as $error) {
if ('fos_user.email.already_used' === $error->getMessageTemplate()) {
$hasEmailAlreadyInUserError = true;
}
}
$email = $emailForm->getData();
}
}
return $this->render('@BidcozFrontend/Registration/organization.html.twig', [
'organization' => $organization,
'form' => $form->createView(),
'hasEmailAlreadyInUserError' => $hasEmailAlreadyInUserError,
'last_username' => $email,
]);
}
# TODO: New authenticator behaves differently for @Security and @IsGranted
# Issue: "Symfony\Component\Security\Core\Exception\AccessDeniedException: No user token or you forgot to put your controller behind a firewall while using a @Security tag
# PR fixes this (still "Open"): https://github.com/sensiolabs/SensioFrameworkExtraBundle/pull/763
# Docs: https://symfony.com/doc/5.2/security/experimental_authenticators.html#enabling-the-system
# Notes: When PR gets merged, switch back to using the @Security tag: @Security("is_granted('VIEW', organization) and is_granted('FRONT_END', campaign)")
/**
* @Route("/{campaignSlug}/register", name="campaign_register_user")
* @IsGranted("VIEW", subject="organization")
* @IsGranted("FRONT_END", subject="campaign")
*/
public function campaignAction(Request $request, Organization $organization, Campaign $campaign)
{
$userManager = $this->getUserManager();
$dispatcher = $this->getEventDispatcher();
$user = $userManager->createUser();
$user->setEnabled(true);
$event = new BidcozGetResponseUserEvent($user, $request);
$event->setOrganization($organization);
$event->setCampaign($campaign);
$dispatcher->dispatch($event, FOSUserEvents::REGISTRATION_INITIALIZE);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
$email = '';
$ccProxy = new StripeCreditCardProxy();
$ccForm = $this->getCCForm($ccProxy);
$form = $this->getRegistrationFormFactory()->createForm();
$form->setData($user);
$hasEmailAlreadyInUserError = false;
$withCc = $organization->isStripeAllowed()
&& $organization->hasPaymentGatewayAccountType(Account::STRIPE)
&& $campaign->getCollectCcInfo();
if ('POST' === $request->getMethod()) {
$form->handleRequest($request);
$ccForm->handleRequest($request);
if (($form->isSubmitted() && $form->isValid()) && (!$withCc || $customer = $this->ccCheck($campaign, $user, $ccForm))) {
$event = new FormEvent($form, $request);
$dispatcher->dispatch($event, FOSUserEvents::REGISTRATION_SUCCESS);
$user->setLoggedIn();
$userManager->updateUser($user);
$contact = $this->getContactManager()->findOrCreateContact($organization, $user, true);
$campaignDetail = $this->getContactManager()->findOrCreateCampaignDetail($campaign, $contact, false);
if ($withCc && $customer) {
$cc = $this->getCcManager()->createCC($campaign, $user, $customer->id);
$this->getCcManager()->setCcInfo($cc, $customer, $ccProxy);
$this->getEntityManager()->flush();
}
$url = $this->getRouter()->generate('campaign_home', [
'orgSlug' => $organization->getSlug(),
'campaignSlug' => $campaign->getSlug(),
]);
if (null === $response = $event->getResponse()) {
$response = new RedirectResponse($url);
}
if ($request->isXmlHttpRequest()) {
$response = $this->returnJsonSuccess(['redirect_url' => $url]);
}
$event = new BidcozFilterUserResponseEvent($user, $request, $response);
$event->setOrganization($organization);
$event->setCampaign($campaign);
$dispatcher->dispatch($event, FOSUserEvents::REGISTRATION_COMPLETED);
return $response;
} else {
$emailForm = $form->get('email')->get('first'); // for first email
$errors = $emailForm->getErrors();
foreach ($emailForm->getErrors() as $error) {
if ('fos_user.email.already_used' === $error->getMessageTemplate()) {
$hasEmailAlreadyInUserError = true;
}
}
$email = $emailForm->getData();
}
}
return $this->render('@BidcozFrontend/Registration/campaign.html.twig', [
'organization' => $organization,
'campaign' => $campaign,
'form' => $form->createView(),
'ccForm' => $ccForm->createView(),
'withCc' => $withCc,
'hasEmailAlreadyInUserError' => $hasEmailAlreadyInUserError,
'last_username' => $email,
]);
}
protected function getCCForm(StripeCreditCardProxy $proxy)
{
return $this->createForm(StripeCreditCardType::class, $proxy);
}
protected function ccCheck(Campaign $campaign, User $user, Form &$ccForm)
{
if (!($ccForm->isSubmitted() && $ccForm->isValid())) {
$this->addFlash('danger', 'Credit Card Required to Participate');
return false;
}
$token = $ccForm->get('token')->getData();
try {
$customer = $this->getStripeManager()->createOrgCustomer($campaign->getOrganization(), $user, $token);
} catch (\Stripe\Error\Base $e) {
$this->addFlash('danger', $e->getMessage());
$ccProxy = new StripeCreditCardProxy();
$ccForm = $this->getCCForm($ccProxy);
return false;
}
return $customer;
}
}