Simplified UserService

This commit is contained in:
Marcin Kurczewski 2014-09-10 18:22:15 +02:00
parent f81fe6bb65
commit 29b173de65
3 changed files with 202 additions and 55 deletions

View file

@ -5,9 +5,10 @@ class UserEditFormData implements \Szurubooru\IValidatable
{ {
public $userName; public $userName;
public $email; public $email;
public $accessRank;
public $password; public $password;
public $accessRank;
public $avatarStyle; public $avatarStyle;
public $avatarContent;
public $browsingSettings; public $browsingSettings;
public function __construct($inputReader = null) public function __construct($inputReader = null)

View file

@ -78,25 +78,17 @@ class UserService
{ {
$formData->validate($this->validator); $formData->validate($this->validator);
if ($formData->email and $this->userDao->getByEmail($formData->email))
throw new \DomainException('User with this e-mail already exists.');
if ($this->userDao->getByName($formData->userName))
throw new \DomainException('User with this name already exists.');
$user = new \Szurubooru\Entities\User(); $user = new \Szurubooru\Entities\User();
$user->name = $formData->userName; $user->registrationTime = $this->timeService->getCurrentTime();
$user->emailUnconfirmed = $formData->email; $user->lastLoginTime = null;
$user->passwordHash = $this->passwordService->getHash($formData->password);
$user->accessRank = $this->userDao->hasAnyUsers() $user->accessRank = $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;
$user->registrationTime = $this->timeService->getCurrentTime();
$user->lastLoginTime = null;
$user->avatarStyle = \Szurubooru\Entities\User::AVATAR_STYLE_GRAVATAR;
$user = $this->sendActivationEmailIfNeeded($user);
$this->updateUserName($user, $formData->userName);
$this->updateUserPassword($user, $formData->password);
$this->updateUserAvatarStyle($user, \Szurubooru\Entities\User::AVATAR_STYLE_GRAVATAR);
$this->updateUserEmail($user, $formData->email);
return $this->userDao->save($user); return $this->userDao->save($user);
} }
@ -106,51 +98,79 @@ class UserService
if ($formData->avatarStyle !== null) if ($formData->avatarStyle !== null)
{ {
$user->avatarStyle = \Szurubooru\Helpers\EnumHelper::avatarStyleFromString($formData->avatarStyle); $this->updateUserAvatarStyle(
if ($formData->avatarContent) $user,
{ \Szurubooru\Helpers\EnumHelper::avatarStyleFromString($formData->avatarStyle));
$target = $this->getCustomAvatarSourcePath($user);
$this->fileService->saveFromBase64($formData->avatarContent, $target);
$this->thumbnailService->deleteUsedThumbnails($target);
}
} }
if ($formData->userName !== null and $formData->userName !== $user->name) if ($formData->avatarContent !== null)
{ $this->updateUserAvatarContent($user, $formData->avatarContent);
$userWithThisEmail = $this->userDao->getByName($formData->userName);
if ($userWithThisEmail and $userWithThisEmail->id !== $user->id)
throw new \DomainException('User with this name already exists.');
$user->name = $formData->userName; if ($formData->userName !== null)
} $this->updateUserName($user, $formData->userName);
if ($formData->password !== null) if ($formData->password !== null)
{ $this->updateUserPassword($user, $formData->password);
$user->passwordHash = $this->passwordService->getHash($formData->password);
}
if ($formData->email !== null and $formData->email !== $user->email) if ($formData->email !== null)
{ $this->updateUserEmail($user, $formData->email);
if ($this->userDao->getByEmail($formData->email))
throw new \DomainException('User with this e-mail already exists.');
$user->emailUnconfirmed = $formData->email;
$user = $this->sendActivationEmailIfNeeded($user);
}
if ($formData->accessRank !== null) if ($formData->accessRank !== null)
{ $this->updateUserAccessRank($user, \Szurubooru\Helpers\EnumHelper::accessRankFromString($formData->accessRank));
$user->accessRank = \Szurubooru\Helpers\EnumHelper::accessRankFromString($formData->accessRank);
}
if ($formData->browsingSettings !== null) if ($formData->browsingSettings !== null)
{ $this->updateUserBrowsingSettings($user, $formData->browsingSettings);
$user->browsingSettings = $formData->browsingSettings;
}
return $this->userDao->save($user); return $this->userDao->save($user);
} }
public function updateUserAvatarStyle(\Szurubooru\Entities\User $user, $newAvatarStyle)
{
$user->avatarStyle = $newAvatarStyle;
}
public function updateUserAvatarContent(\Szurubooru\Entities\User $user, $newAvatarContentInBase64)
{
$target = $this->getCustomAvatarSourcePath($user);
$this->fileService->saveFromBase64($newAvatarContentInBase64, $target);
$this->thumbnailService->deleteUsedThumbnails($target);
}
public function updateUserName(\Szurubooru\Entities\User $user, $newName)
{
$this->assertNoUserWithThisName($user, $newName);
$user->name = $newName;
}
public function updateUserPassword(\Szurubooru\Entities\User $user, $newPassword)
{
$user->passwordHash = $this->passwordService->getHash($newPassword);
}
public function updateUserEmail(\Szurubooru\Entities\User $user, $newEmail)
{
if ($user->email === $newEmail)
{
$user->emailUnconfirmed = null;
}
else
{
$this->assertNoUserWithThisEmail($user, $newEmail);
$user->emailUnconfirmed = $newEmail;
$user = $this->sendActivationEmailIfNeeded($user);
}
}
public function updateUserAccessRank(\Szurubooru\Entities\User $user, $newAccessRank)
{
$user->accessRank = $newAccessRank;
}
public function updateUserBrowsingSettings(\Szurubooru\Entities\User $user, $newBrowsingSettings)
{
$user->browsingSettings = $newBrowsingSettings;
}
public function updateUserLastLoginTime(\Szurubooru\Entities\User $user) public function updateUserLastLoginTime(\Szurubooru\Entities\User $user)
{ {
$user->lastLoginTime = $this->timeService->getCurrentTime(); $user->lastLoginTime = $this->timeService->getCurrentTime();
@ -235,11 +255,27 @@ class UserService
//5. two users share the same mail --> problem. //5. two users share the same mail --> problem.
//by checking here again for users with such mail, this problem is solved with first-come first-serve approach: //by checking here again for users with such mail, this problem is solved with first-come first-serve approach:
//whoever confirms e-mail first, wins. //whoever confirms e-mail first, wins.
if ($this->userDao->getByEmail($user->emailUnconfirmed)) $this->assertNoUserWithThisEmail($user, $user->emailUnconfirmed);
throw new \DomainException('This e-mail was already confirmed by someone else in the meantime.');
$user->email = $user->emailUnconfirmed; if ($user->emailUnconfirmed)
$user->emailUnconfirmed = null; {
$user->email = $user->emailUnconfirmed;
$user->emailUnconfirmed = null;
}
return $user; return $user;
} }
private function assertNoUserWithThisName(\Szurubooru\Entities\User $owner, $nameToCheck)
{
$userWithThisName = $this->userDao->getByName($nameToCheck);
if ($userWithThisName and $userWithThisName->id !== $owner->id)
throw new \DomainException('User with this name already exists.');
}
private function assertNoUserWithThisEmail(\Szurubooru\Entities\User $owner, $emailToCheck)
{
$userWithThisEmail = $this->userDao->getByEmail($emailToCheck);
if ($userWithThisEmail and $userWithThisEmail->id !== $owner->id)
throw new \DomainException('User with this e-mail already exists.');
}
} }

View file

@ -31,7 +31,7 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
public function testGettingByName() public function testGettingByName()
{ {
$testUser = new \Szurubooru\Entities\User(); $testUser = new \Szurubooru\Entities\User;
$testUser->name = 'godzilla'; $testUser->name = 'godzilla';
$this->userDaoMock->expects($this->once())->method('getByName')->willReturn($testUser); $this->userDaoMock->expects($this->once())->method('getByName')->willReturn($testUser);
$userService = $this->getUserService(); $userService = $this->getUserService();
@ -49,7 +49,7 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
public function testGettingById() public function testGettingById()
{ {
$testUser = new \Szurubooru\Entities\User(); $testUser = new \Szurubooru\Entities\User;
$testUser->name = 'godzilla'; $testUser->name = 'godzilla';
$this->userDaoMock->expects($this->once())->method('getById')->willReturn($testUser); $this->userDaoMock->expects($this->once())->method('getById')->willReturn($testUser);
$userService = $this->getUserService(); $userService = $this->getUserService();
@ -67,7 +67,7 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
public function testGettingFilteredUsers() public function testGettingFilteredUsers()
{ {
$mockUser = new \Szurubooru\Entities\User(); $mockUser = new \Szurubooru\Entities\User;
$mockUser->name = 'user'; $mockUser->name = 'user';
$expected = [$mockUser]; $expected = [$mockUser];
$this->userSearchService->method('getFiltered')->willReturn($expected); $this->userSearchService->method('getFiltered')->willReturn($expected);
@ -121,7 +121,7 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
$this->userDaoMock->method('hasAnyUsers')->willReturn(true); $this->userDaoMock->method('hasAnyUsers')->willReturn(true);
$this->userDaoMock->method('save')->will($this->returnArgument(0)); $this->userDaoMock->method('save')->will($this->returnArgument(0));
$testToken = new \Szurubooru\Entities\Token(); $testToken = new \Szurubooru\Entities\Token;
$this->tokenServiceMock->expects($this->once())->method('createAndSaveToken')->willReturn($testToken); $this->tokenServiceMock->expects($this->once())->method('createAndSaveToken')->willReturn($testToken);
$this->emailServiceMock->expects($this->once())->method('sendActivationEmail')->with( $this->emailServiceMock->expects($this->once())->method('sendActivationEmail')->with(
$this->anything(), $this->anything(),
@ -162,8 +162,11 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
$formData->password = 'password'; $formData->password = 'password';
$formData->email = 'email'; $formData->email = 'email';
$otherUser = new \Szurubooru\Entities\User;
$otherUser->id = 'yes, i exist in database';
$this->userDaoMock->method('hasAnyUsers')->willReturn(true); $this->userDaoMock->method('hasAnyUsers')->willReturn(true);
$this->userDaoMock->method('getByName')->willReturn(new \Szurubooru\Entities\User()); $this->userDaoMock->method('getByName')->willReturn($otherUser);
$this->userDaoMock->method('save')->will($this->returnArgument(0)); $this->userDaoMock->method('save')->will($this->returnArgument(0));
$userService = $this->getUserService(); $userService = $this->getUserService();
@ -172,6 +175,113 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
$savedUser = $userService->createUser($formData); $savedUser = $userService->createUser($formData);
} }
public function testUpdatingName()
{
$testUser = new \Szurubooru\Entities\User;
$testUser->name = 'wojtek';
$formData = new \Szurubooru\FormData\UserEditFormData;
$formData->userName = 'sebastian';
$this->userDaoMock->method('save')->will($this->returnArgument(0));
$userService = $this->getUserService();
$savedUser = $userService->updateUser($testUser, $formData);
$this->assertEquals('sebastian', $savedUser->name);
}
public function testUpdatingNameToExisting()
{
$testUser = new \Szurubooru\Entities\User;
$testUser->name = 'wojtek';
$formData = new \Szurubooru\FormData\UserEditFormData;
$formData->userName = 'sebastian';
$otherUser = new \Szurubooru\Entities\User;
$otherUser->id = 'yes, i exist in database';
$this->userDaoMock->method('getByName')->willReturn($otherUser);
$this->userDaoMock->method('save')->will($this->returnArgument(0));
$this->setExpectedException(\Exception::class, 'User with this name already exists');
$userService = $this->getUserService();
$savedUser = $userService->updateUser($testUser, $formData);
}
public function testUpdatingEmailWithoutConfirmation()
{
$testUser = new \Szurubooru\Entities\User;
$this->configMock->set('security/needEmailActivationToRegister', false);
$formData = new \Szurubooru\FormData\UserEditFormData;
$formData->email = 'hikari@geofront.gov';
$this->userDaoMock->method('save')->will($this->returnArgument(0));
$userService = $this->getUserService();
$savedUser = $userService->updateUser($testUser, $formData);
$this->assertEquals('hikari@geofront.gov', $savedUser->email);
$this->assertNull($savedUser->emailUnconfirmed);
}
public function testUpdatingEmailWithConfirmation()
{
$testUser = new \Szurubooru\Entities\User;
$this->configMock->set('security/needEmailActivationToRegister', true);
$formData = new \Szurubooru\FormData\UserEditFormData;
$formData->email = 'hikari@geofront.gov';
$this->tokenServiceMock->method('createAndSaveToken')->willReturn(new \Szurubooru\Entities\Token());
$this->userDaoMock->method('save')->will($this->returnArgument(0));
$userService = $this->getUserService();
$savedUser = $userService->updateUser($testUser, $formData);
$this->assertNull($savedUser->email);
$this->assertEquals('hikari@geofront.gov', $savedUser->emailUnconfirmed);
}
public function testUpdatingEmailWithConfirmationToExisting()
{
$testUser = new \Szurubooru\Entities\User;
$this->configMock->set('security/needEmailActivationToRegister', true);
$formData = new \Szurubooru\FormData\UserEditFormData;
$formData->email = 'hikari@geofront.gov';
$otherUser = new \Szurubooru\Entities\User;
$otherUser->id = 'yes, i exist in database';
$this->tokenServiceMock->method('createAndSaveToken')->willReturn(new \Szurubooru\Entities\Token());
$this->userDaoMock->method('getByEmail')->willReturn($otherUser);
$this->userDaoMock->method('save')->will($this->returnArgument(0));
$this->setExpectedException(\Exception::class, 'User with this e-mail already exists');
$userService = $this->getUserService();
$userService->updateUser($testUser, $formData);
}
public function testUpdatingEmailToAlreadyConfirmed()
{
$testUser = new \Szurubooru\Entities\User;
$testUser->email = 'hikari@geofront.gov';
$testUser->emailUnconfirmed = 'coolcat32@sakura.ne.jp';
$testUser->id = 5;
$formData = new \Szurubooru\FormData\UserEditFormData;
$formData->email = 'hikari@geofront.gov';
$otherUser = new \Szurubooru\Entities\User;
$otherUser->id = 5;
$this->tokenServiceMock->method('createAndSaveToken')->willReturn(new \Szurubooru\Entities\Token());
$this->userDaoMock->method('getByEmail')->willReturn($otherUser);
$this->userDaoMock->method('save')->will($this->returnArgument(0));
$userService = $this->getUserService();
$savedUser = $userService->updateUser($testUser, $formData);
$this->assertEquals('hikari@geofront.gov', $savedUser->email);
$this->assertNull($savedUser->emailUnconfirmed);
}
private function getUserService() private function getUserService()
{ {
return new \Szurubooru\Services\UserService( return new \Szurubooru\Services\UserService(