szurubooru/src/Services/UserService.php

246 lines
7.9 KiB
PHP
Raw Normal View History

2014-08-31 09:03:11 +02:00
<?php
namespace Szurubooru\Services;
class UserService
{
private $config;
private $validator;
2014-08-31 17:42:48 +02:00
private $userDao;
private $userSearchService;
2014-08-31 17:42:48 +02:00
private $passwordService;
private $emailService;
private $fileService;
private $thumbnailService;
2014-08-31 17:42:48 +02:00
private $timeService;
private $tokenService;
2014-08-31 09:03:11 +02:00
2014-08-31 14:07:46 +02:00
public function __construct(
\Szurubooru\Config $config,
\Szurubooru\Validator $validator,
2014-08-31 14:07:46 +02:00
\Szurubooru\Dao\UserDao $userDao,
\Szurubooru\Dao\Services\UserSearchService $userSearchService,
2014-08-31 17:42:48 +02:00
\Szurubooru\Services\PasswordService $passwordService,
\Szurubooru\Services\EmailService $emailService,
\Szurubooru\Services\FileService $fileService,
\Szurubooru\Services\ThumbnailService $thumbnailService,
\Szurubooru\Services\TimeService $timeService,
\Szurubooru\Services\TokenService $tokenService)
2014-08-31 09:03:11 +02:00
{
$this->config = $config;
$this->validator = $validator;
2014-08-31 17:42:48 +02:00
$this->userDao = $userDao;
$this->userSearchService = $userSearchService;
2014-08-31 17:42:48 +02:00
$this->passwordService = $passwordService;
$this->emailService = $emailService;
$this->fileService = $fileService;
$this->thumbnailService = $thumbnailService;
2014-08-31 17:42:48 +02:00
$this->timeService = $timeService;
$this->tokenService = $tokenService;
}
public function getByNameOrEmail($userNameOrEmail, $allowUnconfirmed = false)
{
$user = $this->userDao->getByName($userNameOrEmail);
if ($user)
return $user;
$user = $this->userDao->getByEmail($userNameOrEmail, $allowUnconfirmed);
if ($user)
return $user;
throw new \InvalidArgumentException('User "' . $userNameOrEmail . '" was not found.');
2014-08-31 09:03:11 +02:00
}
2014-09-08 08:20:31 +02:00
public function getByName($userName)
2014-09-04 19:07:57 +02:00
{
2014-09-08 08:20:31 +02:00
$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;
2014-09-04 19:07:57 +02:00
}
public function getFiltered(\Szurubooru\FormData\SearchFormData $formData)
{
$this->validator->validate($formData);
$searchFilter = new \Szurubooru\Dao\SearchFilter($this->config->users->usersPerPage, $formData);
return $this->userSearchService->getFiltered($searchFilter);
}
public function createUser(\Szurubooru\FormData\RegistrationFormData $formData)
2014-08-31 09:03:11 +02:00
{
$formData->validate($this->validator);
2014-08-31 09:03:11 +02:00
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))
2014-08-31 17:42:48 +02:00
throw new \DomainException('User with this name already exists.');
$user = new \Szurubooru\Entities\User();
$user->name = $formData->userName;
$user->emailUnconfirmed = $formData->email;
2014-08-31 17:42:48 +02:00
$user->passwordHash = $this->passwordService->getHash($formData->password);
2014-09-01 19:43:49 +02:00
$user->accessRank = $this->userDao->hasAnyUsers()
? \Szurubooru\Entities\User::ACCESS_RANK_REGULAR_USER
: \Szurubooru\Entities\User::ACCESS_RANK_ADMINISTRATOR;
2014-08-31 17:42:48 +02:00
$user->registrationTime = $this->timeService->getCurrentTime();
2014-09-01 19:43:49 +02:00
$user->lastLoginTime = null;
$user->avatarStyle = \Szurubooru\Entities\User::AVATAR_STYLE_GRAVATAR;
2014-08-31 17:42:48 +02:00
2014-09-09 12:34:57 +02:00
$user = $this->sendActivationEmailIfNeeded($user);
2014-08-31 09:03:11 +02:00
return $this->userDao->save($user);
}
2014-09-05 13:50:51 +02:00
public function updateUser(\Szurubooru\Entities\User $user, \Szurubooru\FormData\UserEditFormData $formData)
2014-09-05 13:50:51 +02:00
{
$this->validator->validate($formData);
if ($formData->avatarStyle !== null)
{
$user->avatarStyle = \Szurubooru\Helpers\EnumHelper::avatarStyleFromString($formData->avatarStyle);
if ($formData->avatarContent)
{
$target = $this->getCustomAvatarSourcePath($user);
$this->fileService->saveFromBase64($formData->avatarContent, $target);
$this->thumbnailService->deleteUsedThumbnails($target);
}
}
2014-09-09 12:34:57 +02:00
if ($formData->userName !== null and $formData->userName !== $user->name)
{
$userWithThisEmail = $this->userDao->getByName($formData->userName);
2014-09-09 12:34:57 +02:00
if ($userWithThisEmail and $userWithThisEmail->id !== $user->id)
throw new \DomainException('User with this name already exists.');
$user->name = $formData->userName;
}
if ($formData->password !== null)
{
$user->passwordHash = $this->passwordService->getHash($formData->password);
}
2014-09-09 12:34:57 +02:00
if ($formData->email !== null and $formData->email !== $user->email)
{
if ($this->userDao->getByEmail($formData->email))
throw new \DomainException('User with this e-mail already exists.');
$user->emailUnconfirmed = $formData->email;
2014-09-09 12:34:57 +02:00
$user = $this->sendActivationEmailIfNeeded($user);
}
if ($formData->accessRank !== null)
{
$user->accessRank = \Szurubooru\Helpers\EnumHelper::accessRankFromString($formData->accessRank);
}
2014-09-07 14:50:16 +02:00
if ($formData->browsingSettings !== null)
{
$user->browsingSettings = $formData->browsingSettings;
}
return $this->userDao->save($user);
}
public function updateUserLastLoginTime(\Szurubooru\Entities\User $user)
{
$user->lastLoginTime = $this->timeService->getCurrentTime();
$this->userDao->save($user);
}
public function deleteUser(\Szurubooru\Entities\User $user)
{
$this->userDao->deleteById($user->id);
$avatarSource = $this->getCustomAvatarSourcePath($user);
$this->fileService->delete($avatarSource);
$this->thumbnailService->deleteUsedThumbnails($avatarSource);
2014-09-05 13:50:51 +02:00
}
public function sendPasswordResetEmail(\Szurubooru\Entities\User $user)
{
$token = $this->tokenService->createAndSaveToken($user->name, \Szurubooru\Entities\Token::PURPOSE_PASSWORD_RESET);
$this->emailService->sendPasswordResetEmail($user, $token);
}
public function finishPasswordReset(\Szurubooru\Entities\Token $token)
{
2014-09-09 12:34:57 +02:00
if ($token->purpose !== \Szurubooru\Entities\Token::PURPOSE_PASSWORD_RESET)
throw new \Exception('This token is not a password reset token.');
$user = $this->getByName($token->additionalData);
$newPassword = $this->passwordService->getRandomPassword();
$user->passwordHash = $this->passwordService->getHash($newPassword);
$this->userDao->save($user);
$this->tokenService->invalidateByName($token->name);
return $newPassword;
}
public function sendActivationEmail(\Szurubooru\Entities\User $user)
{
$token = $this->tokenService->createAndSaveToken($user->name, \Szurubooru\Entities\Token::PURPOSE_ACTIVATE);
$this->emailService->sendActivationEmail($user, $token);
}
public function finishActivation(\Szurubooru\Entities\Token $token)
{
2014-09-09 12:34:57 +02:00
if ($token->purpose !== \Szurubooru\Entities\Token::PURPOSE_ACTIVATE)
throw new \Exception('This token is not an activation token.');
$user = $this->getByName($token->additionalData);
$user = $this->confirmUserEmail($user);
2014-09-09 12:34:57 +02:00
$this->userDao->save($user);
$this->tokenService->invalidateByName($token->name);
}
public function getCustomAvatarSourcePath(\Szurubooru\Entities\User $user)
{
return 'avatars' . DIRECTORY_SEPARATOR . $user->id;
}
public function getBlankAvatarSourcePath()
{
return 'avatars' . DIRECTORY_SEPARATOR . 'blank.png';
}
2014-09-09 12:34:57 +02:00
private function sendActivationEmailIfNeeded(\Szurubooru\Entities\User $user)
{
2014-09-09 12:34:57 +02:00
if ($user->accessRank === \Szurubooru\Entities\User::ACCESS_RANK_ADMINISTRATOR or !$this->config->security->needEmailActivationToRegister)
{
$user = $this->confirmUserEmail($user);
}
else
{
$this->sendActivationEmail($user);
}
2014-09-09 12:34:57 +02:00
return $user;
}
private function confirmUserEmail(\Szurubooru\Entities\User $user)
{
//security issue:
//1. two users set their unconfirmed mail to godzilla@empire.gov
//2. activation mail is sent to both of them
//3. first user confirms, ok
//4. second user confirms, ok
//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:
//whoever confirms e-mail first, wins.
if ($this->userDao->getByEmail($user->emailUnconfirmed))
throw new \DomainException('This e-mail was already confirmed by someone else in the meantime.');
$user->email = $user->emailUnconfirmed;
$user->emailUnconfirmed = null;
2014-09-09 12:34:57 +02:00
return $user;
}
2014-08-31 09:03:11 +02:00
}