From dabac68ad41dae11711c8e6ee25d796901f430a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D?= Date: Sun, 24 Mar 2024 19:21:03 +0100 Subject: [PATCH] chore(tests): UT for User repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rubén D --- .../Helpers/Account/AccountSearchHelper.php | 8 +- .../Controllers/User/EditPassController.php | 2 +- .../web/Controllers/User/UserSaveBase.php | 4 +- .../web/Controllers/User/UserViewBase.php | 2 +- .../UserProfile/UserProfileViewBase.php | 2 +- .../UserSettingsGeneral/SaveController.php | 8 +- .../UserSettingsManager/IndexController.php | 8 +- app/modules/web/Forms/UserForm.php | 2 +- app/modules/web/Forms/UserProfileForm.php | 2 +- .../material-blue/views/itemshow/user.inc | 4 +- .../views/itemshow/user_group.inc | 4 +- .../views/itemshow/user_pass.inc | 2 +- .../views/itemshow/user_profile.inc | 2 +- .../views/usersettings/general.inc | 9 +- lib/SP/DataModel/User.php | 150 ---- lib/SP/DataModel/UserPassData.php | 97 -- lib/SP/DataModel/UserToUserGroupData.php | 106 --- lib/SP/Domain/Account/Models/Account.php | 4 +- .../Domain/Account/Models/AccountToUser.php | 36 + lib/SP/Domain/Account/Models/PublicLink.php | 2 + lib/SP/Domain/Auth/Services/Login.php | 4 +- lib/SP/Domain/Client/Models/Client.php | 1 + lib/SP/Domain/Import/Services/LdapImport.php | 2 +- .../Install/Services/InstallerService.php | 4 +- lib/SP/Domain/User/Models/User.php | 186 ++++ lib/SP/Domain/User/Models/UserGroup.php | 2 + .../User/Models/UserPreferences.php} | 10 +- .../User/Models}/UserProfile.php | 11 +- lib/SP/Domain/User/Models/UserToUserGroup.php | 54 ++ .../Ports/UserProfileServiceInterface.php | 2 +- lib/SP/Domain/User/Ports/UserRepository.php | 135 ++- .../User/Ports/UserServiceInterface.php | 8 +- .../User/Services/UserLoginResponse.php | 16 +- .../Domain/User/Services/UserPassService.php | 9 +- .../User/Services/UserProfileService.php | 2 +- lib/SP/Domain/User/Services/UserService.php | 23 +- .../User/Services/UserToUserGroupService.php | 4 +- .../Client/Repositories/Client.php | 22 +- lib/SP/Infrastructure/Database/QueryData.php | 4 +- .../Infrastructure/User/Repositories/User.php | 682 ++++++++++++++ .../User/Repositories/UserBaseRepository.php | 849 ------------------ .../UserProfileBaseRepository.php | 38 +- .../UserToUserGroupBaseRepository.php | 20 +- tests/SPT/Core/LanguageTest.php | 4 +- .../Account/Services/AccountSearchTest.php | 2 +- .../Domain/Import/Services/LdapImportTest.php | 2 +- tests/SPT/Generators/PluginGenerator.php | 2 +- tests/SPT/Generators/UserDataGenerator.php | 39 +- .../Generators/UserProfileDataGenerator.php | 2 +- .../User/Repositories/UserTest.php | 684 ++++++++++++++ 50 files changed, 1882 insertions(+), 1395 deletions(-) delete mode 100644 lib/SP/DataModel/User.php delete mode 100644 lib/SP/DataModel/UserPassData.php delete mode 100644 lib/SP/DataModel/UserToUserGroupData.php create mode 100644 lib/SP/Domain/Account/Models/AccountToUser.php create mode 100644 lib/SP/Domain/User/Models/User.php rename lib/SP/{DataModel/UserPreferencesData.php => Domain/User/Models/UserPreferences.php} (94%) rename lib/SP/{DataModel => Domain/User/Models}/UserProfile.php (92%) create mode 100644 lib/SP/Domain/User/Models/UserToUserGroup.php create mode 100644 lib/SP/Infrastructure/User/Repositories/User.php delete mode 100644 lib/SP/Infrastructure/User/Repositories/UserBaseRepository.php create mode 100644 tests/SPT/Infrastructure/User/Repositories/UserTest.php diff --git a/app/modules/web/Controllers/Helpers/Account/AccountSearchHelper.php b/app/modules/web/Controllers/Helpers/Account/AccountSearchHelper.php index 8dc56c7c..d8557a76 100644 --- a/app/modules/web/Controllers/Helpers/Account/AccountSearchHelper.php +++ b/app/modules/web/Controllers/Helpers/Account/AccountSearchHelper.php @@ -29,7 +29,6 @@ use DI\NotFoundException; use SP\Core\Acl\Acl; use SP\Core\Application; use SP\DataModel\ProfileData; -use SP\DataModel\UserPreferencesData; use SP\Domain\Account\Adapters\AccountSearchItem; use SP\Domain\Account\Dtos\AccountSearchFilterDto; use SP\Domain\Account\Ports\AccountSearchConstants; @@ -42,6 +41,7 @@ use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\Http\RequestInterface; use SP\Domain\Tag\Ports\TagService; +use SP\Domain\User\Models\UserPreferences; use SP\Html\DataGrid\Action\DataGridAction; use SP\Html\DataGrid\Action\DataGridActionSearch; use SP\Html\DataGrid\DataGrid; @@ -141,7 +141,7 @@ final class AccountSearchHelper extends HelperBase return $accountSearchFilter; } - $userPreferences = $this->context->getUserData()->getPreferences() ?? new UserPreferencesData(); + $userPreferences = $this->context->getUserData()->getPreferences() ?? new UserPreferences(); $limitCount = $userPreferences->getResultsPerPage() > 0 ? $userPreferences->getResultsPerPage() : $this->configData->getAccountCount(); @@ -214,7 +214,7 @@ final class AccountSearchHelper extends HelperBase || $this->accountSearchFilter->isSearchFavorites() || $this->accountSearchFilter->isSortViews()); - $userPreferences = $this->context->getUserData()->getPreferences() ?? new UserPreferencesData(); + $userPreferences = $this->context->getUserData()->getPreferences() ?? new UserPreferences(); AccountSearchItem::$accountLink = $userPreferences->isAccountLink(); AccountSearchItem::$topNavbar = $userPreferences->isTopNavbar(); @@ -289,7 +289,7 @@ final class AccountSearchHelper extends HelperBase $gridPager->setFilterOn($this->filterOn); $gridPager->setSourceAction(new DataGridActionSearch(AclActionsInterface::ACCOUNT_SEARCH)); - $userPreferences = $this->context->getUserData()->getPreferences() ?? new UserPreferencesData(); + $userPreferences = $this->context->getUserData()->getPreferences() ?? new UserPreferences(); $showOptionalActions = $userPreferences->isOptionalActions() || $userPreferences->isResultsAsCards() || ($userPreferences->getUserId() === 0 diff --git a/app/modules/web/Controllers/User/EditPassController.php b/app/modules/web/Controllers/User/EditPassController.php index a781cc41..e18fc817 100644 --- a/app/modules/web/Controllers/User/EditPassController.php +++ b/app/modules/web/Controllers/User/EditPassController.php @@ -28,8 +28,8 @@ namespace SP\Modules\Web\Controllers\User; use Exception; use JsonException; use SP\Core\Events\Event; -use SP\DataModel\User; use SP\Domain\Core\Acl\AclActionsInterface; +use SP\Domain\User\Models\User; use SP\Http\JsonMessage; use SP\Modules\Web\Controllers\Traits\JsonTrait; diff --git a/app/modules/web/Controllers/User/UserSaveBase.php b/app/modules/web/Controllers/User/UserSaveBase.php index 6083d769..45f2a3a5 100644 --- a/app/modules/web/Controllers/User/UserSaveBase.php +++ b/app/modules/web/Controllers/User/UserSaveBase.php @@ -28,12 +28,12 @@ namespace SP\Modules\Web\Controllers\User; use Defuse\Crypto\Exception\EnvironmentIsBrokenException; use PHPMailer\PHPMailer\Exception; use SP\Core\Application; -use SP\DataModel\User; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\CustomField\Ports\CustomFieldDataService; use SP\Domain\Notification\Ports\MailService; +use SP\Domain\User\Models\User; use SP\Domain\User\Ports\UserPassRecoverServiceInterface; use SP\Domain\User\Ports\UserServiceInterface; use SP\Domain\User\Services\UserPassRecoverService; @@ -73,7 +73,7 @@ abstract class UserSaveBase extends ControllerBase /** * @param int $userId - * @param User $userData + * @param \SP\Domain\User\Models\User $userData * * @throws EnvironmentIsBrokenException * @throws Exception diff --git a/app/modules/web/Controllers/User/UserViewBase.php b/app/modules/web/Controllers/User/UserViewBase.php index 5757ea17..ed8d552b 100644 --- a/app/modules/web/Controllers/User/UserViewBase.php +++ b/app/modules/web/Controllers/User/UserViewBase.php @@ -27,13 +27,13 @@ namespace SP\Modules\Web\Controllers\User; use SP\Core\Acl\Acl; use SP\Core\Application; -use SP\DataModel\User; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Core\Acl\AclActionsInterface; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\CustomField\Ports\CustomFieldDataService; +use SP\Domain\User\Models\User; use SP\Domain\User\Ports\UserGroupServiceInterface; use SP\Domain\User\Ports\UserProfileServiceInterface; use SP\Domain\User\Ports\UserServiceInterface; diff --git a/app/modules/web/Controllers/UserProfile/UserProfileViewBase.php b/app/modules/web/Controllers/UserProfile/UserProfileViewBase.php index 249a52f4..80a5071e 100644 --- a/app/modules/web/Controllers/UserProfile/UserProfileViewBase.php +++ b/app/modules/web/Controllers/UserProfile/UserProfileViewBase.php @@ -28,13 +28,13 @@ namespace SP\Modules\Web\Controllers\UserProfile; use SP\Core\Acl\Acl; use SP\Core\Application; use SP\DataModel\ProfileData; -use SP\DataModel\UserProfile; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Core\Acl\AclActionsInterface; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\CustomField\Ports\CustomFieldDataService; +use SP\Domain\User\Models\UserProfile; use SP\Domain\User\Ports\UserProfileServiceInterface; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Modules\Web\Controllers\ControllerBase; diff --git a/app/modules/web/Controllers/UserSettingsGeneral/SaveController.php b/app/modules/web/Controllers/UserSettingsGeneral/SaveController.php index 0f4669ac..281150fb 100644 --- a/app/modules/web/Controllers/UserSettingsGeneral/SaveController.php +++ b/app/modules/web/Controllers/UserSettingsGeneral/SaveController.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -28,7 +28,7 @@ use Exception; use JsonException; use SP\Core\Application; use SP\Core\Events\Event; -use SP\DataModel\UserPreferencesData; +use SP\Domain\User\Models\UserPreferences; use SP\Domain\User\Ports\UserServiceInterface; use SP\Domain\User\Services\UserLoginResponse; use SP\Domain\User\Services\UserService; @@ -89,9 +89,9 @@ final class SaveController extends SimpleControllerBase /** * @param UserLoginResponse $userData * - * @return UserPreferencesData + * @return UserPreferences */ - private function getUserPreferencesData(UserLoginResponse $userData): UserPreferencesData + private function getUserPreferencesData(UserLoginResponse $userData): UserPreferences { $userPreferencesData = clone $userData->getPreferences(); diff --git a/app/modules/web/Controllers/UserSettingsManager/IndexController.php b/app/modules/web/Controllers/UserSettingsManager/IndexController.php index a0402cf6..091cbb12 100644 --- a/app/modules/web/Controllers/UserSettingsManager/IndexController.php +++ b/app/modules/web/Controllers/UserSettingsManager/IndexController.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -28,9 +28,9 @@ use SP\Core\Acl\Acl; use SP\Core\Application; use SP\Core\Events\Event; use SP\Core\Language; -use SP\DataModel\UserPreferencesData; use SP\Domain\Core\Acl\AclActionsInterface; use SP\Domain\Core\Events\EventDispatcherInterface; +use SP\Domain\User\Models\UserPreferences; use SP\Modules\Web\Controllers\ControllerBase; use SP\Modules\Web\Controllers\Helpers\TabsHelper; use SP\Mvc\Controller\ExtensibleTabControllerInterface; @@ -100,7 +100,7 @@ final class IndexController extends ControllerBase implements ExtensibleTabContr $template->addTemplate('general'); $userData = $this->session->getUserData(); - $userPreferences = $userData->getPreferences() ?? new UserPreferencesData(); + $userPreferences = $userData->getPreferences() ?? new UserPreferences(); $template->assign( 'langs', @@ -139,7 +139,7 @@ final class IndexController extends ControllerBase implements ExtensibleTabContr } /** - * @return \SP\Domain\Core\Events\EventDispatcherInterface + * @return EventDispatcherInterface */ public function getEventDispatcher(): EventDispatcherInterface { diff --git a/app/modules/web/Forms/UserForm.php b/app/modules/web/Forms/UserForm.php index 490ada6a..4eee876f 100644 --- a/app/modules/web/Forms/UserForm.php +++ b/app/modules/web/Forms/UserForm.php @@ -24,10 +24,10 @@ namespace SP\Modules\Web\Forms; -use SP\DataModel\User; use SP\Domain\Core\Acl\AclActionsInterface; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\Core\Exceptions\ValidationException; +use SP\Domain\User\Models\User; /** * Class UserForm diff --git a/app/modules/web/Forms/UserProfileForm.php b/app/modules/web/Forms/UserProfileForm.php index 76b2588f..4d69cd82 100644 --- a/app/modules/web/Forms/UserProfileForm.php +++ b/app/modules/web/Forms/UserProfileForm.php @@ -25,10 +25,10 @@ namespace SP\Modules\Web\Forms; use SP\DataModel\ProfileData; -use SP\DataModel\UserProfile; use SP\Domain\Core\Acl\AclActionsInterface; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\Core\Exceptions\ValidationException; +use SP\Domain\User\Models\UserProfile; /** * Class UserProfileForm diff --git a/app/modules/web/themes/material-blue/views/itemshow/user.inc b/app/modules/web/themes/material-blue/views/itemshow/user.inc index 6ad49f30..6950719e 100644 --- a/app/modules/web/themes/material-blue/views/itemshow/user.inc +++ b/app/modules/web/themes/material-blue/views/itemshow/user.inc @@ -23,16 +23,16 @@ */ /** - * @var User $user + * @var \SP\Domain\User\Models\User $user * @var ThemeIconsInterface $icons * @var ConfigDataInterface $configData * @var callable $_getvar * @var TemplateInterface $this */ -use SP\DataModel\User; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Core\UI\ThemeIconsInterface; +use SP\Domain\User\Models\User; use SP\Mvc\View\Components\SelectItem; use SP\Mvc\View\TemplateInterface; diff --git a/app/modules/web/themes/material-blue/views/itemshow/user_group.inc b/app/modules/web/themes/material-blue/views/itemshow/user_group.inc index 1ad9dfc7..56b3d648 100644 --- a/app/modules/web/themes/material-blue/views/itemshow/user_group.inc +++ b/app/modules/web/themes/material-blue/views/itemshow/user_group.inc @@ -23,7 +23,7 @@ */ /** - * @var UserToUserGroupData $groupUsers + * @var UserToUserGroup $groupUsers * @var UserGroup $group * @var ThemeIconsInterface $icons * @var ConfigDataInterface $configData @@ -31,10 +31,10 @@ * @var TemplateInterface $this */ -use SP\DataModel\UserToUserGroupData; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Core\UI\ThemeIconsInterface; use SP\Domain\User\Models\UserGroup; +use SP\Domain\User\Models\UserToUserGroup; use SP\Mvc\View\Components\SelectItem; use SP\Mvc\View\TemplateInterface; diff --git a/app/modules/web/themes/material-blue/views/itemshow/user_pass.inc b/app/modules/web/themes/material-blue/views/itemshow/user_pass.inc index 602ee8d2..79e6cbe3 100644 --- a/app/modules/web/themes/material-blue/views/itemshow/user_pass.inc +++ b/app/modules/web/themes/material-blue/views/itemshow/user_pass.inc @@ -30,9 +30,9 @@ * @var TemplateInterface $this */ -use SP\DataModel\User; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Core\UI\ThemeIconsInterface; +use SP\Domain\User\Models\User; use SP\Mvc\View\TemplateInterface; $user = $_getvar('user'); diff --git a/app/modules/web/themes/material-blue/views/itemshow/user_profile.inc b/app/modules/web/themes/material-blue/views/itemshow/user_profile.inc index abeaeccf..86b5b252 100644 --- a/app/modules/web/themes/material-blue/views/itemshow/user_profile.inc +++ b/app/modules/web/themes/material-blue/views/itemshow/user_profile.inc @@ -32,9 +32,9 @@ */ use SP\DataModel\ProfileData; -use SP\DataModel\UserProfile; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Core\UI\ThemeIconsInterface; +use SP\Domain\User\Models\UserProfile; use SP\Mvc\View\TemplateInterface; $profile = $_getvar('profile'); diff --git a/app/modules/web/themes/material-blue/views/usersettings/general.inc b/app/modules/web/themes/material-blue/views/usersettings/general.inc index 81ff7d49..7de5af13 100644 --- a/app/modules/web/themes/material-blue/views/usersettings/general.inc +++ b/app/modules/web/themes/material-blue/views/usersettings/general.inc @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -23,15 +23,16 @@ */ /** - * @var UserPreferencesData $userPreferences - * @var \SP\Domain\Core\UI\ThemeIconsInterface $icons + * @var \SP\Domain\User\Models\UserPreferences $userPreferences + * @var ThemeIconsInterface $icons * @var ConfigDataInterface $configData * @var callable $_getvar * @var TemplateInterface $this */ -use SP\DataModel\UserPreferencesData; use SP\Domain\Config\Ports\ConfigDataInterface; +use SP\Domain\Core\UI\ThemeIconsInterface; +use SP\Domain\User\Models\UserPreferences; use SP\Mvc\View\Components\SelectItem; use SP\Mvc\View\TemplateInterface; diff --git a/lib/SP/DataModel/User.php b/lib/SP/DataModel/User.php deleted file mode 100644 index 984cd51f..00000000 --- a/lib/SP/DataModel/User.php +++ /dev/null @@ -1,150 +0,0 @@ -. - */ - -namespace SP\DataModel; - -use SP\Domain\Common\Models\ItemWithIdAndNameModel; - -/** - * Class UserBasicData - * - * @package SP\DataModel - */ -class User extends UserPassData implements ItemWithIdAndNameModel -{ - protected ?string $login = null; - protected ?string $ssoLogin = null; - protected ?string $name = null; - protected ?string $email = null; - protected ?string $notes = null; - protected ?int $userGroupId = null; - protected ?int $userProfileId = null; - protected ?int $isAdminApp = null; - protected bool $isAdminAcc = false; - protected bool $isDisabled = false; - protected bool $isChangePass = false; - protected bool $isChangedPass = false; - protected bool $isLdap = false; - protected ?int $loginCount = null; - protected ?string $lastLogin = null; - protected ?string $lastUpdate = null; - protected ?bool $isMigrate = false; - protected ?string $preferences = null; - protected ?string $userGroupName = null; - - public function getLoginCount(): int - { - return (int)$this->loginCount; - } - - public function getLastLogin(): ?string - { - return $this->lastLogin; - } - - public function getLastUpdate(): ?string - { - return $this->lastUpdate; - } - - public function isMigrate(): int - { - return (int)$this->isMigrate; - } - - public function getPreferences(): ?string - { - return $this->preferences; - } - - public function getEmail(): ?string - { - return $this->email; - } - - public function getNotes(): ?string - { - return $this->notes; - } - - public function getUserGroupId(): int - { - return (int)$this->userGroupId; - } - - public function getUserProfileId(): int - { - return (int)$this->userProfileId; - } - - public function isAdminApp(): int - { - return (int)$this->isAdminApp; - } - - public function isAdminAcc(): int - { - return (int)$this->isAdminAcc; - } - - public function isDisabled(): int - { - return (int)$this->isDisabled; - } - - public function isChangePass(): int - { - return (int)$this->isChangePass; - } - - public function isLdap(): int - { - return (int)$this->isLdap; - } - - public function getLogin(): ?string - { - return $this->login; - } - - public function getName(): ?string - { - return $this->name; - } - - public function getUserGroupName(): ?string - { - return $this->userGroupName; - } - - public function isChangedPass(): int - { - return (int)$this->isChangedPass; - } - - public function getSsoLogin(): ?string - { - return $this->ssoLogin; - } -} diff --git a/lib/SP/DataModel/UserPassData.php b/lib/SP/DataModel/UserPassData.php deleted file mode 100644 index 4a72a6ac..00000000 --- a/lib/SP/DataModel/UserPassData.php +++ /dev/null @@ -1,97 +0,0 @@ -. - */ - -namespace SP\DataModel; - -use SP\Domain\Common\Models\Model; - -/** - * Class UserPassData - * - * @package SP\DataModel - */ -class UserPassData extends Model -{ - protected ?int $id = null; - protected ?string $pass = null; - protected ?string $hashSalt = null; - protected ?string $mPass = null; - protected ?string $mKey = null; - protected ?int $lastUpdateMPass = null; - - public function getPass(): ?string - { - return $this->pass; - } - - public function setPass(string $pass) - { - $this->pass = $pass; - } - - public function getHashSalt(): ?string - { - return $this->hashSalt; - } - - public function getMPass(): ?string - { - return $this->mPass; - } - - public function setMPass(string $mPass) - { - $this->mPass = $mPass; - } - - public function getMKey(): ?string - { - return $this->mKey; - } - - public function setMKey(string $mKey) - { - $this->mKey = $mKey; - } - - public function getLastUpdateMPass(): int - { - return (int)$this->lastUpdateMPass; - } - - public function setLastUpdateMPass(int $lastUpdateMPass) - { - $this->lastUpdateMPass = (int)$lastUpdateMPass; - } - - public function getId(): ?int - { - return (int)$this->id; - } - - public function setId(int $id) - { - $this->id = (int)$id; - } -} diff --git a/lib/SP/DataModel/UserToUserGroupData.php b/lib/SP/DataModel/UserToUserGroupData.php deleted file mode 100644 index 9f83f93d..00000000 --- a/lib/SP/DataModel/UserToUserGroupData.php +++ /dev/null @@ -1,106 +0,0 @@ -. - */ - -namespace SP\DataModel; - -use SP\Domain\Common\Models\Model; - -defined('APP_ROOT') || die(); - -/** - * Class GroupUserData - * - * @package SP\DataModel - */ -class UserToUserGroupData extends Model -{ - /** - * @var int - */ - public $userGroupId = 0; - /** - * @var int - */ - public $userId = 0; - /** - * @var array - */ - public $users = []; - - /** - * @return int - */ - public function getUserGroupId() - { - return (int)$this->userGroupId; - } - - /** - * @param int $userGroupId - */ - public function setUserGroupId($userGroupId) - { - $this->userGroupId = $userGroupId; - } - - /** - * @return int - */ - public function getUserId() - { - return (int)$this->userId; - } - - /** - * @param int $userId - */ - public function setUserId($userId) - { - $this->userId = $userId; - } - - /** - * @return array - */ - public function getUsers() - { - return $this->users; - } - - /** - * @param array $users - */ - public function setUsers(array $users) - { - $this->users = $users; - } - - /** - * @param int $user - */ - public function addUser($user) - { - $this->users[] = (int)$user; - } -} diff --git a/lib/SP/Domain/Account/Models/Account.php b/lib/SP/Domain/Account/Models/Account.php index ebaf729e..162b13ab 100644 --- a/lib/SP/Domain/Account/Models/Account.php +++ b/lib/SP/Domain/Account/Models/Account.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -33,6 +33,8 @@ final class Account extends Model { use AccountUseCases; + public const TABLE = 'Account'; + protected ?int $id = null; protected ?int $userId = null; protected ?int $userGroupId = null; diff --git a/lib/SP/Domain/Account/Models/AccountToUser.php b/lib/SP/Domain/Account/Models/AccountToUser.php new file mode 100644 index 00000000..35e4625b --- /dev/null +++ b/lib/SP/Domain/Account/Models/AccountToUser.php @@ -0,0 +1,36 @@ +. + */ + +namespace SP\Domain\Account\Models; + +use SP\Domain\Common\Models\Model; + +/** + * Class AccountToUser + */ +final class AccountToUser extends Model +{ + + public const TABLE = 'AccountToUser'; +} diff --git a/lib/SP/Domain/Account/Models/PublicLink.php b/lib/SP/Domain/Account/Models/PublicLink.php index f0443150..0c1c68c3 100644 --- a/lib/SP/Domain/Account/Models/PublicLink.php +++ b/lib/SP/Domain/Account/Models/PublicLink.php @@ -32,6 +32,8 @@ use SP\Domain\Common\Models\Model; */ class PublicLink extends Model implements ItemWithIdAndNameModel { + public const TABLE = 'PublicLink'; + protected ?int $id = null; protected ?int $itemId = null; protected ?string $hash = null; diff --git a/lib/SP/Domain/Auth/Services/Login.php b/lib/SP/Domain/Auth/Services/Login.php index bc9e8b62..8d6e4d20 100644 --- a/lib/SP/Domain/Auth/Services/Login.php +++ b/lib/SP/Domain/Auth/Services/Login.php @@ -31,7 +31,6 @@ use SP\Core\Application; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; use SP\DataModel\UserLoginData; -use SP\DataModel\UserPreferencesData; use SP\Domain\Auth\Dtos\LoginResponse; use SP\Domain\Auth\Ports\LdapAuthService; use SP\Domain\Auth\Ports\LoginService; @@ -46,6 +45,7 @@ use SP\Domain\Crypt\Ports\TemporaryMasterPassService; use SP\Domain\Http\RequestInterface; use SP\Domain\Security\Dtos\TrackRequest; use SP\Domain\Security\Ports\TrackService; +use SP\Domain\User\Models\UserPreferences; use SP\Domain\User\Ports\UserPassRecoverServiceInterface; use SP\Domain\User\Ports\UserPassServiceInterface; use SP\Domain\User\Ports\UserProfileServiceInterface; @@ -402,7 +402,7 @@ final class Login extends Service implements LoginService $this->context->setLocale($userLoginResponse->getPreferences()->getLang()); if ($this->configData->isDemoEnabled()) { - $userLoginResponse->setPreferences(new UserPreferencesData()); + $userLoginResponse->setPreferences(new UserPreferences()); } $this->eventDispatcher->notify( diff --git a/lib/SP/Domain/Client/Models/Client.php b/lib/SP/Domain/Client/Models/Client.php index 66d86b60..3afdc748 100644 --- a/lib/SP/Domain/Client/Models/Client.php +++ b/lib/SP/Domain/Client/Models/Client.php @@ -32,6 +32,7 @@ use SP\Domain\Common\Models\Model; */ class Client extends Model implements ItemWithIdAndNameModel { + public const TABLE = 'Client'; protected ?int $isGlobal = null; protected ?int $id = null; protected ?string $name = null; diff --git a/lib/SP/Domain/Import/Services/LdapImport.php b/lib/SP/Domain/Import/Services/LdapImport.php index 9c0f90d9..1bca861c 100644 --- a/lib/SP/Domain/Import/Services/LdapImport.php +++ b/lib/SP/Domain/Import/Services/LdapImport.php @@ -28,7 +28,6 @@ use Exception; use SP\Core\Application; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; -use SP\DataModel\User; use SP\Domain\Auth\Ports\LdapActionsService; use SP\Domain\Auth\Ports\LdapConnectionInterface; use SP\Domain\Auth\Ports\LdapService; @@ -36,6 +35,7 @@ use SP\Domain\Common\Services\Service; use SP\Domain\Import\Dtos\LdapImportParamsDto; use SP\Domain\Import\Dtos\LdapImportResultsDto; use SP\Domain\Import\Ports\LdapImportService; +use SP\Domain\User\Models\User; use SP\Domain\User\Models\UserGroup; use SP\Domain\User\Ports\UserGroupServiceInterface; use SP\Domain\User\Ports\UserServiceInterface; diff --git a/lib/SP/Domain/Install/Services/InstallerService.php b/lib/SP/Domain/Install/Services/InstallerService.php index 5429a352..bfadd33e 100644 --- a/lib/SP/Domain/Install/Services/InstallerService.php +++ b/lib/SP/Domain/Install/Services/InstallerService.php @@ -28,8 +28,6 @@ namespace SP\Domain\Install\Services; use Exception; use SP\Core\Crypt\Hash; use SP\DataModel\ProfileData; -use SP\DataModel\User; -use SP\DataModel\UserProfile; use SP\Domain\Config\Models\Config; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Config\Ports\ConfigFileService; @@ -41,7 +39,9 @@ use SP\Domain\Core\Exceptions\SPException; use SP\Domain\Http\RequestInterface; use SP\Domain\Install\Adapters\InstallData; use SP\Domain\Install\Ports\InstallerServiceInterface; +use SP\Domain\User\Models\User; use SP\Domain\User\Models\UserGroup; +use SP\Domain\User\Models\UserProfile; use SP\Domain\User\Ports\UserGroupServiceInterface; use SP\Domain\User\Ports\UserProfileServiceInterface; use SP\Domain\User\Ports\UserServiceInterface; diff --git a/lib/SP/Domain/User/Models/User.php b/lib/SP/Domain/User/Models/User.php new file mode 100644 index 00000000..1c1af405 --- /dev/null +++ b/lib/SP/Domain/User/Models/User.php @@ -0,0 +1,186 @@ +. + */ + +namespace SP\Domain\User\Models; + +use SP\Domain\Common\Attributes\Hydratable; +use SP\Domain\Common\Models\ItemWithIdAndNameModel; +use SP\Domain\Common\Models\Model; +use SP\Domain\Common\Models\SerializedModel; + +/** + * Class User + */ +#[Hydratable('preferences', [UserPreferences::class])] +class User extends Model implements ItemWithIdAndNameModel +{ + use SerializedModel; + + public const TABLE = 'User'; + + protected ?int $id = null; + protected ?string $pass = null; + protected ?string $hashSalt = null; + protected ?string $mPass = null; + protected ?string $mKey = null; + protected ?int $lastUpdateMPass = null; + protected ?string $login = null; + protected ?string $ssoLogin = null; + protected ?string $name = null; + protected ?string $email = null; + protected ?string $notes = null; + protected ?int $userGroupId = null; + protected ?int $userProfileId = null; + protected ?bool $isAdminApp = null; + protected ?bool $isAdminAcc = null; + protected ?bool $isDisabled = null; + protected ?bool $isChangePass = null; + protected ?bool $isChangedPass = null; + protected ?bool $isLdap = null; + protected ?int $loginCount = null; + protected ?string $lastLogin = null; + protected ?string $lastUpdate = null; + protected ?bool $isMigrate = null; + protected ?string $preferences = null; + + public function getLoginCount(): ?int + { + return $this->loginCount; + } + + public function getLastLogin(): ?string + { + return $this->lastLogin; + } + + public function getLastUpdate(): ?string + { + return $this->lastUpdate; + } + + public function isMigrate(): ?bool + { + return $this->isMigrate; + } + + public function getPreferences(): ?string + { + return $this->preferences; + } + + public function getEmail(): ?string + { + return $this->email; + } + + public function getNotes(): ?string + { + return $this->notes; + } + + public function getUserGroupId(): ?int + { + return $this->userGroupId; + } + + public function getUserProfileId(): ?int + { + return $this->userProfileId; + } + + public function isAdminApp(): ?bool + { + return $this->isAdminApp; + } + + public function isAdminAcc(): ?bool + { + return $this->isAdminAcc; + } + + public function isDisabled(): ?bool + { + return $this->isDisabled; + } + + public function isChangePass(): ?bool + { + return $this->isChangePass; + } + + public function isLdap(): ?bool + { + return $this->isLdap; + } + + public function getLogin(): ?string + { + return $this->login; + } + + public function getName(): ?string + { + return $this->name; + } + + public function isChangedPass(): ?bool + { + return $this->isChangedPass; + } + + public function getSsoLogin(): ?string + { + return $this->ssoLogin; + } + + public function getId(): ?int + { + return $this->id; + } + + public function getPass(): ?string + { + return $this->pass; + } + + public function getHashSalt(): ?string + { + return $this->hashSalt; + } + + public function getMPass(): ?string + { + return $this->mPass; + } + + public function getMKey(): ?string + { + return $this->mKey; + } + + public function getLastUpdateMPass(): ?int + { + return $this->lastUpdateMPass; + } +} diff --git a/lib/SP/Domain/User/Models/UserGroup.php b/lib/SP/Domain/User/Models/UserGroup.php index 3d150484..fc4f2a00 100644 --- a/lib/SP/Domain/User/Models/UserGroup.php +++ b/lib/SP/Domain/User/Models/UserGroup.php @@ -32,6 +32,8 @@ use SP\Domain\Common\Models\Model; */ class UserGroup extends Model implements ItemWithIdAndNameModel { + public const TABLE = 'UserGroup'; + protected ?int $id = null; protected ?string $name = null; protected ?string $description = null; diff --git a/lib/SP/DataModel/UserPreferencesData.php b/lib/SP/Domain/User/Models/UserPreferences.php similarity index 94% rename from lib/SP/DataModel/UserPreferencesData.php rename to lib/SP/Domain/User/Models/UserPreferences.php index d8df2855..fd26c1f5 100644 --- a/lib/SP/DataModel/UserPreferencesData.php +++ b/lib/SP/Domain/User/Models/UserPreferences.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -22,16 +22,14 @@ * along with sysPass. If not, see . */ -namespace SP\DataModel; +namespace SP\Domain\User\Models; use SP\Domain\Common\Models\Model; /** - * Class UserPreferencesData - * - * @package SP\DataModel + * Class UserPreferences */ -class UserPreferencesData extends Model +class UserPreferences extends Model { protected ?string $lang = null; protected ?string $theme = null; diff --git a/lib/SP/DataModel/UserProfile.php b/lib/SP/Domain/User/Models/UserProfile.php similarity index 92% rename from lib/SP/DataModel/UserProfile.php rename to lib/SP/Domain/User/Models/UserProfile.php index 04c28a34..bae6a710 100644 --- a/lib/SP/DataModel/UserProfile.php +++ b/lib/SP/Domain/User/Models/UserProfile.php @@ -22,20 +22,19 @@ * along with sysPass. If not, see . */ -namespace SP\DataModel; +namespace SP\Domain\User\Models; +use SP\DataModel\ProfileData; use SP\Domain\Common\Models\ItemWithIdAndNameModel; use SP\Domain\Common\Models\Model; -defined('APP_ROOT') || die(); - /** - * Class ProfileBaseData - * - * @package SP\DataModel + * Class UserProfile */ class UserProfile extends Model implements ItemWithIdAndNameModel { + public const TABLE = 'UserProfile'; + protected ?int $id = null; protected ?string $name = null; protected ?ProfileData $profile = null; diff --git a/lib/SP/Domain/User/Models/UserToUserGroup.php b/lib/SP/Domain/User/Models/UserToUserGroup.php new file mode 100644 index 00000000..4ffbd17d --- /dev/null +++ b/lib/SP/Domain/User/Models/UserToUserGroup.php @@ -0,0 +1,54 @@ +. + */ + +namespace SP\Domain\User\Models; + +use SP\Domain\Common\Models\Model; + +/** + * Class UserToUserGroup + */ +class UserToUserGroup extends Model +{ + public const TABLE = 'UserToUserGroup'; + + protected ?int $userGroupId = null; + protected ?int $userId = null; + protected ?array $users = null; + + public function getUserGroupId(): ?int + { + return $this->userGroupId; + } + + public function getUserId(): ?int + { + return $this->userId; + } + + public function getUsers(): ?array + { + return $this->users; + } +} diff --git a/lib/SP/Domain/User/Ports/UserProfileServiceInterface.php b/lib/SP/Domain/User/Ports/UserProfileServiceInterface.php index 186348c2..0347fba7 100644 --- a/lib/SP/Domain/User/Ports/UserProfileServiceInterface.php +++ b/lib/SP/Domain/User/Ports/UserProfileServiceInterface.php @@ -25,10 +25,10 @@ namespace SP\Domain\User\Ports; use SP\DataModel\ItemSearchData; -use SP\DataModel\UserProfile; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\User\Models\UserProfile; use SP\Infrastructure\Common\Repositories\DuplicatedItemException; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Infrastructure\Database\QueryResult; diff --git a/lib/SP/Domain/User/Ports/UserRepository.php b/lib/SP/Domain/User/Ports/UserRepository.php index dcf344f8..f8d0d49d 100644 --- a/lib/SP/Domain/User/Ports/UserRepository.php +++ b/lib/SP/Domain/User/Ports/UserRepository.php @@ -24,57 +24,71 @@ namespace SP\Domain\User\Ports; -use SP\DataModel\User; -use SP\DataModel\UserPreferencesData; +use Exception; +use JsonException; +use SP\DataModel\ItemSearchData; use SP\Domain\Common\Ports\Repository; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; -use SP\Domain\User\Services\UpdatePassRequest; +use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\User\Models\User as UserModel; +use SP\Domain\User\Models\UserPreferences; +use SP\Infrastructure\Common\Repositories\DuplicatedItemException; use SP\Infrastructure\Database\QueryResult; /** * Class UserRepository * - * @package SP\Infrastructure\User\Repositories + * @template T of UserModel */ interface UserRepository extends Repository { /** - * Updates an user's pass + * Updates an item * - * @param int $id - * @param UpdatePassRequest $passRequest + * @param UserModel $user + * + * @return int + * @throws ConstraintException + * @throws QueryException + * @throws DuplicatedItemException + */ + public function update(UserModel $user): int; + + /** + * Updates a user's pass + * + * @param UserModel $user * * @return int * @throws ConstraintException * @throws QueryException */ - public function updatePassById(int $id, UpdatePassRequest $passRequest): int; + public function updatePassById(UserModel $user): int; /** * @param $login string * - * @return QueryResult + * @return QueryResult * @throws ConstraintException * @throws QueryException + * @throws Exception */ public function getByLogin(string $login): QueryResult; /** * Returns items' basic information * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException + * @return QueryResult */ - public function getBasicInfo(): QueryResult; + public function getAll(): QueryResult; /** * Updates user's master password * - * @param int $id - * @param string $pass - * @param string $key + * @param int $id + * @param string $pass + * @param string $key * * @return int * @throws ConstraintException @@ -94,7 +108,7 @@ interface UserRepository extends Repository public function updateLastLoginById(int $id): int; /** - * @param string $login + * @param string $login * * @return bool * @throws ConstraintException @@ -103,65 +117,120 @@ interface UserRepository extends Repository public function checkExistsByLogin(string $login): bool; /** - * @param User $itemData + * @param UserModel $user * * @return int * @throws ConstraintException * @throws QueryException */ - public function updateOnLogin(User $itemData): int; + public function updateOnLogin(UserModel $user): int; /** * Updates an user's pass * - * @param int $id - * @param UserPreferencesData $userPreferencesData + * @param int $id + * @param UserPreferences $userPreferences * * @return int * @throws ConstraintException * @throws QueryException + * @throws JsonException */ - public function updatePreferencesById(int $id, UserPreferencesData $userPreferencesData): int; + public function updatePreferencesById(int $id, UserPreferences $userPreferences): int; /** * Obtener el email de los usuarios de un grupo * - * @param int $groupId + * @param int $groupId * - * @return QueryResult + * @return QueryResult * @throws ConstraintException * @throws QueryException + * @throws Exception */ public function getUserEmailForGroup(int $groupId): QueryResult; /** * Obtener el email de los usuarios * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException + * @return QueryResult */ public function getUserEmail(): QueryResult; /** * Return the email of the given user's id * - * @param int[] $ids + * @param array $ids * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException + * @return QueryResult */ public function getUserEmailById(array $ids): QueryResult; /** * Returns the usage of the given user's id * - * @param int $id + * @param int $id + * + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + * @throws Exception + */ + public function getUsageForUser(int $id): QueryResult; + + /** + * Deletes an item + * + * @param int $id * * @return QueryResult * @throws ConstraintException * @throws QueryException */ - public function getUsageForUser(int $id): QueryResult; + public function delete(int $id): QueryResult; + + /** + * Returns the item for given id + * + * @param int $id + * + * @return QueryResult + * @throws QueryException + * @throws ConstraintException + * @throws Exception + */ + public function getById(int $id): QueryResult; + + /** + * Deletes all the items for given ids + * + * @param array $ids + * + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + */ + public function deleteByIdBatch(array $ids): QueryResult; + + /** + * Searches for items by a given filter + * + * @param ItemSearchData $itemSearchData + * + * @return QueryResult + * @throws QueryException + * @throws ConstraintException + * @throws Exception + */ + public function search(ItemSearchData $itemSearchData): QueryResult; + + /** + * Creates an item + * + * @param UserModel $user + * + * @return QueryResult + * @throws SPException + */ + public function create(UserModel $user): QueryResult; } diff --git a/lib/SP/Domain/User/Ports/UserServiceInterface.php b/lib/SP/Domain/User/Ports/UserServiceInterface.php index 831fc832..d3af8bf6 100644 --- a/lib/SP/Domain/User/Ports/UserServiceInterface.php +++ b/lib/SP/Domain/User/Ports/UserServiceInterface.php @@ -26,12 +26,12 @@ namespace SP\Domain\User\Ports; use Defuse\Crypto\Exception\CryptoException; use SP\DataModel\ItemSearchData; -use SP\DataModel\User; -use SP\DataModel\UserPreferencesData; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\User\Models\User; +use SP\Domain\User\Models\UserPreferences; use SP\Domain\User\Services\UserLoginRequest; use SP\Domain\User\Services\UserService; use SP\Infrastructure\Common\Repositories\DuplicatedItemException; @@ -147,7 +147,7 @@ interface UserServiceInterface * @throws ConstraintException * @throws QueryException */ - public function updatePreferencesById(int $userId, UserPreferencesData $userPreferencesData): int; + public function updatePreferencesById(int $userId, UserPreferences $userPreferencesData): int; /** * @throws ConstraintException @@ -158,7 +158,7 @@ interface UserServiceInterface /** * Get all items from the service's repository * - * @return User[] + * @return \SP\Domain\User\Models\User[] * @throws ConstraintException * @throws QueryException */ diff --git a/lib/SP/Domain/User/Services/UserLoginResponse.php b/lib/SP/Domain/User/Services/UserLoginResponse.php index 3b51aeb8..9c5a126e 100644 --- a/lib/SP/Domain/User/Services/UserLoginResponse.php +++ b/lib/SP/Domain/User/Services/UserLoginResponse.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -24,7 +24,7 @@ namespace SP\Domain\User\Services; -use SP\DataModel\UserPreferencesData; +use SP\Domain\User\Models\UserPreferences; /** * Class UserLoginResponse @@ -47,9 +47,9 @@ final class UserLoginResponse private bool $isChangePass = false; private bool $isChangedPass = false; private bool $isLdap = false; - private bool $isMigrate = false; - private ?UserPreferencesData $preferences = null; - private ?string $pass = null; + private bool $isMigrate = false; + private ?UserPreferences $preferences = null; + private ?string $pass = null; private ?string $hashSalt = null; private ?string $mPass = null; private ?string $mKey = null; @@ -212,12 +212,12 @@ final class UserLoginResponse return $this; } - public function getPreferences(): ?UserPreferencesData + public function getPreferences(): ?UserPreferences { return $this->preferences; } - public function setPreferences(UserPreferencesData $preferences): UserLoginResponse + public function setPreferences(UserPreferences $preferences): UserLoginResponse { $this->preferences = $preferences; @@ -320,4 +320,4 @@ final class UserLoginResponse return $this; } -} \ No newline at end of file +} diff --git a/lib/SP/Domain/User/Services/UserPassService.php b/lib/SP/Domain/User/Services/UserPassService.php index 93adeb2b..67e90227 100644 --- a/lib/SP/Domain/User/Services/UserPassService.php +++ b/lib/SP/Domain/User/Services/UserPassService.php @@ -30,7 +30,6 @@ use SP\Core\Crypt\Crypt; use SP\Core\Crypt\Hash; use SP\DataModel\UserLoginData; use SP\Domain\Common\Services\Service; -use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Config\Ports\ConfigService; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; @@ -38,7 +37,6 @@ use SP\Domain\Core\Exceptions\SPException; use SP\Domain\User\Ports\UserPassServiceInterface; use SP\Domain\User\Ports\UserRepository; use SP\Infrastructure\Common\Repositories\NoSuchItemException; -use SP\Infrastructure\User\Repositories\UserBaseRepository; /** * Class UserPassService @@ -58,9 +56,8 @@ final class UserPassService extends Service implements UserPassServiceInterface // Comprobar la clave maestra con la clave del usuario anterior public const MPASS_CHECKOLD = 4; - private ConfigDataInterface $configData; - private UserBaseRepository $userRepository; - private ConfigService $configService; + private UserRepository $userRepository; + private ConfigService $configService; public function __construct( Application $application, @@ -71,8 +68,6 @@ final class UserPassService extends Service implements UserPassServiceInterface $this->userRepository = $userRepository; $this->configService = $configService; - - $this->configData = $this->config->getConfigData(); } /** diff --git a/lib/SP/Domain/User/Services/UserProfileService.php b/lib/SP/Domain/User/Services/UserProfileService.php index 2c7ede81..a5cef70a 100644 --- a/lib/SP/Domain/User/Services/UserProfileService.php +++ b/lib/SP/Domain/User/Services/UserProfileService.php @@ -27,13 +27,13 @@ namespace SP\Domain\User\Services; use SP\Core\Application; use SP\DataModel\ItemSearchData; use SP\DataModel\ProfileData; -use SP\DataModel\UserProfile; use SP\Domain\Common\Services\Service; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Common\Services\ServiceItemTrait; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\User\Models\UserProfile; use SP\Domain\User\Ports\UserProfileRepository; use SP\Domain\User\Ports\UserProfileServiceInterface; use SP\Infrastructure\Common\Repositories\DuplicatedItemException; diff --git a/lib/SP/Domain/User/Services/UserService.php b/lib/SP/Domain/User/Services/UserService.php index 39a1a7a3..fd53f79b 100644 --- a/lib/SP/Domain/User/Services/UserService.php +++ b/lib/SP/Domain/User/Services/UserService.php @@ -28,21 +28,20 @@ use Defuse\Crypto\Exception\CryptoException; use SP\Core\Application; use SP\Core\Crypt\Hash; use SP\DataModel\ItemSearchData; -use SP\DataModel\User; -use SP\DataModel\UserPreferencesData; use SP\Domain\Common\Services\Service; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Common\Services\ServiceItemTrait; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\User\Models\User; +use SP\Domain\User\Models\UserPreferences; use SP\Domain\User\Ports\UserPassServiceInterface; use SP\Domain\User\Ports\UserRepository; use SP\Domain\User\Ports\UserServiceInterface; use SP\Infrastructure\Common\Repositories\DuplicatedItemException; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Infrastructure\Database\QueryResult; -use SP\Infrastructure\User\Repositories\UserBaseRepository; use SP\Util\Util; /** @@ -54,8 +53,8 @@ final class UserService extends Service implements UserServiceInterface { use ServiceItemTrait; - private UserBaseRepository $userRepository; - private UserPassService $userPassService; + private UserRepository $userRepository; + private UserPassServiceInterface $userPassService; public function __construct( Application $application, @@ -98,13 +97,13 @@ final class UserService extends Service implements UserServiceInterface /** * Returns user's preferences object */ - public static function getUserPreferences(?string $preferences): UserPreferencesData + public static function getUserPreferences(?string $preferences): UserPreferences { if (!empty($preferences)) { - return Util::unserialize(UserPreferencesData::class, $preferences, 'SP\UserPreferences'); + return Util::unserialize(UserPreferences::class, $preferences, 'SP\UserPreferences'); } - return new UserPreferencesData(); + return new UserPreferences(); } /** @@ -185,7 +184,7 @@ final class UserService extends Service implements UserServiceInterface } /** - * @param int[] $ids + * @param int[] $ids * * @throws ServiceException * @throws ConstraintException @@ -321,7 +320,7 @@ final class UserService extends Service implements UserServiceInterface * @throws ConstraintException * @throws QueryException */ - public function updatePreferencesById(int $userId, UserPreferencesData $userPreferencesData): int + public function updatePreferencesById(int $userId, UserPreferences $userPreferencesData): int { return $this->userRepository->updatePreferencesById( $userId, @@ -354,7 +353,7 @@ final class UserService extends Service implements UserServiceInterface */ public function getAll(): array { - return $this->userRepository->getBasicInfo()->getDataAsArray(); + return $this->userRepository->getAll()->getDataAsArray(); } /** @@ -385,7 +384,7 @@ final class UserService extends Service implements UserServiceInterface /** * Return the email of the given user's id * - * @param int[] $ids + * @param int[] $ids * * @throws ConstraintException * @throws QueryException diff --git a/lib/SP/Domain/User/Services/UserToUserGroupService.php b/lib/SP/Domain/User/Services/UserToUserGroupService.php index 05f23914..84669cc9 100644 --- a/lib/SP/Domain/User/Services/UserToUserGroupService.php +++ b/lib/SP/Domain/User/Services/UserToUserGroupService.php @@ -25,11 +25,11 @@ namespace SP\Domain\User\Services; use SP\Core\Application; -use SP\DataModel\UserToUserGroupData; use SP\Domain\Common\Services\Service; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\User\Models\UserToUserGroup; use SP\Domain\User\Ports\UserToUserGroupRepositoryInterface; use SP\Domain\User\Ports\UserToUserGroupServiceInterface; use SP\Infrastructure\Common\Repositories\NoSuchItemException; @@ -81,7 +81,7 @@ final class UserToUserGroupService extends Service implements UserToUserGroupSer { $usersId = []; - /** @var UserToUserGroupData $userToUserGroupData */ + /** @var \SP\Domain\User\Models\UserToUserGroup $userToUserGroupData */ $userByGroup = $this->userToUserGroupRepository->getById($id)->getDataAsArray(); foreach ($userByGroup as $userToUserGroupData) { diff --git a/lib/SP/Infrastructure/Client/Repositories/Client.php b/lib/SP/Infrastructure/Client/Repositories/Client.php index 22051ee2..8f0fd04e 100644 --- a/lib/SP/Infrastructure/Client/Repositories/Client.php +++ b/lib/SP/Infrastructure/Client/Repositories/Client.php @@ -48,8 +48,6 @@ final class Client extends BaseRepository implements ClientRepository { use RepositoryItemTrait; - public const TABLE = 'Client'; - /** * Creates an item * @@ -67,7 +65,7 @@ final class Client extends BaseRepository implements ClientRepository $query = $this->queryFactory ->newInsert() - ->into(self::TABLE) + ->into(ClientModel::TABLE) ->cols($client->toArray(null, ['id', 'hash'])) ->col('hash', $this->makeItemHash($client->getName())); @@ -89,7 +87,7 @@ final class Client extends BaseRepository implements ClientRepository $query = $this->queryFactory ->newSelect() ->cols(['id']) - ->from(self::TABLE) + ->from(ClientModel::TABLE) ->where('hash = :hash') ->orWhere('name = :name') ->bindValues( @@ -120,7 +118,7 @@ final class Client extends BaseRepository implements ClientRepository $query = $this->queryFactory ->newUpdate() - ->table(self::TABLE) + ->table(ClientModel::TABLE) ->cols($client->toArray(null, ['id', 'hash'])) ->where('id = :id') ->limit(1) @@ -150,7 +148,7 @@ final class Client extends BaseRepository implements ClientRepository $query = $this->queryFactory ->newSelect() ->cols(['id']) - ->from(self::TABLE) + ->from(ClientModel::TABLE) ->where('(hash = :hash OR name = :name)') ->where('id <> :id') ->bindValues( @@ -175,7 +173,7 @@ final class Client extends BaseRepository implements ClientRepository { $query = $this->queryFactory ->newSelect() - ->from(self::TABLE) + ->from(ClientModel::TABLE) ->cols(ClientModel::getCols()) ->where('id = :id') ->bindValues(['id' => $clientId]) @@ -197,7 +195,7 @@ final class Client extends BaseRepository implements ClientRepository { $query = $this->queryFactory ->newSelect() - ->from(self::TABLE) + ->from(ClientModel::TABLE) ->cols(ClientModel::getCols()) ->where('(name = :name OR hash = :hash)') ->bindValues(['name' => $name, 'hash' => $this->makeItemHash($name)]) @@ -217,7 +215,7 @@ final class Client extends BaseRepository implements ClientRepository { $query = $this->queryFactory ->newSelect() - ->from(self::TABLE) + ->from(ClientModel::TABLE) ->cols(ClientModel::getCols()); return $this->db->doSelect(QueryData::buildWithMapper($query, ClientModel::class)); @@ -240,7 +238,7 @@ final class Client extends BaseRepository implements ClientRepository $query = $this->queryFactory ->newDelete() - ->from(self::TABLE) + ->from(ClientModel::TABLE) ->where('id IN (:ids)', ['ids' => $clientIds]); $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while deleting the clients')); @@ -261,7 +259,7 @@ final class Client extends BaseRepository implements ClientRepository { $query = $this->queryFactory ->newDelete() - ->from(self::TABLE) + ->from(ClientModel::TABLE) ->where('id = :id') ->bindValues(['id' => $id]); @@ -281,7 +279,7 @@ final class Client extends BaseRepository implements ClientRepository { $query = $this->queryFactory ->newSelect() - ->from(self::TABLE) + ->from(ClientModel::TABLE) ->cols(ClientModel::getCols(['hash'])) ->orderBy(['name']) ->limit($itemSearchData->getLimitCount()) diff --git a/lib/SP/Infrastructure/Database/QueryData.php b/lib/SP/Infrastructure/Database/QueryData.php index 164eda99..a3d6249c 100644 --- a/lib/SP/Infrastructure/Database/QueryData.php +++ b/lib/SP/Infrastructure/Database/QueryData.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -33,8 +33,6 @@ use function SP\__u; /** * Class QueryData - * - * @package SP\Storage */ final class QueryData { diff --git a/lib/SP/Infrastructure/User/Repositories/User.php b/lib/SP/Infrastructure/User/Repositories/User.php new file mode 100644 index 00000000..ea799271 --- /dev/null +++ b/lib/SP/Infrastructure/User/Repositories/User.php @@ -0,0 +1,682 @@ +. + */ + +namespace SP\Infrastructure\User\Repositories; + +use Exception; +use JsonException; +use SP\DataModel\ItemSearchData; +use SP\Domain\Account\Models\Account as AccountModel; +use SP\Domain\Account\Models\AccountToUser as AccountToUserModel; +use SP\Domain\Account\Models\PublicLink as PublicLinkModel; +use SP\Domain\Client\Models\Client as ClientModel; +use SP\Domain\Core\Exceptions\ConstraintException; +use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\User\Models\User as UserModel; +use SP\Domain\User\Models\UserGroup as UserGroupModel; +use SP\Domain\User\Models\UserPreferences; +use SP\Domain\User\Models\UserProfile as UserProfileModel; +use SP\Domain\User\Models\UserToUserGroup as UserToUserGroupModel; +use SP\Domain\User\Ports\UserRepository; +use SP\Infrastructure\Common\Repositories\BaseRepository; +use SP\Infrastructure\Common\Repositories\DuplicatedItemException; +use SP\Infrastructure\Common\Repositories\RepositoryItemTrait; +use SP\Infrastructure\Database\QueryData; +use SP\Infrastructure\Database\QueryResult; + +use function SP\__u; + +/** + * Class User + * + * @template T of UserModel + */ +final class User extends BaseRepository implements UserRepository +{ + use RepositoryItemTrait; + + /** + * Updates an item + * + * @param UserModel $user + * + * @return int + * @throws ConstraintException + * @throws QueryException + * @throws DuplicatedItemException + */ + public function update(UserModel $user): int + { + if ($this->checkDuplicatedOnUpdate($user)) { + throw DuplicatedItemException::error(__u('Duplicated user login/email')); + } + + $query = $this->queryFactory + ->newUpdate() + ->table(UserModel::TABLE) + ->cols($user->toArray(null, ['id', 'hashSalt'])) + ->set('lastUpdate', 'NOW()') + ->where('id = :id', ['id' => $user->getId()]) + ->limit(1); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while updating the user')); + + return $this->db->doQuery($queryData)->getAffectedNumRows(); + } + + /** + * Checks whether the item is duplicated on updating + * + * @param UserModel $user + * + * @return bool + * @throws ConstraintException + * @throws QueryException + */ + private function checkDuplicatedOnUpdate(UserModel $user): bool + { + $query = $this->queryFactory + ->newSelect() + ->cols(['id']) + ->from(UserModel::TABLE) + ->where('id <> :id') + ->where( + 'UPPER(login) = UPPER(login) + OR (UPPER(:ssoLogin) = UPPER(ssoLogin) AND ssoLogin IS NOT NULL AND ssoLogin <> \'\' + OR (UPPER(:email) = UPPER(email) AND email IS NOT NULL AND email <> \'\'' + ) + ->bindValues( + [ + 'id' => $user->getId(), + 'login' => $user->getLogin(), + 'ssoLogin' => $user->getSsoLogin(), + 'email' => $user->getEmail(), + ] + ); + + return $this->db->doQuery(QueryData::build($query))->getNumRows() > 0; + } + + /** + * Updates a user's pass + * + * @param UserModel $user + * + * @return int + * @throws ConstraintException + * @throws QueryException + */ + public function updatePassById(UserModel $user): int + { + $query = $this->queryFactory + ->newUpdate() + ->table(UserModel::TABLE) + ->cols($user->toArray(['pass', 'isChangePass', 'isChangedPass'])) + ->set('lastUpdate', 'NOW()') + ->set('hashSalt', '') + ->set('isMigrate', 0) + ->where('id = :id', ['id' => $user->getId()]) + ->limit(1); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while updating the password')); + + return $this->db->doQuery($queryData)->getAffectedNumRows(); + } + + /** + * Deletes an item + * + * @param int $id + * + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + */ + public function delete(int $id): QueryResult + { + $query = $this->queryFactory + ->newDelete() + ->from(UserModel::TABLE) + ->where('id = :id', ['id' => $id]) + ->limit(1); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while deleting the user')); + + return $this->db->doQuery($queryData); + } + + /** + * Returns the item for given id + * + * @param int $id + * + * @return QueryResult + * @throws QueryException + * @throws ConstraintException + * @throws Exception + */ + public function getById(int $id): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->cols(UserModel::getColsWithPreffix(UserModel::TABLE)) + ->cols(UserGroupModel::getColsWithPreffix(UserGroupModel::TABLE)) + ->from(UserModel::TABLE) + ->innerJoin( + UserGroupModel::TABLE, + sprintf('%s.id = %s.userGroupId', UserGroupModel::TABLE, UserModel::TABLE) + ) + ->where('User.id = :id') + ->bindValues(['id' => $id]) + ->limit(1); + + return $this->db->doSelect(QueryData::buildWithMapper($query, UserModel::class)); + } + + /** + * Deletes all the items for given ids + * + * @param array $ids + * + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + */ + public function deleteByIdBatch(array $ids): QueryResult + { + if (count($ids) === 0) { + return new QueryResult(); + } + + $query = $this->queryFactory + ->newDelete() + ->from(UserModel::TABLE) + ->where('id IN (:ids)', ['ids' => $ids]); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while deleting the users')); + + return $this->db->doQuery($queryData); + } + + /** + * Searches for items by a given filter + * + * @param ItemSearchData $itemSearchData + * + * @return QueryResult + * @throws QueryException + * @throws ConstraintException + * @throws Exception + */ + public function search(ItemSearchData $itemSearchData): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->from(UserModel::TABLE) + ->innerJoin( + UserGroupModel::TABLE, + sprintf('%s.id = %s.userGroupId', UserGroupModel::TABLE, UserModel::TABLE) + ) + ->innerJoin( + UserProfileModel::TABLE, + sprintf('%s.id = %s.userProfileId', UserProfileModel::TABLE, UserModel::TABLE) + ) + ->cols(UserModel::getCols(['hash'])) + ->cols(UserGroupModel::getColsWithPreffix(UserGroupModel::TABLE)) + ->cols(UserProfileModel::getColsWithPreffix(UserProfileModel::TABLE)) + ->orderBy(['name']) + ->limit($itemSearchData->getLimitCount()) + ->offset($itemSearchData->getLimitStart()); + + if (!$this->context->getUserData()->getIsAdminApp()) { + $query->where(sprintf('%s.isAdminApp = 0', UserModel::TABLE)); + } + + if (!empty($itemSearchData->getSeachString())) { + $query->where(sprintf('%s.name LIKE :name OR %s.login LIKE :login', UserModel::TABLE, UserModel::TABLE)); + + $search = '%' . $itemSearchData->getSeachString() . '%'; + + $query->bindValues(['name' => $search, 'login' => $search]); + } + + $queryData = QueryData::build($query)->setMapClassName(UserModel::class); + + return $this->db->doSelect($queryData, true); + } + + /** + * Creates an item + * + * @param UserModel $user + * + * @return QueryResult + * @throws SPException + */ + public function create(UserModel $user): QueryResult + { + if ($this->checkDuplicatedOnAdd($user)) { + throw DuplicatedItemException::error(__u('Duplicated user login/email')); + } + + $query = $this->queryFactory + ->newInsert() + ->into(UserModel::TABLE) + ->cols($user->toArray(null, ['id', 'hashSalt'])) + ->set('hashSalt', ''); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while creating the user')); + + return $this->db->doQuery($queryData); + } + + /** + * Checks whether the item is duplicated on adding + * + * @param UserModel $user + * + * @return bool + * @throws ConstraintException + * @throws QueryException + */ + private function checkDuplicatedOnAdd(UserModel $user): bool + { + $query = $this->queryFactory + ->newSelect() + ->cols(['id']) + ->from(UserModel::TABLE) + ->where( + 'UPPER(login) = UPPER(login) + OR (UPPER(:ssoLogin) = UPPER(ssoLogin) AND ssoLogin IS NOT NULL AND ssoLogin <> \'\' + OR (UPPER(:email) = UPPER(email) AND email IS NOT NULL AND email <> \'\'' + ) + ->bindValues( + [ + 'login' => $user->getLogin(), + 'ssoLogin' => $user->getSsoLogin(), + 'email' => $user->getEmail(), + ] + ); + + return $this->db->doQuery(QueryData::build($query))->getNumRows() > 0; + } + + /** + * @param $login string + * + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + * @throws Exception + */ + public function getByLogin(string $login): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->cols(UserModel::getColsWithPreffix(UserModel::TABLE)) + ->cols(UserGroupModel::getColsWithPreffix(UserGroupModel::TABLE)) + ->from(UserModel::TABLE) + ->innerJoin( + UserGroupModel::TABLE, + sprintf('%s.id = %s.userGroupId', UserGroupModel::TABLE, UserModel::TABLE) + ) + ->where(sprintf('%s.login = :login', UserModel::TABLE)) + ->orWhere(sprintf('%s.ssoLogin = :login', UserModel::TABLE)) + ->bindValues(['login' => $login]) + ->limit(1); + + return $this->db->doSelect(QueryData::buildWithMapper($query, UserModel::class)); + } + + /** + * Returns items' basic information + * + * @return QueryResult + */ + public function getAll(): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->from(UserModel::TABLE) + ->cols(UserModel::getCols()) + ->orderBy(['name']); + + return $this->db->doSelect(QueryData::buildWithMapper($query, UserModel::class)); + } + + /** + * Updates user's master password + * + * @param int $id + * @param string $pass + * @param string $key + * + * @return int + * @throws ConstraintException + * @throws QueryException + */ + public function updateMasterPassById(int $id, string $pass, string $key): int + { + $query = $this->queryFactory + ->newUpdate() + ->table(UserModel::TABLE) + ->cols(['pass' => $pass, 'key' => $key]) + ->set('lastUpdateMPass', 'UNIX_TIMESTAMP()') + ->set('isMigrate', 0) + ->set('isChangedPass', 0) + ->where('id = :id', ['id' => $id]) + ->limit(1); + + return $this->db->doQuery(QueryData::build($query))->getAffectedNumRows(); + } + + /** + * Actualiza el último inicio de sesión del usuario en la BBDD. + * + * @param $id int El id del usuario + * + * @return int + * @throws QueryException + * @throws ConstraintException + */ + public function updateLastLoginById(int $id): int + { + $query = $this->queryFactory + ->newUpdate() + ->table(UserModel::TABLE) + ->set('lastLogin', 'NOW()') + ->set('loginCount', 'loginCount + 1') + ->where('id = :id', ['id' => $id]) + ->limit(1); + + return $this->db->doQuery(QueryData::build($query))->getAffectedNumRows(); + } + + /** + * @param string $login + * + * @return bool + */ + public function checkExistsByLogin(string $login): bool + { + $query = $this->queryFactory + ->newSelect() + ->cols(['id']) + ->from(UserModel::TABLE) + ->where('UPPER(login) = UPPER(:login)') + ->where('UPPER(ssoLogin) = UPPER(:login)') + ->bindValues(['login' => $login]); + + return $this->db->doSelect(QueryData::build($query))->getNumRows() > 0; + } + + /** + * @param UserModel $user + * + * @return int + * @throws ConstraintException + * @throws QueryException + */ + public function updateOnLogin(UserModel $user): int + { + $query = $this->queryFactory + ->newUpdate() + ->table(UserModel::TABLE) + ->cols([ + 'pass' => $user->getPass(), + 'name' => $user->getName(), + 'email' => $user->getEmail(), + 'isLdap' => $user->isLdap() + ]) + ->set('hashSalt', '') + ->set('lastLogin', 'NOW()') + ->set('lastUpdate', 'NOW()') + ->set('loginCount', 'loginCount + 1') + ->where('UPPER(login) = UPPER(:login)') + ->where('UPPER(ssoLogin) = UPPER(:login)') + ->bindValues(['login' => $user->getLogin()]) + ->limit(1); + + return $this->db->doQuery(QueryData::build($query))->getAffectedNumRows(); + } + + /** + * Updates an user's pass + * + * @param int $id + * @param UserPreferences $userPreferences + * + * @return int + * @throws ConstraintException + * @throws QueryException + * @throws JsonException + * + * TODO: Handle serialized model migration + */ + public function updatePreferencesById(int $id, UserPreferences $userPreferences): int + { + $query = $this->queryFactory + ->newUpdate() + ->table(UserModel::TABLE) + ->cols(['preferences' => $userPreferences->toJson()]) + ->where('id = :id', ['id' => $id]) + ->limit(1); + + return $this->db->doQuery(QueryData::build($query))->getAffectedNumRows(); + } + + /** + * Obtener el email de los usuarios de un grupo + * + * @param int $groupId + * + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + * @throws Exception + */ + public function getUserEmailForGroup(int $groupId): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->cols(UserModel::getColsWithPreffix(UserModel::TABLE)) + ->from(UserModel::TABLE) + ->innerJoin( + UserGroupModel::TABLE, + sprintf('%s.id = %s.userGroupId', UserGroupModel::TABLE, UserModel::TABLE) + ) + ->leftJoin( + UserToUserGroupModel::TABLE, + sprintf('%s.userId = %s.id', UserToUserGroupModel::TABLE, UserModel::TABLE) + ) + ->where(sprintf('%s.email IS NOT NULL', UserModel::TABLE)) + ->where( + sprintf( + '(%s.userGroupId = :userGroupId OR %s.userGroupId = :userGroupId)', + UserModel::TABLE, + UserToUserGroupModel::TABLE + ) + ) + ->where(sprintf('%s.isDisabled = 0', UserModel::TABLE)) + ->orderBy([sprintf('%s.login', UserModel::TABLE)]) + ->bindValues(['userGroupId' => $groupId]); + + return $this->db->doSelect(QueryData::build($query)->setMapClassName(UserModel::class)); + } + + /** + * Obtener el email de los usuarios + * + * @return QueryResult + */ + public function getUserEmail(): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->cols(UserModel::getCols()) + ->from(UserModel::TABLE) + ->where('email IS NOT NULL') + ->where('isDisabled = 0') + ->orderBy(['login']); + + return $this->db->doSelect(QueryData::build($query)->setMapClassName(UserModel::class)); + } + + /** + * Return the email of the given user's id + * + * @param array $ids + * + * @return QueryResult + */ + public function getUserEmailById(array $ids): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->cols(UserModel::getCols()) + ->from(UserModel::TABLE) + ->where('id IN (:ids)', ['ids' => $ids]) + ->where('email IS NOT NULL') + ->where('isDisabled = 0') + ->orderBy(['login']); + + return $this->db->doSelect(QueryData::build($query)->setMapClassName(UserModel::class)); + } + + /** + * Returns the usage of the given user's id + * + * @param int $id + * + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + * @throws Exception + */ + public function getUsageForUser(int $id): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->cols(['Items.ref', 'Items.name', 'Items.id']) + ->fromSubSelect( + $this->queryFactory + ->newSelect() + ->from(AccountModel::TABLE) + ->innerJoin( + ClientModel::TABLE, + sprintf('%s.id = %s.clientId', ClientModel::TABLE, AccountModel::TABLE) + ) + ->where( + sprintf( + '%s.userId = :userId OR %s.userEditId = :userId', + AccountModel::TABLE, + AccountModel::TABLE + ) + ) + ->cols( + [ + sprintf('%s.id as id', AccountModel::TABLE), + sprintf( + 'CONCAT(%s.name, "(", %s.name, ")") AS name', + AccountModel::TABLE, + ClientModel::TABLE + ), + '"Account" AS ref' + ] + ) + ->unionAll() + ->from(AccountToUserModel::TABLE) + ->innerJoin( + AccountModel::TABLE, + sprintf('%s.id = %s.accountId', AccountModel::TABLE, AccountToUserModel::TABLE) + ) + ->innerJoin( + ClientModel::TABLE, + sprintf('%s.id = %s.clientId', ClientModel::TABLE, AccountModel::TABLE) + ) + ->where(sprintf('%s.userId = :userId', AccountToUserModel::TABLE)) + ->cols( + [ + sprintf('%s.accountId as id', AccountToUserModel::TABLE), + sprintf( + 'CONCAT(%s.name, "(", %s.name, ")") AS name', + AccountModel::TABLE, + ClientModel::TABLE + ), + '"Account" AS ref' + ] + ) + ->unionAll() + ->from(UserToUserGroupModel::TABLE) + ->innerJoin( + UserGroupModel::TABLE, + sprintf( + '%s.id = %s.userGroupId', + UserGroupModel::TABLE, + UserToUserGroupModel::TABLE + ) + ) + ->where(sprintf('%s.userId = :userId', UserToUserGroupModel::TABLE)) + ->cols( + [ + sprintf('%s.userGroupId AS id', UserToUserGroupModel::TABLE), + sprintf('%s.name AS name', UserGroupModel::TABLE), + '"UserGroup" AS ref' + ] + ) + ->unionAll() + ->from(PublicLinkModel::TABLE) + ->innerJoin( + AccountModel::TABLE, + sprintf( + '%s.itemId = %s.id', + PublicLinkModel::TABLE, + AccountModel::TABLE + ) + ) + ->innerJoin( + ClientModel::TABLE, + sprintf('%s.id = %s.clientId', ClientModel::TABLE, AccountModel::TABLE) + ) + ->where(sprintf('%s.userId = :userId', PublicLinkModel::TABLE)) + ->cols( + [ + sprintf('%s.id AS id', PublicLinkModel::TABLE), + sprintf( + 'CONCAT(%s.name, "(", %s.name, ")") AS name', + AccountModel::TABLE, + ClientModel::TABLE + ), + '"PublicLink" AS ref' + ] + ), + 'Items' + ) + ->orderBy(['Items.ref']) + ->bindValues(['userId' => $id]); + + return $this->db->doSelect(QueryData::build($query)); + } +} diff --git a/lib/SP/Infrastructure/User/Repositories/UserBaseRepository.php b/lib/SP/Infrastructure/User/Repositories/UserBaseRepository.php deleted file mode 100644 index 97b73193..00000000 --- a/lib/SP/Infrastructure/User/Repositories/UserBaseRepository.php +++ /dev/null @@ -1,849 +0,0 @@ -. - */ - -namespace SP\Infrastructure\User\Repositories; - -use RuntimeException; -use SP\DataModel\ItemSearchData; -use SP\DataModel\User; -use SP\DataModel\UserPreferencesData; -use SP\Domain\Core\Exceptions\ConstraintException; -use SP\Domain\Core\Exceptions\QueryException; -use SP\Domain\Core\Exceptions\SPException; -use SP\Domain\User\Ports\UserRepository; -use SP\Domain\User\Services\UpdatePassRequest; -use SP\Infrastructure\Common\Repositories\BaseRepository; -use SP\Infrastructure\Common\Repositories\DuplicatedItemException; -use SP\Infrastructure\Common\Repositories\RepositoryItemTrait; -use SP\Infrastructure\Database\QueryData; -use SP\Infrastructure\Database\QueryResult; - -/** - * Class UserRepository - * - * @package SP\Infrastructure\User\Repositories - */ -final class UserBaseRepository extends BaseRepository implements UserRepository -{ - use RepositoryItemTrait; - - /** - * Updates an item - * - * @param User $itemData - * - * @return int - * @throws ConstraintException - * @throws QueryException - * @throws DuplicatedItemException - */ - public function update($itemData): int - { - if ($this->checkDuplicatedOnUpdate($itemData)) { - throw new DuplicatedItemException(__u('Duplicated user login/email')); - } - - $query = /** @lang SQL */ - 'UPDATE User SET - `name` = ?, - login = ?, - ssoLogin = ?, - email = ?, - notes = ?, - userGroupId = ?, - userProfileId = ?, - isAdminApp = ?, - isAdminAcc = ?, - isDisabled = ?, - isChangePass = ?, - isLdap = ?, - lastUpdate = NOW() - WHERE id = ? LIMIT 1'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams([ - $itemData->getName(), - $itemData->getLogin(), - $itemData->getSsoLogin(), - $itemData->getEmail(), - $itemData->getNotes(), - $itemData->getUserGroupId(), - $itemData->getUserProfileId(), - $itemData->isAdminApp(), - $itemData->isAdminAcc(), - $itemData->isDisabled(), - $itemData->isChangePass(), - $itemData->isLdap(), - $itemData->getId(), - ]); - $queryData->setOnErrorMessage(__u('Error while updating the user')); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Checks whether the item is duplicated on updating - * - * @param User $itemData - * - * @return bool - * @throws ConstraintException - * @throws QueryException - */ - public function checkDuplicatedOnUpdate($itemData): bool - { - $query = /** @lang SQL */ - 'SELECT id - FROM User - WHERE id <> ? AND (UPPER(login) = UPPER(?) - OR (UPPER(?) = ssoLogin AND ssoLogin IS NOT NULL AND ssoLogin <> \'\') - OR (UPPER(?) = email AND email IS NOT NULL AND email <> \'\'))'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams([ - $itemData->getId(), - $itemData->getLogin(), - $itemData->getSsoLogin(), - $itemData->getEmail(), - ]); - - return $this->db->doSelect($queryData)->getNumRows() > 0; - } - - /** - * Updates an user's pass - * - * @param int $id - * @param UpdatePassRequest $passRequest - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function updatePassById( - int $id, - UpdatePassRequest $passRequest - ): int { - $query = /** @lang SQL */ - 'UPDATE User SET - pass = ?, - hashSalt = \'\', - isChangePass = ?, - isChangedPass = ?, - isMigrate = 0, - lastUpdate = NOW() - WHERE id = ? LIMIT 1'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams([ - $passRequest->getPass(), - (int)$passRequest->getisChangePass(), - (int)$passRequest->getisChangedPass(), - $id, - ]); - $queryData->setOnErrorMessage(__u('Error while updating the password')); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Deletes an item - * - * @param int $id - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function delete(int $id): int - { - $queryData = new QueryData(); - $queryData->setQuery('DELETE FROM User WHERE id = ? LIMIT 1'); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while deleting the user')); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Returns the item for given id - * - * @param int $id - * - * @return QueryResult - * @throws QueryException - * @throws ConstraintException - */ - public function getById(int $id): QueryResult - { - $query = /** @lang SQL */ - 'SELECT U.id, - U.name, - U.userGroupId, - UG.name AS userGroupName, - U.login, - U.ssoLogin, - U.email, - U.notes, - U.loginCount, - U.userProfileId, - U.lastLogin, - U.lastUpdate, - U.lastUpdateMPass, - U.preferences, - U.pass, - U.hashSalt, - U.mPass, - U.mKey, - U.isAdminApp, - U.isAdminAcc, - U.isLdap, - U.isDisabled, - U.isChangePass, - U.isChangedPass, - U.isMigrate - FROM User U - INNER JOIN UserGroup UG ON U.userGroupId = UG.id - WHERE U.id = ? LIMIT 1'; - - $queryData = new QueryData(); - $queryData->setMapClassName(User::class); - $queryData->setQuery($query); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while retrieving the user\'s data')); - - return $this->db->doSelect($queryData); - } - - /** - * Returns all the items - * - * @return User[] - * @throws QueryException - * @throws ConstraintException - */ - public function getAll(): array - { - $query = /** @lang SQL */ - 'SELECT U.id, - U.name, - U.userGroupId, - U.login, - U.ssoLogin, - U.email, - U.notes, - U.loginCount, - U.userProfileId, - U.lastLogin, - U.lastUpdate, - U.lastUpdateMPass, - U.preferences, - U.pass, - U.hashSalt, - U.mPass, - U.mKey, - U.isAdminApp, - U.isAdminAcc, - U.isLdap, - U.isDisabled, - U.isChangePass, - U.isChangedPass, - U.isMigrate - FROM User U'; - - $queryData = new QueryData(); - $queryData->setMapClassName(User::class); - $queryData->setQuery($query); - - return $this->db->doSelect($queryData)->getDataAsArray(); - } - - /** - * Returns all the items for given ids - * - * @param array $ids - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getByIdBatch(array $ids): QueryResult - { - if (count($ids) === 0) { - return new QueryResult(); - } - - $query = /** @lang SQL */ - 'SELECT U.id, - U.name, - U.userGroupId, - UG.name AS userGroupName, - U.login, - U.ssoLogin, - U.email, - U.notes, - U.loginCount, - U.userProfileId, - U.lastLogin, - U.lastUpdate, - U.lastUpdateMPass, - U.preferences, - U.pass, - U.hashSalt, - U.mPass, - U.mKey, - U.isAdminApp, - U.isAdminAcc, - U.isLdap, - U.isDisabled, - U.isChangePass, - U.isChangedPass, - U.isMigrate - FROM User U - INNER JOIN UserGroup UG ON U.userGroupId = UG.id - WHERE U.id IN ('.$this->buildParamsFromArray($ids).')'; - - $queryData = new QueryData(); - $queryData->setMapClassName(User::class); - $queryData->setQuery($query); - $queryData->setParams($ids); - - return $this->db->doSelect($queryData); - } - - /** - * Deletes all the items for given ids - * - * @param array $ids - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function deleteByIdBatch(array $ids): int - { - if (count($ids) === 0) { - return 0; - } - - $queryData = new QueryData(); - $queryData->setQuery('DELETE FROM User WHERE id IN ('.$this->buildParamsFromArray($ids).')'); - $queryData->setParams($ids); - $queryData->setOnErrorMessage(__u('Error while deleting the users')); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Checks whether the item is in use or not - * - * @param $id int - * - * @return void - */ - public function checkInUse(int $id): bool - { - throw new RuntimeException('Not implemented'); - } - - /** - * Searches for items by a given filter - * - * @param ItemSearchData $itemSearchData - * - * @return QueryResult - * @throws QueryException - * @throws ConstraintException - */ - public function search(ItemSearchData $itemSearchData): QueryResult - { - $queryData = new QueryData(); - $queryData->setSelect( - 'User.id, - User.name, - User.login, - UserProfile.name AS userProfileName, - UserGroup.name AS userGroupName, - User.isAdminApp, - User.isAdminAcc, - User.isLdap, - User.isDisabled, - User.isChangePass' - ); - $queryData->setFrom( - 'User - INNER JOIN UserProfile ON User.userProfileId = UserProfile.id - INNER JOIN UserGroup ON User.userGroupId = UserGroup.id' - ); - $queryData->setOrder('User.name'); - - $isAdminApp = $this->context->getUserData()->getIsAdminApp(); - - if (!empty($itemSearchData->getSeachString())) { - if ($isAdminApp) { - $queryData->setWhere('User.name LIKE ? OR User.login LIKE ?'); - } else { - $queryData->setWhere('User.name LIKE ? OR User.login LIKE ? AND User.isAdminApp = 0'); - } - - $search = '%'.$itemSearchData->getSeachString().'%'; - $queryData->addParam($search); - $queryData->addParam($search); - } elseif (!$isAdminApp) { - $queryData->setWhere('User.isAdminApp = 0'); - } - - $queryData->setLimit( - '?,?', - [$itemSearchData->getLimitStart(), $itemSearchData->getLimitCount()] - ); - - return $this->db->doSelect($queryData, true); - } - - /** - * Creates an item - * - * @param User $itemData - * - * @return int - * @throws SPException - */ - public function create($itemData): int - { - if ($this->checkDuplicatedOnAdd($itemData)) { - throw new DuplicatedItemException(__u('Duplicated user login/email')); - } - - $query = /** @lang SQL */ - 'INSERT INTO User SET - `name` = ?, - login = ?, - ssoLogin = ?, - email = ?, - notes = ?, - userGroupId = ?, - userProfileId = ?, - mPass = ?, - mKey = ?, - lastUpdateMPass = ?, - isAdminApp = ?, - isAdminAcc = ?, - isDisabled = ?, - isChangePass = ?, - isLdap = ?, - pass = ?, - hashSalt = \'\''; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams([ - $itemData->getName(), - $itemData->getLogin(), - $itemData->getSsoLogin(), - $itemData->getEmail(), - $itemData->getNotes(), - $itemData->getUserGroupId(), - $itemData->getUserProfileId(), - $itemData->getMPass(), - $itemData->getMKey(), - $itemData->getLastUpdateMPass(), - $itemData->isAdminApp(), - $itemData->isAdminAcc(), - $itemData->isDisabled(), - $itemData->isChangePass(), - $itemData->isLdap(), - $itemData->getPass(), - - ]); - $queryData->setOnErrorMessage(__u('Error while creating the user')); - - return $this->db->doQuery($queryData)->getLastId(); - } - - /** - * Checks whether the item is duplicated on adding - * - * @param User $itemData - * - * @return bool - * @throws ConstraintException - * @throws QueryException - */ - public function checkDuplicatedOnAdd($itemData): bool - { - $query = /** @lang SQL */ - 'SELECT id - FROM User - WHERE UPPER(login) = UPPER(?) - OR (UPPER(?) = ssoLogin AND ssoLogin IS NOT NULL AND ssoLogin <> \'\') - OR (UPPER(?) = email AND email IS NOT NULL AND email <> \'\')'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams([ - $itemData->getLogin(), - $itemData->getSsoLogin(), - $itemData->getEmail(), - ]); - - return $this->db->doSelect($queryData)->getNumRows() > 0; - } - - /** - * @param $login string - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getByLogin(string $login): QueryResult - { - $query = /** @lang SQL */ - 'SELECT U.id, - U.name, - U.userGroupId, - UG.name AS userGroupName, - U.login, - U.ssoLogin, - U.email, - U.notes, - U.loginCount, - U.userProfileId, - U.lastLogin, - U.lastUpdate, - U.lastUpdateMPass, - U.preferences, - U.pass, - U.hashSalt, - U.mPass, - U.mKey, - U.isAdminApp, - U.isAdminAcc, - U.isLdap, - U.isDisabled, - U.isChangePass, - U.isChangedPass, - U.isMigrate - FROM User U - INNER JOIN UserGroup UG ON U.userGroupId = UG.id - WHERE U.login = ? OR U.ssoLogin = ? LIMIT 1'; - - $queryData = new QueryData(); - $queryData->setMapClassName(User::class); - $queryData->setQuery($query); - $queryData->setParams([$login, $login]); - $queryData->setOnErrorMessage(__u('Error while retrieving the user\'s data')); - - return $this->db->doSelect($queryData); - } - - /** - * Returns items' basic information - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getBasicInfo(): QueryResult - { - $query = /** @lang SQL */ - 'SELECT U.id, - U.name, - U.login, - U.email, - U.userGroupId, - U.userProfileId, - U.isAdminApp, - U.isAdminAcc, - U.isLdap, - U.isDisabled - FROM User U'; - - $queryData = new QueryData(); - $queryData->setMapClassName(User::class); - $queryData->setQuery($query); - - return $this->db->doSelect($queryData); - } - - /** - * Updates user's master password - * - * @param int $id - * @param string $pass - * @param string $key - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function updateMasterPassById( - int $id, - string $pass, - string $key - ): int { - $query = /** @lang SQL */ - 'UPDATE User SET - mPass = ?, - mKey = ?, - lastUpdateMPass = UNIX_TIMESTAMP(), - isMigrate = 0, - isChangedPass = 0 - WHERE id = ? LIMIT 1'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams([$pass, $key, $id]); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Actualiza el último inicio de sesión del usuario en la BBDD. - * - * @param $id int El id del usuario - * - * @return int - * @throws QueryException - * @throws ConstraintException - */ - public function updateLastLoginById(int $id): int - { - $queryData = new QueryData(); - $queryData->setQuery('UPDATE User SET lastLogin = NOW(), loginCount = loginCount + 1 WHERE id = ? LIMIT 1'); - $queryData->addParam($id); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * @param string $login - * - * @return bool - * @throws ConstraintException - * @throws QueryException - */ - public function checkExistsByLogin(string $login): bool - { - $queryData = new QueryData(); - $queryData->setQuery('SELECT id FROM User WHERE UPPER(login) = UPPER(?) OR UPPER(ssoLogin) = UPPER(?) LIMIT 1'); - $queryData->setParams([$login, $login]); - - return $this->db->doSelect($queryData)->getNumRows() > 0; - } - - /** - * @param User $itemData - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function updateOnLogin(User $itemData): int - { - $query = 'UPDATE User SET - pass = ?, - hashSalt = \'\', - `name` = ?, - email = ?, - lastUpdate = NOW(), - lastLogin = NOW(), - isLdap = ? - WHERE UPPER(login) = UPPER(?) OR UPPER(ssoLogin) = UPPER(?) LIMIT 1'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams([ - $itemData->getPass(), - $itemData->getName(), - $itemData->getEmail(), - $itemData->isLdap(), - $itemData->getLogin(), - $itemData->getLogin(), - ]); - $queryData->setOnErrorMessage(__u('Error while updating the user')); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Updates an user's pass - * - * @param int $id - * @param UserPreferencesData $userPreferencesData - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function updatePreferencesById( - int $id, - UserPreferencesData $userPreferencesData - ): int { - $queryData = new QueryData(); - $queryData->setQuery('UPDATE User SET preferences = ? WHERE id = ? LIMIT 1'); - $queryData->setParams([serialize($userPreferencesData), $id]); - $queryData->setOnErrorMessage(__u('Error while updating the preferences')); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Obtener el email de los usuarios de un grupo - * - * @param int $groupId - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getUserEmailForGroup(int $groupId): QueryResult - { - $query = /** @lang SQL */ - 'SELECT U.id, U.login, U.name, U.email - FROM User U - INNER JOIN UserGroup UG ON U.userGroupId = UG.id - LEFT JOIN UserToUserGroup UUG ON U.id = UUG.userId - WHERE U.email IS NOT NULL - AND U.userGroupId = ? OR UUG.userGroupId = ? - AND U.isDisabled = 0 - ORDER BY U.login'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams([$groupId, $groupId]); - - return $this->db->doSelect($queryData); - } - - /** - * Obtener el email de los usuarios - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - * - * @TODO create unit test - */ - public function getUserEmail(): QueryResult - { - $query = /** @lang SQL */ - 'SELECT id, login, `name`, email - FROM User - WHERE email IS NOT NULL - AND isDisabled = 0 - ORDER BY login'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - - return $this->db->doSelect($queryData); - } - - /** - * Return the email of the given user's id - * - * @param int[] $ids - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - * @TODO create unit test - */ - public function getUserEmailById(array $ids): QueryResult - { - $query = /** @lang SQL */ - 'SELECT id, login, `name`, email - FROM User - WHERE email IS NOT NULL - AND isDisabled = 0 - AND id IN ('.$this->buildParamsFromArray($ids).') - ORDER BY login'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams($ids); - - return $this->db->doSelect($queryData); - } - - /** - * Returns the usage of the given user's id - * - * @param int $id - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getUsageForUser(int $id): QueryResult - { - $query = 'SELECT * FROM (SELECT - A.id, - CONCAT(A.name, " (", C.name, ")") AS name, - \'Account\' AS ref - FROM Account A - INNER JOIN Client C on A.clientId = C.id - WHERE A.userId = ? OR A.userEditId = ? - UNION ALL - SELECT - AU.accountId AS id, - CONCAT(A.name, " (", C.name, ")") AS name, - \'Account\' AS ref - FROM AccountToUser AU - INNER JOIN Account A on AU.accountId = A.id - INNER JOIN Client C on A.clientId = C.id - WHERE AU.userId = ? - UNION ALL - SELECT - UUG.userGroupId AS id, - G.name, - \'UserGroup\' AS ref - FROM - UserToUserGroup UUG - INNER JOIN UserGroup G on UUG.userGroupId = G.id - WHERE UUG.userId = ? - UNION ALL - SELECT - PL.id, - CONCAT(A.name, " (", C.name, ")") AS name, - \'PublicLink\' AS ref - FROM - PublicLink PL - INNER JOIN Account A ON A.id = PL.itemId - INNER JOIN Client C on A.clientId = C.id - WHERE PL.userId = ?) Items - ORDER BY Items.ref'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams(array_fill(0, 5, (int)$id)); - - return $this->db->doSelect($queryData); - } -} diff --git a/lib/SP/Infrastructure/User/Repositories/UserProfileBaseRepository.php b/lib/SP/Infrastructure/User/Repositories/UserProfileBaseRepository.php index b2030055..cb226dcf 100644 --- a/lib/SP/Infrastructure/User/Repositories/UserProfileBaseRepository.php +++ b/lib/SP/Infrastructure/User/Repositories/UserProfileBaseRepository.php @@ -25,9 +25,9 @@ namespace SP\Infrastructure\User\Repositories; use SP\DataModel\ItemSearchData; -use SP\DataModel\UserProfile; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\User\Models\UserProfile; use SP\Domain\User\Ports\UserProfileRepository; use SP\Infrastructure\Common\Repositories\BaseRepository; use SP\Infrastructure\Common\Repositories\DuplicatedItemException; @@ -65,7 +65,7 @@ final class UserProfileBaseRepository extends BaseRepository implements UserProf /** * Deletes an item * - * @param int $id + * @param int $id * * @return int * @throws ConstraintException @@ -102,7 +102,7 @@ final class UserProfileBaseRepository extends BaseRepository implements UserProf /** * Returns the item for given id * - * @param int $id + * @param int $id * * @return QueryResult * @throws ConstraintException @@ -137,7 +137,7 @@ final class UserProfileBaseRepository extends BaseRepository implements UserProf /** * Returns all the items for given ids * - * @param array $ids + * @param array $ids * * @return QueryResult * @throws ConstraintException @@ -150,7 +150,7 @@ final class UserProfileBaseRepository extends BaseRepository implements UserProf } $query = /** @lang SQL */ - 'SELECT id, `name` FROM UserProfile WHERE id IN ('.$this->buildParamsFromArray($ids).')'; + 'SELECT id, `name` FROM UserProfile WHERE id IN (' . $this->buildParamsFromArray($ids) . ')'; $queryData = new QueryData(); $queryData->setMapClassName(UserProfile::class); @@ -163,7 +163,7 @@ final class UserProfileBaseRepository extends BaseRepository implements UserProf /** * Deletes all the items for given ids * - * @param int[] $ids + * @param int[] $ids * * @return int * @throws ConstraintException @@ -176,7 +176,7 @@ final class UserProfileBaseRepository extends BaseRepository implements UserProf } $queryData = new QueryData(); - $queryData->setQuery('DELETE FROM UserProfile WHERE id IN ('.$this->buildParamsFromArray($ids).')'); + $queryData->setQuery('DELETE FROM UserProfile WHERE id IN (' . $this->buildParamsFromArray($ids) . ')'); $queryData->setParams($ids); $queryData->setOnErrorMessage(__u('Error while removing the profiles')); @@ -186,7 +186,7 @@ final class UserProfileBaseRepository extends BaseRepository implements UserProf /** * Searches for items by a given filter * - * @param ItemSearchData $itemSearchData + * @param ItemSearchData $itemSearchData * * @return QueryResult * @throws ConstraintException @@ -202,7 +202,7 @@ final class UserProfileBaseRepository extends BaseRepository implements UserProf if (!empty($itemSearchData->getSeachString())) { $queryData->setWhere('name LIKE ?'); - $search = '%'.$itemSearchData->getSeachString().'%'; + $search = '%' . $itemSearchData->getSeachString() . '%'; $queryData->addParam($search); } @@ -233,9 +233,9 @@ final class UserProfileBaseRepository extends BaseRepository implements UserProf $queryData = new QueryData(); $queryData->setQuery('INSERT INTO UserProfile SET `name` = ?, `profile` = ?'); $queryData->setParams([ - $itemData->getName(), - serialize($itemData->getProfile()), - ]); + $itemData->getName(), + serialize($itemData->getProfile()), + ]); $queryData->setOnErrorMessage(__u('Error while creating the profile')); return $this->db->doQuery($queryData)->getLastId(); @@ -281,10 +281,10 @@ final class UserProfileBaseRepository extends BaseRepository implements UserProf $queryData = new QueryData(); $queryData->setQuery($query); $queryData->setParams([ - $itemData->getName(), - serialize($itemData->getProfile()), - $itemData->getId(), - ]); + $itemData->getName(), + serialize($itemData->getProfile()), + $itemData->getId(), + ]); $queryData->setOnErrorMessage(__u('Error while updating the profile')); return $this->db->doQuery($queryData)->getAffectedNumRows(); @@ -309,9 +309,9 @@ final class UserProfileBaseRepository extends BaseRepository implements UserProf $queryData = new QueryData(); $queryData->setParams([ - $itemData->getName(), - $itemData->getId(), - ]); + $itemData->getName(), + $itemData->getId(), + ]); $queryData->setQuery($query); return $this->db->doSelect($queryData)->getNumRows() > 0; diff --git a/lib/SP/Infrastructure/User/Repositories/UserToUserGroupBaseRepository.php b/lib/SP/Infrastructure/User/Repositories/UserToUserGroupBaseRepository.php index 8d154297..e6db2af8 100644 --- a/lib/SP/Infrastructure/User/Repositories/UserToUserGroupBaseRepository.php +++ b/lib/SP/Infrastructure/User/Repositories/UserToUserGroupBaseRepository.php @@ -24,9 +24,9 @@ namespace SP\Infrastructure\User\Repositories; -use SP\DataModel\UserToUserGroupData; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\User\Models\UserToUserGroup as UserToUserGroupModel; use SP\Domain\User\Ports\UserToUserGroupRepositoryInterface; use SP\Infrastructure\Common\Repositories\BaseRepository; use SP\Infrastructure\Common\Repositories\RepositoryItemTrait; @@ -45,8 +45,8 @@ final class UserToUserGroupBaseRepository extends BaseRepository implements User /** * Checks whether the user is included in the group * - * @param int $groupId - * @param int $userId + * @param int $groupId + * @param int $userId * * @return bool * @throws ConstraintException @@ -64,7 +64,7 @@ final class UserToUserGroupBaseRepository extends BaseRepository implements User /** * Returns the groups which the user belongs to * - * @param int $userId + * @param int $userId * * @return QueryResult * @throws ConstraintException @@ -82,8 +82,8 @@ final class UserToUserGroupBaseRepository extends BaseRepository implements User /** * Updates users from a group * - * @param int $id - * @param array $users + * @param int $id + * @param array $users * * @return int * @throws ConstraintException @@ -118,8 +118,8 @@ final class UserToUserGroupBaseRepository extends BaseRepository implements User /** * Adds users to a group * - * @param int $groupId - * @param array $users + * @param int $groupId + * @param array $users * * @return int * @throws ConstraintException @@ -132,7 +132,7 @@ final class UserToUserGroupBaseRepository extends BaseRepository implements User } $query = /** @lang SQL */ - 'INSERT INTO UserToUserGroup (userId, userGroupId) VALUES '.$this->buildParamsFromArray($users, '(?,?)'); + 'INSERT INTO UserToUserGroup (userId, userGroupId) VALUES ' . $this->buildParamsFromArray($users, '(?,?)'); $queryData = new QueryData(); $queryData->setQuery($query); @@ -159,7 +159,7 @@ final class UserToUserGroupBaseRepository extends BaseRepository implements User public function getById(int $id): QueryResult { $queryData = new QueryData(); - $queryData->setMapClassName(UserToUserGroupData::class); + $queryData->setMapClassName(UserToUserGroupModel::class); $queryData->setQuery('SELECT userGroupId, userId FROM UserToUserGroup WHERE userGroupId = ?'); $queryData->addParam($id); diff --git a/tests/SPT/Core/LanguageTest.php b/tests/SPT/Core/LanguageTest.php index 38bb8def..fce5476e 100644 --- a/tests/SPT/Core/LanguageTest.php +++ b/tests/SPT/Core/LanguageTest.php @@ -27,9 +27,9 @@ namespace SPT\Core; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\MockObject\MockObject; use SP\Core\Language; -use SP\DataModel\UserPreferencesData; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Http\RequestInterface; +use SP\Domain\User\Models\UserPreferences; use SP\Domain\User\Services\UserLoginResponse; use SPT\UnitaryTestCase; @@ -80,7 +80,7 @@ class LanguageTest extends UnitaryTestCase $userData = $this->context->getUserData(); - $userData->setPreferences(new UserPreferencesData(['lang' => $locale])); + $userData->setPreferences(new UserPreferences(['lang' => $locale])); $this->language->setLanguage(true); diff --git a/tests/SPT/Domain/Account/Services/AccountSearchTest.php b/tests/SPT/Domain/Account/Services/AccountSearchTest.php index 25f92f08..40a3c36f 100644 --- a/tests/SPT/Domain/Account/Services/AccountSearchTest.php +++ b/tests/SPT/Domain/Account/Services/AccountSearchTest.php @@ -29,7 +29,6 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\MockObject\Builder\InvocationStubber; use PHPUnit\Framework\MockObject\MockObject; use RuntimeException; -use SP\DataModel\User; use SP\Domain\Account\Dtos\AccountSearchFilterDto; use SP\Domain\Account\Ports\AccountSearchConstants; use SP\Domain\Account\Ports\AccountSearchDataBuilder; @@ -38,6 +37,7 @@ use SP\Domain\Account\Services\AccountSearch; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\User\Models\User; use SP\Domain\User\Models\UserGroup; use SP\Domain\User\Ports\UserGroupServiceInterface; use SP\Domain\User\Ports\UserServiceInterface; diff --git a/tests/SPT/Domain/Import/Services/LdapImportTest.php b/tests/SPT/Domain/Import/Services/LdapImportTest.php index 65ecd109..3c02c7b3 100644 --- a/tests/SPT/Domain/Import/Services/LdapImportTest.php +++ b/tests/SPT/Domain/Import/Services/LdapImportTest.php @@ -29,11 +29,11 @@ use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\MockObject\MockObject; use RuntimeException; -use SP\DataModel\User; use SP\Domain\Auth\Ports\LdapActionsService; use SP\Domain\Auth\Ports\LdapConnectionInterface; use SP\Domain\Import\Dtos\LdapImportParamsDto; use SP\Domain\Import\Services\LdapImport; +use SP\Domain\User\Models\User; use SP\Domain\User\Models\UserGroup; use SP\Domain\User\Ports\UserGroupServiceInterface; use SP\Domain\User\Ports\UserServiceInterface; diff --git a/tests/SPT/Generators/PluginGenerator.php b/tests/SPT/Generators/PluginGenerator.php index ffe01152..c2ac1ba8 100644 --- a/tests/SPT/Generators/PluginGenerator.php +++ b/tests/SPT/Generators/PluginGenerator.php @@ -44,7 +44,7 @@ final class PluginGenerator extends DataGenerator 'name' => $this->faker->colorName(), 'data' => $this->faker->text(), 'enabled' => $this->faker->boolean(), - 'versionLevel' => sprintf('%d.%d', $this->faker->randomNumber(3, true), $this->faker->randomNumber(6, true)) + 'versionLevel' => sprintf('%d.%d', $this->faker->randomNumber(4, true), $this->faker->randomNumber(6, true)) ]; } } diff --git a/tests/SPT/Generators/UserDataGenerator.php b/tests/SPT/Generators/UserDataGenerator.php index 51b81233..d2956ab9 100644 --- a/tests/SPT/Generators/UserDataGenerator.php +++ b/tests/SPT/Generators/UserDataGenerator.php @@ -24,9 +24,8 @@ namespace SPT\Generators; -use SP\DataModel\User; -use SP\DataModel\UserPassData; -use SP\DataModel\UserPreferencesData; +use SP\Domain\User\Models\User; +use SP\Domain\User\Models\UserPreferences; /** * Class UserDataGenerator @@ -35,7 +34,7 @@ final class UserDataGenerator extends DataGenerator { public function buildUserData(): User { - return new User(array_merge($this->getUserProperties(), $this->getUserPassProperties())); + return new User($this->getUserProperties()); } /** @@ -51,7 +50,6 @@ final class UserDataGenerator extends DataGenerator 'ssoLogin' => $this->faker->userName(), 'notes' => $this->faker->text(), 'userGroupId' => $this->faker->randomNumber(3), - 'userGroupName' => $this->faker->name(), 'userProfileId' => $this->faker->randomNumber(3), 'isAdminApp' => $this->faker->boolean(), 'isAdminAcc' => $this->faker->boolean(), @@ -63,13 +61,18 @@ final class UserDataGenerator extends DataGenerator 'loginCount' => $this->faker->randomNumber(3), 'lastLogin' => $this->faker->unixTime(), 'lastUpdate' => $this->faker->unixTime(), - 'preferences' => serialize($this->buildUserPreferencesData()), + 'preferences' => serialize($this->buildUserPreferencesData()), + 'pass' => $this->faker->password(), + 'hashSalt' => $this->faker->sha1(), + 'mPass' => $this->faker->sha1(), + 'mKey' => $this->faker->sha1(), + 'lastUpdateMPass' => $this->faker->dateTime()->getTimestamp(), ]; } - public function buildUserPreferencesData(): UserPreferencesData + public function buildUserPreferencesData(): UserPreferences { - return new UserPreferencesData($this->getUserPreferencesProperties()); + return new UserPreferences($this->getUserPreferencesProperties()); } private function getUserPreferencesProperties(): array @@ -88,24 +91,4 @@ final class UserDataGenerator extends DataGenerator 'user_id' => $this->faker->randomNumber(3), ]; } - - /** - * @return array - */ - private function getUserPassProperties(): array - { - return [ - 'id' => $this->faker->randomNumber(3), - 'pass' => $this->faker->password(), - 'hashSalt' => $this->faker->sha1(), - 'mPass' => $this->faker->sha1(), - 'mKey' => $this->faker->sha1(), - 'lastUpdateMPass' => $this->faker->dateTime()->getTimestamp(), - ]; - } - - public function buildUserPassData(): UserPassData - { - return new UserPassData($this->getUserPassProperties()); - } } diff --git a/tests/SPT/Generators/UserProfileDataGenerator.php b/tests/SPT/Generators/UserProfileDataGenerator.php index 872ffbfd..53d143f5 100644 --- a/tests/SPT/Generators/UserProfileDataGenerator.php +++ b/tests/SPT/Generators/UserProfileDataGenerator.php @@ -25,7 +25,7 @@ namespace SPT\Generators; use SP\DataModel\ProfileData; -use SP\DataModel\UserProfile; +use SP\Domain\User\Models\UserProfile; /** * Class UserProfileDataGenerator diff --git a/tests/SPT/Infrastructure/User/Repositories/UserTest.php b/tests/SPT/Infrastructure/User/Repositories/UserTest.php new file mode 100644 index 00000000..dea1cdfe --- /dev/null +++ b/tests/SPT/Infrastructure/User/Repositories/UserTest.php @@ -0,0 +1,684 @@ +. + */ + +namespace SPT\Infrastructure\User\Repositories; + +use Aura\SqlQuery\Common\DeleteInterface; +use Aura\SqlQuery\Common\InsertInterface; +use Aura\SqlQuery\Common\SelectInterface; +use Aura\SqlQuery\Common\UpdateInterface; +use Aura\SqlQuery\QueryFactory; +use JsonException; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Constraint\Callback; +use PHPUnit\Framework\MockObject\MockObject; +use SP\DataModel\ItemSearchData; +use SP\Domain\Common\Models\Simple as SimpleModel; +use SP\Domain\Core\Exceptions\ConstraintException; +use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\User\Models\User as UserModel; +use SP\Infrastructure\Common\Repositories\DuplicatedItemException; +use SP\Infrastructure\Database\DatabaseInterface; +use SP\Infrastructure\Database\QueryData; +use SP\Infrastructure\Database\QueryResult; +use SP\Infrastructure\User\Repositories\User; +use SPT\Generators\UserDataGenerator; +use SPT\UnitaryTestCase; + +/** + * Class UserTest + */ +#[Group('unitary')] +class UserTest extends UnitaryTestCase +{ + + private User $user; + private MockObject|DatabaseInterface $database; + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testGetUsageForUser() + { + $this->database + ->expects($this->once()) + ->method('doSelect') + ->with( + self::callback(static function (QueryData $queryData) { + $params = $queryData->getQuery()->getBindValues(); + + return count($params) === 1 + && $params['userId'] === 100; + }) + ); + + $this->user->getUsageForUser(100); + } + + /** + * @throws SPException + */ + public function testCreate() + { + $user = UserDataGenerator::factory()->buildUserData(); + + $callbackDuplicate = new Callback( + static function (QueryData $arg) use ($user) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 3 + && $params['login'] === $user->getLogin() + && $params['email'] === $user->getEmail() + && $params['ssoLogin'] === $user->getSsoLogin() + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $callbackCreate = new Callback( + static function (QueryData $arg) use ($user) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 22 + && count(array_diff_assoc($params, $user->toArray(null, ['id', 'hashSalt']))) === 0 + && is_a($query, InsertInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::exactly(2)) + ->method('doQuery') + ->with(...self::withConsecutive([$callbackDuplicate], [$callbackCreate])) + ->willReturn(new QueryResult([]), new QueryResult([1])); + + $this->user->create($user); + } + + /** + * @throws SPException + */ + public function testCreateWithDuplicate() + { + $user = UserDataGenerator::factory()->buildUserData(); + + $callbackDuplicate = new Callback( + static function (QueryData $arg) use ($user) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 3 + && $params['login'] === $user->getLogin() + && $params['email'] === $user->getEmail() + && $params['ssoLogin'] === $user->getSsoLogin() + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callbackDuplicate) + ->willReturn(new QueryResult([1])); + + $this->expectException(DuplicatedItemException::class); + $this->expectExceptionMessage('Duplicated user login/email'); + + $this->user->create($user); + } + + public function testGetUserEmail() + { + $this->database + ->expects($this->once()) + ->method('doSelect') + ->with( + self::callback(static function (QueryData $queryData) { + $params = $queryData->getQuery()->getBindValues(); + + return count($params) === 0 + && $queryData->getMapClassName() === UserModel::class; + }) + ); + + $this->user->getUserEmail(); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testUpdateOnLogin() + { + $user = UserDataGenerator::factory()->buildUserData(); + + $callbackUpdate = new Callback( + static function (QueryData $arg) use ($user) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + $count = count(array_diff_assoc($params, $user->toArray(['pass', 'name', 'email', 'isLdap', 'login']))); + + return count($params) === 5 + && $count === 0 + && is_a($query, UpdateInterface::class) + && !empty($query->getStatement()); + } + ); + + $queryResult = new QueryResult([]); + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callbackUpdate) + ->willReturn($queryResult->setAffectedNumRows(1)); + + $out = $this->user->updateOnLogin($user); + + $this->assertEquals(1, $out); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testUpdateMasterPassById() + { + $callbackUpdate = new Callback( + static function (QueryData $arg) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 3 + && $params['pass'] === 'super_secret' + && $params['key'] === 'a_key' + && $params['id'] === 100 + && is_a($query, UpdateInterface::class) + && !empty($query->getStatement()); + } + ); + + $queryResult = new QueryResult([]); + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callbackUpdate) + ->willReturn($queryResult->setAffectedNumRows(1)); + + $out = $this->user->updateMasterPassById(100, 'super_secret', 'a_key'); + + $this->assertEquals(1, $out); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testDelete() + { + $id = self::$faker->randomNumber(); + + $callback = new Callback( + static function (QueryData $arg) use ($id) { + $query = $arg->getQuery(); + + return $query->getBindValues()['id'] === $id + && is_a($query, DeleteInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database->expects(self::once())->method('doQuery')->with($callback); + + $this->user->delete($id); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testGetById() + { + $this->database + ->expects($this->once()) + ->method('doSelect') + ->with( + self::callback(static function (QueryData $queryData) { + $params = $queryData->getQuery()->getBindValues(); + + return count($params) === 1 + && $params['id'] === 100 + && $queryData->getMapClassName() === UserModel::class; + }) + ); + + $this->user->getById(100); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testDeleteByIdBatch() + { + $ids = [self::$faker->randomNumber(), self::$faker->randomNumber(), self::$faker->randomNumber()]; + + $callback = new Callback( + static function (QueryData $arg) use ($ids) { + $query = $arg->getQuery(); + $values = $query->getBindValues(); + + return count($values) === 3 + && array_shift($values) === array_shift($ids) + && array_shift($values) === array_shift($ids) + && array_shift($values) === array_shift($ids) + && $arg->getMapClassName() === SimpleModel::class + && is_a($query, DeleteInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callback); + + $this->user->deleteByIdBatch($ids); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testDeleteByIdBatchWithNoIds(): void + { + $this->database + ->expects(self::never()) + ->method('doQuery'); + + $this->user->deleteByIdBatch([]); + } + + public function testGetAll() + { + $callback = new Callback( + static function (QueryData $arg) { + $query = $arg->getQuery(); + return $arg->getMapClassName() === UserModel::class + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback); + + $this->user->getAll(); + } + + public function testUpdateLastLoginById() + { + $callbackUpdate = new Callback( + static function (QueryData $arg) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 1 + && $params['id'] === 100 + && is_a($query, UpdateInterface::class) + && !empty($query->getStatement()); + } + ); + + $queryResult = new QueryResult([]); + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callbackUpdate) + ->willReturn($queryResult->setAffectedNumRows(1)); + + $out = $this->user->updateLastLoginById(100); + + $this->assertEquals(1, $out); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testGetByLogin() + { + $this->database + ->expects($this->once()) + ->method('doSelect') + ->with( + self::callback(static function (QueryData $queryData) { + $params = $queryData->getQuery()->getBindValues(); + + return count($params) === 1 + && $params['login'] === 'a_login' + && $queryData->getMapClassName() === UserModel::class; + }) + ); + + $this->user->getByLogin('a_login'); + } + + /** + * @throws DuplicatedItemException + * @throws ConstraintException + * @throws QueryException + */ + public function testUpdate() + { + $user = UserDataGenerator::factory()->buildUserData(); + + $callbackDuplicate = new Callback( + static function (QueryData $arg) use ($user) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 4 + && $params['id'] === $user->getId() + && $params['login'] === $user->getLogin() + && $params['email'] === $user->getEmail() + && $params['ssoLogin'] === $user->getSsoLogin() + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $callbackUpdate = new Callback( + static function (QueryData $arg) use ($user) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 23 + && count(array_diff_assoc($params, $user->toArray(null, ['hashSalt']))) === 0 + && is_a($query, UpdateInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::exactly(2)) + ->method('doQuery') + ->with(...self::withConsecutive([$callbackDuplicate], [$callbackUpdate])) + ->willReturn(new QueryResult([]), new QueryResult([1])); + + $this->user->update($user); + } + + /** + * @throws SPException + */ + public function testUpdateWithDuplicate() + { + $user = UserDataGenerator::factory()->buildUserData(); + + $callbackDuplicate = new Callback( + static function (QueryData $arg) use ($user) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 4 + && $params['id'] === $user->getId() + && $params['login'] === $user->getLogin() + && $params['email'] === $user->getEmail() + && $params['ssoLogin'] === $user->getSsoLogin() + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callbackDuplicate) + ->willReturn(new QueryResult([1])); + + $this->expectException(DuplicatedItemException::class); + $this->expectExceptionMessage('Duplicated user login/email'); + + $this->user->update($user); + } + + public function testGetUserEmailById() + { + $this->database + ->expects($this->once()) + ->method('doSelect') + ->with( + self::callback(static function (QueryData $queryData) { + $params = $queryData->getQuery()->getBindValues(); + + return count($params) === 2 + && array_shift($params) === 100 + && array_shift($params) === 200 + && $queryData->getMapClassName() === UserModel::class; + }) + ); + + $this->user->getUserEmailById([100, 200]); + } + + public function testCheckExistsByLogin() + { + $this->database + ->expects($this->once()) + ->method('doSelect') + ->with( + self::callback(static function (QueryData $queryData) { + $params = $queryData->getQuery()->getBindValues(); + + return count($params) === 1 + && $params['login'] === 'a_login' + && $queryData->getMapClassName() === SimpleModel::class; + }) + ) + ->willReturn(new QueryResult([1])); + + $out = $this->user->checkExistsByLogin('a_login'); + + $this->assertTrue($out); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testGetUserEmailForGroup() + { + $this->database + ->expects($this->once()) + ->method('doSelect') + ->with( + self::callback(static function (QueryData $queryData) { + $params = $queryData->getQuery()->getBindValues(); + + return count($params) === 1 + && $params['userGroupId'] === 100 + && $queryData->getMapClassName() === UserModel::class; + }) + ); + + $this->user->getUserEmailForGroup(100); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testSearch() + { + $item = new ItemSearchData(self::$faker->name); + + $callback = new Callback( + static function (QueryData $arg) use ($item) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + $searchStringLike = '%' . $item->getSeachString() . '%'; + + return count($params) === 2 + && $params['name'] === $searchStringLike + && $params['login'] === $searchStringLike + && $arg->getMapClassName() === UserModel::class + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback, true); + + $this->user->search($item); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testSearchWithAdmin() + { + $userData = $this->context->getUserData(); + $userData->setIsAdminApp(true); + + $this->context->setUserData($userData); + + $item = new ItemSearchData(self::$faker->name); + + $callback = new Callback( + static function (QueryData $arg) use ($item) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + $searchStringLike = '%' . $item->getSeachString() . '%'; + + return count($params) === 2 + && $params['name'] === $searchStringLike + && $params['login'] === $searchStringLike + && $arg->getMapClassName() === UserModel::class + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback, true); + + $this->user->search($item); + } + + /** + * @throws ConstraintException + * @throws JsonException + * @throws QueryException + */ + public function testUpdatePreferencesById() + { + $userPreferences = UserDataGenerator::factory()->buildUserPreferencesData(); + + $callbackUpdate = new Callback( + static function (QueryData $arg) use ($userPreferences) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 2 + && $params['id'] === 100 + && $params['preferences'] === $userPreferences->toJson() + && is_a($query, UpdateInterface::class) + && !empty($query->getStatement()); + } + ); + + $queryResult = new QueryResult(); + + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callbackUpdate) + ->willReturn($queryResult->setAffectedNumRows(1)); + + $this->user->updatePreferencesById(100, $userPreferences); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testUpdatePassById() + { + $user = UserDataGenerator::factory()->buildUserData(); + + $callbackUpdate = new Callback( + static function (QueryData $arg) use ($user) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 4 + && $params['id'] === $user->getId() + && $params['pass'] === $user->getPass() + && $params['isChangePass'] === $user->isChangePass() + && $params['isChangedPass'] === $user->isChangedPass() + && is_a($query, UpdateInterface::class) + && !empty($query->getStatement()); + } + ); + + $queryResult = new QueryResult(); + + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callbackUpdate) + ->willReturn($queryResult->setAffectedNumRows(1)); + + $this->user->updatePassById($user); + } + + protected function setUp(): void + { + parent::setUp(); + + $this->database = $this->createMock(DatabaseInterface::class); + $queryFactory = new QueryFactory('mysql'); + + $this->user = new User( + $this->database, + $this->context, + $this->application->getEventDispatcher(), + $queryFactory, + ); + } +}