Refactored AuthService and UserService

This commit is contained in:
Marcin Kurczewski 2014-09-08 08:20:31 +02:00
parent aa4c401df9
commit 121c2f80dc
7 changed files with 111 additions and 86 deletions

View file

@ -28,8 +28,6 @@ final class UserAvatarController extends AbstractController
public function getAvatarByName($userName, $size)
{
$user = $this->userService->getByName($userName);
if (!$user)
throw new \InvalidArgumentException('User with name "' . $userName . '" was not found.');
switch ($user->avatarStyle)
{

View file

@ -32,8 +32,6 @@ final class UserController extends AbstractController
public function getByName($userName)
{
$user = $this->userService->getByName($userName);
if (!$user)
throw new \InvalidArgumentException('User with name "' . $userName . '" was not found.');
return $this->userViewProxy->fromEntity($user);
}

View file

@ -9,23 +9,23 @@ class AuthService
private $validator;
private $passwordService;
private $timeService;
private $userDao;
private $tokenDao;
private $userService;
private $tokenService;
public function __construct(
\Szurubooru\Validator $validator,
\Szurubooru\Services\PasswordService $passwordService,
\Szurubooru\Services\TimeService $timeService,
\Szurubooru\Dao\TokenDao $tokenDao,
\Szurubooru\Dao\UserDao $userDao)
\Szurubooru\Services\TokenService $tokenService,
\Szurubooru\Services\UserService $userService)
{
$this->loggedInUser = $this->getAnonymousUser();
$this->validator = $validator;
$this->passwordService = $passwordService;
$this->timeService = $timeService;
$this->tokenDao = $tokenDao;
$this->userDao = $userDao;
$this->tokenService = $tokenService;
$this->userService = $userService;
$this->loggedInUser = $this->getAnonymousUser();
}
public function isLoggedIn()
@ -48,9 +48,7 @@ class AuthService
$this->validator->validateUserName($userName);
$this->validator->validatePassword($password);
$user = $this->userDao->getByName($userName);
if (!$user)
throw new \InvalidArgumentException('User not found.');
$user = $this->userService->getByName($userName);
$passwordHash = $this->passwordService->getHash($password);
if ($user->passwordHash != $passwordHash)
@ -58,31 +56,22 @@ class AuthService
$this->loginToken = $this->createAndSaveLoginToken($user);
$this->loggedInUser = $user;
$this->updateLoginTime($user);
$this->userService->updateUserLastLoginTime($user);
}
public function loginFromToken($loginTokenName)
{
$this->validator->validateToken($loginTokenName);
$loginToken = $this->tokenDao->getByName($loginTokenName);
if (!$loginToken)
throw new \Exception('Invalid login token.');
$loginToken = $this->tokenService->getByName($loginTokenName);
if ($loginToken->purpose != \Szurubooru\Entities\Token::PURPOSE_LOGIN)
throw new \Exception('This token is not a login token.');
$this->loginToken = $loginToken;
$this->loggedInUser = $this->userDao->getById($loginToken->additionalData);
if (!$this->loggedInUser)
throw new \Exception('User was deleted.');
$this->updateLoginTime($this->loggedInUser);
$user = $this->userService->getById($loginToken->additionalData);
if (!$this->loggedInUser)
{
$this->logout();
throw new \RuntimeException('Token is correct, but user is not. Have you deleted your account?');
}
$this->loginToken = $loginToken;
$this->loggedInUser = $user;
$this->userService->updateUserLastLoginTime($this->loggedInUser);
}
public function getAnonymousUser()
@ -104,24 +93,12 @@ class AuthService
if (!$this->isLoggedIn())
throw new \Exception('Not logged in.');
$this->tokenDao->deleteByName($this->loginToken);
$this->tokenService->invalidateByToken($this->loginToken);
$this->loginToken = null;
}
private function createAndSaveLoginToken(\Szurubooru\Entities\User $user)
{
$loginToken = new \Szurubooru\Entities\Token();
$loginToken->name = hash('sha256', $user->name . '/' . microtime(true));
$loginToken->additionalData = $user->id;
$loginToken->purpose = \Szurubooru\Entities\Token::PURPOSE_LOGIN;
$this->tokenDao->deleteByAdditionalData($loginToken->additionalData);
$this->tokenDao->save($loginToken);
return $loginToken;
}
private function updateLoginTime($user)
{
$user->lastLoginTime = $this->timeService->getCurrentTime();
$this->userDao->save($user);
return $this->tokenService->createAndSaveToken($user, \Szurubooru\Entities\Token::PURPOSE_LOGIN);
}
}

View file

@ -10,23 +10,32 @@ class TokenService
$this->tokenDao = $tokenDao;
}
public function getById($tokenId)
{
return $this->tokenDao->getById($tokenId);
}
public function getByName($tokenName)
{
return $this->tokenDao->getByName($tokenName);
$token = $this->tokenDao->getByName($tokenName);
if (!$token)
throw new \InvalidArgumentException('Token with identifier "' . $tokenName . '" not found.');
return $token;
}
public function deleteByName($tokenName)
public function invalidateByToken($tokenName)
{
return $this->tokenDao->deleteByName($tokenName);
}
public function save($token)
public function invalidateByUser(\Szurubooru\Entities\User $user)
{
return $this->tokenDao->save($token);
return $this->tokenDao->deleteByAdditionalData($user->id);
}
public function createAndSaveToken(\Szurubooru\Entities\User $user, $tokenPurpose)
{
$token = new \Szurubooru\Entities\Token();
$token->name = hash('sha256', $user->name . '/' . microtime(true));
$token->additionalData = $user->id;
$token->purpose = $tokenPurpose;
$this->invalidateByUser($user);
$this->tokenDao->save($token);
return $token;
}
}

View file

@ -32,9 +32,20 @@ class UserService
$this->timeService = $timeService;
}
public function getByName($name)
public function getByName($userName)
{
return $this->userDao->getByName($name);
$user = $this->userDao->getByName($userName);
if (!$user)
throw new \InvalidArgumentException('User with name "' . $userName . '" was not found.');
return $user;
}
public function getById($userId)
{
$user = $this->userDao->getById($userId);
if (!$user)
throw new \InvalidArgumentException('User with id "' . $userId . '" was not found.');
return $user;
}
public function getFiltered(\Szurubooru\FormData\SearchFormData $formData)
@ -73,8 +84,6 @@ class UserService
public function updateUser($userName, \Szurubooru\FormData\UserEditFormData $formData)
{
$user = $this->getByName($userName);
if (!$user)
throw new \InvalidArgumentException('User with name "' . $userName . '" was not found.');
if ($formData->avatarStyle !== null)
{
@ -127,15 +136,12 @@ class UserService
public function deleteUserByName($userName)
{
$user = $this->getByName($userName);
if (!$user)
throw new \InvalidArgumentException('User with name "' . $userName . '" was not found.');
$this->userDao->deleteByName($userName);
$this->fileService->delete($this->getCustomAvatarSourcePath($user));
return true;
}
public function getCustomAvatarSourcePath($user)
public function getCustomAvatarSourcePath(\Szurubooru\Entities\User $user)
{
return 'avatars' . DIRECTORY_SEPARATOR . $user->id;
}
@ -145,6 +151,12 @@ class UserService
return 'avatars' . DIRECTORY_SEPARATOR . 'blank.png';
}
public function updateUserLastLoginTime(\Szurubooru\Entities\User $user)
{
$user->lastLoginTime = $this->timeService->getCurrentTime();
$this->userDao->save($user);
}
private function sendActivationMailIfNeeded(\Szurubooru\Entities\User &$user)
{
//todo

View file

@ -6,24 +6,16 @@ class AuthServiceTest extends \Szurubooru\Tests\AbstractTestCase
private $validatorMock;
private $passwordServiceMock;
private $timeServiceMock;
private $tokenDaoMock;
private $userDaoMock;
private $tokenServiceMock;
private $userServiceMock;
public function setUp()
{
$this->validatorMock = $this->mock(\Szurubooru\Validator::class);
$this->passwordServiceMock = $this->mock(\Szurubooru\Services\PasswordService::class);
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
$this->tokenDaoMock = $this->mock(\Szurubooru\Dao\TokenDao::class);
$this->userDaoMock = $this->mock(\Szurubooru\Dao\UserDao::class);
}
public function testInvalidUser()
{
$this->setExpectedException(\InvalidArgumentException::class, 'User not found');
$authService = $this->getAuthService();
$authService->loginFromCredentials('dummy', 'godzilla');
$this->tokenServiceMock = $this->mock(\Szurubooru\Services\TokenService::class);
$this->userServiceMock = $this->mock(\Szurubooru\Services\UserService::class);
}
public function testInvalidPassword()
@ -33,23 +25,27 @@ class AuthServiceTest extends \Szurubooru\Tests\AbstractTestCase
$testUser = new \Szurubooru\Entities\User();
$testUser->name = 'dummy';
$testUser->passwordHash = 'hash';
$this->userDaoMock->expects($this->once())->method('getByName')->willReturn($testUser);
$this->userServiceMock->expects($this->once())->method('getByName')->willReturn($testUser);
$authService = $this->getAuthService();
$this->setExpectedException(\InvalidArgumentException::class, 'Specified password is invalid');
$this->setExpectedException(\Exception::class, 'Specified password is invalid');
$authService->loginFromCredentials('dummy', 'godzilla');
}
public function testValidCredentials()
{
$this->tokenDaoMock->expects($this->once())->method('save');
$this->passwordServiceMock->method('getHash')->willReturn('hash');
$testUser = new \Szurubooru\Entities\User();
$testUser->name = 'dummy';
$testUser->passwordHash = 'hash';
$this->userDaoMock->expects($this->once())->method('getByName')->willReturn($testUser);
$this->tokenDaoMock->expects($this->once())->method('deleteByAdditionalData')->with($testUser->id);
$this->userServiceMock->expects($this->once())->method('getByName')->willReturn($testUser);
$testToken = new \Szurubooru\Entities\Token();
$testToken->name = 'mummy';
$this->tokenServiceMock->expects($this->once())->method('createAndSaveToken')->with(
$testUser,
\Szurubooru\Entities\Token::PURPOSE_LOGIN)->willReturn($testToken);
$authService = $this->getAuthService();
$authService->loginFromCredentials('dummy', 'godzilla');
@ -57,12 +53,12 @@ class AuthServiceTest extends \Szurubooru\Tests\AbstractTestCase
$this->assertTrue($authService->isLoggedIn());
$this->assertEquals($testUser, $authService->getLoggedInUser());
$this->assertNotNull($authService->getLoginToken());
$this->assertNotNull($authService->getLoginToken()->name);
$this->assertEquals('mummy', $authService->getLoginToken()->name);
}
public function testInvalidToken()
{
$this->tokenDaoMock->expects($this->once())->method('getByName')->willReturn(null);
$this->tokenServiceMock->expects($this->once())->method('getByName')->willReturn(null);
$this->setExpectedException(\Exception::class);
$authService = $this->getAuthService();
@ -74,14 +70,13 @@ class AuthServiceTest extends \Szurubooru\Tests\AbstractTestCase
$testUser = new \Szurubooru\Entities\User();
$testUser->id = 5;
$testUser->name = 'dummy';
$testUser->passwordHash = 'hash';
$this->userDaoMock->expects($this->once())->method('getById')->willReturn($testUser);
$this->userServiceMock->expects($this->once())->method('getById')->willReturn($testUser);
$testToken = new \Szurubooru\Entities\Token();
$testToken->name = 'dummy_token';
$testToken->additionalData = $testUser->id;
$testToken->purpose = \Szurubooru\Entities\Token::PURPOSE_LOGIN;
$this->tokenDaoMock->expects($this->once())->method('getByName')->willReturn($testToken);
$this->tokenServiceMock->expects($this->once())->method('getByName')->willReturn($testToken);
$authService = $this->getAuthService();
$authService->loginFromToken($testToken->name);
@ -89,7 +84,7 @@ class AuthServiceTest extends \Szurubooru\Tests\AbstractTestCase
$this->assertTrue($authService->isLoggedIn());
$this->assertEquals($testUser, $authService->getLoggedInUser());
$this->assertNotNull($authService->getLoginToken());
$this->assertNotNull($authService->getLoginToken()->name);
$this->assertEquals('dummy_token', $authService->getLoginToken()->name);
}
private function getAuthService()
@ -98,7 +93,7 @@ class AuthServiceTest extends \Szurubooru\Tests\AbstractTestCase
$this->validatorMock,
$this->passwordServiceMock,
$this->timeServiceMock,
$this->tokenDaoMock,
$this->userDaoMock);
$this->tokenServiceMock,
$this->userServiceMock);
}
}

View file

@ -24,6 +24,42 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
}
public function testGettingByName()
{
$testUser = new \Szurubooru\Entities\User();
$testUser->name = 'godzilla';
$this->userDaoMock->expects($this->once())->method('getByName')->willReturn($testUser);
$userService = $this->getUserService();
$expected = $testUser;
$actual = $userService->getByName('godzilla');
$this->assertEquals($expected, $actual);
}
public function testGettingByNameNonExistentUsers()
{
$this->setExpectedException(\Exception::class, 'User with name "godzilla" was not found.');
$userService = $this->getUserService();
$userService->getByName('godzilla');
}
public function testGettingById()
{
$testUser = new \Szurubooru\Entities\User();
$testUser->name = 'godzilla';
$this->userDaoMock->expects($this->once())->method('getById')->willReturn($testUser);
$userService = $this->getUserService();
$expected = $testUser;
$actual = $userService->getById('godzilla');
$this->assertEquals($expected, $actual);
}
public function testGettingByIdNonExistentUsers()
{
$this->setExpectedException(\Exception::class, 'User with id "godzilla" was not found.');
$userService = $this->getUserService();
$userService->getById('godzilla');
}
public function testGettingFilteredUsers()
{
$mockUser = new \Szurubooru\Entities\User();