<?php
namespace App\Controller;
use App\Components\PaymentStatus;
use App\Entity\Account;
use App\Entity\ApiKey;
use App\Entity\Payment;
use App\Entity\Plan;
use App\Entity\Service;
use App\Form\RegistrationFormType;
use App\Repository\AccountRepository;
use App\Security\EmailVerifier;
use App\Security\LoginFormAuthenticator;
use App\Services\ApiKeyGenerator;
use App\Services\MailHandler;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
class RegistrationController extends AbstractController
{
private $emailVerifier;
private $session;
private $apiKeyGenerator;
private $mailHandler;
public function __construct(
EmailVerifier $emailVerifier,
SessionInterface $session,
ApiKeyGenerator $apiKeyGenerator,
MailHandler $mailHandler
) {
$this->emailVerifier = $emailVerifier;
$this->session = $session;
$this->apiKeyGenerator = $apiKeyGenerator;
$this->mailHandler = $mailHandler;
}
/**
* @param Request $request
* @return Response
*
* @Route("/register/thank-you", name="app_register_thankyou")
*/
public function finishedRegistration(Request $request): Response
{
return $this->render('registration/thank_you.html.twig');
}
/**
* @Route("/verify/email", name="app_verify_email")
*/
public function verifyUserEmail(
Request $request,
AccountRepository $accountRepository,
GuardAuthenticatorHandler $guardHandler,
LoginFormAuthenticator $authenticator
): Response {
$id = $request->get('id');
if (null === $id) {
return $this->redirectToRoute('app_register');
}
$user = $accountRepository->find($id);
if (null === $user) {
return $this->redirectToRoute('app_register');
}
// validate email confirmation link, sets User::isVerified=true and persists
try {
$this->emailVerifier->handleEmailConfirmation($request, $user);
} catch (VerifyEmailExceptionInterface $exception) {
$this->addFlash('verify_email_error', $exception->getReason());
// generate a signed url and email it to the user
$this->emailVerifier->sendEmailConfirmation('app_verify_email', $user,
(new TemplatedEmail())
->from(new Address('support@theeasyapi.com', 'The Easy API'))
->to($user->getEmail())
->subject('Please Confirm your Email')
->htmlTemplate('registration/confirmation_email.html.twig')
);
return $this->redirectToRoute('app_register_thankyou');
}
$this->addFlash('success', 'Your email address has been verified.');
if ($user->getPlan()) {
return $guardHandler->authenticateUserAndHandleSuccess(
$user,
$request,
$authenticator,
'main' // firewall name in security.yaml
);
}
$this->session->set('userId', $user->getId());
return $this->redirectToRoute('app_register_plan', ['plan' => $user->getDesiredPlan()->getName()]);
}
/**
* @param Plan $plan
* @param string|null $auth
* @return Response
*
* @Route("/register/plan/{plan}", name="app_register_plan")
* @Route("/register/plan/{plan}/{auth}", name="app_register_plan_auth")
* @ParamConverter("plan", options={"mapping": {"plan":"name"}})
*/
public function registerPlan(Plan $plan, $auth = null): Response
{
// Catch someone coming from an email with an auth token set
if ($auth) {
$userId = $this->apiKeyGenerator->getUserIdFromKey($auth);
// They either waited more than a year, or messed up the token
if (!$userId) {
return $this->redirectToRoute("app_login");
}
$this->session->set('userId', $userId);
} else {
$userId = $this->session->get('userId');
}
/** @var Account $user */
$user = $this->getDoctrine()->getRepository(Account::class)->findOneById($userId);
if ($user->getPlan()) {
$this->addFlash("flash_success", "You have already completed this step, please login.");
return $this->redirectToRoute("app_login");
}
// Catch a logged in user, set their UserId
if ($this->getUser()) {
$user = $this->getDoctrine()->getRepository(Account::class)->findOneByEmail($this->getUser()->getUsername());
$this->session->set('userId', $user->getId());
}
$plans = $this->getDoctrine()->getRepository(Plan::class)->findBy([
'version' => 2,
'show' => 1
], ['price' => 'DESC']);
return $this->render('registration/register_plan.html.twig', [
'plans' => $plans,
'plan' => $plan
]);
}
/**
* @param Request $request
* @param AccountRepository $accountRepository
* @param GuardAuthenticatorHandler $guardHandler
* @param LoginFormAuthenticator $authenticator
* @param Plan $plan
* @return Response
*
* @Route("/register/complete/{plan}", name="app_complete_plan")
* @ParamConverter("plan", options={"mapping": {"plan":"name"}})
*/
public function completeRegistration(
Request $request,
AccountRepository $accountRepository,
GuardAuthenticatorHandler $guardHandler,
LoginFormAuthenticator $authenticator,
Plan $plan
): Response {
$user = $accountRepository->find($this->session->get('userId'));
if (null === $user) {
return $this->redirectToRoute('app_register');
}
if ($plan->getPrice() > 0) {
$payment = $this->getDoctrine()->getRepository(Payment::class)->findOneBy([
'account' => $user,
'status' => PaymentStatus::INITIALIZED
]);
if (!$payment) {
return $this->redirectToRoute('app_register_plan', ['plan' => $plan->getName()]);
}
}
// Set the plan they picked
$user->setPlan($plan);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
return $guardHandler->authenticateUserAndHandleSuccess(
$user,
$request,
$authenticator,
'main' // firewall name in security.yaml
);
}
/**
* @Route("/register/{plan}", name="app_register")
* @ParamConverter("plan", options={"mapping": {"plan":"name"}})
*
* @param Request $request
* @param UserPasswordEncoderInterface $passwordEncoder
* @param Plan|null $plan
* @return Response
*/
public function register(
Request $request,
UserPasswordEncoderInterface $passwordEncoder,
Plan $plan = null
): Response {
if (!$plan) {
$plan = $this->getDoctrine()->getRepository(Plan::class)->findOneBy([
'version' => 2,
'name' => 'Starter'
]);
}
$user = new Account();
$user->setDesiredPlan($plan);
$form = $this->createForm(RegistrationFormType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// encode the plain password
$user->setPassword(
$passwordEncoder->encodePassword(
$user,
$form->get('plainPassword')->getData()
)
);
$nameArr = explode(" ", $form->get('name')->getData(), 2);
if (count($nameArr) == 1) {
$user->setFirstname($nameArr[0]);
$user->setLastname(" ");
} else {
$user->setFirstname($nameArr[0]);
$user->setLastname($nameArr[1]);
}
try {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
} catch (\Exception $e) {
$this->addFlash("flash_error",
"We were unable to create your account. Please check your information and try again.");
return $this->redirectToRoute("app_register");
}
// Create a default API Key
$apiKey = new ApiKey($user);
$apiKey->setName("Default")->setApikey($this->apiKeyGenerator->createKey($user));
$entityManager->persist($apiKey);
$entityManager->flush();
// Setting the user
$this->session->set('userId', $user->getId());
// Send e-mail
$this->mailHandler->sendRegistration($user, $apiKey);
return $this->redirectToRoute('app_register_plan', ['plan' => $user->getDesiredPlan()->getName()]);
}
return $this->render('registration/register.html.twig', [
'registrationForm' => $form->createView(),
]);
}
}