Worked on user registration
This commit is contained in:
parent
c7051a40e9
commit
03b65c196c
8 changed files with 139 additions and 39 deletions
|
@ -3,35 +3,36 @@ namespace Szurubooru\Controllers;
|
||||||
|
|
||||||
final class UserController extends AbstractController
|
final class UserController extends AbstractController
|
||||||
{
|
{
|
||||||
private $userService;
|
|
||||||
private $passwordService;
|
|
||||||
private $inputReader;
|
private $inputReader;
|
||||||
|
private $userService;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
\Szurubooru\Services\UserService $userService,
|
\Szurubooru\Services\UserService $userService,
|
||||||
\Szurubooru\Services\PasswordService $passwordService,
|
|
||||||
\Szurubooru\Helpers\InputReader $inputReader)
|
\Szurubooru\Helpers\InputReader $inputReader)
|
||||||
{
|
{
|
||||||
$this->inputReader = $inputReader;
|
$this->inputReader = $inputReader;
|
||||||
$this->userService = $userService;
|
$this->userService = $userService;
|
||||||
$this->passwordService = $passwordService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function registerRoutes(\Szurubooru\Router $router)
|
public function registerRoutes(\Szurubooru\Router $router)
|
||||||
{
|
{
|
||||||
$router->post('/api/users', [$this, 'create']);
|
$router->post('/api/users', [$this, 'register']);
|
||||||
$router->get('/api/users', [$this, 'getAll']);
|
$router->get('/api/users', [$this, 'getAll']);
|
||||||
$router->get('/api/users/:id', [$this, 'getById']);
|
$router->get('/api/users/:id', [$this, 'getById']);
|
||||||
$router->put('/api/users/:id', [$this, 'update']);
|
$router->put('/api/users/:id', [$this, 'update']);
|
||||||
$router->delete('/api/users/:id', [$this, 'delete']);
|
$router->delete('/api/users/:id', [$this, 'delete']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create()
|
public function register()
|
||||||
{
|
{
|
||||||
$this->userService->validateUserName($this->inputReader->userName);
|
$input = new \Szurubooru\FormData\RegistrationFormData;
|
||||||
$this->passwordService->validatePassword($this->inputReader->password);
|
$input->name = $this->inputReader->userName;
|
||||||
|
$input->password = $this->inputReader->password;
|
||||||
|
$input->email = $this->inputReader->email;
|
||||||
|
|
||||||
throw new \BadMethodCallException('Not implemented');
|
$user = $this->userService->register($input);
|
||||||
|
|
||||||
|
return new \Szurubooru\ViewProxies\User($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update($id)
|
public function update($id)
|
||||||
|
|
|
@ -12,4 +12,7 @@ final class User extends Entity
|
||||||
|
|
||||||
public $name;
|
public $name;
|
||||||
public $passwordHash;
|
public $passwordHash;
|
||||||
|
public $email;
|
||||||
|
public $registrationDate;
|
||||||
|
public $lastLoginTime;
|
||||||
}
|
}
|
||||||
|
|
9
src/FormData/RegistrationFormData.php
Normal file
9
src/FormData/RegistrationFormData.php
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\FormData;
|
||||||
|
|
||||||
|
class RegistrationFormData
|
||||||
|
{
|
||||||
|
public $name;
|
||||||
|
public $password;
|
||||||
|
public $email;
|
||||||
|
}
|
|
@ -7,19 +7,21 @@ final class AuthService
|
||||||
private $loginToken = null;
|
private $loginToken = null;
|
||||||
|
|
||||||
private $passwordService;
|
private $passwordService;
|
||||||
|
private $timeService;
|
||||||
private $userDao;
|
private $userDao;
|
||||||
private $tokenDao;
|
private $tokenDao;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
\Szurubooru\Services\PasswordService $passwordService,
|
\Szurubooru\Services\PasswordService $passwordService,
|
||||||
|
\Szurubooru\Services\TimeService $timeService,
|
||||||
\Szurubooru\Dao\TokenDao $tokenDao,
|
\Szurubooru\Dao\TokenDao $tokenDao,
|
||||||
\Szurubooru\Dao\UserDao $userDao)
|
\Szurubooru\Dao\UserDao $userDao)
|
||||||
{
|
{
|
||||||
$this->loggedInUser = new \Szurubooru\Entities\User();
|
$this->loggedInUser = $this->getAnonymousUser();
|
||||||
$this->loggedInUser->name = 'Anonymous';
|
|
||||||
$this->userDao = $userDao;
|
|
||||||
$this->tokenDao = $tokenDao;
|
|
||||||
$this->passwordService = $passwordService;
|
$this->passwordService = $passwordService;
|
||||||
|
$this->timeService = $timeService;
|
||||||
|
$this->tokenDao = $tokenDao;
|
||||||
|
$this->userDao = $userDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isLoggedIn()
|
public function isLoggedIn()
|
||||||
|
@ -47,8 +49,9 @@ final class AuthService
|
||||||
if ($user->passwordHash != $passwordHash)
|
if ($user->passwordHash != $passwordHash)
|
||||||
throw new \InvalidArgumentException('Specified password is invalid.');
|
throw new \InvalidArgumentException('Specified password is invalid.');
|
||||||
|
|
||||||
$this->loggedInUser = $user;
|
|
||||||
$this->loginToken = $this->createAndSaveLoginToken($user);
|
$this->loginToken = $this->createAndSaveLoginToken($user);
|
||||||
|
$this->loggedInUser = $user;
|
||||||
|
$this->updateLoginTime($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loginFromToken($loginTokenName)
|
public function loginFromToken($loginTokenName)
|
||||||
|
@ -59,6 +62,8 @@ final class AuthService
|
||||||
|
|
||||||
$this->loginToken = $loginToken;
|
$this->loginToken = $loginToken;
|
||||||
$this->loggedInUser = $this->userDao->getById($loginToken->additionalData);
|
$this->loggedInUser = $this->userDao->getById($loginToken->additionalData);
|
||||||
|
$this->updateLoginTime($this->loggedInUser);
|
||||||
|
|
||||||
if (!$this->loggedInUser)
|
if (!$this->loggedInUser)
|
||||||
{
|
{
|
||||||
$this->logout();
|
$this->logout();
|
||||||
|
@ -66,10 +71,18 @@ final class AuthService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAnonymousUser()
|
||||||
|
{
|
||||||
|
$user = new \Szurubooru\Entities\User();
|
||||||
|
$user->name = 'Anonymous user';
|
||||||
|
$user->accessRank = \Szurubooru\Entities\User::ACCESS_RANK_ANONYMOUS;
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
public function loginAnonymous()
|
public function loginAnonymous()
|
||||||
{
|
{
|
||||||
$this->loginToken = null;
|
$this->loginToken = null;
|
||||||
$this->loggedInUser = $this->userService->getAnonymousUser();
|
$this->loggedInUser = $this->getAnonymousUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function logout()
|
public function logout()
|
||||||
|
@ -90,4 +103,10 @@ final class AuthService
|
||||||
$this->tokenDao->save($loginToken);
|
$this->tokenDao->save($loginToken);
|
||||||
return $loginToken;
|
return $loginToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function updateLoginTime($user)
|
||||||
|
{
|
||||||
|
$user->lastLoginTime = $this->timeService->getCurrentTime();
|
||||||
|
$this->userDao->save($user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,34 +3,52 @@ namespace Szurubooru\Services;
|
||||||
|
|
||||||
class UserService
|
class UserService
|
||||||
{
|
{
|
||||||
private $userDao;
|
|
||||||
private $config;
|
private $config;
|
||||||
|
private $userDao;
|
||||||
|
private $passwordService;
|
||||||
|
private $emailService;
|
||||||
|
private $timeService;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
\Szurubooru\Config $config,
|
||||||
\Szurubooru\Dao\UserDao $userDao,
|
\Szurubooru\Dao\UserDao $userDao,
|
||||||
\Szurubooru\Config $config)
|
\Szurubooru\Services\PasswordService $passwordService,
|
||||||
|
\Szurubooru\Services\EmailService $emailService,
|
||||||
|
\Szurubooru\Services\TimeService $timeService)
|
||||||
{
|
{
|
||||||
$this->userDao = $userDao;
|
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
|
$this->userDao = $userDao;
|
||||||
|
$this->passwordService = $passwordService;
|
||||||
|
$this->emailService = $emailService;
|
||||||
|
$this->timeService = $timeService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getById($userId)
|
public function register(\Szurubooru\FormData\RegistrationFormData $formData)
|
||||||
{
|
{
|
||||||
return $this->userDao->getById($userId);
|
$this->validateUserName($formData->name);
|
||||||
}
|
$this->passwordService->validatePassword($formData->password);
|
||||||
|
$this->emailService->validateEmail($formData->email);
|
||||||
|
|
||||||
public function getByName($userName)
|
if ($this->userDao->getByName($formData->name))
|
||||||
{
|
throw new \DomainException('User with this name already exists.');
|
||||||
return $this->userDao->getByName($userName);
|
|
||||||
}
|
//todo: privilege checking
|
||||||
|
|
||||||
|
$user = new \Szurubooru\Entities\User();
|
||||||
|
$user->name = $formData->name;
|
||||||
|
$user->email = $formData->email;
|
||||||
|
$user->passwordHash = $this->passwordService->getHash($formData->password);
|
||||||
|
$user->registrationTime = $this->timeService->getCurrentTime();
|
||||||
|
|
||||||
|
//todo: send activation mail if necessary
|
||||||
|
|
||||||
public function save($user)
|
|
||||||
{
|
|
||||||
return $this->userDao->save($user);
|
return $this->userDao->save($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validateUserName($userName)
|
public function validateUserName(&$userName)
|
||||||
{
|
{
|
||||||
|
$userName = trim($userName);
|
||||||
|
|
||||||
if (!$userName)
|
if (!$userName)
|
||||||
throw new \DomainException('User name cannot be empty.');
|
throw new \DomainException('User name cannot be empty.');
|
||||||
|
|
||||||
|
@ -41,11 +59,4 @@ class UserService
|
||||||
if (strlen($userName) < $maxUserNameLength)
|
if (strlen($userName) < $maxUserNameLength)
|
||||||
throw new \DomainException('User name must have at most ' . $minUserNameLength . ' character(s).');
|
throw new \DomainException('User name must have at most ' . $minUserNameLength . ' character(s).');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAnonymousUser()
|
|
||||||
{
|
|
||||||
$user = new \Szurubooru\Entities\User();
|
|
||||||
$user->name = 'Anonymous user';
|
|
||||||
$user->accessRank = \Szurubooru\Entities\User::ACCESS_RANK_ANONYMOUS;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ namespace Szurubooru\ViewProxies;
|
||||||
|
|
||||||
class User
|
class User
|
||||||
{
|
{
|
||||||
|
public $id;
|
||||||
public $name;
|
public $name;
|
||||||
|
|
||||||
public function __construct($user)
|
public function __construct($user)
|
||||||
|
@ -10,6 +11,7 @@ class User
|
||||||
if (!$user)
|
if (!$user)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
$this->id = $user->id;
|
||||||
$this->name = $user->name;
|
$this->name = $user->name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
28
tests/Dao/TokenDaoTest.php
Normal file
28
tests/Dao/TokenDaoTest.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Tests\Dao;
|
||||||
|
|
||||||
|
final class TokenDaoTest extends \Szurubooru\Tests\AbstractDatabaseTest
|
||||||
|
{
|
||||||
|
public function testRetrievingByValidName()
|
||||||
|
{
|
||||||
|
$tokenDao = new \Szurubooru\Dao\TokenDao($this->databaseConnection);
|
||||||
|
|
||||||
|
$token = new \Szurubooru\Entities\Token();
|
||||||
|
$token->name = 'test';
|
||||||
|
|
||||||
|
$tokenDao->save($token);
|
||||||
|
$expected = $token;
|
||||||
|
$actual = $tokenDao->getByName($token->name);
|
||||||
|
|
||||||
|
$this->assertEquals($actual, $expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRetrievingByInvalidName()
|
||||||
|
{
|
||||||
|
$tokenDao = new \Szurubooru\Dao\TokenDao($this->databaseConnection);
|
||||||
|
|
||||||
|
$actual = $tokenDao->getByName('rubbish');
|
||||||
|
|
||||||
|
$this->assertNull($actual);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,18 +6,20 @@ class AuthServiceTest extends \PHPUnit_Framework_TestCase
|
||||||
public function testInvalidUser()
|
public function testInvalidUser()
|
||||||
{
|
{
|
||||||
$passwordServiceMock = $this->getPasswordServiceMock();
|
$passwordServiceMock = $this->getPasswordServiceMock();
|
||||||
|
$timeServiceMock = $this->getTimeServiceMock();
|
||||||
$tokenDaoMock = $this->getTokenDaoMock();
|
$tokenDaoMock = $this->getTokenDaoMock();
|
||||||
$userDaoMock = $this->getUserDaoMock();
|
$userDaoMock = $this->getUserDaoMock();
|
||||||
|
|
||||||
$this->setExpectedException(\InvalidArgumentException::class, 'User not found');
|
$this->setExpectedException(\InvalidArgumentException::class, 'User not found');
|
||||||
|
|
||||||
$authService = new \Szurubooru\Services\AuthService($passwordServiceMock, $tokenDaoMock, $userDaoMock);
|
$authService = new \Szurubooru\Services\AuthService($passwordServiceMock, $timeServiceMock, $tokenDaoMock, $userDaoMock);
|
||||||
$authService->loginFromCredentials('dummy', 'godzilla');
|
$authService->loginFromCredentials('dummy', 'godzilla');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testInvalidPassword()
|
public function testInvalidPassword()
|
||||||
{
|
{
|
||||||
$passwordServiceMock = $this->getPasswordServiceMock();
|
$passwordServiceMock = $this->getPasswordServiceMock();
|
||||||
|
$timeServiceMock = $this->getTimeServiceMock();
|
||||||
$tokenDaoMock = $this->getTokenDaoMock();
|
$tokenDaoMock = $this->getTokenDaoMock();
|
||||||
$userDaoMock = $this->getUserDaoMock();
|
$userDaoMock = $this->getUserDaoMock();
|
||||||
|
|
||||||
|
@ -28,7 +30,7 @@ class AuthServiceTest extends \PHPUnit_Framework_TestCase
|
||||||
$testUser->passwordHash = 'hash';
|
$testUser->passwordHash = 'hash';
|
||||||
$userDaoMock->expects($this->once())->method('getByName')->willReturn($testUser);
|
$userDaoMock->expects($this->once())->method('getByName')->willReturn($testUser);
|
||||||
|
|
||||||
$authService = new \Szurubooru\Services\AuthService($passwordServiceMock, $tokenDaoMock, $userDaoMock);
|
$authService = new \Szurubooru\Services\AuthService($passwordServiceMock, $timeServiceMock, $tokenDaoMock, $userDaoMock);
|
||||||
$this->setExpectedException(\InvalidArgumentException::class, 'Specified password is invalid');
|
$this->setExpectedException(\InvalidArgumentException::class, 'Specified password is invalid');
|
||||||
$authService->loginFromCredentials('dummy', 'godzilla');
|
$authService->loginFromCredentials('dummy', 'godzilla');
|
||||||
}
|
}
|
||||||
|
@ -36,6 +38,7 @@ class AuthServiceTest extends \PHPUnit_Framework_TestCase
|
||||||
public function testValidCredentials()
|
public function testValidCredentials()
|
||||||
{
|
{
|
||||||
$passwordServiceMock = $this->getPasswordServiceMock();
|
$passwordServiceMock = $this->getPasswordServiceMock();
|
||||||
|
$timeServiceMock = $this->getTimeServiceMock();
|
||||||
$tokenDaoMock = $this->getTokenDaoMock();
|
$tokenDaoMock = $this->getTokenDaoMock();
|
||||||
$userDaoMock = $this->getUserDaoMock();
|
$userDaoMock = $this->getUserDaoMock();
|
||||||
|
|
||||||
|
@ -47,16 +50,33 @@ class AuthServiceTest extends \PHPUnit_Framework_TestCase
|
||||||
$testUser->passwordHash = 'hash';
|
$testUser->passwordHash = 'hash';
|
||||||
$userDaoMock->expects($this->once())->method('getByName')->willReturn($testUser);
|
$userDaoMock->expects($this->once())->method('getByName')->willReturn($testUser);
|
||||||
|
|
||||||
$authService = new \Szurubooru\Services\AuthService($passwordServiceMock, $tokenDaoMock, $userDaoMock);
|
$authService = new \Szurubooru\Services\AuthService($passwordServiceMock, $timeServiceMock, $tokenDaoMock, $userDaoMock);
|
||||||
$authService->loginFromCredentials('dummy', 'godzilla');
|
$authService->loginFromCredentials('dummy', 'godzilla');
|
||||||
|
|
||||||
$this->assertTrue($authService->isLoggedIn());
|
$this->assertTrue($authService->isLoggedIn());
|
||||||
$this->assertEquals($testUser, $authService->getLoggedInUser());
|
$this->assertEquals($testUser, $authService->getLoggedInUser());
|
||||||
|
$this->assertNotNull($authService->getLoginToken());
|
||||||
|
$this->assertNotNull($authService->getLoginToken()->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInvalidToken()
|
||||||
|
{
|
||||||
|
$passwordServiceMock = $this->getPasswordServiceMock();
|
||||||
|
$timeServiceMock = $this->getTimeServiceMock();
|
||||||
|
$tokenDaoMock = $this->getTokenDaoMock();
|
||||||
|
$userDaoMock = $this->getUserDaoMock();
|
||||||
|
|
||||||
|
$tokenDaoMock->expects($this->once())->method('getByName')->willReturn(null);
|
||||||
|
|
||||||
|
$this->setExpectedException(\Exception::class);
|
||||||
|
$authService = new \Szurubooru\Services\AuthService($passwordServiceMock, $timeServiceMock, $tokenDaoMock, $userDaoMock);
|
||||||
|
$authService->loginFromToken('');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testValidToken()
|
public function testValidToken()
|
||||||
{
|
{
|
||||||
$passwordServiceMock = $this->getPasswordServiceMock();
|
$passwordServiceMock = $this->getPasswordServiceMock();
|
||||||
|
$timeServiceMock = $this->getTimeServiceMock();
|
||||||
$tokenDaoMock = $this->getTokenDaoMock();
|
$tokenDaoMock = $this->getTokenDaoMock();
|
||||||
$userDaoMock = $this->getUserDaoMock();
|
$userDaoMock = $this->getUserDaoMock();
|
||||||
|
|
||||||
|
@ -71,11 +91,13 @@ class AuthServiceTest extends \PHPUnit_Framework_TestCase
|
||||||
$testToken->additionalData = $testUser->id;
|
$testToken->additionalData = $testUser->id;
|
||||||
$tokenDaoMock->expects($this->once())->method('getByName')->willReturn($testToken);
|
$tokenDaoMock->expects($this->once())->method('getByName')->willReturn($testToken);
|
||||||
|
|
||||||
$authService = new \Szurubooru\Services\AuthService($passwordServiceMock, $tokenDaoMock, $userDaoMock);
|
$authService = new \Szurubooru\Services\AuthService($passwordServiceMock, $timeServiceMock, $tokenDaoMock, $userDaoMock);
|
||||||
$authService->loginFromToken($testToken->name);
|
$authService->loginFromToken($testToken->name);
|
||||||
|
|
||||||
$this->assertTrue($authService->isLoggedIn());
|
$this->assertTrue($authService->isLoggedIn());
|
||||||
$this->assertEquals($testUser, $authService->getLoggedInUser());
|
$this->assertEquals($testUser, $authService->getLoggedInUser());
|
||||||
|
$this->assertNotNull($authService->getLoginToken());
|
||||||
|
$this->assertNotNull($authService->getLoginToken()->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getTokenDaoMock()
|
private function getTokenDaoMock()
|
||||||
|
@ -92,4 +114,9 @@ class AuthServiceTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
return $this->getMockBuilder(\Szurubooru\Services\PasswordService::class)->disableOriginalConstructor()->getMock();
|
return $this->getMockBuilder(\Szurubooru\Services\PasswordService::class)->disableOriginalConstructor()->getMock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getTimeServiceMock()
|
||||||
|
{
|
||||||
|
return $this->getMockBuilder(\Szurubooru\Services\TimeService::class)->disableOriginalConstructor()->getMock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue