diff --git a/.gitignore b/.gitignore
index 683c9d3..73fe2a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,4 @@ html/css/
html/images/
html/js/
lib/
-t.php
-test.php
variables.less
diff --git a/.php_cs b/.php_cs
index 9afb8c5..68b3b2e 100644
--- a/.php_cs
+++ b/.php_cs
@@ -52,6 +52,11 @@ return PhpCsFixer\Config::create()
->ignoreDotFiles(true)
->ignoreVCS(true)
->name('*.php')
- ->in('src')
- ->in('html')
+ ->name(__DIR__.'/app/Kernel.php')
+ ->in([
+ 'src',
+ 'app',
+ 'bin',
+ 'html',
+ ])
);
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ebbf62f..d030b24 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added
- .php_cs
- php-cs-fixer
+- Console
+- Doctrine/DoctrineProvider/OrmProvider/DoctrineConsoleProvider
## [0.0.1] - 2017-02-07
### Added
diff --git a/app/Kernel.php b/app/Kernel.php
index 42bcb9d..819eeef 100644
--- a/app/Kernel.php
+++ b/app/Kernel.php
@@ -30,7 +30,6 @@ use Monolog\{
Handler\StreamHandler,
Logger
};
-use Sikofitt\App\Controller\DefaultController;
use Sikofitt\App\Entity\User;
use Sikofitt\App\Traits\EntityManagerTrait;
use Sikofitt\App\Traits\FlashTrait;
@@ -86,7 +85,6 @@ class Kernel extends Application
use TwigTrait;
use UrlGeneratorTrait;
-
/**
* Kernel constructor.
*
@@ -108,12 +106,11 @@ class Kernel extends Application
$this->setUpLogger();
$this->setUpMailer();
}
+
public function setUpRoutes(\Kernel $app)
{
- $app->match('/login', DefaultController::class.'::loginAction')
- ->method('GET|POST');
-
}
+
/**
* @param array $values
*
@@ -228,10 +225,16 @@ class Kernel extends Application
'password' => 'doughnut',
],
]);
-
+ //$j = new Doctrine\Common\Cache\FilesystemCache()
$this->register(new DoctrineOrmServiceProvider(), [
- 'orm.proxies_dir' => $this->getCacheDir().'/doctrine/proxies',
- 'orm.default_cache' => 'array',
+ 'orm.proxies_dir' => $this->getCacheDir().'/doctrine/proxies/Doughnut/Wedding',
+ 'orm.proxies_namespace' => 'Doughnut\Wedding',
+ 'orm.default_cache' => [
+ 'driver' => 'filesystem',
+ 'path' => $this->getCacheDir().'/doctrine/cache',
+ ],
+ 'orm.auto_generate_proxies' => true,
+ 'orm.strategy' => 'naming',
'orm.em.options' => [
'connection' => 'default',
'mappings' => [
@@ -239,6 +242,8 @@ class Kernel extends Application
'type' => 'annotation',
'path' => $this->getBaseDir().'/src/Sikofitt/App/Entity',
'namespace' => 'Sikofitt\App\Entity',
+ 'alias' => 'Sikofitt',
+ 'auto_generate_proxies' => true,
'use_simple_annotation_reader' => false,
],
],
@@ -327,10 +332,10 @@ class Kernel extends Application
// 'anonymous' => true
);*/
- $this['protected_pages'] = function() {
+ $this['protected_pages'] = function () {
return [
'gallery',
- 'rsvp/update'
+ 'rsvp/update',
];
};
@@ -341,7 +346,6 @@ class Kernel extends Application
//->register(new SecurityServiceProvider())
;
-
$this->extend('form.extensions', function ($extensions) {
return $extensions;
});
diff --git a/app/views/form/token.html.twig b/app/views/form/token.html.twig
new file mode 100644
index 0000000..bc359f2
--- /dev/null
+++ b/app/views/form/token.html.twig
@@ -0,0 +1,33 @@
+{% extends 'base.html.twig' %}
+{% block body %}
+ {{ dump(app.session.get('user')) }}
+ {{ form_start(form) }}
+
+
+
+ {{ form_row(form.user_token) }}
+
+
+ {{ form_row(form.submit) }}
+
+
+
+
+
+ You can also send a new auto login link to your email.
+
+
+
+ {{ form_row(form.email) }}
+
+
+ {{ form_row(form.update_token) }}
+
+
+
+ {{ form_rest(form) }}
+
+ {{ form_end(form) }}
+{% endblock %}
\ No newline at end of file
diff --git a/app/views/user/index.html.twig b/app/views/user/index.html.twig
new file mode 100644
index 0000000..a8e1fc6
--- /dev/null
+++ b/app/views/user/index.html.twig
@@ -0,0 +1,4 @@
+{% extends 'base.html.twig' %}
+{% block body %}
+{{ dump(app.session.get('user')) }}
+{% endblock %}
diff --git a/app/views/user/logout.html.twig b/app/views/user/logout.html.twig
new file mode 100644
index 0000000..b25ff8b
--- /dev/null
+++ b/app/views/user/logout.html.twig
@@ -0,0 +1,10 @@
+{% extends 'base.html.twig' %}
+{% block body %}
+ You have been successfully logged out.
+
+ You can log in again by going to the login page.
+
+
+ You can also login using a token by going to the token login page.
+
+{% endblock %}
\ No newline at end of file
diff --git a/bin/console b/bin/console
new file mode 120000
index 0000000..cf4512a
--- /dev/null
+++ b/bin/console
@@ -0,0 +1 @@
+console.php
\ No newline at end of file
diff --git a/bin/console.php b/bin/console.php
index 9de444c..1c15ab4 100755
--- a/bin/console.php
+++ b/bin/console.php
@@ -19,14 +19,10 @@
* along with this program. If not, see .
*/
-use Doctrine\ORM\Tools\Console\Command\ClearCache\EntityRegionCommand;
-use Doctrine\ORM\Tools\Console\Command\MappingDescribeCommand;
use Knp\Provider\ConsoleServiceProvider;
-use PhpCsFixer\Console\Command\DescribeCommand;
-use PhpCsFixer\Console\Command\SelfUpdateCommand;
use Sikofitt\App\Provider\DoctrineConsoleProvider;
-use Symfony\Component\Console\Application;
-use Symfony\Component\Yaml\Command\LintCommand;
+use Symfony\Bridge\Twig\Command\DebugCommand;
+use Symfony\Bridge\Twig\Command\LintCommand;
$loader = require __DIR__.'/../vendor/autoload.php';
$app = new \Kernel($loader, true);
@@ -39,12 +35,20 @@ $consoleConfig = [
$app
->register(new ConsoleServiceProvider(), $consoleConfig)
->register(new DoctrineConsoleProvider());
-/**
- * @var Application $console
- */
-$console = $app['console'];
-$console->add(new Symfony\Bridge\Twig\Command\LintCommand());
-$console->add(new Symfony\Bridge\Twig\Command\DebugCommand());
-$console->add(new PhpCsFixer\Console\Command\FixCommand());
-$console->add(new Symfony\Component\Yaml\Command\LintCommand());
+
+$fixCommand = new \PhpCsFixer\Console\Command\FixCommand();
+$fixCommand->setName('dev:fixer')->setDescription('PhpCSFixer - Fixes directories and files according to a set of rules.');
+$twigLintCommand = new LintCommand();
+$twigLintCommand->setTwigEnvironment($app['twig']);
+$twigDebugCommand = new DebugCommand();
+$twigDebugCommand->setTwigEnvironment($app['twig']);
+$fixCommand->setHidden(true);
+
+$app['console']->addCommands([
+ $twigDebugCommand,
+ $twigLintCommand,
+ new \Symfony\Component\Yaml\Command\LintCommand(),
+ $fixCommand,
+]);
+
$app['console']->run();
diff --git a/composer.json b/composer.json
index 75f11e0..c2cd2cd 100644
--- a/composer.json
+++ b/composer.json
@@ -20,8 +20,6 @@
"paragonie/cookie": "^3.1",
"paragonie/csp-builder": "^2.0",
"paragonie/sodium_compat": "^0.4.0",
- "psr/http-message": "^1.0",
- "psr/log": "^1.0",
"silex/silex": "^2.0",
"swiftmailer/swiftmailer": "^5.4",
"symfony/asset": "^3.2",
diff --git a/html/index.php b/html/index.php
index fefff3c..953bd13 100644
--- a/html/index.php
+++ b/html/index.php
@@ -18,8 +18,8 @@
* along with this program. If not, see .
*/
-use Sikofitt\App\Controller\DefaultController;
-use Sikofitt\App\Controller\RsvpController;
+use Sikofitt\App\Controller\RsvpControllerProvider;
+use Sikofitt\App\Controller\UserController;
use Sikofitt\App\Middleware\CspMiddleware;
use Sikofitt\App\Middleware\HeaderMiddleware;
@@ -28,25 +28,11 @@ $loader = require __DIR__.'/../vendor/autoload.php';
$app = new Kernel($loader, true);
// Controllers
// Default
-$app->setUpRoutes($app);
-//$app->match('/login', DefaultController::class.'loginAction')
-// ->bind('login');
-// RSVP Actions
+$app->mount('/rsvp', new RsvpControllerProvider());
+
+$app->mount('/user', new UserController());
-$app->match('/rsvp', RsvpController::class.'::indexAction')
- ->method('GET|POST')
- ->bind('rsvp');
-$app->match('/rsvp/reset', RsvpController::class.'::resetAction')
- ->method('GET|POST')
- ->bind('rsvp_password_reset');
-$app->match('/rsvp/reset/{token}', RsvpController::class.'::tokenAction')
- ->bind('rsvp_token')
- ->method('GET|POST');
- //->before(new MysqlAuthenticatorMiddleware());
-$app->match('/rsvp/edit', RsvpController::class.'::editAction')
- ->method('GET|POST')
- ->bind('rsvp_edit');
//->before(new MysqlAuthenticatorMiddleware());
// Middleware
$app->before(new CspMiddleware(), \Kernel::EARLY_EVENT);
diff --git a/src/Sikofitt/App/Controller/DefaultController.php b/src/Sikofitt/App/Controller/DefaultController.php
index 716e536..37daf37 100644
--- a/src/Sikofitt/App/Controller/DefaultController.php
+++ b/src/Sikofitt/App/Controller/DefaultController.php
@@ -20,9 +20,6 @@
namespace Sikofitt\App\Controller;
-use Sikofitt\App\Entity\User;
-use Sikofitt\App\Form\UserLoginType;
-use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\Request;
class DefaultController
@@ -31,48 +28,4 @@ class DefaultController
{
return $app->render('index.html.twig', ['request' => $request]);
}
-
- public function loginAction(Request $request, \Kernel $app)
- {
- if ($app->session()->has('user')) {
- //return $app->redirect($app->url('rsvp_edit'));
- }
- $loginForm = $app->getFormFactory()->create(UserLoginType::class);
- if ($request->isMethod('POST')) {
- $loginForm->handleRequest($request);
- if ($loginForm->isValid() && $loginForm->isSubmitted()) {
- $user = $app->getEntityManager()->getRepository(User::class)->findByEmail($loginForm->get('email_username')->getData());
- if (null !== $user && true === password_verify($loginForm->get('password')->getData(), $user[0]->getPassword())) {
- $userSession = [
- 'firstName' => $user[0]->getFirstName(),
- 'lastName' => $user[0]->getLastName(),
- 'fullName' => sprintf('%s %s', $user[0]->getFirstName(), $user[0]->getLastName()),
- 'familySide' => $user[0]->getFamilySide(),
- 'email' => $user[0]->getEmail(),
- 'family' => $user[0]->getFamily(),
- 'created' => $user[0]->getCreated()->format('U'),
- 'updated' => $user[0]->getUpdated()->format('U'),
- 'guests' => $user[0]->getRsvp()->getGuests(),
- ];
- $app->getSession()->set('user', $userSession);
- $app->redirect($app->url('rsvp'));
- } else {
- $error = new FormError('Your password or email is incorrect.');
- $error->setOrigin($loginForm);
- $loginForm->get('password')->addError($error);
-
- return $app->render('login.html.twig', ['form' => $loginForm->createView()]);
- }
- }
- }
-
- return $app->render('login.html.twig', ['form' => $loginForm->createView()]);
- }
-
- public function logoutAction(Request $request, \Kernel $app)
- {
- $app->session()->remove('user');
-
- return $app->render('logout.html.twig');
- }
}
diff --git a/src/Sikofitt/App/Controller/RouterCollector.php b/src/Sikofitt/App/Controller/RouterCollector.php
new file mode 100644
index 0000000..2c53fd6
--- /dev/null
+++ b/src/Sikofitt/App/Controller/RouterCollector.php
@@ -0,0 +1,43 @@
+.
+ */
+
+namespace Sikofitt\App\Controller;
+
+class RouterCollector
+{
+ /**
+ * @var \Kernel
+ */
+ private $application;
+
+ public function setApplication(\Kernel $application)
+ {
+ $this->application = $application;
+
+ return $this;
+ }
+
+ public function buildRoutes()
+ {
+ $this->application->match('/login', DefaultController::class.'::loginAction')
+ ->method('GET|POST')
+ ->bind('login');
+ }
+}
diff --git a/src/Sikofitt/App/Controller/RsvpController.php b/src/Sikofitt/App/Controller/RsvpController.php
index 9f196f9..ff7112e 100644
--- a/src/Sikofitt/App/Controller/RsvpController.php
+++ b/src/Sikofitt/App/Controller/RsvpController.php
@@ -45,9 +45,9 @@ class RsvpController
* @var UserRepository $userRepo
*/
$em = $app['orm.em'];
- $rsvpRepo = $em->getRepository('Sikofitt\App\Entity\Rsvp');
+ $rsvpRepo = $em->getRepository('Sikofitt:Rsvp');
$count = (40 - $rsvpRepo->getRsvpCount());
- $userRepo = $em->getRepository('Sikofitt\App\Entity\User');
+ $userRepo = $em->getRepository('Sikofitt:User');
$kCount = $userRepo->getKatrinaCount();
$eCount = $userRepo->getEricCount();
/**
diff --git a/src/Sikofitt/App/Controller/RsvpControllerProvider.php b/src/Sikofitt/App/Controller/RsvpControllerProvider.php
new file mode 100644
index 0000000..266f59a
--- /dev/null
+++ b/src/Sikofitt/App/Controller/RsvpControllerProvider.php
@@ -0,0 +1,54 @@
+.
+ */
+
+namespace Sikofitt\App\Controller;
+
+use Pimple\Container;
+use Silex\Api\ControllerProviderInterface;
+use Silex\Application;
+use Silex\ControllerCollection;
+
+class RsvpControllerProvider implements ControllerProviderInterface
+{
+ /**
+ * Returns routes to connect to the given application.
+ *
+ * @param Application $app An Application instance
+ *
+ * @return ControllerCollection A ControllerCollection instance
+ */
+ public function connect(Application $app)
+ {
+ /**
+ * @var ControllerCollection $rsvpControllers;
+ */
+ $rsvpControllers = $app['controllers_factory'];
+ $rsvpControllers
+ ->match('/', RsvpController::class.'::indexAction')
+ ->method('GET|POST')
+ ->bind('rsvp');
+
+ return $rsvpControllers;
+ }
+
+ public function register(Container $pimple)
+ {
+ }
+}
diff --git a/src/Sikofitt/App/Controller/UserController.php b/src/Sikofitt/App/Controller/UserController.php
new file mode 100644
index 0000000..7199d5d
--- /dev/null
+++ b/src/Sikofitt/App/Controller/UserController.php
@@ -0,0 +1,234 @@
+.
+ */
+
+namespace Sikofitt\App\Controller;
+
+use Sikofitt\App\Form\UserLoginType;
+use Sikofitt\App\Form\UserTokenType;
+use Sikofitt\Security\TokenGenerator;
+use Silex\Api\ControllerProviderInterface;
+use Silex\Application;
+use Symfony\Component\Form\FormError;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\StreamedResponse;
+
+/**
+ * Class UserController.
+ */
+class UserController implements ControllerProviderInterface
+{
+ public function connect(Application $app)
+ {
+ /**
+ * @var ControllerCollection $userControllers
+ */
+ $userControllers = $app['controllers_factory'];
+ $userControllers->match('/', __CLASS__.'::indexAction')
+ ->method('GET')
+ ->bind('user_index');
+
+ $userControllers->match('/login', __CLASS__.'::loginAction')
+ ->method('GET|POST')
+ ->bind('login');
+ $userControllers->get('/logout', __CLASS__.'::logoutAction')
+ ->bind('logout');
+ $userControllers->match('/login/token/{token}', __CLASS__.'::tokenLoginAction')
+ ->method('GET|POST')
+ ->bind('token_login')
+ ->value('token', null);
+
+ $userControllers->match('/reset', __CLASS__.'::resetAction')
+ ->method('GET|POST')
+ ->bind('user_reset');
+ $userControllers->match('/reset/{token}', __CLASS__.'::tokenAction')
+ ->bind('user_reset_token')
+ ->method('GET|POST');
+ //->before(new MysqlAuthenticatorMiddleware());
+ $userControllers->match('/edit', __CLASS__.'::editAction')
+ ->method('GET|POST')
+ ->bind('user_edit');
+
+ return $userControllers;
+ }
+
+ public function logoutAction(\Kernel $app)
+ {
+ if (true === $app->session()->has('user')) {
+ $app->session()->remove('user');
+ }
+
+ return $app->render('user/logout.html.twig');
+ }
+
+ public function tokenLoginAction(Request $request, \Kernel $app, string $token = null)
+ {
+ if (null === $token) {
+ $tokenForm = $app->getFormFactory()->create(UserTokenType::class);
+ if ($request->isMethod('POST')) {
+ $tokenForm->handleRequest($request);
+ if ($tokenForm->isValid() && $tokenForm->isSubmitted()) {
+ if ($tokenForm->get('update_token')->isClicked()) {
+ if (null !== $tokenForm->get('email')->getData()) {
+ return $this->updateAndSendTokenLoginLink($app,
+ $tokenForm);
+ } else {
+ $tokenForm->get('email')
+ ->addError(new FormError('Email address is a required field to send a new login link.'));
+
+ return $app->render('form/token.html.twig',
+ ['form' => $tokenForm->createView()]);
+ }
+ } else {
+ $userToken = $tokenForm->get('user_token')->getData();
+ $user = $app->getEntityManager()
+ ->getRepository('Sikofitt:User')
+ ->getUserByUserToken($userToken);
+ if (null === $user) {
+ $tokenForm->get('user_token')
+ ->addError(new FormError('Token is invalid.'));
+ } else {
+ $app->session()->set('user', $user);
+ }
+
+ return $app->render('form/token.html.twig',
+ ['form' => $tokenForm->createView()]);
+ }
+ } else {
+ return $app->render('form/token.html.twig',
+ ['form' => $tokenForm->createView()]);
+ }
+ }
+
+ return $app->render('form/token.html.twig', ['form' => $tokenForm->createView()]);
+ } else {
+ // Token has been included.
+ $app->session()->remove('user');
+ $tokenForm = $app->getFormFactory()->create(UserTokenType::class);
+ //$user = $app->getEntityManager()->getRepository('Sikofitt:User')->getUserByUserToken($token);
+ $user = $app->getEntityManager()->getRepository('Sikofitt:User')->findOneBy(['userToken' => $token]);
+ if (null !== $user) {
+ $app->session()->set('user', $user);
+
+ return $app->render('user/index.html.twig');
+ } else {
+ return new StreamedResponse(function () use ($app, $tokenForm, $token) {
+ $tokenForm->get('user_token')->setData($token);
+ $tokenForm->get('user_token')->addError(new FormError('Invalid token.'));
+ print $app->renderView('form/token.html.twig', ['form' => $tokenForm->createView()]);
+ });
+ }
+ }
+ }
+
+ public function indexAction(Request $request, \Kernel $app)
+ {
+ if ($app->session()->has('user')) {
+ return new JsonResponse(
+ [
+ 'request' => $request->request->all(),
+ 'server' => $request->server->all(),
+ 'headers' => $request->headers->all(),
+ 'session' => $app->getSession()->get('user'),
+ 'token' => (string) new TokenGenerator(),
+ ]
+ );
+ }
+ }
+
+ public function loginAction(Request $request, \Kernel $app)
+ {
+ if ($app->session()->has('user')) {
+ //return $app->redirect($app->url('rsvp_edit'));
+ }
+ $loginForm = $app->getFormFactory()->create(UserLoginType::class);
+ if ($request->isMethod('POST')) {
+ $loginForm->handleRequest($request);
+ if ($loginForm->isValid() && $loginForm->isSubmitted()) {
+ $user = $app->getEntityManager()->getRepository(User::class)->findByEmail($loginForm->get('email_username')->getData());
+ if (null !== $user && true === password_verify($loginForm->get('password')->getData(), $user[0]->getPassword())) {
+ $userSession = [
+ 'firstName' => $user[0]->getFirstName(),
+ 'lastName' => $user[0]->getLastName(),
+ 'fullName' => sprintf('%s %s', $user[0]->getFirstName(), $user[0]->getLastName()),
+ 'familySide' => $user[0]->getFamilySide(),
+ 'email' => $user[0]->getEmail(),
+ 'family' => $user[0]->getFamily(),
+ 'created' => $user[0]->getCreated()->format('U'),
+ 'updated' => $user[0]->getUpdated()->format('U'),
+ 'guests' => $user[0]->getRsvp()->getGuests(),
+ ];
+ $app->getSession()->set('user', $userSession);
+ $app->redirect($app->url('rsvp'));
+ } else {
+ $error = new FormError('Your password or email is incorrect.');
+ $error->setOrigin($loginForm);
+ $loginForm->get('password')->addError($error);
+
+ return $app->render('login.html.twig', ['form' => $loginForm->createView()]);
+ }
+ }
+ }
+
+ return $app->render('login.html.twig', ['form' => $loginForm->createView()]);
+ }
+
+ public function resetAction(Request $request, \Kernel $app)
+ {
+ }
+
+ public function tokenAction(Request $request, \Kernel $app)
+ {
+ }
+
+ public function editAction(Request $request, \Kernel $app)
+ {
+ }
+
+ private function tokenFormGenerator(\Kernel $app)
+ {
+ return;
+ }
+
+ private function updateAndSendTokenLoginLink(\Kernel $app, \Symfony\Component\Form\FormInterface $tokenForm)
+ {
+ $email = $tokenForm->get('email')->getData();
+ $user = $app->getEntityManager()
+ ->getRepository('Sikofitt:User')
+ ->findByEmail($email);
+ if (null === $user) {
+ $tokenForm->get('email')->addError(new FormError('Sorry we couldn\'t find your email address.'));
+
+ return $app->render('form/token.html.twig', ['form' => $tokenForm->createView()]);
+ }
+ $newToken = $app->getEntityManager()
+ ->getRepository('Sikofitt:User')
+ ->setUserToken($email);
+ if (false !== $newToken) {
+ $user->setUserToken($newToken);
+ $app->session()->set('user', $user);
+
+ return $app->render('form/token.html.twig', ['form' => $tokenForm->createView()]);
+ }
+ $tokenForm->get('email')->addError(new FormError('An Unknown error occured. Please try again.'));
+
+ return $app->render('form/token.html.twig', ['form' => $tokenForm->createView()]);
+ }
+}
diff --git a/src/Sikofitt/App/Controller/UserControllerProvider.php b/src/Sikofitt/App/Controller/UserControllerProvider.php
new file mode 100644
index 0000000..86436ed
--- /dev/null
+++ b/src/Sikofitt/App/Controller/UserControllerProvider.php
@@ -0,0 +1,59 @@
+.
+ */
+
+namespace Sikofitt\App\Controller;
+
+use Silex\Api\ControllerProviderInterface;
+use Silex\Application;
+use Silex\ControllerCollection;
+
+class UserControllerProvider implements ControllerProviderInterface
+{
+ /**
+ * Returns routes to connect to the given application.
+ *
+ * @param Application $app An Application instance
+ *
+ * @return ControllerCollection A ControllerCollection instance
+ */
+ public function connect(Application $app)
+ {
+ /**
+ * @var ControllerCollection $userControllers
+ */
+ $userControllers = $app['controllers_factory'];
+ $app->match('/user', UserController::class.'::indexAction')
+ ->method('GET')
+ ->bind('user_index');
+
+ $app->match('/user/reset', UserController::class.'::resetAction')
+ ->method('GET|POST')
+ ->bind('user_reset');
+ $app->match('/user/reset/{token}', UserController::class.'::tokenAction')
+ ->bind('user_reset_token')
+ ->method('GET|POST');
+ //->before(new MysqlAuthenticatorMiddleware());
+ $app->match('/user/edit', UserController::class.'::editAction')
+ ->method('GET|POST')
+ ->bind('user_edit');
+
+ return $userControllers;
+ }
+}
diff --git a/src/Sikofitt/App/Form/UserTokenType.php b/src/Sikofitt/App/Form/UserTokenType.php
new file mode 100644
index 0000000..42ec935
--- /dev/null
+++ b/src/Sikofitt/App/Form/UserTokenType.php
@@ -0,0 +1,89 @@
+.
+ */
+
+namespace Sikofitt\App\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\EmailType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+use Symfony\Component\Validator\Constraints\Email;
+use Symfony\Component\Validator\Constraints\Length;
+
+class UserTokenType extends AbstractType
+{
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ $builder
+ ->add('user_token', TextType::class, [
+ 'attr' => [
+ 'class' => 'uk-input uk-form-large',
+ 'placehoder' => 'Token',
+ ],
+ 'required' => false,
+ 'label_attr' => [
+ 'class' => 'uk-form-label uk-hidden',
+ ],
+ 'constraints' => [
+ new Length([
+ 'min' => 64,
+ 'max' => 64,
+ 'minMessage' => 'Token should be exactly {{ limit }} characters.',
+ 'maxMessage' => 'Token should be exactly {{ limit }} characters.',
+ 'exactMessage' => 'Token should be exactly {{ limit }} characters.',
+ ]),
+ ],
+ ])->add('submit', SubmitType::class, [
+ 'attr' => [
+ 'class' => 'uk-button uk-button-large uk-button-primary',
+ ],
+ 'label' => 'Login',
+ ])->add('email', EmailType::class, [
+ 'required' => false,
+ 'constraints' => [
+ new Email([
+ 'strict' => true,
+ 'checkMX' => true,
+ 'checkHost' => true,
+ ]),
+ ],
+ 'attr' => [
+ 'class' => 'uk-input uk-form-large uk-text-center',
+ 'placeholder' => 'Email Address',
+ ],
+ 'label_attr' => [
+ 'class' => 'uk-form-label',
+ ],
+ ])->add('update_token', SubmitType::class, [
+ 'attr' => [
+ 'class' => 'uk-button uk-button-large uk-button-primary',
+ ],
+ 'label' => 'Send New Login Link',
+ ])
+ ;
+ }
+
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $resolver->setDefault('attr', ['class' => 'uk-form uk-align-center']);
+ }
+}
diff --git a/src/Sikofitt/App/Provider/DoctrineConsoleProvider.php b/src/Sikofitt/App/Provider/DoctrineConsoleProvider.php
index 43a55db..49d2303 100644
--- a/src/Sikofitt/App/Provider/DoctrineConsoleProvider.php
+++ b/src/Sikofitt/App/Provider/DoctrineConsoleProvider.php
@@ -20,12 +20,12 @@
namespace Sikofitt\App\Provider;
-
use Doctrine\DBAL\Tools\Console\Command\{
ImportCommand,
ReservedWordsCommand,
RunSqlCommand
};
+use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
use Doctrine\ORM\Tools\Console\Command\{
ClearCache\EntityRegionCommand, ClearCache\MetadataCommand,
ClearCache\QueryCommand, ClearCache\ResultCommand,
@@ -52,6 +52,8 @@ class DoctrineConsoleProvider implements ServiceProviderInterface
* It should not get services.
*
* @param Container $pimple A container instance
+ *
+ * @throws \LogicException
*/
public function register(Container $pimple)
{
@@ -61,24 +63,26 @@ class DoctrineConsoleProvider implements ServiceProviderInterface
if (false === isset($pimple['db.options'])) {
throw new \LogicException('You must enable the DoctrineServiceProvider to use the DoctrineConsoleProvider.');
}
- if(false === isset($pimple['orm.em'])) {
+ if (false === isset($pimple['orm.em'])) {
throw new \LogicException('You must enable the Dflydev\Provider\DoctrineOrm\DoctrineOrmServiceProvider to use the DoctrineConsoleProvider.');
}
$console = $pimple['console'];
- $console->setHelperSet(new HelperSet(array(
- 'em' => new EntityManagerHelper($pimple['orm.em'])
- )));
+ $console->setHelperSet(new HelperSet([
+ 'em' => new EntityManagerHelper($pimple['orm.em']),
+ 'db' => new ConnectionHelper($pimple['db']),
+ ]));
- $updateCommand = new UpdateCommand();
- $updateCommand->setName('orm:schema:update');
+ $schemaUpdateCommand = (new UpdateCommand())
+ ->setName('orm:schema:update');
$schemaValidateCommand = (new ValidateSchemaCommand())
->setName('orm:schema:validate')
- ->setAliases(['orm:validate']);
+ ->setAliases(['validate']);
$schemaDropCommand = (new DropCommand())
->setName('orm:schema:drop');
$schemaCreateCommand = (new CreateCommand())
->setName('orm:schema:create');
+ $queryCommand = new QueryCommand();
$console->addCommands([
new ConvertDoctrine1SchemaCommand(),
@@ -99,8 +103,8 @@ class DoctrineConsoleProvider implements ServiceProviderInterface
new ResultCommand(),
$schemaCreateCommand,
$schemaDropCommand,
+ $schemaUpdateCommand,
$schemaValidateCommand,
]);
}
-
}
diff --git a/src/Sikofitt/App/Repository/UserRepository.php b/src/Sikofitt/App/Repository/UserRepository.php
index 66375bd..9a62f33 100644
--- a/src/Sikofitt/App/Repository/UserRepository.php
+++ b/src/Sikofitt/App/Repository/UserRepository.php
@@ -23,7 +23,7 @@ namespace Sikofitt\App\Repository;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use Sikofitt\App\Entity\User;
-use Symfony\Component\Security\Core\User\UserInterface;
+use Sikofitt\Security\TokenGenerator;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Validation;
@@ -34,17 +34,25 @@ use Symfony\Component\Validator\Validation;
*/
class UserRepository extends EntityRepository
{
+ /**
+ * @param string $email
+ *
+ * @return null|User
+ */
public function findByEmail(string $email)
{
- return $this->findBy(['email' => $email]);
- /*return $this->createQueryBuilder('u')
- ->select('u')
+ return $this->createQueryBuilder('u')
+ ->select(['u', 'r'])
+ ->leftJoin('u.rsvp', 'r', 'WITH', 'u.rsvp = r.id')
->where('u.email = :email')
->setParameter('email', $email)
->getQuery()
- ->getOneOrNullResult(Query::HYDRATE_OBJECT);*/
+ ->getOneOrNullResult(Query::HYDRATE_OBJECT);
}
+ /**
+ * @return int
+ */
public function getKatrinaCount()
{
return $this->createQueryBuilder('u')
@@ -53,9 +61,12 @@ class UserRepository extends EntityRepository
->where('u.familySide = :side')
->setParameter('side', User::KATRINA_SIDE)
->getQuery()
- ->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR);
+ ->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR) ?? 0;
}
+ /**
+ * @return int
+ */
public function getEricCount()
{
return $this->createQueryBuilder('u')
@@ -64,9 +75,14 @@ class UserRepository extends EntityRepository
->where('u.familySide = :side')
->setParameter('side', User::ERIC_SIDE)
->getQuery()
- ->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR);
+ ->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR) ?? 0;
}
+ /**
+ * @param string $email
+ *
+ * @return mixed|\Symfony\Component\Validator\ConstraintViolationListInterface
+ */
public function getEmail(string $email)
{
$validator = Validation::createValidator();
@@ -90,35 +106,90 @@ class UserRepository extends EntityRepository
->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR);
}
- public function getUserByToken(string $token)
+ /**
+ * @param string $resetToken
+ *
+ * @return User|null
+ */
+ public function getUserByResetToken(string $resetToken)
{
return $this->createQueryBuilder('u')
- ->select(['u'])
- ->where('u.token = :token')
- ->setParameter('token', $token)
+ ->select(['u', 'r'])
+ ->leftJoin('u.rsvp', 'r', 'WITH', 'u.rsvp = r.id')
+ ->where('u.resetToken = :resetToken')
+ ->setParameter('resetToken', $resetToken)
->getQuery()
- ->getOneOrNullResult();
+ ->getOneOrNullResult(Query::HYDRATE_OBJECT);
}
+ /**
+ * @param string $userToken
+ *
+ * @return User|null
+ */
+ public function getUserByUserToken(string $userToken)
+ {
+ return $this->createQueryBuilder('u')
+ ->select(['u', 'r'])
+ ->leftJoin('u.rsvp', 'r', 'WITH', 'u.rsvp = r.id')
+ ->where('u.userToken = :userToken')
+ ->setParameter('userToken', $userToken)
+ ->getQuery()
+ ->getOneOrNullResult(Query::HYDRATE_OBJECT);
+ }
+
+ /**
+ * Sets or updates user's user login token.
+ *
+ * @param string $email
+ *
+ * @return bool|string
+ */
+ public function setUserToken(string $email)
+ {
+ $userToken = (string) new TokenGenerator();
+
+ $result = (bool) $this->createQueryBuilder('u')
+ ->update()
+ ->set('u.userToken', ':userToken')
+ ->setParameter('userToken', $userToken)
+ ->where('u.email = :email')
+ ->setParameter('email', $email)
+ ->getQuery()
+ ->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR);
+
+ return true === $result ? $userToken : false;
+ }
+
+ /**
+ * Sets or updates user's reset password token.
+ *
+ * @param string $email
+ *
+ * @return bool
+ */
public function setResetToken(string $email)
{
- $bytes = \ParagonIE_Sodium_Compat::randombytes_buf(22);
- $blake = \ParagonIE_Sodium_Compat::crypto_generichash($bytes);
- $token = \ParagonIE_Sodium_Core_BLAKE2b::bin2hex($blake);
+ $resetToken = (string) new TokenGenerator();
return (bool) $this->createQueryBuilder('u')
->update()
- ->set('u.token', ':token')
- ->setParameter('token', $token)
+ ->set('u.resetToken', ':resetToken')
+ ->setParameter('resetToken', $resetToken)
->where('u.email = :email')
->setParameter('email', $email)
->getQuery()
->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR);
}
- public function updatePassword(UserInterface $user)
+ /**
+ * Updates a user.
+ *
+ * @param User|\Symfony\Component\Security\Core\User\UserInterface $user
+ */
+ public function destoryUserResetToken(User $user)
{
- $user->setToken(null);
+ $user->setResetToken(null);
$this->getEntityManager()->persist($user);
$this->getEntityManager()->flush();
}
diff --git a/src/Sikofitt/Security/TokenGenerator.php b/src/Sikofitt/Security/TokenGenerator.php
new file mode 100644
index 0000000..5a63ccc
--- /dev/null
+++ b/src/Sikofitt/Security/TokenGenerator.php
@@ -0,0 +1,60 @@
+.
+ */
+
+namespace Sikofitt\Security;
+
+use ParagonIE_Sodium_Compat as SodiumCompat;
+use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
+
+/**
+ * Class TokenGenerator.
+ */
+class TokenGenerator implements TokenGeneratorInterface
+{
+ public function __toString()
+ {
+ return $this->generateToken();
+ }
+
+ /**
+ * Generates a reset or user token.
+ *
+ * @return string The generated token
+ */
+ public function generateToken()
+ {
+ $randomBytes = substr(
+ SodiumCompat::randombytes_buf(512),
+ random_int(SodiumCompat::CRYPTO_GENERICHASH_BYTES, 512),
+ SodiumCompat::CRYPTO_GENERICHASH_BYTES_MAX
+ );
+
+ $rawToken = SodiumCompat::crypto_generichash(
+ $randomBytes,
+ SodiumCompat::randombytes_buf(
+ SodiumCompat::CRYPTO_GENERICHASH_BYTES_MAX
+ ),
+ 32
+ );
+ $token = SodiumCompat::bin2hex($rawToken);
+
+ return $token;
+ }
+}