diff --git a/src/Controllers/UserAvatarController.php b/src/Controllers/UserAvatarController.php index e2a67811..e5e5877a 100644 --- a/src/Controllers/UserAvatarController.php +++ b/src/Controllers/UserAvatarController.php @@ -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) { diff --git a/src/Controllers/UserController.php b/src/Controllers/UserController.php index 89cd1e18..e215d1cd 100644 --- a/src/Controllers/UserController.php +++ b/src/Controllers/UserController.php @@ -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); } diff --git a/src/Services/AuthService.php b/src/Services/AuthService.php index 4d396c81..fbd3d493 100644 --- a/src/Services/AuthService.php +++ b/src/Services/AuthService.php @@ -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); } } diff --git a/src/Services/TokenService.php b/src/Services/TokenService.php index 9d53e732..985a48bc 100644 --- a/src/Services/TokenService.php +++ b/src/Services/TokenService.php @@ -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; } } diff --git a/src/Services/UserService.php b/src/Services/UserService.php index 8e4dc5dc..885a00f0 100644 --- a/src/Services/UserService.php +++ b/src/Services/UserService.php @@ -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 diff --git a/tests/Services/AuthServiceTest.php b/tests/Services/AuthServiceTest.php index 9f1583c6..ba11256f 100644 --- a/tests/Services/AuthServiceTest.php +++ b/tests/Services/AuthServiceTest.php @@ -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); } } diff --git a/tests/Services/UserServiceTest.php b/tests/Services/UserServiceTest.php index 9137c53a..9661e0d5 100644 --- a/tests/Services/UserServiceTest.php +++ b/tests/Services/UserServiceTest.php @@ -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();