Added transaction manager
This commit is contained in:
parent
f71fd106f0
commit
6035cf89b7
8 changed files with 324 additions and 126 deletions
42
src/Dao/TransactionManager.php
Normal file
42
src/Dao/TransactionManager.php
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Dao;
|
||||||
|
|
||||||
|
class TransactionManager
|
||||||
|
{
|
||||||
|
private $databaseConnection;
|
||||||
|
|
||||||
|
public function __construct(\Szurubooru\DatabaseConnection $databaseConnection)
|
||||||
|
{
|
||||||
|
$this->databaseConnection = $databaseConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function commit($callback)
|
||||||
|
{
|
||||||
|
return $this->doInTransaction($callback, 'commit');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rollback($callback)
|
||||||
|
{
|
||||||
|
return $this->doInTransaction($callback, 'rollBack');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function doInTransaction($callback, $operation)
|
||||||
|
{
|
||||||
|
$pdo = $this->databaseConnection->getPDO();
|
||||||
|
if ($pdo->inTransaction())
|
||||||
|
return $callback();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
$ret = $callback();
|
||||||
|
$pdo->$operation();
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
catch (\Exception $e)
|
||||||
|
{
|
||||||
|
$pdo->rollBack();
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Szurubooru;
|
namespace Szurubooru;
|
||||||
|
|
||||||
final class DatabaseConnection
|
class DatabaseConnection
|
||||||
{
|
{
|
||||||
private $pdo;
|
private $pdo;
|
||||||
private $config;
|
private $config;
|
||||||
|
|
|
@ -3,39 +3,55 @@ namespace Szurubooru\Services;
|
||||||
|
|
||||||
class TokenService
|
class TokenService
|
||||||
{
|
{
|
||||||
|
private $transactionManager;
|
||||||
private $tokenDao;
|
private $tokenDao;
|
||||||
|
|
||||||
public function __construct(\Szurubooru\Dao\TokenDao $tokenDao)
|
public function __construct(
|
||||||
|
\Szurubooru\Dao\TransactionManager $transactionManager,
|
||||||
|
\Szurubooru\Dao\TokenDao $tokenDao)
|
||||||
{
|
{
|
||||||
|
$this->transactionManager = $transactionManager;
|
||||||
$this->tokenDao = $tokenDao;
|
$this->tokenDao = $tokenDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getByName($tokenName)
|
public function getByName($tokenName)
|
||||||
{
|
{
|
||||||
$token = $this->tokenDao->findByName($tokenName);
|
return $this->transactionManager->rollback(function() use ($tokenName)
|
||||||
if (!$token)
|
{
|
||||||
throw new \InvalidArgumentException('Token with identifier "' . $tokenName . '" not found.');
|
$token = $this->tokenDao->findByName($tokenName);
|
||||||
return $token;
|
if (!$token)
|
||||||
|
throw new \InvalidArgumentException('Token with identifier "' . $tokenName . '" not found.');
|
||||||
|
return $token;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function invalidateByName($tokenName)
|
public function invalidateByName($tokenName)
|
||||||
{
|
{
|
||||||
return $this->tokenDao->deleteByName($tokenName);
|
$this->transactionManager->commit(function() use ($tokenName)
|
||||||
|
{
|
||||||
|
$this->tokenDao->deleteByName($tokenName);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function invalidateByAdditionalData($additionalData)
|
public function invalidateByAdditionalData($additionalData)
|
||||||
{
|
{
|
||||||
return $this->tokenDao->deleteByAdditionalData($additionalData);
|
$this->transactionManager->commit(function() use ($additionalData)
|
||||||
|
{
|
||||||
|
$this->tokenDao->deleteByAdditionalData($additionalData);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createAndSaveToken($additionalData, $tokenPurpose)
|
public function createAndSaveToken($additionalData, $tokenPurpose)
|
||||||
{
|
{
|
||||||
$token = new \Szurubooru\Entities\Token();
|
return $this->transactionManager->commit(function() use ($additionalData, $tokenPurpose)
|
||||||
$token->setName(sha1(date('r') . uniqid() . microtime(true)));
|
{
|
||||||
$token->setAdditionalData($additionalData);
|
$token = new \Szurubooru\Entities\Token();
|
||||||
$token->setPurpose($tokenPurpose);
|
$token->setName(sha1(date('r') . uniqid() . microtime(true)));
|
||||||
$this->invalidateByAdditionalData($additionalData);
|
$token->setAdditionalData($additionalData);
|
||||||
$this->tokenDao->save($token);
|
$token->setPurpose($tokenPurpose);
|
||||||
return $token;
|
$this->invalidateByAdditionalData($additionalData);
|
||||||
|
$this->tokenDao->save($token);
|
||||||
|
return $token;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ class UserService
|
||||||
{
|
{
|
||||||
private $config;
|
private $config;
|
||||||
private $validator;
|
private $validator;
|
||||||
|
private $transactionManager;
|
||||||
private $userDao;
|
private $userDao;
|
||||||
private $userSearchService;
|
private $userSearchService;
|
||||||
private $passwordService;
|
private $passwordService;
|
||||||
|
@ -17,6 +18,7 @@ class UserService
|
||||||
public function __construct(
|
public function __construct(
|
||||||
\Szurubooru\Config $config,
|
\Szurubooru\Config $config,
|
||||||
\Szurubooru\Validator $validator,
|
\Szurubooru\Validator $validator,
|
||||||
|
\Szurubooru\Dao\TransactionManager $transactionManager,
|
||||||
\Szurubooru\Dao\UserDao $userDao,
|
\Szurubooru\Dao\UserDao $userDao,
|
||||||
\Szurubooru\Dao\Services\UserSearchService $userSearchService,
|
\Szurubooru\Dao\Services\UserSearchService $userSearchService,
|
||||||
\Szurubooru\Services\PasswordService $passwordService,
|
\Szurubooru\Services\PasswordService $passwordService,
|
||||||
|
@ -28,6 +30,7 @@ class UserService
|
||||||
{
|
{
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->validator = $validator;
|
$this->validator = $validator;
|
||||||
|
$this->transactionManager = $transactionManager;
|
||||||
$this->userDao = $userDao;
|
$this->userDao = $userDao;
|
||||||
$this->userSearchService = $userSearchService;
|
$this->userSearchService = $userSearchService;
|
||||||
$this->passwordService = $passwordService;
|
$this->passwordService = $passwordService;
|
||||||
|
@ -40,110 +43,198 @@ class UserService
|
||||||
|
|
||||||
public function getByNameOrEmail($userNameOrEmail, $allowUnconfirmed = false)
|
public function getByNameOrEmail($userNameOrEmail, $allowUnconfirmed = false)
|
||||||
{
|
{
|
||||||
$user = $this->userDao->findByName($userNameOrEmail);
|
return $this->transactionManager->rollback(function() use ($userNameOrEmail, $allowUnconfirmed)
|
||||||
if ($user)
|
{
|
||||||
return $user;
|
$user = $this->userDao->findByName($userNameOrEmail);
|
||||||
|
if ($user)
|
||||||
|
return $user;
|
||||||
|
|
||||||
$user = $this->userDao->findByEmail($userNameOrEmail, $allowUnconfirmed);
|
$user = $this->userDao->findByEmail($userNameOrEmail, $allowUnconfirmed);
|
||||||
if ($user)
|
if ($user)
|
||||||
return $user;
|
return $user;
|
||||||
|
|
||||||
throw new \InvalidArgumentException('User "' . $userNameOrEmail . '" was not found.');
|
throw new \InvalidArgumentException('User "' . $userNameOrEmail . '" was not found.');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getByName($userName)
|
public function getByName($userName)
|
||||||
{
|
{
|
||||||
$user = $this->userDao->findByName($userName);
|
return $this->transactionManager->rollback(function() use ($userName)
|
||||||
if (!$user)
|
{
|
||||||
throw new \InvalidArgumentException('User with name "' . $userName . '" was not found.');
|
$user = $this->userDao->findByName($userName);
|
||||||
return $user;
|
if (!$user)
|
||||||
|
throw new \InvalidArgumentException('User with name "' . $userName . '" was not found.');
|
||||||
|
return $user;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getById($userId)
|
public function getById($userId)
|
||||||
{
|
{
|
||||||
$user = $this->userDao->findById($userId);
|
return $this->transactionManager->rollback(function() use ($userId)
|
||||||
if (!$user)
|
{
|
||||||
throw new \InvalidArgumentException('User with id "' . $userId . '" was not found.');
|
$user = $this->userDao->findById($userId);
|
||||||
return $user;
|
if (!$user)
|
||||||
|
throw new \InvalidArgumentException('User with id "' . $userId . '" was not found.');
|
||||||
|
return $user;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFiltered(\Szurubooru\FormData\SearchFormData $formData)
|
public function getFiltered(\Szurubooru\FormData\SearchFormData $formData)
|
||||||
{
|
{
|
||||||
$this->validator->validate($formData);
|
return $this->transactionManager->rollback(function() use ($formData)
|
||||||
$searchFilter = new \Szurubooru\Dao\SearchFilter($this->config->users->usersPerPage, $formData);
|
{
|
||||||
return $this->userSearchService->getFiltered($searchFilter);
|
$this->validator->validate($formData);
|
||||||
|
$searchFilter = new \Szurubooru\Dao\SearchFilter($this->config->users->usersPerPage, $formData);
|
||||||
|
return $this->userSearchService->getFiltered($searchFilter);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createUser(\Szurubooru\FormData\RegistrationFormData $formData)
|
public function createUser(\Szurubooru\FormData\RegistrationFormData $formData)
|
||||||
{
|
{
|
||||||
$formData->validate($this->validator);
|
return $this->transactionManager->commit(function() use ($formData)
|
||||||
|
{
|
||||||
|
$formData->validate($this->validator);
|
||||||
|
|
||||||
$user = new \Szurubooru\Entities\User();
|
$user = new \Szurubooru\Entities\User();
|
||||||
$user->setRegistrationTime($this->timeService->getCurrentTime());
|
$user->setRegistrationTime($this->timeService->getCurrentTime());
|
||||||
$user->setLastLoginTime(null);
|
$user->setLastLoginTime(null);
|
||||||
$user->setAccessRank($this->userDao->hasAnyUsers()
|
$user->setAccessRank($this->userDao->hasAnyUsers()
|
||||||
? \Szurubooru\Entities\User::ACCESS_RANK_REGULAR_USER
|
? \Szurubooru\Entities\User::ACCESS_RANK_REGULAR_USER
|
||||||
: \Szurubooru\Entities\User::ACCESS_RANK_ADMINISTRATOR);
|
: \Szurubooru\Entities\User::ACCESS_RANK_ADMINISTRATOR);
|
||||||
|
|
||||||
$this->updateUserName($user, $formData->userName);
|
$this->updateUserName($user, $formData->userName);
|
||||||
$this->updateUserPassword($user, $formData->password);
|
$this->updateUserPassword($user, $formData->password);
|
||||||
$this->updateUserAvatarStyle($user, \Szurubooru\Entities\User::AVATAR_STYLE_GRAVATAR);
|
$this->updateUserAvatarStyle($user, \Szurubooru\Entities\User::AVATAR_STYLE_GRAVATAR);
|
||||||
$this->updateUserEmail($user, $formData->email);
|
$this->updateUserEmail($user, $formData->email);
|
||||||
return $this->userDao->save($user);
|
return $this->userDao->save($user);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateUser(\Szurubooru\Entities\User $user, \Szurubooru\FormData\UserEditFormData $formData)
|
public function updateUser(\Szurubooru\Entities\User $user, \Szurubooru\FormData\UserEditFormData $formData)
|
||||||
{
|
{
|
||||||
$this->validator->validate($formData);
|
return $this->transactionManager->commit(function() use ($user, $formData)
|
||||||
|
{
|
||||||
|
$this->validator->validate($formData);
|
||||||
|
|
||||||
if ($formData->avatarStyle !== null)
|
if ($formData->avatarStyle !== null)
|
||||||
$this->updateUserAvatarStyle($user, $formData->avatarStyle);
|
$this->updateUserAvatarStyle($user, $formData->avatarStyle);
|
||||||
|
|
||||||
if ($formData->avatarContent !== null)
|
if ($formData->avatarContent !== null)
|
||||||
$this->updateUserAvatarContent($user, $formData->avatarContent);
|
$this->updateUserAvatarContent($user, $formData->avatarContent);
|
||||||
|
|
||||||
if ($formData->userName !== null)
|
if ($formData->userName !== null)
|
||||||
$this->updateUserName($user, $formData->userName);
|
$this->updateUserName($user, $formData->userName);
|
||||||
|
|
||||||
if ($formData->password !== null)
|
if ($formData->password !== null)
|
||||||
$this->updateUserPassword($user, $formData->password);
|
$this->updateUserPassword($user, $formData->password);
|
||||||
|
|
||||||
if ($formData->email !== null)
|
if ($formData->email !== null)
|
||||||
$this->updateUserEmail($user, $formData->email);
|
$this->updateUserEmail($user, $formData->email);
|
||||||
|
|
||||||
if ($formData->accessRank !== null)
|
if ($formData->accessRank !== null)
|
||||||
$this->updateUserAccessRank($user, $formData->accessRank);
|
$this->updateUserAccessRank($user, $formData->accessRank);
|
||||||
|
|
||||||
if ($formData->browsingSettings !== null)
|
if ($formData->browsingSettings !== null)
|
||||||
$this->updateUserBrowsingSettings($user, $formData->browsingSettings);
|
$this->updateUserBrowsingSettings($user, $formData->browsingSettings);
|
||||||
|
|
||||||
return $this->userDao->save($user);
|
return $this->userDao->save($user);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateUserAvatarStyle(\Szurubooru\Entities\User $user, $newAvatarStyle)
|
public function deleteUser(\Szurubooru\Entities\User $user)
|
||||||
|
{
|
||||||
|
$this->transactionManager->commit(function() use ($user)
|
||||||
|
{
|
||||||
|
$this->userDao->deleteById($user->getId());
|
||||||
|
|
||||||
|
$avatarSource = $this->getCustomAvatarSourcePath($user);
|
||||||
|
$this->fileService->delete($avatarSource);
|
||||||
|
$this->thumbnailService->deleteUsedThumbnails($avatarSource);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendPasswordResetEmail(\Szurubooru\Entities\User $user)
|
||||||
|
{
|
||||||
|
$this->transactionManager->commit(function() use ($user)
|
||||||
|
{
|
||||||
|
$token = $this->tokenService->createAndSaveToken($user->getName(), \Szurubooru\Entities\Token::PURPOSE_PASSWORD_RESET);
|
||||||
|
$this->emailService->sendPasswordResetEmail($user, $token);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function finishPasswordReset(\Szurubooru\Entities\Token $token)
|
||||||
|
{
|
||||||
|
return $this->transactionManager->commit(function() use ($token)
|
||||||
|
{
|
||||||
|
if ($token->getPurpose() !== \Szurubooru\Entities\Token::PURPOSE_PASSWORD_RESET)
|
||||||
|
throw new \Exception('This token is not a password reset token.');
|
||||||
|
|
||||||
|
$user = $this->getByName($token->getAdditionalData());
|
||||||
|
$newPassword = $this->passwordService->getRandomPassword();
|
||||||
|
$user->setPasswordHash($this->passwordService->getHash($newPassword));
|
||||||
|
$this->userDao->save($user);
|
||||||
|
$this->tokenService->invalidateByName($token->getName());
|
||||||
|
return $newPassword;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sendActivationEmail(\Szurubooru\Entities\User $user)
|
||||||
|
{
|
||||||
|
$this->transactionManager->commit(function() use ($user)
|
||||||
|
{
|
||||||
|
$token = $this->tokenService->createAndSaveToken($user->getName(), \Szurubooru\Entities\Token::PURPOSE_ACTIVATE);
|
||||||
|
$this->emailService->sendActivationEmail($user, $token);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function finishActivation(\Szurubooru\Entities\Token $token)
|
||||||
|
{
|
||||||
|
$this->transactionManager->commit(function() use ($token)
|
||||||
|
{
|
||||||
|
if ($token->getPurpose() !== \Szurubooru\Entities\Token::PURPOSE_ACTIVATE)
|
||||||
|
throw new \Exception('This token is not an activation token.');
|
||||||
|
|
||||||
|
$user = $this->getByName($token->getAdditionalData());
|
||||||
|
$user = $this->confirmUserEmail($user);
|
||||||
|
$this->userDao->save($user);
|
||||||
|
$this->tokenService->invalidateByName($token->getName());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCustomAvatarSourcePath(\Szurubooru\Entities\User $user)
|
||||||
|
{
|
||||||
|
return 'avatars' . DIRECTORY_SEPARATOR . $user->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlankAvatarSourcePath()
|
||||||
|
{
|
||||||
|
return 'avatars' . DIRECTORY_SEPARATOR . 'blank.png';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateUserAvatarStyle(\Szurubooru\Entities\User $user, $newAvatarStyle)
|
||||||
{
|
{
|
||||||
$user->setAvatarStyle($newAvatarStyle);
|
$user->setAvatarStyle($newAvatarStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateUserAvatarContent(\Szurubooru\Entities\User $user, $newAvatarContentInBase64)
|
private function updateUserAvatarContent(\Szurubooru\Entities\User $user, $newAvatarContentInBase64)
|
||||||
{
|
{
|
||||||
$target = $this->getCustomAvatarSourcePath($user);
|
$target = $this->getCustomAvatarSourcePath($user);
|
||||||
$this->fileService->saveFromBase64($newAvatarContentInBase64, $target);
|
$this->fileService->saveFromBase64($newAvatarContentInBase64, $target);
|
||||||
$this->thumbnailService->deleteUsedThumbnails($target);
|
$this->thumbnailService->deleteUsedThumbnails($target);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateUserName(\Szurubooru\Entities\User $user, $newName)
|
private function updateUserName(\Szurubooru\Entities\User $user, $newName)
|
||||||
{
|
{
|
||||||
$this->assertNoUserWithThisName($user, $newName);
|
$this->assertNoUserWithThisName($user, $newName);
|
||||||
$user->setName($newName);
|
$user->setName($newName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateUserPassword(\Szurubooru\Entities\User $user, $newPassword)
|
private function updateUserPassword(\Szurubooru\Entities\User $user, $newPassword)
|
||||||
{
|
{
|
||||||
$user->setPasswordHash($this->passwordService->getHash($newPassword));
|
$user->setPasswordHash($this->passwordService->getHash($newPassword));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateUserEmail(\Szurubooru\Entities\User $user, $newEmail)
|
private function updateUserEmail(\Szurubooru\Entities\User $user, $newEmail)
|
||||||
{
|
{
|
||||||
if ($user->getEmail() === $newEmail)
|
if ($user->getEmail() === $newEmail)
|
||||||
{
|
{
|
||||||
|
@ -157,80 +248,29 @@ class UserService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateUserAccessRank(\Szurubooru\Entities\User $user, $newAccessRank)
|
private function updateUserAccessRank(\Szurubooru\Entities\User $user, $newAccessRank)
|
||||||
{
|
{
|
||||||
$user->setAccessRank($newAccessRank);
|
$user->setAccessRank($newAccessRank);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateUserBrowsingSettings(\Szurubooru\Entities\User $user, $newBrowsingSettings)
|
private function updateUserBrowsingSettings(\Szurubooru\Entities\User $user, $newBrowsingSettings)
|
||||||
{
|
{
|
||||||
$user->setBrowsingSettings($newBrowsingSettings);
|
$user->setBrowsingSettings($newBrowsingSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateUserLastLoginTime(\Szurubooru\Entities\User $user)
|
public function updateUserLastLoginTime(\Szurubooru\Entities\User $user)
|
||||||
{
|
{
|
||||||
$user->setLastLoginTime($this->timeService->getCurrentTime());
|
$this->transactionManager->commit(function() use ($user)
|
||||||
$this->userDao->save($user);
|
{
|
||||||
}
|
$user->setLastLoginTime($this->timeService->getCurrentTime());
|
||||||
|
$this->userDao->save($user);
|
||||||
public function deleteUser(\Szurubooru\Entities\User $user)
|
});
|
||||||
{
|
|
||||||
$this->userDao->deleteById($user->getId());
|
|
||||||
|
|
||||||
$avatarSource = $this->getCustomAvatarSourcePath($user);
|
|
||||||
$this->fileService->delete($avatarSource);
|
|
||||||
$this->thumbnailService->deleteUsedThumbnails($avatarSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function sendPasswordResetEmail(\Szurubooru\Entities\User $user)
|
|
||||||
{
|
|
||||||
$token = $this->tokenService->createAndSaveToken($user->getName(), \Szurubooru\Entities\Token::PURPOSE_PASSWORD_RESET);
|
|
||||||
$this->emailService->sendPasswordResetEmail($user, $token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function finishPasswordReset(\Szurubooru\Entities\Token $token)
|
|
||||||
{
|
|
||||||
if ($token->getPurpose() !== \Szurubooru\Entities\Token::PURPOSE_PASSWORD_RESET)
|
|
||||||
throw new \Exception('This token is not a password reset token.');
|
|
||||||
|
|
||||||
$user = $this->getByName($token->getAdditionalData());
|
|
||||||
$newPassword = $this->passwordService->getRandomPassword();
|
|
||||||
$user->setPasswordHash($this->passwordService->getHash($newPassword));
|
|
||||||
$this->userDao->save($user);
|
|
||||||
$this->tokenService->invalidateByName($token->getName());
|
|
||||||
return $newPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function sendActivationEmail(\Szurubooru\Entities\User $user)
|
|
||||||
{
|
|
||||||
$token = $this->tokenService->createAndSaveToken($user->getName(), \Szurubooru\Entities\Token::PURPOSE_ACTIVATE);
|
|
||||||
$this->emailService->sendActivationEmail($user, $token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function finishActivation(\Szurubooru\Entities\Token $token)
|
|
||||||
{
|
|
||||||
if ($token->getPurpose() !== \Szurubooru\Entities\Token::PURPOSE_ACTIVATE)
|
|
||||||
throw new \Exception('This token is not an activation token.');
|
|
||||||
|
|
||||||
$user = $this->getByName($token->getAdditionalData());
|
|
||||||
$user = $this->confirmUserEmail($user);
|
|
||||||
$this->userDao->save($user);
|
|
||||||
$this->tokenService->invalidateByName($token->getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCustomAvatarSourcePath(\Szurubooru\Entities\User $user)
|
|
||||||
{
|
|
||||||
return 'avatars' . DIRECTORY_SEPARATOR . $user->getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBlankAvatarSourcePath()
|
|
||||||
{
|
|
||||||
return 'avatars' . DIRECTORY_SEPARATOR . 'blank.png';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function sendActivationEmailIfNeeded(\Szurubooru\Entities\User $user)
|
private function sendActivationEmailIfNeeded(\Szurubooru\Entities\User $user)
|
||||||
{
|
{
|
||||||
if ($user->getAccessRank() === \Szurubooru\Entities\User::ACCESS_RANK_ADMINISTRATOR or !$this->config->security->needEmailActivationToRegister)
|
if ($user->getAccessRank() === \Szurubooru\Entities\User::ACCESS_RANK_ADMINISTRATOR
|
||||||
|
or !$this->config->security->needEmailActivationToRegister)
|
||||||
{
|
{
|
||||||
$user = $this->confirmUserEmail($user);
|
$user = $this->confirmUserEmail($user);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,11 @@ abstract class AbstractTestCase extends \PHPUnit_Framework_TestCase
|
||||||
return new ConfigMock($path);
|
return new ConfigMock($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function mockTransactionManager()
|
||||||
|
{
|
||||||
|
return new TransactionManagerMock($this->mock(\Szurubooru\DatabaseConnection::class));
|
||||||
|
}
|
||||||
|
|
||||||
public function createTestDirectory()
|
public function createTestDirectory()
|
||||||
{
|
{
|
||||||
$path = $this->getTestDirectoryPath();
|
$path = $this->getTestDirectoryPath();
|
||||||
|
|
77
tests/Dao/TransactionManagerTest.php
Normal file
77
tests/Dao/TransactionManagerTest.php
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Tests\Dao;
|
||||||
|
|
||||||
|
class TransactionManagerTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
||||||
|
{
|
||||||
|
public function testCommit()
|
||||||
|
{
|
||||||
|
$testEntity = $this->getTestEntity();
|
||||||
|
$testDao = $this->getTestDao();
|
||||||
|
|
||||||
|
$transactionManager = $this->getTransactionManager();
|
||||||
|
$transactionManager->commit(function() use ($testDao, &$testEntity)
|
||||||
|
{
|
||||||
|
$testDao->save($testEntity);
|
||||||
|
$this->assertNotNull($testEntity->getId());
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertNotNull($testEntity->getId());
|
||||||
|
$this->assertEquals($testEntity, $testDao->findById($testEntity->getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRollback()
|
||||||
|
{
|
||||||
|
$testEntity = $this->getTestEntity();
|
||||||
|
$testDao = $this->getTestDao();
|
||||||
|
|
||||||
|
$transactionManager = $this->getTransactionManager();
|
||||||
|
$transactionManager->rollback(function() use ($testDao, &$testEntity)
|
||||||
|
{
|
||||||
|
$testDao->save($testEntity);
|
||||||
|
$this->assertNotNull($testEntity->getId());
|
||||||
|
});
|
||||||
|
|
||||||
|
//ids that could be forged in transaction get left behind after rollback
|
||||||
|
$this->assertNotNull($testEntity->getId());
|
||||||
|
|
||||||
|
//but entities shouldn't be saved to database
|
||||||
|
$this->assertNull($testDao->findById($testEntity->getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNestedTransactions()
|
||||||
|
{
|
||||||
|
$testEntity = $this->getTestEntity();
|
||||||
|
$testDao = $this->getTestDao();
|
||||||
|
|
||||||
|
$transactionManager = $this->getTransactionManager();
|
||||||
|
$transactionManager->commit(function() use ($transactionManager, $testDao, &$testEntity)
|
||||||
|
{
|
||||||
|
$transactionManager->commit(function() use ($testDao, &$testEntity)
|
||||||
|
{
|
||||||
|
$testDao->save($testEntity);
|
||||||
|
$this->assertNotNull($testEntity->getId());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertNotNull($testEntity->getId());
|
||||||
|
$this->assertEquals($testEntity, $testDao->findById($testEntity->getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getTestEntity()
|
||||||
|
{
|
||||||
|
$token = new \Szurubooru\Entities\Token();
|
||||||
|
$token->setName('yo');
|
||||||
|
$token->setPurpose(\Szurubooru\Entities\Token::PURPOSE_ACTIVATE);
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getTestDao()
|
||||||
|
{
|
||||||
|
return \Szurubooru\Injector::get(\Szurubooru\Dao\TokenDao::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getTransactionManager()
|
||||||
|
{
|
||||||
|
return \Szurubooru\Injector::get(\Szurubooru\Dao\TransactionManager::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
{
|
{
|
||||||
private $configMock;
|
private $configMock;
|
||||||
private $validatorMock;
|
private $validatorMock;
|
||||||
|
private $transactionManagerMock;
|
||||||
private $userDaoMock;
|
private $userDaoMock;
|
||||||
private $userSearchServiceMock;
|
private $userSearchServiceMock;
|
||||||
private $passwordServiceMock;
|
private $passwordServiceMock;
|
||||||
|
@ -18,6 +19,7 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
$this->configMock = $this->mockConfig();
|
$this->configMock = $this->mockConfig();
|
||||||
|
$this->transactionManagerMock = $this->mockTransactionManager();
|
||||||
$this->validatorMock = $this->mock(\Szurubooru\Validator::class);
|
$this->validatorMock = $this->mock(\Szurubooru\Validator::class);
|
||||||
$this->userDaoMock = $this->mock(\Szurubooru\Dao\UserDao::class);
|
$this->userDaoMock = $this->mock(\Szurubooru\Dao\UserDao::class);
|
||||||
$this->userSearchService = $this->mock(\Szurubooru\Dao\Services\UserSearchService::class);
|
$this->userSearchService = $this->mock(\Szurubooru\Dao\Services\UserSearchService::class);
|
||||||
|
@ -288,6 +290,7 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
return new \Szurubooru\Services\UserService(
|
return new \Szurubooru\Services\UserService(
|
||||||
$this->configMock,
|
$this->configMock,
|
||||||
$this->validatorMock,
|
$this->validatorMock,
|
||||||
|
$this->transactionManagerMock,
|
||||||
$this->userDaoMock,
|
$this->userDaoMock,
|
||||||
$this->userSearchService,
|
$this->userSearchService,
|
||||||
$this->passwordServiceMock,
|
$this->passwordServiceMock,
|
||||||
|
|
15
tests/TransactionManagerMock.php
Normal file
15
tests/TransactionManagerMock.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Tests;
|
||||||
|
|
||||||
|
class TransactionManagerMock extends \Szurubooru\Dao\TransactionManager
|
||||||
|
{
|
||||||
|
public function rollback($callback)
|
||||||
|
{
|
||||||
|
return $callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function commit($callback)
|
||||||
|
{
|
||||||
|
return $callback();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue