From 329f6a025969ccd58c08e2d8c44cd93ef37f156d Mon Sep 17 00:00:00 2001 From: Marcin Kurczewski Date: Wed, 7 May 2014 17:39:40 +0200 Subject: [PATCH] Fixed account activation links --- lib/chibi-core | 2 +- public_html/dispatch.php | 124 ---------------- src/Api/Jobs/ActivateUserEmailJob.php | 2 +- src/Mail.php | 2 + src/Mailer.php | 23 ++- src/Models/Entities/TokenEntity.php | 43 +++++- src/Models/TokenModel.php | 12 +- src/Models/UserModel.php | 7 +- src/core.php | 2 + src/routes.php | 119 ++++++++++++++++ tests/JobTests/ActivateUserEmailJobTest.php | 149 ++++++++++++++++++++ tests/JobTests/AddUserJobTest.php | 42 ++++++ 12 files changed, 382 insertions(+), 145 deletions(-) create mode 100644 src/routes.php create mode 100644 tests/JobTests/ActivateUserEmailJobTest.php diff --git a/lib/chibi-core b/lib/chibi-core index 5e78e0a6..3c70aa33 160000 --- a/lib/chibi-core +++ b/lib/chibi-core @@ -1 +1 @@ -Subproject commit 5e78e0a68a1188851d12e26c0f58c1ffe95ffb69 +Subproject commit 3c70aa336c0571d83557d5fe66ff1b5cc0f3478f diff --git a/public_html/dispatch.php b/public_html/dispatch.php index 6bc48d0f..0c8ca3c2 100644 --- a/public_html/dispatch.php +++ b/public_html/dispatch.php @@ -36,130 +36,6 @@ $context->simpleActionName = null; $context->simpleActionName); }); -\Chibi\Router::register(['StaticPagesController', 'mainPageView'], 'GET', ''); -\Chibi\Router::register(['StaticPagesController', 'mainPageView'], 'GET', '/index'); -\Chibi\Router::register(['StaticPagesController', 'helpView'], 'GET', '/help'); -\Chibi\Router::register(['StaticPagesController', 'helpView'], 'GET', '/help/{tab}'); - -\Chibi\Router::register(['AuthController', 'loginView'], 'GET', '/auth/login'); -\Chibi\Router::register(['AuthController', 'loginAction'], 'POST', '/auth/login'); -\Chibi\Router::register(['AuthController', 'logoutAction'], 'POST', '/auth/logout'); -\Chibi\Router::register(['AuthController', 'logoutAction'], 'GET', '/auth/logout'); - -\Chibi\Router::register(['LogController', 'listView'], 'GET', '/logs'); -\Chibi\Router::register(['LogController', 'logView'], 'GET', '/log/{name}', ['name' => '[0-9a-zA-Z._-]+']); -\Chibi\Router::register(['LogController', 'logView'], 'GET', '/log/{name}/{page}', ['name' => '[0-9a-zA-Z._-]+', 'page' => '\d*']); -\Chibi\Router::register(['LogController', 'logView'], 'GET', '/log/{name}/{page}/{filter}', ['name' => '[0-9a-zA-Z._-]+', 'page' => '\d*', 'filter' => '.*']); - -$postValidation = -[ - 'tag' => '[^\/]*', - 'enable' => '0|1', - 'source' => 'posts|mass-tag', - 'query' => '[^\/]*', - 'additionalInfo' => '[^\/]*', - 'score' => '-1|0|1', -]; - -\Chibi\Router::register(['PostController', 'uploadView'], 'GET', '/posts/upload', $postValidation); -\Chibi\Router::register(['PostController', 'uploadAction'], 'POST', '/posts/upload', $postValidation); -\Chibi\Router::register(['PostController', 'editView'], 'GET', '/post/{id}/edit', $postValidation); -\Chibi\Router::register(['PostController', 'editAction'], 'POST', '/post/{id}/edit', $postValidation); -\Chibi\Router::register(['PostController', 'deleteAction'], 'POST', '/post/{id}/delete', $postValidation); - -\Chibi\Router::register(['PostController', 'listView'], 'GET', '/{source}', $postValidation); -\Chibi\Router::register(['PostController', 'listView'], 'GET', '/{source}/{query}', $postValidation); -\Chibi\Router::register(['PostController', 'listView'], 'GET', '/{source}/{query}/{page}', $postValidation); -\Chibi\Router::register(['PostController', 'listView'], 'GET', '/{source}/{additionalInfo}/{query}/{page}', $postValidation); - -\Chibi\Router::register(['PostController', 'randomView'], 'GET', '/random', $postValidation); -\Chibi\Router::register(['PostController', 'randomView'], 'GET', '/random/{page}', $postValidation); -\Chibi\Router::register(['PostController', 'favoritesView'], 'GET', '/favorites', $postValidation); -\Chibi\Router::register(['PostController', 'favoritesView'], 'GET', '/favorites/{page}', $postValidation); -\Chibi\Router::register(['PostController', 'upvotedView'], 'GET', '/upvoted', $postValidation); -\Chibi\Router::register(['PostController', 'upvotedView'], 'GET', '/upvoted/{page}', $postValidation); - -\Chibi\Router::register(['PostController', 'genericView'], 'GET', '/post/{id}', $postValidation); -\Chibi\Router::register(['PostController', 'fileView'], 'GET', '/post/{name}/retrieve', $postValidation); -\Chibi\Router::register(['PostController', 'thumbView'], 'GET', '/post/{name}/thumb', $postValidation); - -\Chibi\Router::register(['PostController', 'toggleTagAction'], 'POST', '/post/{id}/toggle-tag/{tag}/{enable}', $postValidation); -\Chibi\Router::register(['PostController', 'flagAction'], 'POST', '/post/{id}/flag', $postValidation); -\Chibi\Router::register(['PostController', 'hideAction'], 'POST', '/post/{id}/hide', $postValidation); -\Chibi\Router::register(['PostController', 'unhideAction'], 'POST', '/post/{id}/unhide', $postValidation); -\Chibi\Router::register(['PostController', 'removeFavoriteAction'], 'POST', '/post/{id}/rem-fav', $postValidation); -\Chibi\Router::register(['PostController', 'addFavoriteAction'], 'POST', '/post/{id}/add-fav', $postValidation); -\Chibi\Router::register(['PostController', 'scoreAction'], 'POST', '/post/{id}/score/{score}', $postValidation); -\Chibi\Router::register(['PostController', 'featureAction'], 'POST', '/post/{id}/feature', $postValidation); - -$commentValidation = -[ - 'id' => '\d+', - 'page' => '\d+', -]; - -\Chibi\Router::register(['CommentController', 'listView'], 'GET', '/comments', $commentValidation); -\Chibi\Router::register(['CommentController', 'listView'], 'GET', '/comments/{page}', $commentValidation); -\Chibi\Router::register(['CommentController', 'addAction'], 'POST', '/comment/add', $commentValidation); -\Chibi\Router::register(['CommentController', 'deleteAction'], 'POST', '/comment/{id}/delete', $commentValidation); -\Chibi\Router::register(['CommentController', 'editView'], 'GET', '/comment/{id}/edit', $commentValidation); -\Chibi\Router::register(['CommentController', 'editAction'], 'POST', '/comment/{id}/edit', $commentValidation); - -$tagValidation = -[ - 'page' => '\d*', - 'filter' => '[^\/]+', -]; - -\Chibi\Router::register(['TagController', 'listView'], 'GET', '/tags', $tagValidation); -\Chibi\Router::register(['TagController', 'listView'], 'GET', '/tags/{page}', $tagValidation); -\Chibi\Router::register(['TagController', 'listView'], 'GET', '/tags/{filter}/{page}', $tagValidation); -\Chibi\Router::register(['TagController', 'autoCompleteView'], 'GET', '/tags-autocomplete', $tagValidation); -\Chibi\Router::register(['TagController', 'relatedView'], 'GET', '/tags-related', $tagValidation); -\Chibi\Router::register(['TagController', 'renameView'], 'GET', '/tags-rename', $tagValidation); -\Chibi\Router::register(['TagController', 'renameAction'], 'POST', '/tags-rename', $tagValidation); -\Chibi\Router::register(['TagController', 'mergeView'], 'GET', '/tags-merge', $tagValidation); -\Chibi\Router::register(['TagController', 'mergeAction'], 'POST', '/tags-merge', $tagValidation); - -$userValidation = -[ - 'name' => '[^\/]+', - 'page' => '\d*', - 'tab' => 'favs|uploads|settings|edit|delete', - 'filter' => '[^\/]+', -]; - -\Chibi\Router::register(['UserController', 'listView'], 'GET', '/users', $userValidation); -\Chibi\Router::register(['UserController', 'listView'], 'GET', '/users/{page}', $userValidation); -\Chibi\Router::register(['UserController', 'listView'], 'GET', '/users/{filter}/{page}', $userValidation); -\Chibi\Router::register(['UserController', 'genericView'], 'GET', '/user/{name}/{tab}', $userValidation); -\Chibi\Router::register(['UserController', 'genericView'], 'GET', '/user/{name}/{tab}/{page}', $userValidation); - -\Chibi\Router::register(['UserController', 'registrationView'], 'GET', '/register', $userValidation); -\Chibi\Router::register(['UserController', 'registrationAction'], 'POST', '/register', $userValidation); - -\Chibi\Router::register(['UserController', 'activationView'], 'GET', '/activation', $userValidation); -\Chibi\Router::register(['UserController', 'activationAction'], 'POST', '/activation', $userValidation); -\Chibi\Router::register(['UserController', 'activationAction'], 'GET', '/activation/{tokenText}', $userValidation); -\Chibi\Router::register(['UserController', 'passwordResetView'], 'GET', '/password-reset', $userValidation); -\Chibi\Router::register(['UserController', 'passwordResetAction'], 'POST', '/password-reset', $userValidation); -\Chibi\Router::register(['UserController', 'passwordResetAction'], 'GET', '/password-reset/{tokenText}', $userValidation); - -\Chibi\Router::register(['UserController', 'flagAction'], 'POST', '/user/{name}/flag', $userValidation); -\Chibi\Router::register(['UserController', 'banAction'], 'POST', '/user/{name}/ban', $userValidation); -\Chibi\Router::register(['UserController', 'unbanAction'], 'POST', '/user/{name}/unban', $userValidation); -\Chibi\Router::register(['UserController', 'acceptRegistrationAction'], 'POST', '/user/{name}/accept-registration', $userValidation); -\Chibi\Router::register(['UserController', 'deleteAction'], 'POST', '/user/{name}/delete', $userValidation); -\Chibi\Router::register(['UserController', 'settingsAction'], 'POST', '/user/{name}/settings', $userValidation); -\Chibi\Router::register(['UserController', 'editAction'], 'POST', '/user/{name}/edit', $userValidation); - -foreach (['GET', 'POST'] as $method) -{ - \Chibi\Router::register(['TagController', 'massTagRedirectAction'], $method, '/mass-tag-redirect', $tagValidation); - - \Chibi\Router::register(['UserController', 'toggleSafetyAction'], $method, '/user/toggle-safety/{safety}', $userValidation); -} - Assets::setTitle($config->main->title); $context->handleExceptions = false; diff --git a/src/Api/Jobs/ActivateUserEmailJob.php b/src/Api/Jobs/ActivateUserEmailJob.php index 250fbb16..313a3a35 100644 --- a/src/Api/Jobs/ActivateUserEmailJob.php +++ b/src/Api/Jobs/ActivateUserEmailJob.php @@ -29,7 +29,7 @@ class ActivateUserEmailJob extends AbstractJob $user = $token->getUser(); $user->confirmEmail(); - $token->used = true; + $token->setUsed(true); TokenModel::save($token); UserModel::save($user); diff --git a/src/Mail.php b/src/Mail.php index 503ffee7..ec4c9e4e 100644 --- a/src/Mail.php +++ b/src/Mail.php @@ -6,4 +6,6 @@ class Mail public $senderName; public $senderEmail; public $recipientEmail; + + public $tokens; } diff --git a/src/Mailer.php b/src/Mailer.php index 4b75af04..244e6771 100644 --- a/src/Mailer.php +++ b/src/Mailer.php @@ -1,12 +1,14 @@ tokens = $tokens; + self::$mailsSent []= $mail; self::$mailCounter ++; Logger::log('Sending e-mail with subject "{subject}" to {mail}', [ @@ -79,13 +88,13 @@ class Mailer //prepare unique user token $token = TokenModel::spawn(); $token->setUser($user); - $token->token = TokenModel::forgeUnusedToken(); - $token->used = false; - $token->expires = null; + $token->setText(TokenModel::forgeUnusedToken()); + $token->setUsed(false); + $token->setExpirationDate(null); TokenModel::save($token); - if (!self::$mock) - $tokens['link'] = \Chibi\Router::linkTo($linkDestination, ['token' => $token->token]); + $tokens['link'] = \Chibi\Router::linkTo($linkDestination, ['tokenText' => $token->getText()]); + $tokens['token'] = $token->getText(); //yeah return self::sendMail($mail, $tokens); } diff --git a/src/Models/Entities/TokenEntity.php b/src/Models/Entities/TokenEntity.php index 01dac09c..f0f6a899 100644 --- a/src/Models/Entities/TokenEntity.php +++ b/src/Models/Entities/TokenEntity.php @@ -1,21 +1,56 @@ token; + } + + public function setText($tokenText) + { + $this->token = $tokenText; + } + + public function isUsed() + { + return $this->used; + } + + public function setUsed($used) + { + $this->used = $used; + } + + public function getExpirationDate() + { + return $this->expires; + } + + public function setExpirationDate($time) + { + $this->expires = $time; + } + public function getUser() { return UserModel::findById($this->userId); } + public function getUserId() + { + return $this->userId; + } + public function setUser($user) { $this->userId = $user ? $user->getId() : null; diff --git a/src/Models/TokenModel.php b/src/Models/TokenModel.php index faafcc42..18577b33 100644 --- a/src/Models/TokenModel.php +++ b/src/Models/TokenModel.php @@ -18,10 +18,10 @@ class TokenModel extends AbstractCrudModel self::forgeId($token); $bindings = [ - 'user_id' => $token->userId, - 'token' => $token->token, - 'used' => $token->used, - 'expires' => $token->expires, + 'user_id' => $token->getUserId(), + 'token' => $token->getText(), + 'used' => $token->isUsed(), + 'expires' => $token->getExpirationDate(), ]; $stmt = new Sql\UpdateStatement(); @@ -61,10 +61,10 @@ class TokenModel extends AbstractCrudModel if (empty($token)) throw new SimpleException('Invalid security token'); - if ($token->used) + if ($token->isUsed()) throw new SimpleException('This token was already used'); - if ($token->expires !== null and time() > $token->expires) + if ($token->getExpirationDate() !== null and time() > $token->getExpirationDate()) throw new SimpleException('This token has expired'); } diff --git a/src/Models/UserModel.php b/src/Models/UserModel.php index e079a464..1005669e 100644 --- a/src/Models/UserModel.php +++ b/src/Models/UserModel.php @@ -120,12 +120,15 @@ class UserModel extends AbstractCrudModel public static function findByNameOrEmail($key, $throw = true) { + $key = trim($key); + $stmt = new Sql\SelectStatement(); $stmt->setColumn('*'); $stmt->setTable('user'); $stmt->setCriterion((new Sql\DisjunctionFunctor) - ->add(new Sql\NoCaseFunctor(new Sql\EqualsFunctor('name', new Sql\Binding(trim($key))))) - ->add(new Sql\NoCaseFunctor(new Sql\EqualsFunctor('email_confirmed', new Sql\Binding(trim($key)))))); + ->add(new Sql\NoCaseFunctor(new Sql\EqualsFunctor('name', new Sql\Binding($key)))) + ->add(new Sql\NoCaseFunctor(new Sql\EqualsFunctor('email_unconfirmed', new Sql\Binding($key)))) + ->add(new Sql\NoCaseFunctor(new Sql\EqualsFunctor('email_confirmed', new Sql\Binding($key))))); $row = Database::fetchOne($stmt); if ($row) diff --git a/src/core.php b/src/core.php index 186fc1f9..5f80fee6 100644 --- a/src/core.php +++ b/src/core.php @@ -20,6 +20,8 @@ require_once $rootDir . 'lib' . DS . 'chibi-core' . DS . 'include.php'; \Chibi\AutoLoader::registerFilesystem($rootDir . 'lib' . DS . 'chibi-sql'); \Chibi\AutoLoader::registerFilesystem(__DIR__); +require_once $rootDir . 'src' . DS . 'routes.php'; + function getConfig() { global $config; diff --git a/src/routes.php b/src/routes.php new file mode 100644 index 00000000..4e442986 --- /dev/null +++ b/src/routes.php @@ -0,0 +1,119 @@ + '[0-9a-zA-Z._-]+']); +\Chibi\Router::register(['LogController', 'logView'], 'GET', '/log/{name}/{page}', ['name' => '[0-9a-zA-Z._-]+', 'page' => '\d*']); +\Chibi\Router::register(['LogController', 'logView'], 'GET', '/log/{name}/{page}/{filter}', ['name' => '[0-9a-zA-Z._-]+', 'page' => '\d*', 'filter' => '.*']); + +$postValidation = +[ + 'tag' => '[^\/]*', + 'enable' => '0|1', + 'source' => 'posts|mass-tag', + 'query' => '[^\/]*', + 'additionalInfo' => '[^\/]*', + 'score' => '-1|0|1', +]; + +\Chibi\Router::register(['PostController', 'uploadView'], 'GET', '/posts/upload', $postValidation); +\Chibi\Router::register(['PostController', 'uploadAction'], 'POST', '/posts/upload', $postValidation); +\Chibi\Router::register(['PostController', 'editView'], 'GET', '/post/{id}/edit', $postValidation); +\Chibi\Router::register(['PostController', 'editAction'], 'POST', '/post/{id}/edit', $postValidation); +\Chibi\Router::register(['PostController', 'deleteAction'], 'POST', '/post/{id}/delete', $postValidation); + +\Chibi\Router::register(['PostController', 'listView'], 'GET', '/{source}', $postValidation); +\Chibi\Router::register(['PostController', 'listView'], 'GET', '/{source}/{query}', $postValidation); +\Chibi\Router::register(['PostController', 'listView'], 'GET', '/{source}/{query}/{page}', $postValidation); +\Chibi\Router::register(['PostController', 'listView'], 'GET', '/{source}/{additionalInfo}/{query}/{page}', $postValidation); + +\Chibi\Router::register(['PostController', 'randomView'], 'GET', '/random', $postValidation); +\Chibi\Router::register(['PostController', 'randomView'], 'GET', '/random/{page}', $postValidation); +\Chibi\Router::register(['PostController', 'favoritesView'], 'GET', '/favorites', $postValidation); +\Chibi\Router::register(['PostController', 'favoritesView'], 'GET', '/favorites/{page}', $postValidation); +\Chibi\Router::register(['PostController', 'upvotedView'], 'GET', '/upvoted', $postValidation); +\Chibi\Router::register(['PostController', 'upvotedView'], 'GET', '/upvoted/{page}', $postValidation); + +\Chibi\Router::register(['PostController', 'genericView'], 'GET', '/post/{id}', $postValidation); +\Chibi\Router::register(['PostController', 'fileView'], 'GET', '/post/{name}/retrieve', $postValidation); +\Chibi\Router::register(['PostController', 'thumbView'], 'GET', '/post/{name}/thumb', $postValidation); + +\Chibi\Router::register(['PostController', 'toggleTagAction'], 'POST', '/post/{id}/toggle-tag/{tag}/{enable}', $postValidation); +\Chibi\Router::register(['PostController', 'flagAction'], 'POST', '/post/{id}/flag', $postValidation); +\Chibi\Router::register(['PostController', 'hideAction'], 'POST', '/post/{id}/hide', $postValidation); +\Chibi\Router::register(['PostController', 'unhideAction'], 'POST', '/post/{id}/unhide', $postValidation); +\Chibi\Router::register(['PostController', 'removeFavoriteAction'], 'POST', '/post/{id}/rem-fav', $postValidation); +\Chibi\Router::register(['PostController', 'addFavoriteAction'], 'POST', '/post/{id}/add-fav', $postValidation); +\Chibi\Router::register(['PostController', 'scoreAction'], 'POST', '/post/{id}/score/{score}', $postValidation); +\Chibi\Router::register(['PostController', 'featureAction'], 'POST', '/post/{id}/feature', $postValidation); + +$commentValidation = +[ + 'id' => '\d+', + 'page' => '\d+', +]; + +\Chibi\Router::register(['CommentController', 'listView'], 'GET', '/comments', $commentValidation); +\Chibi\Router::register(['CommentController', 'listView'], 'GET', '/comments/{page}', $commentValidation); +\Chibi\Router::register(['CommentController', 'addAction'], 'POST', '/comment/add', $commentValidation); +\Chibi\Router::register(['CommentController', 'deleteAction'], 'POST', '/comment/{id}/delete', $commentValidation); +\Chibi\Router::register(['CommentController', 'editView'], 'GET', '/comment/{id}/edit', $commentValidation); +\Chibi\Router::register(['CommentController', 'editAction'], 'POST', '/comment/{id}/edit', $commentValidation); + +$tagValidation = +[ + 'page' => '\d*', + 'filter' => '[^\/]+', +]; + +\Chibi\Router::register(['TagController', 'listView'], 'GET', '/tags', $tagValidation); +\Chibi\Router::register(['TagController', 'listView'], 'GET', '/tags/{page}', $tagValidation); +\Chibi\Router::register(['TagController', 'listView'], 'GET', '/tags/{filter}/{page}', $tagValidation); +\Chibi\Router::register(['TagController', 'autoCompleteView'], 'GET', '/tags-autocomplete', $tagValidation); +\Chibi\Router::register(['TagController', 'relatedView'], 'GET', '/tags-related', $tagValidation); +\Chibi\Router::register(['TagController', 'renameView'], 'GET', '/tags-rename', $tagValidation); +\Chibi\Router::register(['TagController', 'renameAction'], 'POST', '/tags-rename', $tagValidation); +\Chibi\Router::register(['TagController', 'mergeView'], 'GET', '/tags-merge', $tagValidation); +\Chibi\Router::register(['TagController', 'mergeAction'], 'POST', '/tags-merge', $tagValidation); +\Chibi\Router::register(['TagController', 'massTagRedirectAction'], 'GET', '/mass-tag-redirect', $tagValidation); + +$userValidation = +[ + 'name' => '[^\/]+', + 'page' => '\d*', + 'tab' => 'favs|uploads|settings|edit|delete', + 'filter' => '[^\/]+', +]; + +\Chibi\Router::register(['UserController', 'listView'], 'GET', '/users', $userValidation); +\Chibi\Router::register(['UserController', 'listView'], 'GET', '/users/{page}', $userValidation); +\Chibi\Router::register(['UserController', 'listView'], 'GET', '/users/{filter}/{page}', $userValidation); +\Chibi\Router::register(['UserController', 'genericView'], 'GET', '/user/{name}/{tab}', $userValidation); +\Chibi\Router::register(['UserController', 'genericView'], 'GET', '/user/{name}/{tab}/{page}', $userValidation); + +\Chibi\Router::register(['UserController', 'registrationView'], 'GET', '/register', $userValidation); +\Chibi\Router::register(['UserController', 'registrationAction'], 'POST', '/register', $userValidation); + +\Chibi\Router::register(['UserController', 'activationView'], 'GET', '/activation', $userValidation); +\Chibi\Router::register(['UserController', 'activationAction'], 'POST', '/activation', $userValidation); +\Chibi\Router::register(['UserController', 'activationAction'], 'GET', '/activation/{tokenText}', $userValidation); +\Chibi\Router::register(['UserController', 'passwordResetView'], 'GET', '/password-reset', $userValidation); +\Chibi\Router::register(['UserController', 'passwordResetAction'], 'POST', '/password-reset', $userValidation); +\Chibi\Router::register(['UserController', 'passwordResetAction'], 'GET', '/password-reset/{tokenText}', $userValidation); + +\Chibi\Router::register(['UserController', 'flagAction'], 'POST', '/user/{name}/flag', $userValidation); +\Chibi\Router::register(['UserController', 'banAction'], 'POST', '/user/{name}/ban', $userValidation); +\Chibi\Router::register(['UserController', 'unbanAction'], 'POST', '/user/{name}/unban', $userValidation); +\Chibi\Router::register(['UserController', 'acceptRegistrationAction'], 'POST', '/user/{name}/accept-registration', $userValidation); +\Chibi\Router::register(['UserController', 'deleteAction'], 'POST', '/user/{name}/delete', $userValidation); +\Chibi\Router::register(['UserController', 'settingsAction'], 'POST', '/user/{name}/settings', $userValidation); +\Chibi\Router::register(['UserController', 'editAction'], 'POST', '/user/{name}/edit', $userValidation); +\Chibi\Router::register(['UserController', 'toggleSafetyAction'], 'POST', '/user/toggle-safety/{safety}', $userValidation); diff --git a/tests/JobTests/ActivateUserEmailJobTest.php b/tests/JobTests/ActivateUserEmailJobTest.php new file mode 100644 index 00000000..a326f59c --- /dev/null +++ b/tests/JobTests/ActivateUserEmailJobTest.php @@ -0,0 +1,149 @@ +registration->needEmailForRegistering = true; + Mailer::mockSending(); + + $user = $this->mockUser(); + $user->setUnconfirmedEmail('godzilla@whitestar.gov'); + UserModel::save($user); + + $this->assert->areEqual(0, Mailer::getMailCounter()); + + $this->assert->doesNotThrow(function() use ($user) + { + Api::run( + new ActivateUserEmailJob(), + [ + ActivateUserEmailJob::USER_NAME => $user->getName(), + ]); + }); + + $this->assert->areEqual(1, Mailer::getMailCounter()); + + $tokens = Mailer::getMailsSent()[0]->tokens; + $tokenText = $tokens['token']; + $token = TokenModel::findByToken($tokenText); + + $this->assert->areEqual($user->getId(), $token->getUser()->getId()); + $this->assert->isTrue(strpos($tokens['link'], $tokenText) !== false); + + return $tokenText; + } + + public function testConfirming() + { + getConfig()->registration->needEmailForRegistering = true; + Mailer::mockSending(); + + $user = $this->mockUser(); + $user->setUnconfirmedEmail('godzilla@whitestar.gov'); + UserModel::save($user); + + $this->assert->areEqual('godzilla@whitestar.gov', $user->getUnconfirmedEmail()); + $this->assert->areEqual(null, $user->getConfirmedEmail()); + + $this->assert->doesNotThrow(function() use ($user) + { + Api::run( + new ActivateUserEmailJob(), + [ + ActivateUserEmailJob::USER_NAME => $user->getName(), + ]); + }); + + $tokenText = Mailer::getMailsSent()[0]->tokens['token']; + + $this->assert->doesNotThrow(function() use ($tokenText) + { + Api::run( + new ActivateUserEmailJob(), + [ + ActivateUserEmailJob::TOKEN => $tokenText, + ]); + }); + + //reload local entity after changes done by the job + $user = UserModel::findById($user->getId()); + + $this->assert->areEqual(null, $user->getUnconfirmedEmail()); + $this->assert->areEqual('godzilla@whitestar.gov', $user->getConfirmedEmail()); + } + + + public function testUsingTokenTwice() + { + getConfig()->registration->needEmailForRegistering = true; + Mailer::mockSending(); + + $user = $this->mockUser(); + $user->setUnconfirmedEmail('godzilla@whitestar.gov'); + UserModel::save($user); + + $this->assert->areEqual('godzilla@whitestar.gov', $user->getUnconfirmedEmail()); + $this->assert->areEqual(null, $user->getConfirmedEmail()); + + Api::run( + new ActivateUserEmailJob(), + [ + ActivateUserEmailJob::USER_NAME => $user->getName(), + ]); + + $tokenText = Mailer::getMailsSent()[0]->tokens['token']; + + Api::run( + new ActivateUserEmailJob(), + [ + ActivateUserEmailJob::TOKEN => $tokenText, + ]); + + $this->assert->throws(function() use ($tokenText) + { + Api::run( + new ActivateUserEmailJob(), + [ + ActivateUserEmailJob::TOKEN => $tokenText, + ]); + }, 'This token was already used'); + } + + public function testTokensTwoUsersSameMail() + { + getConfig()->registration->needEmailForRegistering = true; + Mailer::mockSending(); + + $user1 = $this->mockUser(); + $user2 = $this->mockUser(); + $user1->setUnconfirmedEmail('godzilla@whitestar.gov'); + $user2->setUnconfirmedEmail('godzilla@whitestar.gov'); + UserModel::save($user1); + UserModel::save($user2); + + Api::run( + new ActivateUserEmailJob(), + [ + ActivateUserEmailJob::USER_NAME => $user1->getName(), + ]); + + Api::run( + new ActivateUserEmailJob(), + [ + ActivateUserEmailJob::USER_NAME => $user2->getName(), + ]); + + $tokens1 = Mailer::getMailsSent()[0]->tokens; + $tokens2 = Mailer::getMailsSent()[1]->tokens; + $token1text = $tokens1['token']; + $token2text = $tokens2['token']; + $this->assert->areNotEqual($token1text, $token2text); + + $token1 = TokenModel::findByToken($token1text); + $token2 = TokenModel::findByToken($token2text); + + $this->assert->areEqual($user1->getId(), $token1->getUser()->getId()); + $this->assert->areEqual($user2->getId(), $token2->getUser()->getId()); + $this->assert->areNotEqual($token1->getUserId(), $token2->getUserId()); + } +} diff --git a/tests/JobTests/AddUserJobTest.php b/tests/JobTests/AddUserJobTest.php index 41bd9307..97d49f83 100644 --- a/tests/JobTests/AddUserJobTest.php +++ b/tests/JobTests/AddUserJobTest.php @@ -263,6 +263,48 @@ class AddUserJobTest extends AbstractTest $this->assert->areEqual(0, Mailer::getMailCounter()); } + public function testEmailsTwoUsersSameMail() + { + getConfig()->registration->needEmailForRegistering = true; + Mailer::mockSending(); + $this->assert->areEqual(0, Mailer::getMailCounter()); + + $this->grantAccess('registerAccount'); + + $user1 = $this->assert->doesNotThrow(function() + { + return Api::run( + new AddUserJob(), + [ + EditUserNameJob::NEW_USER_NAME => 'dummy', + EditUserPasswordJob::NEW_PASSWORD => 'sekai', + EditUserEmailJob::NEW_EMAIL => 'godzilla@whitestar.gov', + ]); + }); + + $user2 = $this->assert->doesNotThrow(function() + { + return Api::run( + new AddUserJob(), + [ + EditUserNameJob::NEW_USER_NAME => 'dummy2', + EditUserPasswordJob::NEW_PASSWORD => 'sekai', + EditUserEmailJob::NEW_EMAIL => 'godzilla@whitestar.gov', + ]); + }); + + $this->assert->areEqual(2, Mailer::getMailCounter()); + $token1text = Mailer::getMailsSent()[0]->tokens['token']; + $token2text = Mailer::getMailsSent()[1]->tokens['token']; + $this->assert->areNotEqual($token1text, $token2text); + + $token1 = TokenModel::findByToken($token1text); + $token2 = TokenModel::findByToken($token2text); + + $this->assert->areEqual($user1->getId(), $token1->getUser()->getId()); + $this->assert->areEqual($user2->getId(), $token2->getUser()->getId()); + } + public function testLogBuffering() { $this->testSaving();