chore(tests): UT for User repository

Signed-off-by: Rubén D <nuxsmin@syspass.org>
This commit is contained in:
Rubén D
2024-03-24 19:21:03 +01:00
parent a766de876f
commit dabac68ad4
50 changed files with 1882 additions and 1395 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();

View File

@@ -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
{

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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');

View File

@@ -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');

View File

@@ -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;

View File

@@ -1,150 +0,0 @@
<?php
/*
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -1,97 +0,0 @@
<?php
/*
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -1,106 +0,0 @@
<?php
/*
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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;

View File

@@ -0,0 +1,36 @@
<?php
/*
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Domain\Account\Models;
use SP\Domain\Common\Models\Model;
/**
* Class AccountToUser
*/
final class AccountToUser extends Model
{
public const TABLE = 'AccountToUser';
}

View File

@@ -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;

View File

@@ -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(

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -0,0 +1,186 @@
<?php
/*
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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;

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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;

View File

@@ -22,20 +22,19 @@
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
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;

View File

@@ -0,0 +1,54 @@
<?php
/*
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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;

View File

@@ -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<T>
* @throws ConstraintException
* @throws QueryException
* @throws Exception
*/
public function getByLogin(string $login): QueryResult;
/**
* Returns items' basic information
*
* @return QueryResult
* @throws ConstraintException
* @throws QueryException
* @return QueryResult<T>
*/
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<T>
* @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<T>
*/
public function getUserEmail(): QueryResult;
/**
* Return the email of the given user's id
*
* @param int[] $ids
* @param array<int> $ids
*
* @return QueryResult
* @throws ConstraintException
* @throws QueryException
* @return QueryResult<T>
*/
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<T>
* @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;
}

View File

@@ -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
*/

View File

@@ -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;
}
}
}

View File

@@ -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();
}
/**

View File

@@ -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;

View File

@@ -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

View File

@@ -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) {

View File

@@ -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())

View File

@@ -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
{

View File

@@ -0,0 +1,682 @@
<?php
/*
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
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<T>
* @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<T>
* @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<T>
*/
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<T>
* @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<T>
*/
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<int> $ids
*
* @return QueryResult<T>
*/
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));
}
}

View File

@@ -1,849 +0,0 @@
<?php
/*
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
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);
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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))
];
}
}

View File

@@ -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());
}
}

View File

@@ -25,7 +25,7 @@
namespace SPT\Generators;
use SP\DataModel\ProfileData;
use SP\DataModel\UserProfile;
use SP\Domain\User\Models\UserProfile;
/**
* Class UserProfileDataGenerator

View File

@@ -0,0 +1,684 @@
<?php
/*
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
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,
);
}
}