Refactored AuthService and UserService
This commit is contained in:
parent
aa4c401df9
commit
121c2f80dc
7 changed files with 111 additions and 86 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue