diff --git a/app/modules/web/Controllers/AccountFavoriteController.php b/app/modules/web/Controllers/AccountFavoriteController.php
index 0a3f0926..84252852 100644
--- a/app/modules/web/Controllers/AccountFavoriteController.php
+++ b/app/modules/web/Controllers/AccountFavoriteController.php
@@ -26,7 +26,7 @@ namespace SP\Modules\Web\Controllers;
use SP\Http\JsonResponse;
use SP\Modules\Web\Controllers\Traits\JsonTrait;
-use SP\Services\Account\AccountFavoriteService;
+use SP\Services\Account\AccountToFavoriteService;
/**
* Class AccountFavoriteController
@@ -38,7 +38,7 @@ class AccountFavoriteController extends SimpleControllerBase
use JsonTrait;
/**
- * @var AccountFavoriteService
+ * @var AccountToFavoriteService
*/
private $accountFavoriteService;
@@ -78,7 +78,7 @@ class AccountFavoriteController extends SimpleControllerBase
{
$this->checks();
- $this->accountFavoriteService = $this->dic->get(AccountFavoriteService::class);
+ $this->accountFavoriteService = $this->dic->get(AccountToFavoriteService::class);
}
}
\ No newline at end of file
diff --git a/app/modules/web/Controllers/Helpers/ItemsGridHelper.php b/app/modules/web/Controllers/Helpers/ItemsGridHelper.php
index af7923c8..6978d5ee 100644
--- a/app/modules/web/Controllers/Helpers/ItemsGridHelper.php
+++ b/app/modules/web/Controllers/Helpers/ItemsGridHelper.php
@@ -359,7 +359,9 @@ class ItemsGridHelper extends HelperBase
$GridData->addDataRowSource('clientName');
$GridData->addDataRowSource('name');
$GridData->addDataRowSource('type');
- $GridData->addDataRowSource('size');
+ $GridData->addDataRowSource('size', false, function ($value) {
+ return sprintf('%.2f KB', $value / 1000);
+ });
$GridData->setData($queryResult);
// Grid
diff --git a/lib/SP/Core/Context/ContextInterface.php b/lib/SP/Core/Context/ContextInterface.php
index edec1689..1f03d51b 100644
--- a/lib/SP/Core/Context/ContextInterface.php
+++ b/lib/SP/Core/Context/ContextInterface.php
@@ -25,6 +25,7 @@
namespace SP\Core\Context;
use SP\Config\ConfigData;
+use SP\DataModel\Dto\AccountCache;
use SP\DataModel\ProfileData;
use SP\Services\User\UserLoginResponse;
@@ -109,7 +110,6 @@ interface ContextInterface
/**
* @param $sk
- * @return mixed
*/
public function setSecurityKey($sk);
@@ -154,4 +154,9 @@ interface ContextInterface
* @return bool
*/
public function resetAppStatus();
+
+ /**
+ * @return AccountCache[]|null
+ */
+ public function getAccountsCache();
}
\ No newline at end of file
diff --git a/lib/SP/Core/Context/SessionContext.php b/lib/SP/Core/Context/SessionContext.php
index 9c510227..00c6e86b 100644
--- a/lib/SP/Core/Context/SessionContext.php
+++ b/lib/SP/Core/Context/SessionContext.php
@@ -27,6 +27,7 @@ namespace SP\Core\Context;
use SP\Account\AccountSearchFilter;
use SP\Config\ConfigData;
use SP\Core\Crypt\Vault;
+use SP\DataModel\Dto\AccountCache;
use SP\DataModel\ProfileData;
use SP\Services\User\UserLoginResponse;
@@ -87,6 +88,7 @@ class SessionContext extends ContextBase
*
* @param string $key
* @param mixed $default
+ *
* @return mixed
*/
protected function getContextKey($key, $default = null)
@@ -115,6 +117,7 @@ class SessionContext extends ContextBase
*
* @param string $key El nombre de la variable
* @param mixed $value El valor de la variable
+ *
* @return mixed
*/
protected function setContextKey($key, $value)
@@ -292,6 +295,7 @@ class SessionContext extends ContextBase
/**
* @param $sk
+ *
* @return mixed
*/
public function setSecurityKey($sk)
@@ -343,6 +347,7 @@ class SessionContext extends ContextBase
* Establecer el timeout de la sesión
*
* @param int $timeout El valor en segundos
+ *
* @return int
*/
public function setSessionTimeout($timeout)
@@ -386,6 +391,7 @@ class SessionContext extends ContextBase
* Establece la hora de creación del SID
*
* @param $time int La marca de hora
+ *
* @return int
*/
public function setSidStartTime($time)
@@ -409,6 +415,7 @@ class SessionContext extends ContextBase
* Establece la hora de inicio de actividad
*
* @param $time int La marca de hora
+ *
* @return int
*/
public function setStartActivity($time)
@@ -520,10 +527,12 @@ class SessionContext extends ContextBase
/**
* Devuelve la cache de cuentas
+ *
+ * @return AccountCache[]
*/
public function getAccountsCache()
{
- $this->getContextKey('accountsCache');
+ return $this->getContextKey('accountsCache');
}
/**
diff --git a/lib/SP/Core/Context/StatelessContext.php b/lib/SP/Core/Context/StatelessContext.php
index d36d1895..f653dbe6 100644
--- a/lib/SP/Core/Context/StatelessContext.php
+++ b/lib/SP/Core/Context/StatelessContext.php
@@ -50,6 +50,7 @@ class StatelessContext extends ContextBase
*
* @param string $key El nombre de la variable
* @param mixed $value El valor de la variable
+ *
* @return mixed
*/
protected function setContextKey($key, $value)
@@ -90,6 +91,7 @@ class StatelessContext extends ContextBase
*
* @param string $key
* @param mixed $default
+ *
* @return mixed
*/
protected function getContextKey($key, $default = null)
@@ -151,6 +153,7 @@ class StatelessContext extends ContextBase
/**
* @param $sk
+ *
* @return mixed
*/
public function setSecurityKey($sk)
@@ -246,4 +249,12 @@ class StatelessContext extends ContextBase
{
return $this->getContextKey('configTime');
}
+
+ /**
+ * @return null
+ */
+ public function getAccountsCache()
+ {
+ return null;
+ }
}
\ No newline at end of file
diff --git a/lib/SP/Log/LogUtil.php b/lib/SP/Core/Exceptions/InvalidImageException.php
similarity index 60%
rename from lib/SP/Log/LogUtil.php
rename to lib/SP/Core/Exceptions/InvalidImageException.php
index 1372af90..9f632ad3 100644
--- a/lib/SP/Log/LogUtil.php
+++ b/lib/SP/Core/Exceptions/InvalidImageException.php
@@ -22,27 +22,14 @@
* along with sysPass. If not, see .
*/
-namespace SP\Log;
+namespace SP\Core\Exceptions;
/**
- * Class LogUtil
+ * Class InvalidImageException
*
- * @package SP\Log
+ * @package SP\Core\Exceptions
*/
-class LogUtil
+class InvalidImageException extends SPException
{
- /**
- * Registrar que una extensión no ha sido cargada
- *
- * @param string $extension La extensión no cargada
- * @param string $source El origen del error
- * @return Log
- * @throws \SP\Core\Exceptions\SPException
- */
- public static function extensionNotLoaded($extension, $source = __FUNCTION__)
- {
- $msg = sprintf(__('Extensión \'%s\' no cargada'), $extension);
- return Log::writeNewLog($source, $msg, Log::ERROR);
- }
}
\ No newline at end of file
diff --git a/lib/SP/DataModel/Dto/AccountHistoryCreateDto.php b/lib/SP/DataModel/Dto/AccountHistoryCreateDto.php
new file mode 100644
index 00000000..366a2805
--- /dev/null
+++ b/lib/SP/DataModel/Dto/AccountHistoryCreateDto.php
@@ -0,0 +1,99 @@
+.
+ */
+
+namespace SP\DataModel\Dto;
+
+
+/**
+ * Class AccountHistoryCreateDto
+ *
+ * @package SP\DataModel\Dto
+ */
+class AccountHistoryCreateDto
+{
+ /**
+ * @var int
+ */
+ private $accountId;
+ /**
+ * @var bool
+ */
+ private $isModify;
+ /**
+ * @var bool
+ */
+ private $isDelete;
+ /**
+ * @var string
+ */
+ private $masterPassHash;
+
+ /**
+ * AccountHistoryCreateDto constructor.
+ *
+ * @param int $accountId
+ * @param bool $isModify
+ * @param bool $isDelete
+ * @param string $masterPassHash
+ */
+ public function __construct(int $accountId, bool $isModify, bool $isDelete, string $masterPassHash)
+ {
+ $this->accountId = $accountId;
+ $this->isModify = $isModify;
+ $this->isDelete = $isDelete;
+ $this->masterPassHash = $masterPassHash;
+ }
+
+ /**
+ * @return int
+ */
+ public function getAccountId(): int
+ {
+ return $this->accountId;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isModify(): bool
+ {
+ return $this->isModify;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDelete(): bool
+ {
+ return $this->isDelete;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMasterPassHash(): string
+ {
+ return $this->masterPassHash;
+ }
+}
\ No newline at end of file
diff --git a/lib/SP/DataModel/FileExtData.php b/lib/SP/DataModel/FileExtData.php
index e89ab3e7..b4a7d2b1 100644
--- a/lib/SP/DataModel/FileExtData.php
+++ b/lib/SP/DataModel/FileExtData.php
@@ -34,7 +34,7 @@ class FileExtData extends FileData
/**
* @var string
*/
- public $customerName = '';
+ public $clientName = '';
/**
* @var string
*/
@@ -43,17 +43,17 @@ class FileExtData extends FileData
/**
* @return string
*/
- public function getCustomerName()
+ public function getClientName()
{
- return $this->customerName;
+ return $this->clientName;
}
/**
- * @param string $customerName
+ * @param string $clientName
*/
- public function setCustomerName($customerName)
+ public function setClientName($clientName)
{
- $this->customerName = $customerName;
+ $this->clientName = $clientName;
}
/**
diff --git a/lib/SP/Repositories/Account/AccountFileRepository.php b/lib/SP/Repositories/Account/AccountFileRepository.php
index b30a01a0..1ef0b639 100644
--- a/lib/SP/Repositories/Account/AccountFileRepository.php
+++ b/lib/SP/Repositories/Account/AccountFileRepository.php
@@ -27,11 +27,11 @@ namespace SP\Repositories\Account;
use SP\DataModel\FileData;
use SP\DataModel\FileExtData;
use SP\DataModel\ItemSearchData;
-use SP\Repositories\NoSuchItemException;
use SP\Repositories\Repository;
use SP\Repositories\RepositoryItemInterface;
use SP\Repositories\RepositoryItemTrait;
use SP\Storage\Database\QueryData;
+use SP\Storage\Database\QueryResult;
/**
* Class AccountFileRepository
@@ -94,7 +94,7 @@ class AccountFileRepository extends Repository implements RepositoryItemInterfac
/**
* @param $id
*
- * @return FileExtData
+ * @return \SP\Storage\Database\QueryResult
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
@@ -118,7 +118,7 @@ class AccountFileRepository extends Repository implements RepositoryItemInterfac
$queryData->setQuery($query);
$queryData->addParam($id);
- return $this->db->doSelect($queryData)->getData();
+ return $this->db->doSelect($queryData);
}
/**
@@ -126,7 +126,7 @@ class AccountFileRepository extends Repository implements RepositoryItemInterfac
*
* @param int $id
*
- * @return FileExtData
+ * @return \SP\Storage\Database\QueryResult
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
@@ -153,7 +153,7 @@ class AccountFileRepository extends Repository implements RepositoryItemInterfac
$queryData->setQuery($query);
$queryData->addParam($id);
- return $this->db->doSelect($queryData)->getData();
+ return $this->db->doSelect($queryData);
}
/**
@@ -161,36 +161,37 @@ class AccountFileRepository extends Repository implements RepositoryItemInterfac
*
* @param int $id
*
- * @return FileData[]
+ * @return \SP\Storage\Database\QueryResult
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function getByAccountId($id)
{
$query = /** @lang SQL */
- 'SELECT AF.id,
- AF.name,
- AF.size,
- AF.type,
- AF.accountId,
- AF.content,
- AF.thumb,
- AF.extension
- FROM AccountFile AF
- WHERE accountId = ?';
+ 'SELECT id,
+ `name`,
+ size,
+ type,
+ accountId,
+ content,
+ thumb,
+ extension
+ FROM AccountFile
+ WHERE accountId = ?
+ ORDER BY `name`';
$queryData = new QueryData();
$queryData->setMapClassName(FileData::class);
$queryData->setQuery($query);
$queryData->addParam($id);
- return $this->db->doSelect($queryData)->getDataAsArray();
+ return $this->db->doSelect($queryData);
}
/**
* Returns all the items
*
- * @return FileExtData[]
+ * @return \SP\Storage\Database\QueryResult
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
@@ -209,13 +210,14 @@ class AccountFileRepository extends Repository implements RepositoryItemInterfac
C.name AS clientName
FROM AccountFile AF
INNER JOIN Account A ON A.id = AF.accountId
- INNER JOIN Client C ON A.clientId = C.id';
+ INNER JOIN Client C ON A.clientId = C.id
+ ORDER BY AF.name';
$queryData = new QueryData();
$queryData->setMapClassName(FileExtData::class);
$queryData->setQuery($query);
- return $this->db->doSelect($queryData)->getDataAsArray();
+ return $this->db->doSelect($queryData);
}
/**
@@ -223,12 +225,16 @@ class AccountFileRepository extends Repository implements RepositoryItemInterfac
*
* @param array $ids
*
- * @return array
+ * @return \SP\Storage\Database\QueryResult
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function getByIdBatch(array $ids)
{
+ if (empty($ids)) {
+ return new QueryResult();
+ }
+
$query = /** @lang SQL */
'SELECT AF.id,
AF.name,
@@ -250,7 +256,7 @@ class AccountFileRepository extends Repository implements RepositoryItemInterfac
$queryData->setQuery($query);
$queryData->setParams($ids);
- return $this->db->doQuery($queryData)->getDataAsArray();
+ return $this->db->doQuery($queryData);
}
/**
@@ -258,8 +264,7 @@ class AccountFileRepository extends Repository implements RepositoryItemInterfac
*
* @param $id
*
- * @return AccountFileRepository
- * @throws NoSuchItemException
+ * @return int
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
@@ -273,11 +278,7 @@ class AccountFileRepository extends Repository implements RepositoryItemInterfac
$queryData->addParam($id);
$queryData->setOnErrorMessage(__u('Error al eliminar el archivo'));
- if ($this->db->doQuery($queryData)->getAffectedNumRows() === 0) {
- throw new NoSuchItemException(__u('Archivo no encontrado'));
- }
-
- return $this;
+ return $this->db->doQuery($queryData)->getAffectedNumRows();
}
/**
@@ -291,6 +292,10 @@ class AccountFileRepository extends Repository implements RepositoryItemInterfac
*/
public function deleteByIdBatch(array $ids)
{
+ if (empty($ids)) {
+ return 0;
+ }
+
$queryData = new QueryData();
$queryData->setQuery('DELETE FROM AccountFile WHERE id IN (' . $this->getParamsFromArray($ids) . ')');
$queryData->setParams($ids);
@@ -342,7 +347,7 @@ class AccountFileRepository extends Repository implements RepositoryItemInterfac
{
$queryData = new QueryData();
$queryData->setMapClassName(FileExtData::class);
- $queryData->setSelect('AF.id, AF.name, CONCAT(ROUND(AF.size/1000, 2), "KB") AS size, AF.thumb, AF.type, A.name as accountName, C.name as clientName');
+ $queryData->setSelect('AF.id, AF.accountId, AF.name, AF.size, AF.thumb, AF.type, AF.extension, A.name as accountName, C.name as clientName');
$queryData->setFrom('AccountFile AF INNER JOIN Account A ON A.id = AF.accountId INNER JOIN Client C ON A.clientId = C.id');
$queryData->setOrder('A.name');
diff --git a/lib/SP/Repositories/Account/AccountHistoryRepository.php b/lib/SP/Repositories/Account/AccountHistoryRepository.php
index fc9e7f0b..ffced50f 100644
--- a/lib/SP/Repositories/Account/AccountHistoryRepository.php
+++ b/lib/SP/Repositories/Account/AccountHistoryRepository.php
@@ -30,6 +30,7 @@ use SP\Core\Exceptions\QueryException;
use SP\Core\Exceptions\SPException;
use SP\DataModel\AccountHistoryData;
use SP\DataModel\AccountPassData;
+use SP\DataModel\Dto\AccountHistoryCreateDto;
use SP\DataModel\ItemSearchData;
use SP\Repositories\Repository;
use SP\Repositories\RepositoryItemInterface;
@@ -104,13 +105,13 @@ class AccountHistoryRepository extends Repository implements RepositoryItemInter
/**
* Crea una nueva cuenta en la BBDD
*
- * @param array $itemData ['id' => , 'isModify' => ,'isDelete' => , 'masterPassHash' => ]
+ * @param AccountHistoryCreateDto $dto
*
* @return int
* @throws QueryException
* @throws ConstraintException
*/
- public function create($itemData)
+ public function create($dto)
{
$queryData = new QueryData();
$query = /** @lang SQL */
@@ -161,10 +162,10 @@ class AccountHistoryRepository extends Repository implements RepositoryItemInter
?,?,? FROM Account WHERE id = ?';
$queryData->setQuery($query);
- $queryData->addParam($itemData['isModify']);
- $queryData->addParam($itemData['isDelete']);
- $queryData->addParam($itemData['masterPassHash']);
- $queryData->addParam($itemData['id']);
+ $queryData->addParam((int)$dto->isModify());
+ $queryData->addParam((int)$dto->isDelete());
+ $queryData->addParam($dto->getMasterPassHash());
+ $queryData->addParam($dto->getAccountId());
$queryData->setOnErrorMessage(__u('Error al actualizar el historial'));
return $this->db->doQuery($queryData)->getLastId();
diff --git a/lib/SP/Repositories/Account/AccountRepository.php b/lib/SP/Repositories/Account/AccountRepository.php
index 564f2e0d..af8a435d 100644
--- a/lib/SP/Repositories/Account/AccountRepository.php
+++ b/lib/SP/Repositories/Account/AccountRepository.php
@@ -641,15 +641,15 @@ class AccountRepository extends Repository implements RepositoryItemInterface
$queryJoins = new QueryJoin();
if ($accountSearchFilter->isSearchFavorites() === true) {
- $queryJoins->addJoin('INNER JOIN AccountToFavorite AF ON (AF.accountId = Account.id AND AF.userId = ?)', [$this->context->getUserData()->getId()]);
+ $queryJoins->addJoin('INNER JOIN AccountToFavorite ON (AccountToFavorite.accountId = Account.id AND AccountToFavorite.userId = ?)', [$this->context->getUserData()->getId()]);
}
if ($accountSearchFilter->hasTags()) {
- $queryJoins->addJoin('INNER JOIN AccountToTag AT ON AT.accountId = Account.id');
- $queryFilters->addFilter('AT.tagId IN (' . $this->getParamsFromArray($accountSearchFilter->getTagsId()) . ')', $accountSearchFilter->getTagsId());
+ $queryJoins->addJoin('INNER JOIN AccountToTag ON AccountToTag.accountId = Account.id');
+ $queryFilters->addFilter('AccountToTag.tagId IN (' . $this->getParamsFromArray($accountSearchFilter->getTagsId()) . ')', $accountSearchFilter->getTagsId());
if (QueryCondition::CONDITION_AND === $accountSearchFilter->getFilterOperator()) {
- $queryData->setGroupBy('Account.id HAVING COUNT(DISTINCT AT.tagId) = ' . count($accountSearchFilter->getTagsId()));
+ $queryData->setGroupBy('Account.id HAVING COUNT(DISTINCT AccountToTag.tagId) = ' . count($accountSearchFilter->getTagsId()));
}
}
diff --git a/lib/SP/Repositories/Account/AccountFavoriteRepository.php b/lib/SP/Repositories/Account/AccountToFavoriteRepository.php
similarity index 98%
rename from lib/SP/Repositories/Account/AccountFavoriteRepository.php
rename to lib/SP/Repositories/Account/AccountToFavoriteRepository.php
index e2137725..4969622c 100644
--- a/lib/SP/Repositories/Account/AccountFavoriteRepository.php
+++ b/lib/SP/Repositories/Account/AccountToFavoriteRepository.php
@@ -32,7 +32,7 @@ use SP\Storage\Database\QueryData;
*
* @package SP\Repositories\Account
*/
-class AccountFavoriteRepository extends Repository
+class AccountToFavoriteRepository extends Repository
{
/**
* Obtener un array con los Ids de cuentas favoritas
diff --git a/lib/SP/Repositories/RepositoryItemTrait.php b/lib/SP/Repositories/RepositoryItemTrait.php
index 8ca44c45..88d87d4b 100644
--- a/lib/SP/Repositories/RepositoryItemTrait.php
+++ b/lib/SP/Repositories/RepositoryItemTrait.php
@@ -24,7 +24,6 @@
namespace SP\Repositories;
-use SP\Core\Exceptions\SPException;
use SP\DataModel\DataModelInterface;
use SP\Storage\Database\DBStorageInterface;
use SP\Storage\Database\DBUtil;
@@ -52,7 +51,7 @@ trait RepositoryItemTrait
foreach ($items as $key => $item) {
try {
$this->delete($item->getId());
- } catch (SPException $e) {
+ } catch (\Exception $e) {
unset($items[$key]);
}
}
diff --git a/lib/SP/Repositories/User/UserRepository.php b/lib/SP/Repositories/User/UserRepository.php
index 811161df..2c4ae74e 100644
--- a/lib/SP/Repositories/User/UserRepository.php
+++ b/lib/SP/Repositories/User/UserRepository.php
@@ -513,9 +513,8 @@ class UserRepository extends Repository implements RepositoryItemInterface
/**
* @param $login string
*
- * @return UserData
+ * @return QueryResult
* @throws ConstraintException
- * @throws NoSuchItemException
* @throws QueryException
*/
public function getByLogin($login)
@@ -556,13 +555,7 @@ class UserRepository extends Repository implements RepositoryItemInterface
$queryData->setParams([$login, $login]);
$queryData->setOnErrorMessage(__u('Error al obtener los datos del usuario'));
- $result = $this->db->doSelect($queryData);
-
- if ($result->getNumRows() === 0) {
- throw new NoSuchItemException(__u('El usuario no existe'));
- }
-
- return $result->getData();
+ return$this->db->doSelect($queryData);
}
/**
diff --git a/lib/SP/Services/Account/AccountFileService.php b/lib/SP/Services/Account/AccountFileService.php
index 8a714857..845d6e38 100644
--- a/lib/SP/Services/Account/AccountFileService.php
+++ b/lib/SP/Services/Account/AccountFileService.php
@@ -2,8 +2,8 @@
/**
* sysPass
*
- * @author nuxsmin
- * @link https://syspass.org
+ * @author nuxsmin
+ * @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
@@ -29,6 +29,7 @@ use SP\DataModel\FileData;
use SP\DataModel\FileExtData;
use SP\DataModel\ItemSearchData;
use SP\Repositories\Account\AccountFileRepository;
+use SP\Repositories\NoSuchItemException;
use SP\Services\Service;
use SP\Services\ServiceException;
use SP\Storage\Database\QueryResult;
@@ -47,20 +48,12 @@ class AccountFileService extends Service
*/
protected $accountFileRepository;
- /**
- * @throws \Psr\Container\ContainerExceptionInterface
- * @throws \Psr\Container\NotFoundExceptionInterface
- */
- public function initialize()
- {
- $this->accountFileRepository = $this->dic->get(AccountFileRepository::class);
- }
-
/**
* Creates an item
*
* @param FileData $itemData
- * @return mixed
+ *
+ * @return int
* @throws SPException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
@@ -85,7 +78,7 @@ class AccountFileService extends Service
*/
public function getInfoById($id)
{
- return $this->accountFileRepository->getInfoById($id);
+ return $this->accountFileRepository->getInfoById($id)->getData();
}
/**
@@ -99,7 +92,7 @@ class AccountFileService extends Service
*/
public function getById($id)
{
- return $this->accountFileRepository->getById($id);
+ return $this->accountFileRepository->getById($id)->getData();
}
/**
@@ -111,7 +104,7 @@ class AccountFileService extends Service
*/
public function getAll()
{
- return $this->accountFileRepository->getAll();
+ return $this->accountFileRepository->getAll()->getDataAsArray();
}
/**
@@ -119,19 +112,20 @@ class AccountFileService extends Service
*
* @param array $ids
*
- * @return array
+ * @return FileExtData[]
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function getByIdBatch(array $ids)
{
- return $this->accountFileRepository->getByIdBatch($ids);
+ return $this->accountFileRepository->getByIdBatch($ids)->getDataAsArray();
}
/**
* Deletes all the items for given ids
*
* @param array $ids
+ *
* @return int
* @throws ServiceException
* @throws \SP\Core\Exceptions\ConstraintException
@@ -150,14 +144,16 @@ class AccountFileService extends Service
* Deletes an item
*
* @param $id
+ *
* @return AccountFileService
- * @throws SPException
- * @throws ServiceException
+ * @throws NoSuchItemException
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
*/
public function delete($id)
{
if ($this->accountFileRepository->delete($id) === 0) {
- throw new ServiceException(__u('Archivo no encontrado'), ServiceException::INFO);
+ throw new NoSuchItemException(__u('Archivo no encontrado'));
}
return $this;
@@ -188,6 +184,15 @@ class AccountFileService extends Service
*/
public function getByAccountId($id)
{
- return $this->accountFileRepository->getByAccountId($id);
+ return $this->accountFileRepository->getByAccountId($id)->getDataAsArray();
+ }
+
+ /**
+ * @throws \Psr\Container\ContainerExceptionInterface
+ * @throws \Psr\Container\NotFoundExceptionInterface
+ */
+ protected function initialize()
+ {
+ $this->accountFileRepository = $this->dic->get(AccountFileRepository::class);
}
}
\ No newline at end of file
diff --git a/lib/SP/Services/Account/AccountHistoryService.php b/lib/SP/Services/Account/AccountHistoryService.php
index ed8ae324..aed43037 100644
--- a/lib/SP/Services/Account/AccountHistoryService.php
+++ b/lib/SP/Services/Account/AccountHistoryService.php
@@ -27,6 +27,7 @@ namespace SP\Services\Account;
use SP\Core\Exceptions\QueryException;
use SP\Core\Exceptions\SPException;
use SP\DataModel\AccountHistoryData;
+use SP\DataModel\Dto\AccountHistoryCreateDto;
use SP\DataModel\ItemData;
use SP\DataModel\ItemSearchData;
use SP\Repositories\Account\AccountHistoryRepository;
@@ -57,17 +58,6 @@ class AccountHistoryService extends Service
*/
protected $accountToUserRepository;
- /**
- * @throws \Psr\Container\ContainerExceptionInterface
- * @throws \Psr\Container\NotFoundExceptionInterface
- */
- public function initialize()
- {
- $this->accountHistoryRepository = $this->dic->get(AccountHistoryRepository::class);
- $this->accountToUserRepository = $this->dic->get(AccountToUserRepository::class);
- $this->accountToUserGroupRepository = $this->dic->get(AccountToUserGroupRepository::class);
- }
-
/**
* Returns the item for given id
*
@@ -166,16 +156,15 @@ class AccountHistoryService extends Service
/**
* Crea una nueva cuenta en la BBDD
*
- * @param array $itemData ['id' => , 'isModify' => ,'isDelete' => , 'masterPassHash' => ]
+ * @param AccountHistoryCreateDto $dto
*
* @return bool
* @throws QueryException
* @throws \SP\Core\Exceptions\ConstraintException
- * @throws \SP\Core\Exceptions\QueryException
*/
- public function create($itemData)
+ public function create(AccountHistoryCreateDto $dto)
{
- return $this->accountHistoryRepository->create($itemData);
+ return $this->accountHistoryRepository->create($dto);
}
/**
@@ -240,6 +229,17 @@ class AccountHistoryService extends Service
*/
public function getAll()
{
- return self::mapHistoryForDateSelect($this->accountHistoryRepository->getAll()->getDataAsArray());
+ return $this->accountHistoryRepository->getAll()->getDataAsArray();
+ }
+
+ /**
+ * @throws \Psr\Container\ContainerExceptionInterface
+ * @throws \Psr\Container\NotFoundExceptionInterface
+ */
+ protected function initialize()
+ {
+ $this->accountHistoryRepository = $this->dic->get(AccountHistoryRepository::class);
+ $this->accountToUserRepository = $this->dic->get(AccountToUserRepository::class);
+ $this->accountToUserGroupRepository = $this->dic->get(AccountToUserGroupRepository::class);
}
}
\ No newline at end of file
diff --git a/lib/SP/Services/Account/AccountSearchService.php b/lib/SP/Services/Account/AccountSearchService.php
index 76a61aff..8794d386 100644
--- a/lib/SP/Services/Account/AccountSearchService.php
+++ b/lib/SP/Services/Account/AccountSearchService.php
@@ -54,7 +54,7 @@ class AccountSearchService extends Service
* Regex filters for special searching
*/
const FILTERS_REGEX_IS = '#(?(?:is|not):(?:expired|private))#';
- const FILTERS_REGEX = '#(?id|user|group|file|owner|maingroup):"?(?[\w\.]+)"?#';
+ const FILTERS_REGEX = '#(?id|user|group|file|owner|maingroup):(?:"(?[\w\s\.]+)"|(?[\w\.]+))#';
const FILTERS_REGEX_OPERATOR = '#op:(?and|or)#';
const COLORS_CACHE_FILE = CACHE_PATH . DIRECTORY_SEPARATOR . 'colors.cache';
@@ -137,7 +137,11 @@ class AccountSearchService extends Service
public function processSearchResults(AccountSearchFilter $accountSearchFilter)
{
$accountSearchFilter->setStringFilters($this->analyzeQueryFilters($accountSearchFilter->getTxtSearch()));
- $accountSearchFilter->setFilterOperator($this->filterOperator);
+
+ if ($accountSearchFilter->getFilterOperator() === null) {
+ $accountSearchFilter->setFilterOperator($this->filterOperator);
+ }
+
$accountSearchFilter->setCleanTxtSearch($this->cleanString);
$accountSearchResponse = $this->accountRepository->getByFilter($accountSearchFilter);
@@ -146,7 +150,7 @@ class AccountSearchService extends Service
$maxTextLength = $this->configData->isResultsAsCards() ? 40 : 60;
$accountLinkEnabled = $this->context->getUserData()->getPreferences()->isAccountLink() || $this->configData->isAccountLink();
- $favorites = $this->dic->get(AccountFavoriteService::class)->getForUserId($this->context->getUserData()->getId());
+ $favorites = $this->dic->get(AccountToFavoriteService::class)->getForUserId($this->context->getUserData()->getId());
$accountAclService = $this->dic->get(AccountAclService::class);
@@ -178,7 +182,7 @@ class AccountSearchService extends Service
$accountsData[] = $accountsSearchItem;
}
- return (new QueryResult($accountsData))->setTotalNumRows($accountSearchResponse->getCount());
+ return QueryResult::fromResults($accountsData, $accountSearchResponse->getCount());
}
/**
@@ -202,6 +206,18 @@ class AccountSearchService extends Service
return $queryCondition;
}
+ $this->extractFilterOperator($string);
+ $this->extractFilterIs($string, $queryCondition);
+ $this->extractFilterItems($string, $queryCondition);
+
+ return $queryCondition;
+ }
+
+ /**
+ * @param $string
+ */
+ private function extractFilterOperator($string)
+ {
if (preg_match(self::FILTERS_REGEX_OPERATOR, $string, $matches)) {
// Removes the operator from the string to increase regex performance
$this->cleanString = trim(str_replace($matches[0], '', $this->cleanString));
@@ -215,7 +231,14 @@ class AccountSearchService extends Service
break;
}
}
+ }
+ /**
+ * @param string $string
+ * @param QueryCondition $queryCondition
+ */
+ private function extractFilterIs($string, QueryCondition $queryCondition)
+ {
if (preg_match_all(self::FILTERS_REGEX_IS, $string, $matches, PREG_SET_ORDER) > 0) {
foreach ($matches as $filter) {
// Removes the current filter from the string to increase regex performance
@@ -237,21 +260,31 @@ class AccountSearchService extends Service
}
}
}
+ }
+ /**
+ * @param string $string
+ * @param QueryCondition $queryCondition
+ */
+ private function extractFilterItems($string, QueryCondition $queryCondition)
+ {
if (preg_match_all(self::FILTERS_REGEX, $string, $matches, PREG_SET_ORDER) > 0) {
foreach ($matches as $filter) {
// Removes the current filter from the string to increase regex performance
$this->cleanString = trim(str_replace($filter[0], '', $this->cleanString));
- if (($text = $filter['filter']) !== '') {
- try {
+ $text = !empty($filter['filter_quoted']) ? $filter['filter_quoted'] : $filter['filter'];
+ if ($text !== '') {
+ try {
switch ($filter['type']) {
case 'user':
if (is_object(($userData = $this->dic->get(UserService::class)->getByLogin($text)))) {
$queryCondition->addFilter(
- 'Account.userId = ? OR Account.id IN (SELECT AU.accountId FROM AccountToUser AU WHERE AU.accountId = Account.id AND AU.userId = ?
- UNION ALL SELECT AUG.accountId FROM AccountToUserGroup AUG WHERE AUG.accountId = Account.id AND AUG.userGroupId = ?)',
+ 'Account.userId = ? OR Account.id IN
+ (SELECT AccountToUser.accountId FROM AccountToUser WHERE AccountToUser.accountId = Account.id AND AccountToUser.userId = ?
+ UNION ALL
+ SELECT AccountToUserGroup.accountId FROM AccountToUserGroup WHERE AccountToUserGroup.accountId = Account.id AND AccountToUserGroup.userGroupId = ?)',
[$userData->getId(), $userData->getId(), $userData->getUserGroupId()]);
}
break;
@@ -261,15 +294,15 @@ class AccountSearchService extends Service
case 'group':
if (is_object(($userGroupData = $this->dic->get(UserGroupService::class)->getByName($text)))) {
$queryCondition->addFilter(
- 'Account.userGroupId = ? OR Account.id IN (SELECT AUG.accountId FROM AccountToUserGroup AUG WHERE AUG.accountId = id AND AUG.userGroupId = ?)',
+ 'Account.userGroupId = ? OR Account.id IN (SELECT AccountToUserGroup.accountId FROM AccountToUserGroup WHERE AccountToUserGroup.accountId = id AND AccountToUserGroup.userGroupId = ?)',
[$userGroupData->getId(), $userGroupData->getId()]);
}
break;
case 'maingroup':
- $queryCondition->addFilter('Account.userGroupName = ?', ['%' . $text . '%']);
+ $queryCondition->addFilter('Account.userGroupName LIKE ?', ['%' . $text . '%']);
break;
case 'file':
- $queryCondition->addFilter('Account.id IN (SELECT AF.accountId FROM AccountFile AF WHERE AF.name LIKE ?)', ['%' . $text . '%']);
+ $queryCondition->addFilter('Account.id IN (SELECT AccountFile.accountId FROM AccountFile WHERE AccountFile.name LIKE ?)', ['%' . $text . '%']);
break;
case 'id':
$queryCondition->addFilter('Account.id = ?', [(int)$text]);
@@ -277,12 +310,11 @@ class AccountSearchService extends Service
}
} catch (\Exception $e) {
+ processException($e);
}
}
}
}
-
- return $queryCondition;
}
/**
@@ -301,7 +333,10 @@ class AccountSearchService extends Service
/** @var AccountCache[] $cache */
$cache = $this->context->getAccountsCache();
- if (!isset($cache[$accountId])
+ $hasCache = $cache !== null;
+
+ if ($cache === false
+ || !isset($cache[$accountId])
|| $cache[$accountId]->getTime() < (int)strtotime($accountSearchData->getDateEdit())
) {
$cache[$accountId] = new AccountCache(
@@ -309,7 +344,9 @@ class AccountSearchService extends Service
$this->accountToUserRepository->getUsersByAccountId($accountId),
$this->accountToUserGroupRepository->getUserGroupsByAccountId($accountId));
- $this->context->setAccountsCache($cache);
+ if ($hasCache) {
+ $this->context->setAccountsCache($cache);
+ }
}
return $cache[$accountId];
diff --git a/lib/SP/Services/Account/AccountService.php b/lib/SP/Services/Account/AccountService.php
index 08adbb6a..1c857c7f 100644
--- a/lib/SP/Services/Account/AccountService.php
+++ b/lib/SP/Services/Account/AccountService.php
@@ -35,6 +35,7 @@ use SP\Core\Exceptions\SPException;
use SP\DataModel\AccountData;
use SP\DataModel\AccountPassData;
use SP\DataModel\Dto\AccountDetailsResponse;
+use SP\DataModel\Dto\AccountHistoryCreateDto;
use SP\DataModel\Dto\AccountSearchResponse;
use SP\DataModel\ItemSearchData;
use SP\Repositories\Account\AccountRepository;
@@ -307,12 +308,12 @@ class AccountService extends Service implements AccountServiceInterface
$accountHistoryRepository = $this->dic->get(AccountHistoryService::class);
$configService = $this->dic->get(ConfigService::class);
- return $accountHistoryRepository->create([
- 'id' => $accountId,
- 'isDelete' => (int)$isDelete,
- 'isModify' => (int)!$isDelete,
- 'masterPassHash' => $configService->getByParam('masterPwd')
- ]);
+ return $accountHistoryRepository->create(new AccountHistoryCreateDto(
+ $accountId,
+ $isDelete,
+ !$isDelete,
+ $configService->getByParam('masterPwd'))
+ );
}
/**
diff --git a/lib/SP/Services/Account/AccountFavoriteService.php b/lib/SP/Services/Account/AccountToFavoriteService.php
similarity index 89%
rename from lib/SP/Services/Account/AccountFavoriteService.php
rename to lib/SP/Services/Account/AccountToFavoriteService.php
index ba77c91e..a53207d6 100644
--- a/lib/SP/Services/Account/AccountFavoriteService.php
+++ b/lib/SP/Services/Account/AccountToFavoriteService.php
@@ -24,7 +24,7 @@
namespace SP\Services\Account;
-use SP\Repositories\Account\AccountFavoriteRepository;
+use SP\Repositories\Account\AccountToFavoriteRepository;
use SP\Services\Service;
/**
@@ -32,10 +32,10 @@ use SP\Services\Service;
*
* @package SP\Services\Account
*/
-class AccountFavoriteService extends Service
+class AccountToFavoriteService extends Service
{
/**
- * @var AccountFavoriteRepository
+ * @var AccountToFavoriteRepository
*/
protected $accountFavoriteRepository;
@@ -60,7 +60,8 @@ class AccountFavoriteService extends Service
* @param $userId int El Id del usuario
*
* @return bool
- * @throws \SP\Core\Exceptions\SPException
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
*/
public function add($accountId, $userId)
{
@@ -88,6 +89,6 @@ class AccountFavoriteService extends Service
*/
protected function initialize()
{
- $this->accountFavoriteRepository = $this->dic->get(AccountFavoriteRepository::class);
+ $this->accountFavoriteRepository = $this->dic->get(AccountToFavoriteRepository::class);
}
}
\ No newline at end of file
diff --git a/lib/SP/Services/Service.php b/lib/SP/Services/Service.php
index 3a927e80..da164c5e 100644
--- a/lib/SP/Services/Service.php
+++ b/lib/SP/Services/Service.php
@@ -28,8 +28,6 @@ use DI\Container;
use Psr\Container\ContainerInterface;
use SP\Config\Config;
use SP\Core\Context\ContextInterface;
-use SP\Core\Context\SessionContext;
-use SP\Core\Context\StatelessContext;
use SP\Core\Events\EventDispatcher;
/**
@@ -46,7 +44,7 @@ abstract class Service
*/
protected $config;
/**
- * @var SessionContext|StatelessContext
+ * @var ContextInterface
*/
protected $context;
/**
diff --git a/lib/SP/Services/User/UserService.php b/lib/SP/Services/User/UserService.php
index 65642f23..36eb45d4 100644
--- a/lib/SP/Services/User/UserService.php
+++ b/lib/SP/Services/User/UserService.php
@@ -32,6 +32,7 @@ use SP\DataModel\ItemSearchData;
use SP\DataModel\UserData;
use SP\DataModel\UserPreferencesData;
use SP\Repositories\DuplicatedItemException;
+use SP\Repositories\NoSuchItemException;
use SP\Repositories\User\UserRepository;
use SP\Services\Service;
use SP\Services\ServiceException;
@@ -153,7 +154,13 @@ class UserService extends Service
*/
public function getByLogin($login)
{
- return $this->userRepository->getByLogin($login);
+ $result = $this->userRepository->getByLogin($login);
+
+ if ($result->getNumRows() === 0) {
+ throw new NoSuchItemException(__u('El usuario no existe'));
+ }
+
+ return $result->getData();
}
/**
diff --git a/lib/SP/Storage/Database/QueryResult.php b/lib/SP/Storage/Database/QueryResult.php
index 17639c6e..52b63ceb 100644
--- a/lib/SP/Storage/Database/QueryResult.php
+++ b/lib/SP/Storage/Database/QueryResult.php
@@ -34,7 +34,7 @@ class QueryResult
/**
* @var array
*/
- private $data = [];
+ private $data;
/**
* @var int
*/
@@ -69,6 +69,23 @@ class QueryResult
}
}
+ /**
+ * @param array $data
+ * @param null $totalNumRows
+ *
+ * @return QueryResult
+ */
+ public static function fromResults(array $data, $totalNumRows = null)
+ {
+ $result = new self($data);
+
+ if ($totalNumRows !== null) {
+ $result->totalNumRows = $totalNumRows;
+ }
+
+ return $result;
+ }
+
/**
* @return mixed
*/
@@ -79,7 +96,7 @@ class QueryResult
return $this->data[0];
}
- return $this->data;
+ return null;
}
/**
@@ -89,7 +106,7 @@ class QueryResult
*/
public function getDataAsArray(): array
{
- return $this->data;
+ return (array)$this->data;
}
/**
@@ -179,5 +196,4 @@ class QueryResult
return $this;
}
-
}
\ No newline at end of file
diff --git a/lib/SP/Util/FileUtil.php b/lib/SP/Util/FileUtil.php
index c36fd9a3..fb199ec1 100644
--- a/lib/SP/Util/FileUtil.php
+++ b/lib/SP/Util/FileUtil.php
@@ -68,12 +68,12 @@ class FileUtil
}
/**
- * @param FileData $FileData
+ * @param FileData $fileData
*
* @return bool
*/
- public static function isImage(FileData $FileData)
+ public static function isImage(FileData $fileData)
{
- return in_array(mb_strtoupper($FileData->getExtension()), self::$imageExtensions, true);
+ return in_array(mb_strtoupper($fileData->getExtension()), self::$imageExtensions, true);
}
}
\ No newline at end of file
diff --git a/lib/SP/Util/ImageUtil.php b/lib/SP/Util/ImageUtil.php
index ac229185..7ea50878 100644
--- a/lib/SP/Util/ImageUtil.php
+++ b/lib/SP/Util/ImageUtil.php
@@ -24,6 +24,7 @@
namespace SP\Util;
+use SP\Core\Exceptions\InvalidImageException;
use SP\Log\LogUtil;
defined('APP_ROOT') || die();
@@ -39,13 +40,13 @@ class ImageUtil
* Convertir un texto a imagen
*
* @param $text string El texto a convertir
+ *
* @return bool|string
- * @throws \SP\Core\Exceptions\SPException
*/
public static function convertText($text)
{
if (!Checks::gdIsAvailable()) {
- LogUtil::extensionNotLoaded('GD');
+ debugLog(sprintf(__('Extensión \'%s\' no cargada'), 'GD'));
return false;
}
@@ -89,18 +90,21 @@ class ImageUtil
* Crear miniatura de una imagen
*
* @param $image string La imagen a redimensionar
+ *
* @return bool|string
- * @throws \SP\Core\Exceptions\SPException
+ * @throws InvalidImageException
*/
public static function createThumbnail($image)
{
if (!Checks::gdIsAvailable()) {
- LogUtil::extensionNotLoaded('GD', __FUNCTION__);
+ debugLog(sprintf(__('Extensión \'%s\' no cargada'), 'GD'));
return false;
}
- $im = imagecreatefromstring($image);
+ if (($im = @imagecreatefromstring($image)) === false) {
+ throw new InvalidImageException(__u('Imagen no válida'));
+ }
$width = imagesx($im);
$height = imagesy($im);
diff --git a/lib/SP/Util/Util.php b/lib/SP/Util/Util.php
index 4a516010..d28084fa 100644
--- a/lib/SP/Util/Util.php
+++ b/lib/SP/Util/Util.php
@@ -174,9 +174,9 @@ class Util
$ConfigData = Bootstrap::getContainer()->get(ConfigData::class);
if (!Checks::curlIsAvailable()) {
- $Log = LogUtil::extensionNotLoaded('CURL', __FUNCTION__);
+ debugLog(sprintf(__('Extensión \'%s\' no cargada'), 'CURL'));
- throw new SPException($Log->getDescription(), SPException::WARNING);
+ throw new SPException(sprintf(__('Extensión \'%s\' no cargada'), 'CURL'));
}
$ch = curl_init($url);
diff --git a/tests/AccountRepositoryTestCase.php b/tests/AccountRepositoryTestCase.php
deleted file mode 100644
index a2e5d347..00000000
--- a/tests/AccountRepositoryTestCase.php
+++ /dev/null
@@ -1,504 +0,0 @@
-.
- */
-
-namespace SP\Tests;
-
-use DI\DependencyException;
-use SP\Account\AccountRequest;
-use SP\Account\AccountSearchFilter;
-use SP\Core\Crypt\Crypt;
-use SP\Core\Exceptions\SPException;
-use SP\DataModel\AccountVData;
-use SP\DataModel\Dto\AccountSearchResponse;
-use SP\DataModel\ItemSearchData;
-use SP\Mvc\Model\QueryCondition;
-use SP\Repositories\Account\AccountRepository;
-use SP\Services\Account\AccountPasswordRequest;
-use SP\Storage\DatabaseConnectionData;
-
-/**
- * Class AccountRepositoryTest
- *
- * Tests unitarios para comprobar las consultas a la BBDD relativas a las cuentas
- *
- * @package SP\Tests
- */
-class AccountRepositoryTest extends DatabaseBaseTest
-{
- const SECURE_KEY_PASSWORD = 'syspass123';
- /**
- * @var AccountRepository
- */
- private static $accountRepository;
-
- /**
- * @throws DependencyException
- * @throws \DI\NotFoundException
- * @throws \SP\Core\Context\ContextException
- */
- public static function setUpBeforeClass()
- {
- $dic = setupContext();
-
- // Datos de conexión a la BBDD
- self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
-
- // Inicializar el repositorio
- self::$accountRepository = $dic->get(AccountRepository::class);
- }
-
- /**
- * Comprobar la eliminación de registros
- *
- * @throws SPException
- */
- public function testDelete()
- {
- // Comprobar registros iniciales
- $this->assertEquals(2, $this->conn->getRowCount('Account'));
-
- // Eliminar un registro y comprobar el total de registros
- $this->assertEquals(1, self::$accountRepository->delete(1));
- $this->assertEquals(1, $this->conn->getRowCount('Account'));
-
- // Eliminar un registro no existente
- $this->assertEquals(0, self::$accountRepository->delete(100));
-
- // Eliminar un registro y comprobar el total de registros
- $this->assertEquals(1, self::$accountRepository->delete(2));
- $this->assertEquals(0, $this->conn->getRowCount('Account'));
- }
-
- /**
- * No implementado
- */
- public function testEditRestore()
- {
- $this->markTestSkipped();
- }
-
- /**
- * Comprobar la modificación de una clave de cuenta
- *
- * @covers \SP\Repositories\Account\AccountRepository::getPasswordForId()
- * @throws SPException
- * @throws \Defuse\Crypto\Exception\CryptoException
- * @throws \SP\Core\Exceptions\ConstraintException
- */
- public function testEditPassword()
- {
- $accountRequest = new AccountRequest();
- $accountRequest->key = Crypt::makeSecuredKey(self::SECURE_KEY_PASSWORD);
- $accountRequest->pass = Crypt::encrypt('1234', $accountRequest->key, self::SECURE_KEY_PASSWORD);
- $accountRequest->id = 2;
- $accountRequest->userEditId = 1;
- $accountRequest->passDateChange = time() + 3600;
-
- // Comprobar que la modificación de la clave es correcta
- $this->assertTrue(self::$accountRepository->editPassword($accountRequest));
-
- $accountPassData = self::$accountRepository->getPasswordForId(2);
- $clearPassword = Crypt::decrypt($accountPassData->pass, $accountPassData->key, self::SECURE_KEY_PASSWORD);
-
- // Comprobar que la clave obtenida es igual a la encriptada anteriormente
- $this->assertEquals('1234', $clearPassword);
-
- // Comprobar que se devuelve un array vacío
- $this->assertCount(0, self::$accountRepository->getPasswordForId(10));
- }
-
- /**
- * No implementado
- */
- public function testCheckInUse()
- {
- $this->markTestSkipped();
- }
-
- /**
- * Comprobar la obtención de cuentas
- *
- * @throws SPException
- */
- public function testGetById()
- {
- $account = self::$accountRepository->getById(1);
-
- $this->assertInstanceOf(AccountVData::class, $account);
- $this->assertEquals(1, $account->getId());
-
- $this->expectException(SPException::class);
-
- self::$accountRepository->getById(100);
- }
-
- /**
- * @throws SPException
- */
- public function testUpdate()
- {
- $accountRequest = new AccountRequest();
- $accountRequest->id = 1;
- $accountRequest->name = 'Prueba 1';
- $accountRequest->login = 'admin';
- $accountRequest->url = 'http://syspass.org';
- $accountRequest->notes = 'notas';
- $accountRequest->userEditId = 1;
- $accountRequest->passDateChange = time() + 3600;
- $accountRequest->clientId = 1;
- $accountRequest->categoryId = 1;
- $accountRequest->isPrivate = 0;
- $accountRequest->isPrivateGroup = 0;
- $accountRequest->parentId = 0;
- $accountRequest->userGroupId = 2;
-
- $this->assertTrue(self::$accountRepository->update($accountRequest));
-
- $account = self::$accountRepository->getById(1);
-
- $this->assertEquals($accountRequest->name, $account->getName());
- $this->assertEquals($accountRequest->login, $account->getLogin());
- $this->assertEquals($accountRequest->url, $account->getUrl());
- $this->assertEquals($accountRequest->notes, $account->getNotes());
- $this->assertEquals($accountRequest->userEditId, $account->getUserEditId());
- $this->assertEquals($accountRequest->passDateChange, $account->getPassDateChange());
- $this->assertEquals($accountRequest->clientId, $account->getClientId());
- $this->assertEquals($accountRequest->categoryId, $account->getCategoryId());
- $this->assertEquals($accountRequest->isPrivate, $account->getIsPrivate());
- $this->assertEquals($accountRequest->isPrivateGroup, $account->getIsPrivateGroup());
- $this->assertEquals($accountRequest->parentId, $account->getParentId());
-
- // El grupo no debe de cambiar si el usuario no tiene permisos
- $this->assertNotEquals($accountRequest->userGroupId, $account->getUserGroupId());
- $this->assertEquals(1, $account->getUserGroupId());
- }
-
- /**
- * No implementado
- */
- public function testCheckDuplicatedOnAdd()
- {
- $this->markTestSkipped();
- }
-
- /**
- * Comprobar la eliminación en lotes
- *
- * @throws \SP\Core\Exceptions\ConstraintException
- * @throws \SP\Core\Exceptions\QueryException
- */
- public function testDeleteByIdBatch()
- {
- // Comprobar registros iniciales
- $this->assertEquals(2, $this->conn->getRowCount('Account'));
-
- $this->assertEquals(2, self::$accountRepository->deleteByIdBatch([1, 2, 100]));
-
- // Comprobar registros tras eliminación
- $this->assertEquals(0, $this->conn->getRowCount('Account'));
- }
-
- /**
- * Comprobar la búsqueda de cuentas
- */
- public function testSearch()
- {
- // Comprobar búsqueda con el texto Google Inc
- $itemSearchData = new ItemSearchData();
- $itemSearchData->setSeachString('Google');
- $itemSearchData->setLimitCount(10);
-
- $search = self::$accountRepository->search($itemSearchData);
-
- $this->assertCount(2, $search);
- $this->assertArrayHasKey('count', $search);
- $this->assertEquals(1, $search['count']);
- $this->assertInstanceOf(\stdClass::class, $search[0]);
- $this->assertEquals(1, $search[0]->id);
- $this->assertEquals('Google', $search[0]->name);
-
- // Comprobar búsqueda con el texto Apple
- $itemSearchData = new ItemSearchData();
- $itemSearchData->setSeachString('Apple');
- $itemSearchData->setLimitCount(1);
-
- $search = self::$accountRepository->search($itemSearchData);
- $this->assertCount(2, $search);
- $this->assertArrayHasKey('count', $search);
- $this->assertEquals(1, $search['count']);
- $this->assertInstanceOf(\stdClass::class, $search[0]);
- $this->assertEquals(2, $search[0]->id);
- $this->assertEquals('Apple', $search[0]->name);
- }
-
- /**
- * Comprobar las cuentas enlazadas
- */
- public function testGetLinked()
- {
- $filter = new QueryCondition();
- $filter->addFilter('Account.parentId = 1');
-
- $this->assertCount(0, self::$accountRepository->getLinked($filter));
- }
-
- /**
- * Comprobar en incremento del contador de vistas
- *
- * @throws \SP\Core\Exceptions\ConstraintException
- * @throws \SP\Core\Exceptions\QueryException
- * @throws SPException
- */
- public function testIncrementViewCounter()
- {
- $accountBefore = self::$accountRepository->getById(1);
-
- $this->assertTrue(self::$accountRepository->incrementViewCounter(1));
-
- $accountAfter = self::$accountRepository->getById(1);
-
- $this->assertEquals($accountBefore->getCountView() + 1, $accountAfter->getCountView());
- }
-
- /**
- * Obtener todas las cuentas
- */
- public function testGetAll()
- {
- $this->assertCount(2, self::$accountRepository->getAll());
- }
-
- /**
- * @throws SPException
- * @throws \Defuse\Crypto\Exception\CryptoException
- * @throws \SP\Core\Exceptions\ConstraintException
- */
- public function testUpdatePassword()
- {
- $accountRequest = new AccountPasswordRequest();
- $accountRequest->id = 2;
- $accountRequest->key = Crypt::makeSecuredKey(self::SECURE_KEY_PASSWORD);
- $accountRequest->pass = Crypt::encrypt('1234', $accountRequest->key, self::SECURE_KEY_PASSWORD);
-
- // Comprobar que la modificación de la clave es correcta
- $this->assertTrue(self::$accountRepository->updatePassword($accountRequest));
-
- $accountPassData = self::$accountRepository->getPasswordForId(2);
- $clearPassword = Crypt::decrypt($accountPassData->pass, $accountPassData->key, self::SECURE_KEY_PASSWORD);
-
- // Comprobar que la clave obtenida es igual a la encriptada anteriormente
- $this->assertEquals('1234', $clearPassword);
- }
-
- /**
- * Comprobar en incremento del contador de desencriptado
- *
- * @throws SPException
- * @throws \SP\Core\Exceptions\ConstraintException
- * @throws \SP\Core\Exceptions\QueryException
- */
- public function testIncrementDecryptCounter()
- {
- $accountBefore = self::$accountRepository->getById(1);
-
- $this->assertTrue(self::$accountRepository->incrementDecryptCounter(1));
-
- $accountAfter = self::$accountRepository->getById(1);
-
- $this->assertEquals($accountBefore->getCountDecrypt() + 1, $accountAfter->getCountDecrypt());
- }
-
- /**
- * Comprobar el número total de cuentas
- */
- public function testGetTotalNumAccounts()
- {
- $this->assertEquals(2, self::$accountRepository->getTotalNumAccounts()->num);
- }
-
- /**
- * No implementado
- */
- public function testGetDataForLink()
- {
- $this->markTestSkipped();
- }
-
- /**
- * Comprobar las cuentas devueltas para un filtro de usuario
- */
- public function testGetForUser()
- {
- $queryCondition = new QueryCondition();
- $queryCondition->addFilter('Account.isPrivate = 1');
-
- $this->assertCount(0, self::$accountRepository->getForUser($queryCondition));
- }
-
- /**
- * Comprobar las cuentas devueltas para obtener los datos de las claves
- */
- public function testGetAccountsPassData()
- {
- $this->assertCount(2, self::$accountRepository->getAccountsPassData());
- }
-
- /**
- * Comprobar la creación de una cuenta
- *
- * @throws SPException
- * @throws \Defuse\Crypto\Exception\CryptoException
- * @throws \SP\Core\Exceptions\ConstraintException
- * @throws \SP\Core\Exceptions\QueryException
- */
- public function testCreate()
- {
- $accountRequest = new AccountRequest();
- $accountRequest->name = 'Prueba 2';
- $accountRequest->login = 'admin';
- $accountRequest->url = 'http://syspass.org';
- $accountRequest->notes = 'notas';
- $accountRequest->userEditId = 1;
- $accountRequest->passDateChange = time() + 3600;
- $accountRequest->clientId = 1;
- $accountRequest->categoryId = 1;
- $accountRequest->isPrivate = 0;
- $accountRequest->isPrivateGroup = 0;
- $accountRequest->parentId = 0;
- $accountRequest->userId = 1;
- $accountRequest->userGroupId = 2;
- $accountRequest->key = Crypt::makeSecuredKey(self::SECURE_KEY_PASSWORD);
- $accountRequest->pass = Crypt::encrypt('1234', $accountRequest->key, self::SECURE_KEY_PASSWORD);
-
- // Comprobar registros iniciales
- $this->assertEquals(2, $this->conn->getRowCount('Account'));
-
- self::$accountRepository->create($accountRequest);
-
- // Comprobar registros finales
- $this->assertEquals(3, $this->conn->getRowCount('Account'));
- }
-
- /**
- * No implementado
- */
- public function testGetByIdBatch()
- {
- $this->markTestSkipped();
- }
-
- /**
- * No implementado
- */
- public function testCheckDuplicatedOnUpdate()
- {
- $this->markTestSkipped();
- }
-
- /**
- * No implementado
- */
- public function testGetPasswordHistoryForId()
- {
- $this->markTestSkipped();
- }
-
- /**
- * Comprobar la búsqueda de cuentas mediante filtros
- */
- public function testGetByFilter()
- {
- $searchFilter = new AccountSearchFilter();
- $searchFilter->setLimitCount(10);
- $searchFilter->setCategoryId(1);
-
- // Comprobar un Id de categoría
- $response = self::$accountRepository->getByFilter($searchFilter);
- $this->assertInstanceOf(AccountSearchResponse::class, $response);
- $this->assertEquals(1, $response->getCount());
- $this->assertCount(1, $response->getData());
-
- // Comprobar un Id de categoría no existente
- $searchFilter->reset();
- $searchFilter->setLimitCount(10);
- $searchFilter->setCategoryId(10);
-
- $response = self::$accountRepository->getByFilter($searchFilter);
- $this->assertInstanceOf(AccountSearchResponse::class, $response);
- $this->assertEquals(0, $response->getCount());
- $this->assertCount(0, $response->getData());
-
- // Comprobar un Id de cliente
- $searchFilter->reset();
- $searchFilter->setLimitCount(10);
- $searchFilter->setClientId(1);
-
- $response = self::$accountRepository->getByFilter($searchFilter);
- $this->assertInstanceOf(AccountSearchResponse::class, $response);
- $this->assertEquals(1, $response->getCount());
- $this->assertCount(1, $response->getData());
-
- // Comprobar un Id de cliente no existente
- $searchFilter->reset();
- $searchFilter->setLimitCount(10);
- $searchFilter->setClientId(10);
-
- $response = self::$accountRepository->getByFilter($searchFilter);
- $this->assertInstanceOf(AccountSearchResponse::class, $response);
- $this->assertEquals(0, $response->getCount());
- $this->assertCount(0, $response->getData());
-
- // Comprobar una cadena de texto
- $searchFilter->reset();
- $searchFilter->setLimitCount(10);
- $searchFilter->setCleanTxtSearch('apple.com');
-
- $response = self::$accountRepository->getByFilter($searchFilter);
- $this->assertInstanceOf(AccountSearchResponse::class, $response);
- $this->assertEquals(1, $response->getCount());
- $this->assertCount(1, $response->getData());
- $this->assertEquals(2, $response->getData()[0]->getId());
-
- // Comprobar los favoritos
- $searchFilter->reset();
- $searchFilter->setLimitCount(10);
- $searchFilter->setSearchFavorites(true);
-
- $response = self::$accountRepository->getByFilter($searchFilter);
- $this->assertInstanceOf(AccountSearchResponse::class, $response);
- $this->assertEquals(0, $response->getCount());
- $this->assertCount(0, $response->getData());
-
- // Comprobar las etiquetas
- $searchFilter->reset();
- $searchFilter->setLimitCount(10);
- $searchFilter->setTagsId([1]);
-
- $response = self::$accountRepository->getByFilter($searchFilter);
- $this->assertInstanceOf(AccountSearchResponse::class, $response);
- $this->assertEquals(1, $response->getCount());
- $this->assertCount(1, $response->getData());
- $this->assertEquals(1, $response->getData()[0]->getId());
- }
-}
diff --git a/tests/CategoryRepositoryTestCase.php b/tests/CategoryRepositoryTestCase.php
deleted file mode 100644
index 06bcd432..00000000
--- a/tests/CategoryRepositoryTestCase.php
+++ /dev/null
@@ -1,276 +0,0 @@
-.
- */
-
-namespace SP\Tests;
-
-use SP\Core\Exceptions\QueryException;
-use SP\DataModel\CategoryData;
-use SP\DataModel\ItemSearchData;
-use SP\Repositories\Category\CategoryRepository;
-use SP\Repositories\DuplicatedItemException;
-use SP\Storage\DatabaseConnectionData;
-
-/**
- * Class CategoryRepositoryTest
- *
- * @package SP\Tests
- */
-class CategoryRepositoryTest extends DatabaseBaseTest
-{
- /**
- * @var CategoryRepository
- */
- private static $categoryRepository;
-
- /**
- * @throws \DI\NotFoundException
- * @throws \SP\Core\Context\ContextException
- * @throws \DI\DependencyException
- */
- public static function setUpBeforeClass()
- {
- $dic = setupContext();
-
- // Datos de conexión a la BBDD
- self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
-
- // Inicializar el repositorio
- self::$categoryRepository = $dic->get(CategoryRepository::class);
- }
-
- /**
- * Comprobar los resultados de obtener las categorías por nombre
- */
- public function testGetByName()
- {
- $category = self::$categoryRepository->getByName('Prueba');
-
- $this->assertCount(0, $category);
-
- $category = self::$categoryRepository->getByName('Web');
-
- $this->assertEquals(1, $category->getId());
- $this->assertEquals('Web sites', $category->getDescription());
-
- $category = self::$categoryRepository->getByName('Linux');
-
- $this->assertEquals(2, $category->getId());
- $this->assertEquals('Linux server', $category->getDescription());
-
- // Se comprueba que el hash generado es el mismo en para el nombre 'Web'
- $category = self::$categoryRepository->getByName(' web. ');
-
- $this->assertEquals(1, $category->getId());
- $this->assertEquals('Web sites', $category->getDescription());
- }
-
- /**
- * Comprobar la búsqueda mediante texto
- */
- public function testSearch()
- {
- $searchItemData = new ItemSearchData();
- $searchItemData->setLimitCount(10);
- $searchItemData->setSeachString('linux');
-
- $search = self::$categoryRepository->search($searchItemData);
- $this->assertCount(2, $search);
- $this->assertArrayHasKey('count', $search);
- $this->assertEquals(1, $search['count']);
- $this->assertEquals(2, $search[0]->id);
- $this->assertEquals('Linux server', $search[0]->description);
-
- $searchItemData = new ItemSearchData();
- $searchItemData->setLimitCount(10);
- $searchItemData->setSeachString('prueba');
-
- $search = self::$categoryRepository->search($searchItemData);
- $this->assertCount(1, $search);
- $this->assertArrayHasKey('count', $search);
- $this->assertEquals(0, $search['count']);
- }
-
- /**
- * Comprobar los resultados de obtener las categorías por Id
- */
- public function testGetById()
- {
- $category = self::$categoryRepository->getById(10);
-
- $this->assertCount(0, $category);
-
- $category = self::$categoryRepository->getById(1);
-
- $this->assertEquals('Web', $category->getName());
- $this->assertEquals('Web sites', $category->getDescription());
-
- $category = self::$categoryRepository->getById(2);
-
- $this->assertEquals('Linux', $category->getName());
- $this->assertEquals('Linux server', $category->getDescription());
- }
-
- /**
- * Comprobar la obtención de todas las categorías
- */
- public function testGetAll()
- {
- $count = $this->conn->getRowCount('Category');
-
- $results = self::$categoryRepository->getAll();
-
- $this->assertCount($count, $results);
-
- $this->assertInstanceOf(CategoryData::class, $results[0]);
- $this->assertEquals('Linux', $results[0]->getName());
-
- $this->assertInstanceOf(CategoryData::class, $results[1]);
- $this->assertEquals('SSH', $results[1]->getName());
-
- $this->assertInstanceOf(CategoryData::class, $results[2]);
- $this->assertEquals('Web', $results[2]->getName());
- }
-
- /**
- * Comprobar la actualización de categorías
- *
- * @covers \SP\Repositories\Category\CategoryRepository::checkDuplicatedOnUpdate()
- * @throws \SP\Core\Exceptions\ConstraintException
- * @throws \SP\Core\Exceptions\QueryException
- * @throws \SP\Core\Exceptions\SPException
- * @throws \SP\Repositories\DuplicatedItemException
- */
- public function testUpdate()
- {
- $categoryData = new CategoryData();
- $categoryData->id = 1;
- $categoryData->name = 'Web prueba';
- $categoryData->description = 'Descripción web prueba';
-
- self::$categoryRepository->update($categoryData);
-
- $category = self::$categoryRepository->getById(1);
-
- $this->assertEquals($category->getName(), $categoryData->name);
- $this->assertEquals($category->getDescription(), $categoryData->description);
-
- // Comprobar la a actualización con un nombre duplicado comprobando su hash
- $categoryData = new CategoryData();
- $categoryData->id = 1;
- $categoryData->name = ' linux.';
-
- $this->expectException(DuplicatedItemException::class);
-
- self::$categoryRepository->update($categoryData);
- }
-
- /**
- * Comprobar la eliminación de categorías
- *
- * @throws \SP\Core\Exceptions\ConstraintException
- * @throws \SP\Core\Exceptions\QueryException
- */
- public function testDeleteByIdBatch()
- {
- $countBefore = $this->conn->getRowCount('Category');
-
- $this->assertEquals(1, self::$categoryRepository->deleteByIdBatch([3]));
-
- $countAfter = $this->conn->getRowCount('Category');
-
- $this->assertEquals($countBefore - 1, $countAfter);
-
- // Comprobar que se produce una excepción al tratar de eliminar categorías usadas
- $this->expectException(QueryException::class);
-
- $this->assertEquals(1, self::$categoryRepository->deleteByIdBatch([1, 2, 3]));
- }
-
- /**
- * Comprobar la creación de categorías
- *
- * @covers \SP\Repositories\Category\CategoryRepository::checkDuplicatedOnAdd()
- * @throws DuplicatedItemException
- * @throws \SP\Core\Exceptions\SPException
- */
- public function testCreate()
- {
- $countBefore = $this->conn->getRowCount('Category');
-
- $categoryData = new CategoryData();
- $categoryData->name = 'Categoría prueba';
- $categoryData->description = 'Descripción prueba';
-
- $id = self::$categoryRepository->create($categoryData);
-
- // Comprobar que el Id devuelto corresponde con la categoría creada
- $category = self::$categoryRepository->getById($id);
-
- $this->assertEquals($categoryData->name, $category->getName());
-
- $countAfter = $this->conn->getRowCount('Category');
-
- $this->assertEquals($countBefore + 1, $countAfter);
- }
-
- /**
- * Comprobar la eliminación de categorías por Id
- *
- * @throws QueryException
- * @throws \SP\Core\Exceptions\ConstraintException
- */
- public function testDelete()
- {
- $countBefore = $this->conn->getRowCount('Category');
-
- $this->assertEquals(1, self::$categoryRepository->delete(3));
-
- $countAfter = $this->conn->getRowCount('Category');
-
- $this->assertEquals($countBefore - 1, $countAfter);
-
- // Comprobar que se produce una excepción al tratar de eliminar categorías usadas
- $this->expectException(QueryException::class);
-
- $this->assertEquals(1, self::$categoryRepository->delete(2));
- }
-
- /**
- * Comprobar la obtención de categorías por Id en lote
- */
- public function testGetByIdBatch()
- {
- $this->assertCount(3, self::$categoryRepository->getByIdBatch([1, 2, 3]));
- $this->assertCount(3, self::$categoryRepository->getByIdBatch([1, 2, 3, 4, 5]));
- $this->assertCount(0, self::$categoryRepository->getByIdBatch([]));
- }
-
- /**
- * No implementado
- */
- public function testCheckInUse()
- {
- $this->markTestSkipped();
- }
-}
diff --git a/tests/ClientRepositoryTestCase.php b/tests/ClientRepositoryTestCase.php
deleted file mode 100644
index 69439f5a..00000000
--- a/tests/ClientRepositoryTestCase.php
+++ /dev/null
@@ -1,290 +0,0 @@
-.
- */
-
-namespace SP\Tests;
-
-use SP\Core\Exceptions\QueryException;
-use SP\DataModel\ClientData;
-use SP\DataModel\ItemSearchData;
-use SP\Mvc\Model\QueryCondition;
-use SP\Repositories\Client\ClientRepository;
-use SP\Repositories\DuplicatedItemException;
-use SP\Storage\DatabaseConnectionData;
-
-/**
- * Class ClientRepositoryTest
- *
- * @package SP\Tests
- */
-class ClientRepositoryTest extends DatabaseBaseTest
-{
- /**
- * @var ClientRepository
- */
- private static $clientRepository;
-
- /**
- * @throws \DI\NotFoundException
- * @throws \SP\Core\Context\ContextException
- * @throws \DI\DependencyException
- */
- public static function setUpBeforeClass()
- {
- $dic = setupContext();
-
- // Datos de conexión a la BBDD
- self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
-
- // Inicializar el repositorio
- self::$clientRepository = $dic->get(ClientRepository::class);
- }
-
- /**
- * Comprobar los resultados de obtener los cliente por nombre
- */
- public function testGetByName()
- {
- $client = self::$clientRepository->getByName('Amazon');
-
- $this->assertCount(0, $client);
-
- $client = self::$clientRepository->getByName('Google');
-
- $this->assertEquals(1, $client->getId());
- $this->assertEquals('Google Inc.', $client->getDescription());
-
- $client = self::$clientRepository->getByName('Apple');
-
- $this->assertEquals(2, $client->getId());
- $this->assertEquals('Apple Inc.', $client->getDescription());
-
- // Se comprueba que el hash generado es el mismo en para el nombre 'Web'
- $client = self::$clientRepository->getByName(' google. ');
-
- $this->assertEquals(1, $client->getId());
- $this->assertEquals('Google Inc.', $client->getDescription());
- }
-
- /**
- * Comprobar la búsqueda mediante texto
- */
- public function testSearch()
- {
- $searchItemData = new ItemSearchData();
- $searchItemData->setLimitCount(10);
- $searchItemData->setSeachString('google');
-
- $search = self::$clientRepository->search($searchItemData);
- $this->assertCount(2, $search);
- $this->assertArrayHasKey('count', $search);
- $this->assertEquals(1, $search['count']);
- $this->assertEquals(1, $search[0]->id);
- $this->assertEquals('Google Inc.', $search[0]->description);
-
- $searchItemData = new ItemSearchData();
- $searchItemData->setLimitCount(10);
- $searchItemData->setSeachString('prueba');
-
- $search = self::$clientRepository->search($searchItemData);
- $this->assertCount(1, $search);
- $this->assertArrayHasKey('count', $search);
- $this->assertEquals(0, $search['count']);
- }
-
- /**
- * Comprobar los resultados de obtener los clientes por Id
- */
- public function testGetById()
- {
- $client = self::$clientRepository->getById(10);
-
- $this->assertCount(0, $client);
-
- $client = self::$clientRepository->getById(1);
-
- $this->assertEquals('Google', $client->getName());
- $this->assertEquals('Google Inc.', $client->getDescription());
-
- $client = self::$clientRepository->getById(2);
-
- $this->assertEquals('Apple', $client->getName());
- $this->assertEquals('Apple Inc.', $client->getDescription());
- }
-
- /**
- * Comprobar la obtención de todas las client
- */
- public function testGetAll()
- {
- $count = $this->conn->getRowCount('Client');
-
- $results = self::$clientRepository->getAll();
-
- $this->assertCount($count, $results);
-
- $this->assertInstanceOf(ClientData::class, $results[0]);
- $this->assertEquals('Apple', $results[0]->getName());
-
- $this->assertInstanceOf(ClientData::class, $results[1]);
- $this->assertEquals('Google', $results[1]->getName());
-
- $this->assertInstanceOf(ClientData::class, $results[2]);
- $this->assertEquals('Microsoft', $results[2]->getName());
- }
-
- /**
- * Comprobar la actualización de clientes
- *
- * @covers \SP\Repositories\Client\ClientRepository::checkDuplicatedOnUpdate()
- * @throws \SP\Core\Exceptions\ConstraintException
- * @throws \SP\Core\Exceptions\QueryException
- * @throws \SP\Core\Exceptions\SPException
- * @throws \SP\Repositories\DuplicatedItemException
- */
- public function testUpdate()
- {
- $clientData = new ClientData();
- $clientData->id = 1;
- $clientData->name = 'Cliente prueba';
- $clientData->description = 'Descripción cliente prueba';
-
- self::$clientRepository->update($clientData);
-
- $category = self::$clientRepository->getById(1);
-
- $this->assertEquals($category->getName(), $clientData->name);
- $this->assertEquals($category->getDescription(), $clientData->description);
-
- // Comprobar la a actualización con un nombre duplicado comprobando su hash
- $clientData = new ClientData();
- $clientData->id = 1;
- $clientData->name = ' apple.';
-
- $this->expectException(DuplicatedItemException::class);
-
- self::$clientRepository->update($clientData);
- }
-
- /**
- * Comprobar la eliminación de clientes
- *
- * @throws \SP\Core\Exceptions\ConstraintException
- * @throws \SP\Core\Exceptions\QueryException
- */
- public function testDeleteByIdBatch()
- {
- $countBefore = $this->conn->getRowCount('Client');
-
- $this->assertEquals(1, self::$clientRepository->deleteByIdBatch([3]));
-
- $countAfter = $this->conn->getRowCount('Client');
-
- $this->assertEquals($countBefore - 1, $countAfter);
-
- // Comprobar que se produce una excepción al tratar de eliminar clientes usados
- $this->expectException(QueryException::class);
-
- $this->assertEquals(1, self::$clientRepository->deleteByIdBatch([1, 2, 3]));
- }
-
- /**
- * Comprobar la creación de clientes
- *
- * @covers \SP\Repositories\Client\ClientRepository::checkDuplicatedOnAdd()
- * @throws DuplicatedItemException
- * @throws \SP\Core\Exceptions\SPException
- */
- public function testCreate()
- {
- $countBefore = $this->conn->getRowCount('Client');
-
- $clientData = new ClientData();
- $clientData->name = 'Cliente prueba';
- $clientData->description = 'Descripción prueba';
- $clientData->isGlobal = 1;
-
- $id = self::$clientRepository->create($clientData);
-
- // Comprobar que el Id devuelto corresponde con el cliente creado
- $client = self::$clientRepository->getById($id);
-
- $this->assertEquals($clientData->name, $client->getName());
- $this->assertEquals($clientData->isGlobal, $client->getIsGlobal());
-
- $countAfter = $this->conn->getRowCount('Client');
-
- $this->assertEquals($countBefore + 1, $countAfter);
- }
-
- /**
- * Comprobar la eliminación de clientes por Id
- *
- * @throws \SP\Core\Exceptions\QueryException
- * @throws \SP\Core\Exceptions\ConstraintException
- */
- public function testDelete()
- {
- $countBefore = $this->conn->getRowCount('Client');
-
- $this->assertEquals(1, self::$clientRepository->delete(3));
-
- $countAfter = $this->conn->getRowCount('Client');
-
- $this->assertEquals($countBefore - 1, $countAfter);
-
- // Comprobar que se produce una excepción al tratar de eliminar clientes usados
- $this->expectException(QueryException::class);
-
- $this->assertEquals(1, self::$clientRepository->delete(2));
- }
-
- /**
- * Comprobar la obtención de clientes por Id en lote
- */
- public function testGetByIdBatch()
- {
- $this->assertCount(3, self::$clientRepository->getByIdBatch([1, 2, 3]));
- $this->assertCount(3, self::$clientRepository->getByIdBatch([1, 2, 3, 4, 5]));
- $this->assertCount(0, self::$clientRepository->getByIdBatch([]));
- }
-
- /**
- * No implementado
- */
- public function testCheckInUse()
- {
- $this->markTestSkipped();
- }
-
- /**
- * @throws QueryException
- */
- public function testGetAllForFilter()
- {
- $filter = new QueryCondition();
- $filter->addFilter('Account.isPrivate = 0');
-
- $this->assertCount(3, self::$clientRepository->getAllForFilter($filter));
- }
-}
diff --git a/tests/Repositories/AccountFileRepositoryTest.php b/tests/Repositories/AccountFileRepositoryTest.php
new file mode 100644
index 00000000..6d123b6b
--- /dev/null
+++ b/tests/Repositories/AccountFileRepositoryTest.php
@@ -0,0 +1,315 @@
+.
+ */
+
+namespace SP\Tests\Repositories;
+
+use PHPUnit\DbUnit\DataSet\IDataSet;
+use SP\DataModel\FileData;
+use SP\DataModel\FileExtData;
+use SP\DataModel\ItemSearchData;
+use SP\Repositories\Account\AccountFileRepository;
+use SP\Storage\Database\DatabaseConnectionData;
+use SP\Tests\DatabaseTestCase;
+use function SP\Tests\setupContext;
+
+/**
+ * Class AccountFileRepositoryTest
+ *
+ * @package SP\Tests\Repositories
+ */
+class AccountFileRepositoryTest extends DatabaseTestCase
+{
+ /**
+ * @var AccountFileRepository
+ */
+ private static $repository;
+
+ /**
+ * @throws \DI\DependencyException
+ * @throws \DI\NotFoundException
+ * @throws \SP\Core\Context\ContextException
+ */
+ public static function setUpBeforeClass()
+ {
+ $dic = setupContext();
+
+ // Datos de conexión a la BBDD
+ self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
+
+ // Inicializar el repositorio
+ self::$repository = $dic->get(AccountFileRepository::class);
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testDelete()
+ {
+ $this->assertEquals(1, self::$repository->delete(1));
+ $this->assertEquals(1, self::$repository->delete(3));
+ $this->assertEquals(0, self::$repository->delete(10));
+
+ $this->assertEquals(1, $this->conn->getRowCount('AccountFile'));
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testDeleteByIdBatch()
+ {
+ $this->assertEquals(2, self::$repository->deleteByIdBatch([1, 3, 10]));
+ $this->assertEquals(0, self::$repository->deleteByIdBatch([]));
+
+ $this->assertEquals(1, $this->conn->getRowCount('AccountFile'));
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetInfoById()
+ {
+ $result = self::$repository->getInfoById(1);
+ /** @var FileExtData $data */
+ $data = $result->getData();
+
+ $this->assertEquals(1, $result->getNumRows());
+ $this->assertInstanceOf(FileExtData::class, $data);
+ $this->assertEquals('sysPass.xml', $data->getName());
+ $this->assertEquals('text/xml', $data->getType());
+ $this->assertEquals('XML', $data->getExtension());
+ $this->assertEquals('Google', $data->getAccountName());
+ $this->assertEquals('Google', $data->getClientName());
+ $this->assertEquals(1312, $data->getSize());
+ $this->assertEquals(1, $data->getAccountId());
+ $this->assertNull($data->getContent());
+ $this->assertNull($data->getThumb());
+
+ $result = self::$repository->getInfoById(10);
+
+ $this->assertEquals(0, $result->getNumRows());
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetById()
+ {
+ $result = self::$repository->getById(1);
+ /** @var FileExtData $data */
+ $data = $result->getData();
+
+ $this->assertEquals(1, $result->getNumRows());
+ $this->assertInstanceOf(FileExtData::class, $data);
+ $this->assertEquals('sysPass.xml', $data->getName());
+ $this->assertEquals('text/xml', $data->getType());
+ $this->assertEquals('XML', $data->getExtension());
+ $this->assertEquals('Google', $data->getAccountName());
+ $this->assertEquals('Google', $data->getClientName());
+ $this->assertEquals(1312, $data->getSize());
+ $this->assertEquals(1, $data->getAccountId());
+ $this->assertEquals(pack('H*', '3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C526F6F743E0A20203C4D6574613E0A202020203C47656E657261746F723E737973506173733C2F47656E657261746F723E0A202020203C56657273696F6E3E312E322E303C2F56657273696F6E3E0A202020203C54696D653E313433393332353330343C2F54696D653E0A202020203C557365722069643D2231223E61646D696E3C2F557365723E0A202020203C47726F75702069643D2231223E41646D696E733C2F47726F75703E0A202020203C486173683E36646232633238323731393136326630663136316531343731653734636531623C2F486173683E0A20203C2F4D6574613E0A20203C43617465676F726965733E0A202020203C43617465676F72792069643D2231223E0A2020202020203C6E616D653E485454503C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F43617465676F72793E0A20203C2F43617465676F726965733E0A20203C437573746F6D6572733E0A202020203C437573746F6D65722069643D2231223E0A2020202020203C6E616D653E476F6F676C6520496E632E3C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F437573746F6D65723E0A202020203C437573746F6D65722069643D2232223E0A2020202020203C6E616D653E4D6963726F736F667420496E633C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F437573746F6D65723E0A20203C2F437573746F6D6572733E0A20203C4163636F756E74733E0A202020203C4163636F756E742069643D2231223E0A2020202020203C6E616D653E476F6F676C653C2F6E616D653E0A2020202020203C637573746F6D657249643E313C2F637573746F6D657249643E0A2020202020203C63617465676F727949643E313C2F63617465676F727949643E0A2020202020203C6C6F67696E3E61646D696E3C2F6C6F67696E3E0A2020202020203C75726C3E382E382E382E383C2F75726C3E0A2020202020203C6E6F7465732F3E0A2020202020203C706173733E6C4E66513133634B6A384D592B79434F346652536B4773494334357247454C442F424E69345654614671593D3C2F706173733E0A2020202020203C7061737369763E454E6354743338503265346C643350395A553241767939664C466277386C42473947382F75414D785A6D343D3C2F7061737369763E0A202020203C2F4163636F756E743E0A202020203C4163636F756E742069643D2232223E0A2020202020203C6E616D653E4D6963726F736F66743C2F6E616D653E0A2020202020203C637573746F6D657249643E323C2F637573746F6D657249643E0A2020202020203C63617465676F727949643E313C2F63617465676F727949643E0A2020202020203C6C6F67696E3E726F6F743C2F6C6F67696E3E0A2020202020203C75726C3E342E342E342E343C2F75726C3E0A2020202020203C6E6F7465733E4E6F746173206465206D6963726F66736F66743C2F6E6F7465733E0A2020202020203C706173733E3352394F48632B53335A4E56684D795948352F784C476C76625246662F5367573348527261322B325349453D3C2F706173733E0A2020202020203C7061737369763E763637306A596B43547178635332344C4F65453077672B304330376A734C2F4635342B6E56484963544F773D3C2F7061737369763E0A202020203C2F4163636F756E743E0A20203C2F4163636F756E74733E0A3C2F526F6F743E0A'), $data->getContent());
+ $this->assertEquals(pack('H*', '6E6F5F7468756D62'), $data->getThumb());
+
+ $result = self::$repository->getById(4);
+ /** @var FileExtData $data */
+ $data = $result->getData();
+
+ $this->assertEquals(1, $result->getNumRows());
+ $this->assertInstanceOf(FileExtData::class, $data);
+ $this->assertEquals('android.png', $data->getName());
+ $this->assertEquals('image/png', $data->getType());
+ $this->assertEquals('PNG', $data->getExtension());
+ $this->assertEquals('Google', $data->getAccountName());
+ $this->assertEquals('Google', $data->getClientName());
+ $this->assertEquals(4295, $data->getSize());
+ $this->assertEquals(1, $data->getAccountId());
+ $this->assertEquals(pack('H*', '89504E470D0A1A0A0000000D4948445200000080000000800806000000C33E61CB00000006624B474400FF00FF00FFA0BDA793000000097048597300000B1300000B1301009A9C180000000774494D4507DD011D0E180BE2306F78000010544944415478DAED5D6B745CD575FEBE7DEFC8961F3C0C01EC45480C2B8B0026A1D4206B2CB9C27181F208D074816D59069A16280B92A6246D42520A252D210FD2248426818418C9C63CD264C182BAE1154B1A4960CAB35E506A1E5D26501C9E768464CDDCF3F5C7BDA31796A59135F28CE66C2D594B9A19DF73F7FECEB71F67DF7388329096CCC293C1E997845174D1F2FACE374B7DBCCD1B17CF0F42DDDB1BED58F2E74B9E7DBB94C76AE5000069DA05A2CE8CA8EF94FA587FF6507D1503D71A018757D9EC334A7DBC650100B2E79F4C70B0E0336B338BFEA494C75A352DF70D1AE71AB8F9A5F51DCD1E001320AB163FB159C2CD12663A58D35D1DE9D9A538CE350F351C65C6931D1038B9CBAFBA11F200983016705F96DC9B3077CE4EC7926481B0BAF7F208760C22AD69AAEBEC2A07BD960D001AD39DBF27832F986C3A694DEBDA4F9A5352816A5BC332293CD790450AE115E5A2D7B201000050D10310FE57CC9DEAD47342A98CEBB6473E5585A0F72C3077805C78EDF2FAB6B7CA46A7283359DB9E5E2D6A0DA42E9B3E73C9CA850F6547FBCCBAB69A1991719E219C0146F38420A07400E40218009102BA01F70E2D34C1BD48177457F76CDFF6A7CB9ECE8D9AF6B5A76B403C4CEA8528179D76FE92C75E2F177D86E5060089F793DC08CBFD91EBED5905E0D6E1EFB9E7D7A7A5B6CFD85E47BAE3011C23E02002F300CD00381750086086C86133C0DE8364005E045C774FF5CCDFB574A4B7105107A2E0A5C6FA8EA7771D9FE07A11339C70533919BF2C1900009ADBEACE27A31F928E3DCF1FB5EF5F7CF6E7B907375F17BCF6EE7D75845B29E3498110413A5C4415101B5A1020825072E79404821093BF0CFC4100084A10F09E889728E668EE2E58EFFAC69A27B702C0DAAE450B11059B003D09F0338D8B332F7B004C46D09549B782564FD7773314DE01E3B7441C09A91A04094862FC1322C971F14DE21E10A3062024800ECEDD1B657139A6A183C0C141C4BF5B59DFF1BD72D3A3952B00E8EC3B0E511616FCA5026D70D47110A69348883DB139314EE327E44E80313DC43F6240848E38C7A6BB570D3CCCC4E742CDBCBB2CF5586E035ED75A77906374BA8C5F20B9801A740F1404F6D379516290D871C47048CA3CA2EBA37827841FCEDEE785473FFD8937E5015014DAAF3D9BB02F89AA0110304FC87BF12E84FC10040ADB40AC0F72D13F2F5FF2E81B1E0013286B3A177D3E10AF226C7FF4CF7A09E4DEBD07C59C80981048E07527BD2EBAAFAF4E77FDD203604F23FE478EFF10AAAAEE27834F00AAA228F183095C09E5A94E8441B683DCF9DDC6F4A67FF000182FE5B72F3A8EC0DD8E7604291156168C250146413038E46E545FF4E5D50D9BBA7D1650C8CC6FAF6D20C33B6176841162A2D2B2F0AB141C28C081B2CB2C0C7FBCB6ADE610CF00632EF4D42E03ED76331D085122588E050B498A07EE08173E9072D59F3D77C9035B3D03EC2ED8EB38611189663377A0627F3AC4F8FD2CA0815F94285B93481071553119811497103198A394142008C004BA3FDE99DA7E434BF3D98107C0483EBFB5EEE32985FF06E21080026803D9769EB20827C9D14114639A158C2439192088314711A2E8E020231C1947A7FDC3CDC3564412B352C1593AFCB59B3C007635F3DB3FB91F037C3F6270485C6461BE82C7FE843B9E66204593DD41B15E2E3C09D4CD4E8AE2A430FFAEE2794D4104B25BA19D17059C51A75C7635113DDBBFA4306400C99F62F0A608BB706D7BFA2B3E06F84091E7C46B81F06BCC2B99C290544F8098706EE4AE6BAA7FF4CA217143E6842B89F01A9261D18286643549E4EB51A4D3CEAFEF782AFFD2ADBF39E1A3A954F84B92C78DA45AE54B46D2FF98B4AAB1AEF331CF00009A338B9792C165C984573C69862A50042882C2CBA4EEFAC08D38B600F6BC8A896AC6CB4C14EEDA27D5F7CCE0972E6CD8F40AC9FB04E634E20808023D240E75C0579B5B97CCAE7800AC6B4FCF32E03A80FB4914A8DD509500E27D67DA39FCF569E1F6B71DD58D64E1B758819F20107CF59C458FBBE1AF3BB93700971DF1FA94245553ACA6F1D316642FA8780038D829803B7160E68E40DEFD457FCE35D841C35FEEC91E7244001DC4A252401E08EE9896F6F4B45D14001680563DD200E28549E66F0620AE696E3D69DF8A060019FD24B1B9304A7D3751DB1CCABED9D2567F707FFCB0B1617F0BB2D70236BFA8E19F986F275949E8ACC1AFDD96492F03B814D27BA351D0C00206F767D0FDAD8A0D029B330B2F37567D7FA0B83FDAF41506DE1BBDE5E0EE320494AC01D491717C56D4D5E0A4B813E7F764EE61297C4EEA3B9808FE0CB4FEE2C4686B15493E03D04541943A74457DEBFFED0D1B847B177DC15730A4238BA37E228EC1242A3C80D4250E02E3926BB15B0112C62263E34952B014744B8500A425FD64635B9E8C7B952081E6D8FB8F002EAA2817D0D256BB4AC6B990A9309B09042926052011A42545A1C921B498004832C69CD1125B16967C8A202588567767DBA70EACAC1820D05F518100C74279A33FA1E280CD277B7998838A3CFDDC349EFF8324611FC95ACFD9150380B5AD4B3F02D961B1439F84B0BD644549A518331CDD49150300A57A1B44EE17F75C56AAF1630E50E24688E0D0E6CE051FAA1017A005046654B2E9070702A000B92318EDBF60CA03E017FF716695938E066028970E8FE2C612F1CA91611E2D9AFA0CD03B63DB7E06CC2A853A44E96000824888C7ADED4807531A001686F3011E36100555BA07102832E92F98A149AECD4C7A2128723A90B039A050AEAD5E139E4E524999DB8E256C5F00DBA62C009227B7025478FC3FC2F430208B29CD0002B611F8B58499A477018366468A0A36050A764E6900107A42C205F404F0C1A9A1E939B959EF4FBA0B1AAF34676AE691566F48D508EE9DC8E9A954F7EC8D2B4ED9B0DD1BB438D29CA9F918192E31040B1DDC13514EAF9CBF24F3C0A402E0F68DB587E542DE48E014C6FE3CDFB02331474655B734D6B75DECCD3571B2AE75D127A330F839A5A3498679CE889BA4A26E44A9ABB163EBF71A4F7FC51515002D99DAD341DD06700E6183D6C7014870341111216D0E34FDBC1575BFD93CE4463A6A0E92C27B00D5F81CE003723380CF35A633BD43667DC7A28B41DE4467963C953E68E9537020880890D6079AF6D72BEA5AC7FC6472417580E6B69A1300FE2BC53954DC843F78F95B244C8E94810C8E7196BDBBA5BDF6C8A1AE4E7301DB4FCCB779FBAF415FBDC38BA32DED8B9AA8E0BB2658BE6A3878DD5B204C1211880C973B8BD6B4B4D7CD9A700034671A029A7D9BD487018BA7FDB0199C2C6FF6F7650AEEE3802E5DBB71516AD09B1C2097BC3F590EF25F498A3C24396E6E5F7C04C8AB49552BE993E72EEB08A424C6CF26B953A05CD3C43380BAEB9D6909644967EC983C8C447E2E0A73733DBB17E86A371E1FC8B26788383CAE9891BB2B9C924C1E5931C0ECEB130E005AEA6B26CB33FD989D374104ACBA6C70B6E3650CC158387D9621BC3451B546EF978C275CBCEF19E74C3C00C423FB2D3A16FB73A00D5AD2511393784EE92AC050C3C8428AF30BD43959605F9A1500D143C7B37C1B03D20EF3262E500C018854B197CC0B5B0D1C4FF52E0E08236FD1717242912BA6616103E29EDC8A977169ADB83ED30A9BCA1310DC78348C514FC464044C361938E69EE3A8E282C0C9D29379D5577AACE9C50360D2E9CD4BE500C00781A5AD27EF023C03F82CC067015E3C031417DDDEF157781AE879BF5453279F05946A16E083401F04FA20D08B07809729910578A95800F820B0B4F5E483401F047AF12EC08B07800F023D007C10E883402F9E017C16E0B3002F9E012618DDDEF157781AE879BF5453279F05946A16E083401F04961E00343E64FB495FBAAEA0803D82149F9B5CE8F8E39391426FC98215376E9D178901F842FE1C6C150A5FD9666FD142273E7300DFDFC571E4A3E75C2A0600A8479C84E470BEB182588C8F4369F74160614120C93E119D89CE59B0CE271A0074A95FC5C7DE8E313C91440674CAED10ED1E1F0416E8EAA3AA5E8A1B2C7FA450413AEFDB32E10050D0FD2085F6FCE9DEA3108DE2CD0B2384A8FA494AF686377161B2B2FEE11CADF75780B62001C16E483F09B748288714A65D3FE10068AC7D3C47049713B655D26E0F4A14C47833496D702E77FD7975AD7DDEA4E30041EDE35B8C760DA077F346DEB5778ECF1F4D7692BD75F9E2CC2D454903572E6E7B8AD0192032FD916A12AFF6EF6528C45182C32F9C729736D677FDCE9B72FCB2A236D302B87341BC0A80BBD0B980E4CC6C871B2297FB62510B412BD399670CC1994ED94B1CB955122947894E7410B545C0AA200A2F6CAADBF4F264E7B55325081CC2BEE9AE07082E72CA5EE5C8ED8374DE2B3A8AEC14706A900BBFBABA7ED3DB1375DDDDCA6DED7F405AB585C25CC7F0A326CD065C67CEB4A3A9B663C47D01D7654E3C56A8BA437447D14785C366067F00E06F876F17DFAFF3CC1F32642A05051F1683434DAA8E987B5030D794CEB8F15C75DC059AD5754F0A4004E0D5E47BEC90F32CB06BF38FA6F3C5FF29007D005E4CBE27B310E4652ACA5E0280A7FDCA05804830B2F8D21E0815070029F50E8077095750CD7AEAFA7E258513029069AA03C0FD7EF61B0ED816073D1E01C999C17454CEC936AE1A2103983200683AF5DFFB10F17E38F478F303B1FD01839E03DDD3151104EE089EFF1903BE3470D85C654241884F550201133734A53B5EA808005C9A7EABCF145C02302B89042B120194E448C0D96381E1DB159406022BD2ADED705806228B7C8D5B82244DCD4AD1209E4BFA3BE266293E196571DAB9B51DDBF60A08F7B65A9A1F699887AA9DFF02DA1924AAA87C7E38BC3696EF2E62D29352C0D0E3E316C7F639E52F81E458CC424E4AD1C0F8767529451028D144A72CA52F35D677FE60AFB250A9CC8FE6F68663C0F79752C1C930CC27866544F16F1F1335AD20FB4BC9D1C602C4A74104A3CC53519C25623E871DD23A46A70E88DB40BD81E14BE69203AA9E72DAB921E776DC77E192FFDAEB876C975525666D7BDDB330B7000503C000E4D098EE1AD3A7D6B52D5BE8C2DE4D540E5050200144809B76E5AABA8DD7F942D0441ABFAD9EC0EE67EF44615D8CF619FF550850D5E5A2D78A590CF235870A0780970A07805F76F20CE0C503C08B0780179F0578F141A017EF02BC780078F100F000F041A007800F023D00CA62066B4F66BFA780F20600A9713D56986F3F5701144044C975A67EE37A1901C040322C7432934CFA0C830240D3174285870E713323813D78E8D60360448920445D85FB732528C83D53006CBA18F7111674A97827172188824D1E00132C2B1767E4C88D4326DB581120C031BA77CC1F30ED10A2FFD69877C4CA030D800867D97B3C008A2081C3060AEF8820C4E489128D6475411044120E556EDF9BC67A9D55E92E19F023CA90B40703BB799251F90EE6785FC79F8239E701500479FDB73B5F8BA42B81C8C5BBE7891A21BACB3F73176F5785BF5F5EF7E06B05390EA5D608783ADE0E2BDE7D6FF71C0300DAE622BBA17171973C008A20579CF7B864582F879BD11FA727F6C2E07DB4D4FF9280DB65F6CD42AFB5AAAEED1D0997027815200752102529699E7F92A707A45E29FA22DC2BCFF92CA088727EBAF35DF5CCBA42C87E03021C92FD11E3CDD2E418EF4F2C3AC0E1A786E06F9A6A33E3DAA62E65DD5D70D17952EE29C9C131796A20F9D7E59F0171EE2D38AD9866B6AEA9E1B7659539966D816C4DE7B166D1CCA369EE6263D525CEB9300E0DF43E94BDC55C6AFD4EC3A3172EEED8637FBCA67D416A9AED7F7AD6B9CF9BB98678DE0812B790EE6A396E5855D7F15639EAF1FF015841FD48A44C570F0000000049454E44AE426082'), $data->getContent());
+ $this->assertEquals(pack('H*', '6956424F5277304B47676F414141414E53556845556741414144414141414177434149414141445959473751414141414358424957584D41414137454141414F784147564B7734624141414470556C45515652596865315A585567555552512B5A39646358624E4E4C4C4D314E6247303341724B4A585533677167484B336F776968376336442B71682F372F33346F67736A434C364B45777A622B4B54497A6F77536853574E63734C4E61734B4372536367304E79705A437935335477395934732B73366439787252505539444C4E7A7633504F64382B636D5876504C494161584B7A4C557355767461766A44775737387449596D535A7A5645526B6946722F7167316D576730614C516F65387634634636654C546441626F6B4A36653451334C37353075586F453453647A7837475539664D623166704874515941554F6159302F72636E5A67614159546F36344149554F696A72546B504D75614E71616E7347485A424A66597372556244776953674C597675662F37557038712F566857377543354C47344C494E673045584A7762682B423539736A4E5835444A6243696F544E64714E597871524531545A6F354F6D54374B58745046614D4B55665031497A5948544A67414541674C68304B5A6D6A3063676F6B4238416A702F39486E624B7A635149654B30444D4D5357787850515158583072324A49595344713577766D7430376C6A554E6B7171614B7832314E7A3463574E6C4D6941434167446E72346E5868544C48594D685135776E7543524276324A515041366C334A6741457A744742704C4143597A416278536D696F39734B64544A5A59796756523270437049586D7045524743556A455267597844414A7358336E6433667838386E454B476F6D4E304B5068786B4F5642382B55676B4731376F704B566B71425665796571657177474256717A78797153464A614F71544E47457849765253416F65314951394C53704F7A534D7166425A6F4E47716E467030544768786257617033624A323979526549675A4551724B2B31473470735675796C78743968766F6C49304B5A33537065494242736C6F626A35624F4D53574644573450395155413269324F735558667961727033575361696F7279586436353369707A2B3237482F564A723831634B74636E773837733150452F6349694C686D3332517070372B4770706D6A354D623842586D6E61307A512B367355776131676565486646735253424C3956554D445657494C2F47564C43763133554C506866513072346B7A4D55754B3368425749493143386F622B657A51454E385558476D5661724939625A37344B6A4F786F3969373064417A676257586C4D74626C357142306D6750537461704B4F794C617A4E366B434547624F6A6E49306668304F4B57454D327179504771427366722F6350354C756E4A674935696565755348716E4F6C32396E613565663435436F587A392B6F33344E5230732F5975436F4D4F62483250676C6C6B56434F426D7854744647745073432B396D68656B3076397A4B7251676B66514835665650374F64776E55486E2B36317456372F6B496B714B3833696F3338755261376E6E506B6C496A6A78535A704E2B634C703974753148325670582F594638324A464558487548372B57734954576177677269334A73466E6944502B75677878423839626875496843415172714C71345454782F38764354764B536F7172423132415864726E5942454146356A35586E3271576A687A613267446474424C3039777642767351414159454A5365466D397862597477652B504467414138397A6F636F6631784A565A5133502B4138457749412B7133696A634141414141456C46546B5375516D4343'), $data->getThumb());
+
+ $result = self::$repository->getById(10);
+
+ $this->assertEquals(0, $result->getNumRows());
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testCreate()
+ {
+ $data = new FileData();
+ $data->setAccountId(2);
+ $data->setName('test.jpg');
+ $data->setType('image/jpg');
+ $data->setExtension('JPG');
+ $data->setContent('image');
+ $data->setThumb('thumb');
+ $data->setSize(1000);
+
+ $this->assertEquals(5, self::$repository->create($data));
+
+ $result = self::$repository->getById(5);
+ /** @var FileExtData $resultData */
+ $resultData = $result->getData();
+
+ $this->assertEquals(1, $result->getNumRows());
+ $this->assertInstanceOf(FileExtData::class, $resultData);
+ $this->assertEquals($data->getName(), $resultData->getName());
+ $this->assertEquals($data->getType(), $resultData->getType());
+ $this->assertEquals($data->getExtension(), $resultData->getExtension());
+ $this->assertEquals($data->getSize(), $resultData->getSize());
+ $this->assertEquals($data->getAccountId(), $resultData->getAccountId());
+ $this->assertEquals($data->getContent(), $resultData->getContent());
+ $this->assertEquals($data->getThumb(), $resultData->getThumb());
+
+ $this->assertEquals(4, $this->conn->getRowCount('AccountFile'));
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetAll()
+ {
+ $result = self::$repository->getAll();
+ /** @var FileExtData[] $data */
+ $data = $result->getDataAsArray();
+
+ $this->assertEquals(3, $result->getNumRows());
+ $this->assertCount(3, $data);
+ $this->assertInstanceOf(FileExtData::class, $data[0]);
+ $this->assertEquals(4, $data[0]->getId());
+ $this->assertEquals('android.png', $data[0]->getName());
+ $this->assertEquals('image/png', $data[0]->getType());
+ $this->assertEquals('PNG', $data[0]->getExtension());
+ $this->assertEquals('Google', $data[0]->getAccountName());
+ $this->assertEquals('Google', $data[0]->getClientName());
+ $this->assertEquals(4295, $data[0]->getSize());
+ $this->assertEquals(1, $data[0]->getAccountId());
+ $this->assertEquals(pack('H*', '89504E470D0A1A0A0000000D4948445200000080000000800806000000C33E61CB00000006624B474400FF00FF00FFA0BDA793000000097048597300000B1300000B1301009A9C180000000774494D4507DD011D0E180BE2306F78000010544944415478DAED5D6B745CD575FEBE7DEFC8961F3C0C01EC45480C2B8B0026A1D4206B2CB9C27181F208D074816D59069A16280B92A6246D42520A252D210FD2248426818418C9C63CD264C182BAE1154B1A4960CAB35E506A1E5D26501C9E768464CDDCF3F5C7BDA31796A59135F28CE66C2D594B9A19DF73F7FECEB71F67DF7388329096CCC293C1E997845174D1F2FACE374B7DBCCD1B17CF0F42DDDB1BED58F2E74B9E7DBB94C76AE5000069DA05A2CE8CA8EF94FA587FF6507D1503D71A018757D9EC334A7DBC650100B2E79F4C70B0E0336B338BFEA494C75A352DF70D1AE71AB8F9A5F51DCD1E001320AB163FB159C2CD12663A58D35D1DE9D9A538CE350F351C65C6931D1038B9CBAFBA11F200983016705F96DC9B3077CE4EC7926481B0BAF7F208760C22AD69AAEBEC2A07BD960D001AD39DBF27832F986C3A694DEBDA4F9A5352816A5BC332293CD790450AE115E5A2D7B201000050D10310FE57CC9DEAD47342A98CEBB6473E5585A0F72C3077805C78EDF2FAB6B7CA46A7283359DB9E5E2D6A0DA42E9B3E73C9CA850F6547FBCCBAB69A1991719E219C0146F38420A07400E40218009102BA01F70E2D34C1BD48177457F76CDFF6A7CB9ECE8D9AF6B5A76B403C4CEA8528179D76FE92C75E2F177D86E5060089F793DC08CBFD91EBED5905E0D6E1EFB9E7D7A7A5B6CFD85E47BAE3011C23E02002F300CD00381750086086C86133C0DE8364005E045C774FF5CCDFB574A4B7105107A2E0A5C6FA8EA7771D9FE07A11339C70533919BF2C1900009ADBEACE27A31F928E3DCF1FB5EF5F7CF6E7B907375F17BCF6EE7D75845B29E3498110413A5C4415101B5A1020825072E79404821093BF0CFC4100084A10F09E889728E668EE2E58EFFAC69A27B702C0DAAE450B11059B003D09F0338D8B332F7B004C46D09549B782564FD7773314DE01E3B7441C09A91A04094862FC1322C971F14DE21E10A3062024800ECEDD1B657139A6A183C0C141C4BF5B59DFF1BD72D3A3952B00E8EC3B0E511616FCA5026D70D47110A69348883DB139314EE327E44E80313DC43F6240848E38C7A6BB570D3CCCC4E742CDBCBB2CF5586E035ED75A77906374BA8C5F20B9801A740F1404F6D379516290D871C47048CA3CA2EBA37827841FCEDEE785473FFD8937E5015014DAAF3D9BB02F89AA0110304FC87BF12E84FC10040ADB40AC0F72D13F2F5FF2E81B1E0013286B3A177D3E10AF226C7FF4CF7A09E4DEBD07C59C80981048E07527BD2EBAAFAF4E77FDD203604F23FE478EFF10AAAAEE27834F00AAA228F183095C09E5A94E8441B683DCF9DDC6F4A67FF000182FE5B72F3A8EC0DD8E7604291156168C250146413038E46E545FF4E5D50D9BBA7D1650C8CC6FAF6D20C33B6176841162A2D2B2F0AB141C28C081B2CB2C0C7FBCB6ADE610CF00632EF4D42E03ED76331D085122588E050B498A07EE08173E9072D59F3D77C9035B3D03EC2ED8EB38611189663377A0627F3AC4F8FD2CA0815F94285B93481071553119811497103198A394142008C004BA3FDE99DA7E434BF3D98107C0483EBFB5EEE32985FF06E21080026803D9769EB20827C9D14114639A158C2439192088314711A2E8E020231C1947A7FDC3CDC3564412B352C1593AFCB59B3C007635F3DB3FB91F037C3F6270485C6461BE82C7FE843B9E66204593DD41B15E2E3C09D4CD4E8AE2A430FFAEE2794D4104B25BA19D17059C51A75C7635113DDBBFA4306400C99F62F0A608BB706D7BFA2B3E06F84091E7C46B81F06BCC2B99C290544F8098706EE4AE6BAA7FF4CA217143E6842B89F01A9261D18286643549E4EB51A4D3CEAFEF782AFFD2ADBF39E1A3A954F84B92C78DA45AE54B46D2FF98B4AAB1AEF331CF00009A338B9792C165C984573C69862A50042882C2CBA4EEFAC08D38B600F6BC8A896AC6CB4C14EEDA27D5F7CCE0972E6CD8F40AC9FB04E634E20808023D240E75C0579B5B97CCAE7800AC6B4FCF32E03A80FB4914A8DD509500E27D67DA39FCF569E1F6B71DD58D64E1B758819F20107CF59C458FBBE1AF3BB93700971DF1FA94245553ACA6F1D316642FA8780038D829803B7160E68E40DEFD457FCE35D841C35FEEC91E7244001DC4A252401E08EE9896F6F4B45D14001680563DD200E28549E66F0620AE696E3D69DF8A060019FD24B1B9304A7D3751DB1CCABED9D2567F707FFCB0B1617F0BB2D70236BFA8E19F986F275949E8ACC1AFDD96492F03B814D27BA351D0C00206F767D0FDAD8A0D029B330B2F37567D7FA0B83FDAF41506DE1BBDE5E0EE320494AC01D491717C56D4D5E0A4B813E7F764EE61297C4EEA3B9808FE0CB4FEE2C4686B15493E03D04541943A74457DEBFFED0D1B847B177DC15730A4238BA37E228EC1242A3C80D4250E02E3926BB15B0112C62263E34952B014744B8500A425FD64635B9E8C7B952081E6D8FB8F002EAA2817D0D256BB4AC6B990A9309B09042926052011A42545A1C921B498004832C69CD1125B16967C8A202588567767DBA70EACAC1820D05F518100C74279A33FA1E280CD277B7998838A3CFDDC349EFF8324611FC95ACFD9150380B5AD4B3F02D961B1439F84B0BD644549A518331CDD49150300A57A1B44EE17F75C56AAF1630E50E24688E0D0E6CE051FAA1017A005046654B2E9070702A000B92318EDBF60CA03E017FF716695938E066028970E8FE2C612F1CA91611E2D9AFA0CD03B63DB7E06CC2A853A44E96000824888C7ADED4807531A001686F3011E36100555BA07102832E92F98A149AECD4C7A2128723A90B039A050AEAD5E139E4E524999DB8E256C5F00DBA62C009227B7025478FC3FC2F430208B29CD0002B611F8B58499A477018366468A0A36050A764E6900107A42C205F404F0C1A9A1E939B959EF4FBA0B1AAF34676AE691566F48D508EE9DC8E9A954F7EC8D2B4ED9B0DD1BB438D29CA9F918192E31040B1DDC13514EAF9CBF24F3C0A402E0F68DB587E542DE48E014C6FE3CDFB02331474655B734D6B75DECCD3571B2AE75D127A330F839A5A3498679CE889BA4A26E44A9ABB163EBF71A4F7FC51515002D99DAD341DD06700E6183D6C7014870341111216D0E34FDBC1575BFD93CE4463A6A0E92C27B00D5F81CE003723380CF35A633BD43667DC7A28B41DE4467963C953E68E9537020880890D6079AF6D72BEA5AC7FC6472417580E6B69A1300FE2BC53954DC843F78F95B244C8E94810C8E7196BDBBA5BDF6C8A1AE4E7301DB4FCCB779FBAF415FBDC38BA32DED8B9AA8E0BB2658BE6A3878DD5B204C1211880C973B8BD6B4B4D7CD9A700034671A029A7D9BD487018BA7FDB0199C2C6FF6F7650AEEE3802E5DBB71516AD09B1C2097BC3F590EF25F498A3C24396E6E5F7C04C8AB49552BE993E72EEB08A424C6CF26B953A05CD3C43380BAEB9D6909644967EC983C8C447E2E0A73733DBB17E86A371E1FC8B26788383CAE9891BB2B9C924C1E5931C0ECEB130E005AEA6B26CB33FD989D374104ACBA6C70B6E3650CC158387D9621BC3451B546EF978C275CBCEF19E74C3C00C423FB2D3A16FB73A00D5AD2511393784EE92AC050C3C8428AF30BD43959605F9A1500D143C7B37C1B03D20EF3262E500C018854B197CC0B5B0D1C4FF52E0E08236FD1717242912BA6616103E29EDC8A977169ADB83ED30A9BCA1310DC78348C514FC464044C361938E69EE3A8E282C0C9D29379D5577AACE9C50360D2E9CD4BE500C00781A5AD27EF023C03F82CC067015E3C031417DDDEF157781AE879BF5453279F05946A16E083401F04FA20D08B07809729910578A95800F820B0B4F5E483401F047AF12EC08B07800F023D007C10E883402F9E017C16E0B3002F9E012618DDDEF157781AE879BF5453279F05946A16E083401F04961E00343E64FB495FBAAEA0803D82149F9B5CE8F8E39391426FC98215376E9D178901F842FE1C6C150A5FD9666FD142273E7300DFDFC571E4A3E75C2A0600A8479C84E470BEB182588C8F4369F74160614120C93E119D89CE59B0CE271A0074A95FC5C7DE8E313C91440674CAED10ED1E1F0416E8EAA3AA5E8A1B2C7FA450413AEFDB32E10050D0FD2085F6FCE9DEA3108DE2CD0B2384A8FA494AF686377161B2B2FEE11CADF75780B62001C16E483F09B748288714A65D3FE10068AC7D3C47049713B655D26E0F4A14C47833496D702E77FD7975AD7DDEA4E30041EDE35B8C760DA077F346DEB5778ECF1F4D7692BD75F9E2CC2D454903572E6E7B8AD0192032FD916A12AFF6EF6528C45182C32F9C729736D677FDCE9B72FCB2A236D302B87341BC0A80BBD0B980E4CC6C871B2297FB62510B412BD399670CC1994ED94B1CB955122947894E7410B545C0AA200A2F6CAADBF4F264E7B55325081CC2BEE9AE07082E72CA5EE5C8ED8374DE2B3A8AEC14706A900BBFBABA7ED3DB1375DDDDCA6DED7F405AB585C25CC7F0A326CD065C67CEB4A3A9B663C47D01D7654E3C56A8BA437447D14785C366067F00E06F876F17DFAFF3CC1F32642A05051F1683434DAA8E987B5030D794CEB8F15C75DC059AD5754F0A4004E0D5E47BEC90F32CB06BF38FA6F3C5FF29007D005E4CBE27B310E4652ACA5E0280A7FDCA05804830B2F8D21E0815070029F50E8077095750CD7AEAFA7E258513029069AA03C0FD7EF61B0ED816073D1E01C999C17454CEC936AE1A2103983200683AF5DFFB10F17E38F478F303B1FD01839E03DDD3151104EE089EFF1903BE3470D85C654241884F550201133734A53B5EA808005C9A7EABCF145C02302B89042B120194E448C0D96381E1DB159406022BD2ADED705806228B7C8D5B82244DCD4AD1209E4BFA3BE266293E196571DAB9B51DDBF60A08F7B65A9A1F699887AA9DFF02DA1924AAA87C7E38BC3696EF2E62D29352C0D0E3E316C7F639E52F81E458CC424E4AD1C0F8767529451028D144A72CA52F35D677FE60AFB250A9CC8FE6F68663C0F79752C1C930CC27866544F16F1F1335AD20FB4BC9D1C602C4A74104A3CC53519C25623E871DD23A46A70E88DB40BD81E14BE69203AA9E72DAB921E776DC77E192FFDAEB876C975525666D7BDDB330B7000503C000E4D098EE1AD3A7D6B52D5BE8C2DE4D540E5050200144809B76E5AABA8DD7F942D0441ABFAD9EC0EE67EF44615D8CF619FF550850D5E5A2D78A590CF235870A0780970A07805F76F20CE0C503C08B0780179F0578F141A017EF02BC780078F100F000F041A007800F023D00CA62066B4F66BFA780F20600A9713D56986F3F5701144044C975A67EE37A1901C040322C7432934CFA0C830240D3174285870E713323813D78E8D60360448920445D85FB732528C83D53006CBA18F7111674A97827172188824D1E00132C2B1767E4C88D4326DB581120C031BA77CC1F30ED10A2FFD69877C4CA030D800867D97B3C008A2081C3060AEF8820C4E489128D6475411044120E556EDF9BC67A9D55E92E19F023CA90B40703BB799251F90EE6785FC79F8239E701500479FDB73B5F8BA42B81C8C5BBE7891A21BACB3F73176F5785BF5F5EF7E06B05390EA5D608783ADE0E2BDE7D6FF71C0300DAE622BBA17171973C008A20579CF7B864582F879BD11FA727F6C2E07DB4D4FF9280DB65F6CD42AFB5AAAEED1D0997027815200752102529699E7F92A707A45E29FA22DC2BCFF92CA088727EBAF35DF5CCBA42C87E03021C92FD11E3CDD2E418EF4F2C3AC0E1A786E06F9A6A33E3DAA62E65DD5D70D17952EE29C9C131796A20F9D7E59F0171EE2D38AD9866B6AEA9E1B7659539966D816C4DE7B166D1CCA369EE6263D525CEB9300E0DF43E94BDC55C6AFD4EC3A3172EEED8637FBCA67D416A9AED7F7AD6B9CF9BB98678DE0812B790EE6A396E5855D7F15639EAF1FF015841FD48A44C570F0000000049454E44AE426082'), $data[0]->getContent());
+ $this->assertEquals(pack('H*', '6956424F5277304B47676F414141414E53556845556741414144414141414177434149414141445959473751414141414358424957584D41414137454141414F784147564B7734624141414470556C45515652596865315A585567555552512B5A39646358624E4E4C4C4D314E6247303341724B4A585533677167484B336F776968376336442B71682F372F33346F67736A434C364B45777A622B4B54497A6F77536853574E63734C4E61734B4372536367304E79705A437935335477395934732B73366439787252505539444C4E7A7633504F64382B636D5876504C494161584B7A4C557355767461766A44775737387449596D535A7A5645526B6946722F7167316D576730614C516F65387634634636654C546441626F6B4A36653451334C37353075586F453453647A7837475539664D623166704874515941554F6159302F72636E5A67614159546F36344149554F696A72546B504D75614E71616E7347485A424A66597372556244776953674C597675662F37557038712F566857377543354C47344C494E673045584A7762682B423539736A4E5835444A6243696F544E64714E597871524531545A6F354F6D54374B58745046614D4B55665031497A5948544A67414541674C68304B5A6D6A3063676F6B4238416A702F39486E624B7A635149654B30444D4D5357787850515158583072324A49595344713577766D7430376C6A554E6B7171614B7832314E7A3463574E6C4D6941434167446E72346E5868544C48594D685135776E7543524276324A515041366C334A6741457A744742704C4143597A416278536D696F39734B64544A5A59796756523270437049586D7045524743556A455267597844414A7358336E6433667838386E454B476F6D4E304B5068786B4F5642382B55676B4731376F704B566B71425665796571657177474256717A78797153464A614F71544E47457849765253416F65314951394C53704F7A534D7166425A6F4E47716E467030544768786257617033624A323979526549675A4551724B2B31473470735675796C78743968766F6C49304B5A33537065494242736C6F626A35624F4D53574644573450395155413269324F735558667961727033575361696F7279586436353369707A2B3237482F564A723831634B74636E773837733150452F6349694C686D3332517070372B4770706D6A354D623842586D6E61307A512B367355776131676565486646735253424C3956554D445657494C2F47564C43763133554C506866513072346B7A4D55754B3368425749493143386F622B657A51454E385558476D5661724939625A37344B6A4F786F3969373064417A676257586C4D74626C357142306D6750537461704B4F794C617A4E366B434547624F6A6E49306668304F4B57454D327179504771427366722F6350354C756E4A674935696565755348716E4F6C32396E613565663435436F587A392B6F33344E5230732F5975436F4D4F62483250676C6C6B56434F426D7854744647745073432B396D68656B3076397A4B7251676B66514835665650374F64776E55486E2B36317456372F6B496B714B3833696F3338755261376E6E506B6C496A6A78535A704E2B634C703974753148325670582F594638324A464558487548372B57734954576177677269334A73466E6944502B75677878423839626875496843415172714C71345454782F38764354764B536F7172423132415864726E5942454146356A35586E3271576A687A613267446474424C3039777642767351414159454A5365466D397862597477652B504467414138397A6F636F6631784A565A5133502B4138457749412B7133696A634141414141456C46546B5375516D4343'), $data[0]->getThumb());
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testSearch()
+ {
+ $itemSearchData = new ItemSearchData();
+ $itemSearchData->setLimitCount(10);
+ $itemSearchData->setSeachString('android');
+
+ $result = self::$repository->search($itemSearchData);
+ /** @var FileExtData[] $data */
+ $data = $result->getDataAsArray();
+
+ $this->assertEquals(1, $result->getNumRows());
+ $this->assertCount(1, $data);
+ $this->assertInstanceOf(FileExtData::class, $data[0]);
+ $this->assertEquals('android.png', $data[0]->getName());
+ $this->assertEquals('image/png', $data[0]->getType());
+ $this->assertEquals('PNG', $data[0]->getExtension());
+ $this->assertEquals('Google', $data[0]->getAccountName());
+ $this->assertEquals('Google', $data[0]->getClientName());
+ $this->assertEquals(4295, $data[0]->getSize());
+ $this->assertEquals(1, $data[0]->getAccountId());
+
+ $itemSearchData = new ItemSearchData();
+ $itemSearchData->setLimitCount(10);
+ $itemSearchData->setSeachString('');
+
+ $result = self::$repository->search($itemSearchData);
+ $this->assertEquals(3, $result->getNumRows());
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetByAccountId()
+ {
+ $result = self::$repository->getByAccountId(1);
+ /** @var FileData[] $data */
+ $data = $result->getDataAsArray();
+
+ $this->assertEquals(2, $result->getNumRows());
+ $this->assertCount(2, $data);
+ $this->assertInstanceOf(FileData::class, $data[0]);
+ $this->assertEquals(4, $data[0]->getId());
+ $this->assertEquals('android.png', $data[0]->getName());
+ $this->assertEquals('image/png', $data[0]->getType());
+ $this->assertEquals('PNG', $data[0]->getExtension());
+ $this->assertEquals(4295, $data[0]->getSize());
+ $this->assertEquals(1, $data[0]->getAccountId());
+
+ $this->assertInstanceOf(FileData::class, $data[1]);
+ $this->assertEquals(1, $data[1]->getId());
+ $this->assertEquals('sysPass.xml', $data[1]->getName());
+ $this->assertEquals('text/xml', $data[1]->getType());
+ $this->assertEquals('XML', $data[1]->getExtension());
+ $this->assertEquals(1312, $data[1]->getSize());
+ $this->assertEquals(1, $data[1]->getAccountId());
+ $this->assertEquals(pack('H*', '3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C526F6F743E0A20203C4D6574613E0A202020203C47656E657261746F723E737973506173733C2F47656E657261746F723E0A202020203C56657273696F6E3E312E322E303C2F56657273696F6E3E0A202020203C54696D653E313433393332353330343C2F54696D653E0A202020203C557365722069643D2231223E61646D696E3C2F557365723E0A202020203C47726F75702069643D2231223E41646D696E733C2F47726F75703E0A202020203C486173683E36646232633238323731393136326630663136316531343731653734636531623C2F486173683E0A20203C2F4D6574613E0A20203C43617465676F726965733E0A202020203C43617465676F72792069643D2231223E0A2020202020203C6E616D653E485454503C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F43617465676F72793E0A20203C2F43617465676F726965733E0A20203C437573746F6D6572733E0A202020203C437573746F6D65722069643D2231223E0A2020202020203C6E616D653E476F6F676C6520496E632E3C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F437573746F6D65723E0A202020203C437573746F6D65722069643D2232223E0A2020202020203C6E616D653E4D6963726F736F667420496E633C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F437573746F6D65723E0A20203C2F437573746F6D6572733E0A20203C4163636F756E74733E0A202020203C4163636F756E742069643D2231223E0A2020202020203C6E616D653E476F6F676C653C2F6E616D653E0A2020202020203C637573746F6D657249643E313C2F637573746F6D657249643E0A2020202020203C63617465676F727949643E313C2F63617465676F727949643E0A2020202020203C6C6F67696E3E61646D696E3C2F6C6F67696E3E0A2020202020203C75726C3E382E382E382E383C2F75726C3E0A2020202020203C6E6F7465732F3E0A2020202020203C706173733E6C4E66513133634B6A384D592B79434F346652536B4773494334357247454C442F424E69345654614671593D3C2F706173733E0A2020202020203C7061737369763E454E6354743338503265346C643350395A553241767939664C466277386C42473947382F75414D785A6D343D3C2F7061737369763E0A202020203C2F4163636F756E743E0A202020203C4163636F756E742069643D2232223E0A2020202020203C6E616D653E4D6963726F736F66743C2F6E616D653E0A2020202020203C637573746F6D657249643E323C2F637573746F6D657249643E0A2020202020203C63617465676F727949643E313C2F63617465676F727949643E0A2020202020203C6C6F67696E3E726F6F743C2F6C6F67696E3E0A2020202020203C75726C3E342E342E342E343C2F75726C3E0A2020202020203C6E6F7465733E4E6F746173206465206D6963726F66736F66743C2F6E6F7465733E0A2020202020203C706173733E3352394F48632B53335A4E56684D795948352F784C476C76625246662F5367573348527261322B325349453D3C2F706173733E0A2020202020203C7061737369763E763637306A596B43547178635332344C4F65453077672B304330376A734C2F4635342B6E56484963544F773D3C2F7061737369763E0A202020203C2F4163636F756E743E0A20203C2F4163636F756E74733E0A3C2F526F6F743E0A'), $data[1]->getContent());
+ $this->assertEquals(pack('H*', '6E6F5F7468756D62'), $data[1]->getThumb());
+
+ $result = self::$repository->getByAccountId(10);
+ $this->assertEquals(0, $result->getNumRows());
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetByIdBatch()
+ {
+ $result = self::$repository->getByIdBatch([1, 2, 3]);
+ /** @var FileData[] $data */
+ $data = $result->getDataAsArray();
+
+ $this->assertEquals(2, $result->getNumRows());
+ $this->assertCount(2, $data);
+ $this->assertInstanceOf(FileExtData::class, $data[0]);
+ $this->assertEquals(1, $data[0]->getId());
+ $this->assertInstanceOf(FileExtData::class, $data[1]);
+ $this->assertEquals(3, $data[1]->getId());
+
+ $result = self::$repository->getByIdBatch([]);
+ $this->assertEquals(0, $result->getNumRows());
+ }
+
+ /**
+ * Returns the test dataset.
+ *
+ * @return IDataSet
+ */
+ protected function getDataSet()
+ {
+ return $this->createMySQLXMLDataSet(RESOURCE_DIR . DIRECTORY_SEPARATOR . 'datasets' . DIRECTORY_SEPARATOR . 'syspass_accountFile.xml');
+ }
+}
diff --git a/tests/Repositories/AccountHistoryRepositoryTest.php b/tests/Repositories/AccountHistoryRepositoryTest.php
index ec3ca08a..c7b1e682 100644
--- a/tests/Repositories/AccountHistoryRepositoryTest.php
+++ b/tests/Repositories/AccountHistoryRepositoryTest.php
@@ -26,6 +26,7 @@ namespace SP\Tests\Repositories;
use PHPUnit\DbUnit\DataSet\IDataSet;
use SP\DataModel\AccountHistoryData;
+use SP\DataModel\Dto\AccountHistoryCreateDto;
use SP\DataModel\ItemSearchData;
use SP\Repositories\Account\AccountHistoryRepository;
use SP\Services\Account\AccountPasswordRequest;
@@ -142,13 +143,16 @@ class AccountHistoryRepositoryTest extends DatabaseTestCase
*/
public function testCreate()
{
- $result = self::$repository->create(['id' => 2, 'isModify' => 1, 'isDelete' => 0, 'masterPassHash' => Util::generateRandomBytes()]);
+ $result = self::$repository->create(new AccountHistoryCreateDto(2, true, false, Util::generateRandomBytes()));
$this->assertEquals(8, $result);
- $result = self::$repository->create(['id' => 10, 'isModify' => 1, 'isDelete' => 0, 'masterPassHash' => Util::generateRandomBytes()]);
+ $result = self::$repository->create(new AccountHistoryCreateDto(2, true, true, Util::generateRandomBytes()));
+ $this->assertEquals(9, $result);
+
+ $result = self::$repository->create(new AccountHistoryCreateDto(10, true, false, Util::generateRandomBytes()));
$this->assertEquals(0, $result);
- $this->assertEquals(6, $this->conn->getRowCount('AccountHistory'));
+ $this->assertEquals(7, $this->conn->getRowCount('AccountHistory'));
}
/**
diff --git a/tests/Repositories/AccountRepositoryTest.php b/tests/Repositories/AccountRepositoryTest.php
index 5ef1d017..4d841861 100644
--- a/tests/Repositories/AccountRepositoryTest.php
+++ b/tests/Repositories/AccountRepositoryTest.php
@@ -127,7 +127,7 @@ class AccountRepositoryTest extends DatabaseTestCase
$this->assertEquals('1234', $clearPassword);
// Comprobar que se devuelve un array vacío
- $this->assertCount(0, self::$repository->getPasswordForId(10));
+ $this->assertNull(self::$repository->getPasswordForId(10));
}
/**
diff --git a/tests/Repositories/AccountFavoriteRepositoryTest.php b/tests/Repositories/AccountToFavoriteRepositoryTest.php
similarity index 90%
rename from tests/Repositories/AccountFavoriteRepositoryTest.php
rename to tests/Repositories/AccountToFavoriteRepositoryTest.php
index b77ab827..aa767406 100644
--- a/tests/Repositories/AccountFavoriteRepositoryTest.php
+++ b/tests/Repositories/AccountToFavoriteRepositoryTest.php
@@ -27,7 +27,7 @@ namespace SP\Tests\Repositories;
use DI\DependencyException;
use PHPUnit\DbUnit\DataSet\IDataSet;
use SP\Core\Exceptions\ConstraintException;
-use SP\Repositories\Account\AccountFavoriteRepository;
+use SP\Repositories\Account\AccountToFavoriteRepository;
use SP\Storage\Database\DatabaseConnectionData;
use SP\Tests\DatabaseTestCase;
use function SP\Tests\setupContext;
@@ -37,10 +37,10 @@ use function SP\Tests\setupContext;
*
* @package SP\Tests\Repositories
*/
-class AccountFavoriteRepositoryTest extends DatabaseTestCase
+class AccountToFavoriteRepositoryTest extends DatabaseTestCase
{
/**
- * @var AccountFavoriteRepository
+ * @var AccountToFavoriteRepository
*/
private static $repository;
@@ -57,7 +57,7 @@ class AccountFavoriteRepositoryTest extends DatabaseTestCase
self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
// Inicializar el repositorio
- self::$repository = $dic->get(AccountFavoriteRepository::class);
+ self::$repository = $dic->get(AccountToFavoriteRepository::class);
}
/**
@@ -113,6 +113,6 @@ class AccountFavoriteRepositoryTest extends DatabaseTestCase
*/
protected function getDataSet()
{
- return $this->createMySQLXMLDataSet(RESOURCE_DIR . DIRECTORY_SEPARATOR . 'datasets' . DIRECTORY_SEPARATOR . 'syspass_favorite.xml');
+ return $this->createMySQLXMLDataSet(RESOURCE_DIR . DIRECTORY_SEPARATOR . 'datasets' . DIRECTORY_SEPARATOR . 'syspass_accountFavorite.xml');
}
}
diff --git a/tests/Repositories/CategoryRepositoryTest.php b/tests/Repositories/CategoryRepositoryTest.php
index 947413bd..dcd958ca 100644
--- a/tests/Repositories/CategoryRepositoryTest.php
+++ b/tests/Repositories/CategoryRepositoryTest.php
@@ -72,9 +72,7 @@ class CategoryRepositoryTest extends DatabaseTestCase
*/
public function testGetByName()
{
- $category = self::$repository->getByName('Prueba');
-
- $this->assertCount(0, $category);
+ $this->assertNull(self::$repository->getByName('Prueba'));
$category = self::$repository->getByName('Web');
@@ -133,9 +131,7 @@ class CategoryRepositoryTest extends DatabaseTestCase
*/
public function testGetById()
{
- $category = self::$repository->getById(10);
-
- $this->assertCount(0, $category);
+ $this->assertNull(self::$repository->getById(10));
$category = self::$repository->getById(1);
diff --git a/tests/Repositories/ClientRepositoryTest.php b/tests/Repositories/ClientRepositoryTest.php
index 162b9dfd..60a39ce8 100644
--- a/tests/Repositories/ClientRepositoryTest.php
+++ b/tests/Repositories/ClientRepositoryTest.php
@@ -73,9 +73,7 @@ class ClientRepositoryTest extends DatabaseTestCase
*/
public function testGetByName()
{
- $client = self::$repository->getByName('Amazon');
-
- $this->assertCount(0, $client);
+ $this->assertNull(self::$repository->getByName('Amazon'));
$client = self::$repository->getByName('Google');
@@ -133,9 +131,7 @@ class ClientRepositoryTest extends DatabaseTestCase
*/
public function testGetById()
{
- $client = self::$repository->getById(10);
-
- $this->assertCount(0, $client);
+ $this->assertNull(self::$repository->getById(10));
$client = self::$repository->getById(1);
diff --git a/tests/Repositories/TagRepositoryTest.php b/tests/Repositories/TagRepositoryTest.php
index b8021989..2e2fa85c 100644
--- a/tests/Repositories/TagRepositoryTest.php
+++ b/tests/Repositories/TagRepositoryTest.php
@@ -101,9 +101,7 @@ class TagRepositoryTest extends DatabaseTestCase
*/
public function testGetById()
{
- $tag = self::$repository->getById(10);
-
- $this->assertCount(0, $tag);
+ $this->assertNull(self::$repository->getById(10));
$tag = self::$repository->getById(1);
diff --git a/tests/Repositories/UserGroupRepositoryTest.php b/tests/Repositories/UserGroupRepositoryTest.php
index da78bd29..4db5a25c 100644
--- a/tests/Repositories/UserGroupRepositoryTest.php
+++ b/tests/Repositories/UserGroupRepositoryTest.php
@@ -105,8 +105,7 @@ class UserGroupRepositoryTestCase extends DatabaseTestCase
$this->assertEquals('Demo', $group->getName());
$this->assertEmpty($group->getDescription());
- $group = self::$repository->getByName('Prueba');
- $this->assertCount(0, $group);
+ $this->assertNull(self::$repository->getByName('Prueba'));
}
/**
@@ -164,8 +163,7 @@ class UserGroupRepositoryTestCase extends DatabaseTestCase
$this->assertEquals('Demo', $group->getName());
$this->assertEmpty($group->getDescription());
- $group = self::$repository->getById(4);
- $this->assertCount(0, $group);
+ $this->assertNull(self::$repository->getById(4));
}
/**
diff --git a/tests/Repositories/UserProfileRepositoryTest.php b/tests/Repositories/UserProfileRepositoryTest.php
index a3229b81..509ae240 100644
--- a/tests/Repositories/UserProfileRepositoryTest.php
+++ b/tests/Repositories/UserProfileRepositoryTest.php
@@ -212,8 +212,7 @@ class UserProfileRepositoryTest extends DatabaseTestCase
$this->assertEquals('Demo', $profile->getName());
$this->assertNotEmpty($profile->getProfile());
- $profile = self::$repository->getById(4);
- $this->assertCount(0, $profile);
+ $this->assertNull(self::$repository->getById(4));
}
/**
diff --git a/tests/Repositories/UserRepositoryTest.php b/tests/Repositories/UserRepositoryTest.php
index a284fbdf..49916448 100644
--- a/tests/Repositories/UserRepositoryTest.php
+++ b/tests/Repositories/UserRepositoryTest.php
@@ -259,15 +259,18 @@ class UserRepositoryTest extends DatabaseTestCase
*/
public function testGetByLogin()
{
- $user = self::$repository->getByLogin('demo');
+ $result = self::$repository->getByLogin('demo');
- $this->assertInstanceOf(UserData::class, $user);
- $this->assertEquals('sysPass demo', $user->getName());
- $this->assertEquals('demo', $user->getLogin());
+ $this->assertEquals(1, $result->getNumRows());
- $this->expectException(NoSuchItemException::class);
+ /** @var UserData $data */
+ $data = $result->getData();
- self::$repository->getByLogin('prueba');
+ $this->assertInstanceOf(UserData::class, $data);
+ $this->assertEquals('sysPass demo', $data->getName());
+ $this->assertEquals('demo', $data->getLogin());
+
+ $this->assertEquals(0, self::$repository->getByLogin('prueba')->getNumRows());
}
/**
diff --git a/tests/Services/AccountAclServiceTest.php b/tests/Services/AccountAclServiceTest.php
index bdbc67ba..482003cf 100644
--- a/tests/Services/AccountAclServiceTest.php
+++ b/tests/Services/AccountAclServiceTest.php
@@ -789,6 +789,6 @@ class AccountAclServiceTest extends DatabaseTestCase
*/
protected function getDataSet()
{
- return $this->createMySQLXMLDataSet(RESOURCE_DIR . DIRECTORY_SEPARATOR . 'datasets' . DIRECTORY_SEPARATOR . 'syspass_acl.xml');
+ return $this->createMySQLXMLDataSet(RESOURCE_DIR . DIRECTORY_SEPARATOR . 'datasets' . DIRECTORY_SEPARATOR . 'syspass_accountAcl.xml');
}
}
diff --git a/tests/Services/AccountFavoriteServiceTest.php b/tests/Services/AccountFavoriteServiceTest.php
new file mode 100644
index 00000000..afa39645
--- /dev/null
+++ b/tests/Services/AccountFavoriteServiceTest.php
@@ -0,0 +1,113 @@
+.
+ */
+
+namespace SP\Tests\Services;
+
+use PHPUnit\DbUnit\DataSet\IDataSet;
+use SP\Core\Exceptions\ConstraintException;
+use SP\Services\Account\AccountToFavoriteService;
+use SP\Storage\Database\DatabaseConnectionData;
+use SP\Tests\DatabaseTestCase;
+use function SP\Tests\setupContext;
+
+/**
+ * Class AccountFavoriteServiceTest
+ *
+ * @package SP\Tests\Services
+ */
+class AccountFavoriteServiceTest extends DatabaseTestCase
+{
+ /**
+ * @var AccountToFavoriteService
+ */
+ private static $service;
+
+ /**
+ * @throws \DI\NotFoundException
+ * @throws \SP\Core\Context\ContextException
+ * @throws \DI\DependencyException
+ */
+ public static function setUpBeforeClass()
+ {
+ $dic = setupContext();
+
+ // Datos de conexión a la BBDD
+ self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
+
+ // Inicializar el servicio
+ self::$service = $dic->get(AccountToFavoriteService::class);
+ }
+
+ /**
+ * @throws ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testDelete()
+ {
+ $this->assertEquals(1, self::$service->delete(1, 3));
+ $this->assertEquals(0, self::$service->delete(10, 1));
+ }
+
+ /**
+ * @throws ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetForUserId()
+ {
+ $data = self::$service->getForUserId(3);
+
+ $this->assertCount(2, $data);
+ $this->assertArrayHasKey(1, $data);
+ $this->assertArrayHasKey(2, $data);
+ $this->assertEquals(3, $data[1]);
+ $this->assertEquals(3, $data[2]);
+
+ $this->assertCount(0, self::$service->getForUserId(10));
+ }
+
+ /**
+ * @throws ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testAdd()
+ {
+ $this->assertEquals(0, self::$service->add(1, 2));
+
+ $this->expectException(ConstraintException::class);
+
+ self::$service->add(3, 1);
+
+ self::$service->add(1, 3);
+ }
+
+ /**
+ * Returns the test dataset.
+ *
+ * @return IDataSet
+ */
+ protected function getDataSet()
+ {
+ return $this->createMySQLXMLDataSet(RESOURCE_DIR . DIRECTORY_SEPARATOR . 'datasets' . DIRECTORY_SEPARATOR . 'syspass_accountFavorite.xml');
+ }
+}
diff --git a/tests/Services/AccountFileServiceTest.php b/tests/Services/AccountFileServiceTest.php
new file mode 100644
index 00000000..e477327b
--- /dev/null
+++ b/tests/Services/AccountFileServiceTest.php
@@ -0,0 +1,335 @@
+.
+ */
+
+namespace SP\Tests\Services;
+
+use PHPUnit\DbUnit\DataSet\IDataSet;
+use SP\Core\Exceptions\InvalidImageException;
+use SP\DataModel\FileData;
+use SP\DataModel\FileExtData;
+use SP\DataModel\ItemSearchData;
+use SP\Repositories\NoSuchItemException;
+use SP\Services\Account\AccountFileService;
+use SP\Services\ServiceException;
+use SP\Storage\Database\DatabaseConnectionData;
+use SP\Tests\DatabaseTestCase;
+use function SP\Tests\setupContext;
+
+/**
+ * Class AccountFileServiceTest
+ *
+ * @package SP\Tests\Services
+ */
+class AccountFileServiceTest extends DatabaseTestCase
+{
+ /**
+ * @var AccountFileService
+ */
+ private static $service;
+
+ /**
+ * @throws \DI\NotFoundException
+ * @throws \SP\Core\Context\ContextException
+ * @throws \DI\DependencyException
+ */
+ public static function setUpBeforeClass()
+ {
+ $dic = setupContext();
+
+ // Datos de conexión a la BBDD
+ self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
+
+ // Inicializar el servicio
+ self::$service = $dic->get(AccountFileService::class);
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ public function testCreate()
+ {
+ $file = RESOURCE_DIR . DIRECTORY_SEPARATOR . 'imgs' . DIRECTORY_SEPARATOR . 'add.png';
+ $image = file_get_contents($file);
+
+ $data = new FileData();
+ $data->setAccountId(2);
+ $data->setName('app.png');
+ $data->setType('image/png');
+ $data->setExtension('PNG');
+ $data->setContent($image);
+ $data->setSize(filesize($file));
+
+ $this->assertEquals(5, self::$service->create($data));
+
+ $resultData = self::$service->getById(5);
+
+ $this->assertInstanceOf(FileExtData::class, $resultData);
+ $this->assertEquals($data->getName(), $resultData->getName());
+ $this->assertEquals($data->getType(), $resultData->getType());
+ $this->assertEquals($data->getExtension(), $resultData->getExtension());
+ $this->assertEquals($data->getSize(), $resultData->getSize());
+ $this->assertEquals($data->getAccountId(), $resultData->getAccountId());
+ $this->assertEquals($data->getContent(), $resultData->getContent());
+ $this->assertEquals($data->getThumb(), $resultData->getThumb());
+
+ $data = new FileData();
+ $data->setAccountId(2);
+ $data->setName('app.png');
+ $data->setType('image/png');
+ $data->setExtension('SVG');
+ $data->setContent('');
+ $data->setSize(0);
+
+ $this->assertEquals(6, self::$service->create($data));
+
+ $resultData = self::$service->getById(6);
+
+ $this->assertInstanceOf(FileExtData::class, $resultData);
+ $this->assertEquals($data->getName(), $resultData->getName());
+ $this->assertEquals($data->getType(), $resultData->getType());
+ $this->assertEquals($data->getExtension(), $resultData->getExtension());
+ $this->assertEquals($data->getSize(), $resultData->getSize());
+ $this->assertEquals($data->getAccountId(), $resultData->getAccountId());
+ $this->assertEquals($data->getContent(), $resultData->getContent());
+ $this->assertEquals('no_thumb', $resultData->getThumb());
+
+ $this->assertEquals(5, $this->conn->getRowCount('AccountFile'));
+
+ $this->expectException(InvalidImageException::class);
+
+ $data = new FileData();
+ $data->setAccountId(2);
+ $data->setName('app.png');
+ $data->setType('image/png');
+ $data->setExtension('PNG');
+ $data->setContent('');
+ $data->setSize(0);
+
+ $this->assertEquals(6, self::$service->create($data));
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testSearch()
+ {
+ $itemSearchData = new ItemSearchData();
+ $itemSearchData->setLimitCount(10);
+ $itemSearchData->setSeachString('android');
+
+ $result = self::$service->search($itemSearchData);
+ /** @var FileExtData[] $data */
+ $data = $result->getDataAsArray();
+
+ $this->assertEquals(1, $result->getNumRows());
+ $this->assertInstanceOf(FileExtData::class, $data[0]);
+ $this->assertEquals('android.png', $data[0]->getName());
+ $this->assertEquals('image/png', $data[0]->getType());
+ $this->assertEquals('PNG', $data[0]->getExtension());
+ $this->assertEquals('Google', $data[0]->getAccountName());
+ $this->assertEquals('Google', $data[0]->getClientName());
+ $this->assertEquals(4295, $data[0]->getSize());
+ $this->assertEquals(1, $data[0]->getAccountId());
+
+ $itemSearchData = new ItemSearchData();
+ $itemSearchData->setLimitCount(10);
+ $itemSearchData->setSeachString('');
+
+ $result = self::$service->search($itemSearchData);
+ $this->assertEquals(3, $result->getNumRows());
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetById()
+ {
+ $data = self::$service->getById(1);
+
+ $this->assertInstanceOf(FileExtData::class, $data);
+ $this->assertEquals('sysPass.xml', $data->getName());
+ $this->assertEquals('text/xml', $data->getType());
+ $this->assertEquals('XML', $data->getExtension());
+ $this->assertEquals('Google', $data->getAccountName());
+ $this->assertEquals('Google', $data->getClientName());
+ $this->assertEquals(1312, $data->getSize());
+ $this->assertEquals(1, $data->getAccountId());
+ $this->assertEquals(pack('H*', '3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C526F6F743E0A20203C4D6574613E0A202020203C47656E657261746F723E737973506173733C2F47656E657261746F723E0A202020203C56657273696F6E3E312E322E303C2F56657273696F6E3E0A202020203C54696D653E313433393332353330343C2F54696D653E0A202020203C557365722069643D2231223E61646D696E3C2F557365723E0A202020203C47726F75702069643D2231223E41646D696E733C2F47726F75703E0A202020203C486173683E36646232633238323731393136326630663136316531343731653734636531623C2F486173683E0A20203C2F4D6574613E0A20203C43617465676F726965733E0A202020203C43617465676F72792069643D2231223E0A2020202020203C6E616D653E485454503C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F43617465676F72793E0A20203C2F43617465676F726965733E0A20203C437573746F6D6572733E0A202020203C437573746F6D65722069643D2231223E0A2020202020203C6E616D653E476F6F676C6520496E632E3C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F437573746F6D65723E0A202020203C437573746F6D65722069643D2232223E0A2020202020203C6E616D653E4D6963726F736F667420496E633C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F437573746F6D65723E0A20203C2F437573746F6D6572733E0A20203C4163636F756E74733E0A202020203C4163636F756E742069643D2231223E0A2020202020203C6E616D653E476F6F676C653C2F6E616D653E0A2020202020203C637573746F6D657249643E313C2F637573746F6D657249643E0A2020202020203C63617465676F727949643E313C2F63617465676F727949643E0A2020202020203C6C6F67696E3E61646D696E3C2F6C6F67696E3E0A2020202020203C75726C3E382E382E382E383C2F75726C3E0A2020202020203C6E6F7465732F3E0A2020202020203C706173733E6C4E66513133634B6A384D592B79434F346652536B4773494334357247454C442F424E69345654614671593D3C2F706173733E0A2020202020203C7061737369763E454E6354743338503265346C643350395A553241767939664C466277386C42473947382F75414D785A6D343D3C2F7061737369763E0A202020203C2F4163636F756E743E0A202020203C4163636F756E742069643D2232223E0A2020202020203C6E616D653E4D6963726F736F66743C2F6E616D653E0A2020202020203C637573746F6D657249643E323C2F637573746F6D657249643E0A2020202020203C63617465676F727949643E313C2F63617465676F727949643E0A2020202020203C6C6F67696E3E726F6F743C2F6C6F67696E3E0A2020202020203C75726C3E342E342E342E343C2F75726C3E0A2020202020203C6E6F7465733E4E6F746173206465206D6963726F66736F66743C2F6E6F7465733E0A2020202020203C706173733E3352394F48632B53335A4E56684D795948352F784C476C76625246662F5367573348527261322B325349453D3C2F706173733E0A2020202020203C7061737369763E763637306A596B43547178635332344C4F65453077672B304330376A734C2F4635342B6E56484963544F773D3C2F7061737369763E0A202020203C2F4163636F756E743E0A20203C2F4163636F756E74733E0A3C2F526F6F743E0A'), $data->getContent());
+ $this->assertEquals(pack('H*', '6E6F5F7468756D62'), $data->getThumb());
+
+ $data = self::$service->getById(4);
+
+ $this->assertInstanceOf(FileExtData::class, $data);
+ $this->assertEquals('android.png', $data->getName());
+ $this->assertEquals('image/png', $data->getType());
+ $this->assertEquals('PNG', $data->getExtension());
+ $this->assertEquals('Google', $data->getAccountName());
+ $this->assertEquals('Google', $data->getClientName());
+ $this->assertEquals(4295, $data->getSize());
+ $this->assertEquals(1, $data->getAccountId());
+ $this->assertEquals(pack('H*', '89504E470D0A1A0A0000000D4948445200000080000000800806000000C33E61CB00000006624B474400FF00FF00FFA0BDA793000000097048597300000B1300000B1301009A9C180000000774494D4507DD011D0E180BE2306F78000010544944415478DAED5D6B745CD575FEBE7DEFC8961F3C0C01EC45480C2B8B0026A1D4206B2CB9C27181F208D074816D59069A16280B92A6246D42520A252D210FD2248426818418C9C63CD264C182BAE1154B1A4960CAB35E506A1E5D26501C9E768464CDDCF3F5C7BDA31796A59135F28CE66C2D594B9A19DF73F7FECEB71F67DF7388329096CCC293C1E997845174D1F2FACE374B7DBCCD1B17CF0F42DDDB1BED58F2E74B9E7DBB94C76AE5000069DA05A2CE8CA8EF94FA587FF6507D1503D71A018757D9EC334A7DBC650100B2E79F4C70B0E0336B338BFEA494C75A352DF70D1AE71AB8F9A5F51DCD1E001320AB163FB159C2CD12663A58D35D1DE9D9A538CE350F351C65C6931D1038B9CBAFBA11F200983016705F96DC9B3077CE4EC7926481B0BAF7F208760C22AD69AAEBEC2A07BD960D001AD39DBF27832F986C3A694DEBDA4F9A5352816A5BC332293CD790450AE115E5A2D7B201000050D10310FE57CC9DEAD47342A98CEBB6473E5585A0F72C3077805C78EDF2FAB6B7CA46A7283359DB9E5E2D6A0DA42E9B3E73C9CA850F6547FBCCBAB69A1991719E219C0146F38420A07400E40218009102BA01F70E2D34C1BD48177457F76CDFF6A7CB9ECE8D9AF6B5A76B403C4CEA8528179D76FE92C75E2F177D86E5060089F793DC08CBFD91EBED5905E0D6E1EFB9E7D7A7A5B6CFD85E47BAE3011C23E02002F300CD00381750086086C86133C0DE8364005E045C774FF5CCDFB574A4B7105107A2E0A5C6FA8EA7771D9FE07A11339C70533919BF2C1900009ADBEACE27A31F928E3DCF1FB5EF5F7CF6E7B907375F17BCF6EE7D75845B29E3498110413A5C4415101B5A1020825072E79404821093BF0CFC4100084A10F09E889728E668EE2E58EFFAC69A27B702C0DAAE450B11059B003D09F0338D8B332F7B004C46D09549B782564FD7773314DE01E3B7441C09A91A04094862FC1322C971F14DE21E10A3062024800ECEDD1B657139A6A183C0C141C4BF5B59DFF1BD72D3A3952B00E8EC3B0E511616FCA5026D70D47110A69348883DB139314EE327E44E80313DC43F6240848E38C7A6BB570D3CCCC4E742CDBCBB2CF5586E035ED75A77906374BA8C5F20B9801A740F1404F6D379516290D871C47048CA3CA2EBA37827841FCEDEE785473FFD8937E5015014DAAF3D9BB02F89AA0110304FC87BF12E84FC10040ADB40AC0F72D13F2F5FF2E81B1E0013286B3A177D3E10AF226C7FF4CF7A09E4DEBD07C59C80981048E07527BD2EBAAFAF4E77FDD203604F23FE478EFF10AAAAEE27834F00AAA228F183095C09E5A94E8441B683DCF9DDC6F4A67FF000182FE5B72F3A8EC0DD8E7604291156168C250146413038E46E545FF4E5D50D9BBA7D1650C8CC6FAF6D20C33B6176841162A2D2B2F0AB141C28C081B2CB2C0C7FBCB6ADE610CF00632EF4D42E03ED76331D085122588E050B498A07EE08173E9072D59F3D77C9035B3D03EC2ED8EB38611189663377A0627F3AC4F8FD2CA0815F94285B93481071553119811497103198A394142008C004BA3FDE99DA7E434BF3D98107C0483EBFB5EEE32985FF06E21080026803D9769EB20827C9D14114639A158C2439192088314711A2E8E020231C1947A7FDC3CDC3564412B352C1593AFCB59B3C007635F3DB3FB91F037C3F6270485C6461BE82C7FE843B9E66204593DD41B15E2E3C09D4CD4E8AE2A430FFAEE2794D4104B25BA19D17059C51A75C7635113DDBBFA4306400C99F62F0A608BB706D7BFA2B3E06F84091E7C46B81F06BCC2B99C290544F8098706EE4AE6BAA7FF4CA217143E6842B89F01A9261D18286643549E4EB51A4D3CEAFEF782AFFD2ADBF39E1A3A954F84B92C78DA45AE54B46D2FF98B4AAB1AEF331CF00009A338B9792C165C984573C69862A50042882C2CBA4EEFAC08D38B600F6BC8A896AC6CB4C14EEDA27D5F7CCE0972E6CD8F40AC9FB04E634E20808023D240E75C0579B5B97CCAE7800AC6B4FCF32E03A80FB4914A8DD509500E27D67DA39FCF569E1F6B71DD58D64E1B758819F20107CF59C458FBBE1AF3BB93700971DF1FA94245553ACA6F1D316642FA8780038D829803B7160E68E40DEFD457FCE35D841C35FEEC91E7244001DC4A252401E08EE9896F6F4B45D14001680563DD200E28549E66F0620AE696E3D69DF8A060019FD24B1B9304A7D3751DB1CCABED9D2567F707FFCB0B1617F0BB2D70236BFA8E19F986F275949E8ACC1AFDD96492F03B814D27BA351D0C00206F767D0FDAD8A0D029B330B2F37567D7FA0B83FDAF41506DE1BBDE5E0EE320494AC01D491717C56D4D5E0A4B813E7F764EE61297C4EEA3B9808FE0CB4FEE2C4686B15493E03D04541943A74457DEBFFED0D1B847B177DC15730A4238BA37E228EC1242A3C80D4250E02E3926BB15B0112C62263E34952B014744B8500A425FD64635B9E8C7B952081E6D8FB8F002EAA2817D0D256BB4AC6B990A9309B09042926052011A42545A1C921B498004832C69CD1125B16967C8A202588567767DBA70EACAC1820D05F518100C74279A33FA1E280CD277B7998838A3CFDDC349EFF8324611FC95ACFD9150380B5AD4B3F02D961B1439F84B0BD644549A518331CDD49150300A57A1B44EE17F75C56AAF1630E50E24688E0D0E6CE051FAA1017A005046654B2E9070702A000B92318EDBF60CA03E017FF716695938E066028970E8FE2C612F1CA91611E2D9AFA0CD03B63DB7E06CC2A853A44E96000824888C7ADED4807531A001686F3011E36100555BA07102832E92F98A149AECD4C7A2128723A90B039A050AEAD5E139E4E524999DB8E256C5F00DBA62C009227B7025478FC3FC2F430208B29CD0002B611F8B58499A477018366468A0A36050A764E6900107A42C205F404F0C1A9A1E939B959EF4FBA0B1AAF34676AE691566F48D508EE9DC8E9A954F7EC8D2B4ED9B0DD1BB438D29CA9F918192E31040B1DDC13514EAF9CBF24F3C0A402E0F68DB587E542DE48E014C6FE3CDFB02331474655B734D6B75DECCD3571B2AE75D127A330F839A5A3498679CE889BA4A26E44A9ABB163EBF71A4F7FC51515002D99DAD341DD06700E6183D6C7014870341111216D0E34FDBC1575BFD93CE4463A6A0E92C27B00D5F81CE003723380CF35A633BD43667DC7A28B41DE4467963C953E68E9537020880890D6079AF6D72BEA5AC7FC6472417580E6B69A1300FE2BC53954DC843F78F95B244C8E94810C8E7196BDBBA5BDF6C8A1AE4E7301DB4FCCB779FBAF415FBDC38BA32DED8B9AA8E0BB2658BE6A3878DD5B204C1211880C973B8BD6B4B4D7CD9A700034671A029A7D9BD487018BA7FDB0199C2C6FF6F7650AEEE3802E5DBB71516AD09B1C2097BC3F590EF25F498A3C24396E6E5F7C04C8AB49552BE993E72EEB08A424C6CF26B953A05CD3C43380BAEB9D6909644967EC983C8C447E2E0A73733DBB17E86A371E1FC8B26788383CAE9891BB2B9C924C1E5931C0ECEB130E005AEA6B26CB33FD989D374104ACBA6C70B6E3650CC158387D9621BC3451B546EF978C275CBCEF19E74C3C00C423FB2D3A16FB73A00D5AD2511393784EE92AC050C3C8428AF30BD43959605F9A1500D143C7B37C1B03D20EF3262E500C018854B197CC0B5B0D1C4FF52E0E08236FD1717242912BA6616103E29EDC8A977169ADB83ED30A9BCA1310DC78348C514FC464044C361938E69EE3A8E282C0C9D29379D5577AACE9C50360D2E9CD4BE500C00781A5AD27EF023C03F82CC067015E3C031417DDDEF157781AE879BF5453279F05946A16E083401F04FA20D08B07809729910578A95800F820B0B4F5E483401F047AF12EC08B07800F023D007C10E883402F9E017C16E0B3002F9E012618DDDEF157781AE879BF5453279F05946A16E083401F04961E00343E64FB495FBAAEA0803D82149F9B5CE8F8E39391426FC98215376E9D178901F842FE1C6C150A5FD9666FD142273E7300DFDFC571E4A3E75C2A0600A8479C84E470BEB182588C8F4369F74160614120C93E119D89CE59B0CE271A0074A95FC5C7DE8E313C91440674CAED10ED1E1F0416E8EAA3AA5E8A1B2C7FA450413AEFDB32E10050D0FD2085F6FCE9DEA3108DE2CD0B2384A8FA494AF686377161B2B2FEE11CADF75780B62001C16E483F09B748288714A65D3FE10068AC7D3C47049713B655D26E0F4A14C47833496D702E77FD7975AD7DDEA4E30041EDE35B8C760DA077F346DEB5778ECF1F4D7692BD75F9E2CC2D454903572E6E7B8AD0192032FD916A12AFF6EF6528C45182C32F9C729736D677FDCE9B72FCB2A236D302B87341BC0A80BBD0B980E4CC6C871B2297FB62510B412BD399670CC1994ED94B1CB955122947894E7410B545C0AA200A2F6CAADBF4F264E7B55325081CC2BEE9AE07082E72CA5EE5C8ED8374DE2B3A8AEC14706A900BBFBABA7ED3DB1375DDDDCA6DED7F405AB585C25CC7F0A326CD065C67CEB4A3A9B663C47D01D7654E3C56A8BA437447D14785C366067F00E06F876F17DFAFF3CC1F32642A05051F1683434DAA8E987B5030D794CEB8F15C75DC059AD5754F0A4004E0D5E47BEC90F32CB06BF38FA6F3C5FF29007D005E4CBE27B310E4652ACA5E0280A7FDCA05804830B2F8D21E0815070029F50E8077095750CD7AEAFA7E258513029069AA03C0FD7EF61B0ED816073D1E01C999C17454CEC936AE1A2103983200683AF5DFFB10F17E38F478F303B1FD01839E03DDD3151104EE089EFF1903BE3470D85C654241884F550201133734A53B5EA808005C9A7EABCF145C02302B89042B120194E448C0D96381E1DB159406022BD2ADED705806228B7C8D5B82244DCD4AD1209E4BFA3BE266293E196571DAB9B51DDBF60A08F7B65A9A1F699887AA9DFF02DA1924AAA87C7E38BC3696EF2E62D29352C0D0E3E316C7F639E52F81E458CC424E4AD1C0F8767529451028D144A72CA52F35D677FE60AFB250A9CC8FE6F68663C0F79752C1C930CC27866544F16F1F1335AD20FB4BC9D1C602C4A74104A3CC53519C25623E871DD23A46A70E88DB40BD81E14BE69203AA9E72DAB921E776DC77E192FFDAEB876C975525666D7BDDB330B7000503C000E4D098EE1AD3A7D6B52D5BE8C2DE4D540E5050200144809B76E5AABA8DD7F942D0441ABFAD9EC0EE67EF44615D8CF619FF550850D5E5A2D78A590CF235870A0780970A07805F76F20CE0C503C08B0780179F0578F141A017EF02BC780078F100F000F041A007800F023D00CA62066B4F66BFA780F20600A9713D56986F3F5701144044C975A67EE37A1901C040322C7432934CFA0C830240D3174285870E713323813D78E8D60360448920445D85FB732528C83D53006CBA18F7111674A97827172188824D1E00132C2B1767E4C88D4326DB581120C031BA77CC1F30ED10A2FFD69877C4CA030D800867D97B3C008A2081C3060AEF8820C4E489128D6475411044120E556EDF9BC67A9D55E92E19F023CA90B40703BB799251F90EE6785FC79F8239E701500479FDB73B5F8BA42B81C8C5BBE7891A21BACB3F73176F5785BF5F5EF7E06B05390EA5D608783ADE0E2BDE7D6FF71C0300DAE622BBA17171973C008A20579CF7B864582F879BD11FA727F6C2E07DB4D4FF9280DB65F6CD42AFB5AAAEED1D0997027815200752102529699E7F92A707A45E29FA22DC2BCFF92CA088727EBAF35DF5CCBA42C87E03021C92FD11E3CDD2E418EF4F2C3AC0E1A786E06F9A6A33E3DAA62E65DD5D70D17952EE29C9C131796A20F9D7E59F0171EE2D38AD9866B6AEA9E1B7659539966D816C4DE7B166D1CCA369EE6263D525CEB9300E0DF43E94BDC55C6AFD4EC3A3172EEED8637FBCA67D416A9AED7F7AD6B9CF9BB98678DE0812B790EE6A396E5855D7F15639EAF1FF015841FD48A44C570F0000000049454E44AE426082'), $data->getContent());
+ $this->assertEquals(pack('H*', '6956424F5277304B47676F414141414E53556845556741414144414141414177434149414141445959473751414141414358424957584D41414137454141414F784147564B7734624141414470556C45515652596865315A585567555552512B5A39646358624E4E4C4C4D314E6247303341724B4A585533677167484B336F776968376336442B71682F372F33346F67736A434C364B45777A622B4B54497A6F77536853574E63734C4E61734B4372536367304E79705A437935335477395934732B73366439787252505539444C4E7A7633504F64382B636D5876504C494161584B7A4C557355767461766A44775737387449596D535A7A5645526B6946722F7167316D576730614C516F65387634634636654C546441626F6B4A36653451334C37353075586F453453647A7837475539664D623166704874515941554F6159302F72636E5A67614159546F36344149554F696A72546B504D75614E71616E7347485A424A66597372556244776953674C597675662F37557038712F566857377543354C47344C494E673045584A7762682B423539736A4E5835444A6243696F544E64714E597871524531545A6F354F6D54374B58745046614D4B55665031497A5948544A67414541674C68304B5A6D6A3063676F6B4238416A702F39486E624B7A635149654B30444D4D5357787850515158583072324A49595344713577766D7430376C6A554E6B7171614B7832314E7A3463574E6C4D6941434167446E72346E5868544C48594D685135776E7543524276324A515041366C334A6741457A744742704C4143597A416278536D696F39734B64544A5A59796756523270437049586D7045524743556A455267597844414A7358336E6433667838386E454B476F6D4E304B5068786B4F5642382B55676B4731376F704B566B71425665796571657177474256717A78797153464A614F71544E47457849765253416F65314951394C53704F7A534D7166425A6F4E47716E467030544768786257617033624A323979526549675A4551724B2B31473470735675796C78743968766F6C49304B5A33537065494242736C6F626A35624F4D53574644573450395155413269324F735558667961727033575361696F7279586436353369707A2B3237482F564A723831634B74636E773837733150452F6349694C686D3332517070372B4770706D6A354D623842586D6E61307A512B367355776131676565486646735253424C3956554D445657494C2F47564C43763133554C506866513072346B7A4D55754B3368425749493143386F622B657A51454E385558476D5661724939625A37344B6A4F786F3969373064417A676257586C4D74626C357142306D6750537461704B4F794C617A4E366B434547624F6A6E49306668304F4B57454D327179504771427366722F6350354C756E4A674935696565755348716E4F6C32396E613565663435436F587A392B6F33344E5230732F5975436F4D4F62483250676C6C6B56434F426D7854744647745073432B396D68656B3076397A4B7251676B66514835665650374F64776E55486E2B36317456372F6B496B714B3833696F3338755261376E6E506B6C496A6A78535A704E2B634C703974753148325670582F594638324A464558487548372B57734954576177677269334A73466E6944502B75677878423839626875496843415172714C71345454782F38764354764B536F7172423132415864726E5942454146356A35586E3271576A687A613267446474424C3039777642767351414159454A5365466D397862597477652B504467414138397A6F636F6631784A565A5133502B4138457749412B7133696A634141414141456C46546B5375516D4343'), $data->getThumb());
+
+ $this->assertNull(self::$service->getById(10));
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetByIdBatch()
+ {
+ $data = self::$service->getByIdBatch([1, 2, 3]);
+
+ $this->assertInstanceOf(FileExtData::class, $data[0]);
+ $this->assertEquals(1, $data[0]->getId());
+ $this->assertInstanceOf(FileExtData::class, $data[1]);
+ $this->assertEquals(3, $data[1]->getId());
+
+ $this->assertCount(0, self::$service->getByIdBatch([]));
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetInfoById()
+ {
+ $data = self::$service->getInfoById(1);
+
+ $this->assertInstanceOf(FileExtData::class, $data);
+ $this->assertEquals('sysPass.xml', $data->getName());
+ $this->assertEquals('text/xml', $data->getType());
+ $this->assertEquals('XML', $data->getExtension());
+ $this->assertEquals('Google', $data->getAccountName());
+ $this->assertEquals('Google', $data->getClientName());
+ $this->assertEquals(1312, $data->getSize());
+ $this->assertEquals(1, $data->getAccountId());
+ $this->assertNull($data->getContent());
+ $this->assertNull($data->getThumb());
+
+ $this->assertNull(self::$service->getInfoById(10));
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetAll()
+ {
+ $data = self::$service->getAll();
+
+ $this->assertCount(3, $data);
+ $this->assertInstanceOf(FileExtData::class, $data[0]);
+ $this->assertEquals(4, $data[0]->getId());
+ $this->assertEquals('android.png', $data[0]->getName());
+ $this->assertEquals('image/png', $data[0]->getType());
+ $this->assertEquals('PNG', $data[0]->getExtension());
+ $this->assertEquals('Google', $data[0]->getAccountName());
+ $this->assertEquals('Google', $data[0]->getClientName());
+ $this->assertEquals(4295, $data[0]->getSize());
+ $this->assertEquals(1, $data[0]->getAccountId());
+ $this->assertEquals(pack('H*', '89504E470D0A1A0A0000000D4948445200000080000000800806000000C33E61CB00000006624B474400FF00FF00FFA0BDA793000000097048597300000B1300000B1301009A9C180000000774494D4507DD011D0E180BE2306F78000010544944415478DAED5D6B745CD575FEBE7DEFC8961F3C0C01EC45480C2B8B0026A1D4206B2CB9C27181F208D074816D59069A16280B92A6246D42520A252D210FD2248426818418C9C63CD264C182BAE1154B1A4960CAB35E506A1E5D26501C9E768464CDDCF3F5C7BDA31796A59135F28CE66C2D594B9A19DF73F7FECEB71F67DF7388329096CCC293C1E997845174D1F2FACE374B7DBCCD1B17CF0F42DDDB1BED58F2E74B9E7DBB94C76AE5000069DA05A2CE8CA8EF94FA587FF6507D1503D71A018757D9EC334A7DBC650100B2E79F4C70B0E0336B338BFEA494C75A352DF70D1AE71AB8F9A5F51DCD1E001320AB163FB159C2CD12663A58D35D1DE9D9A538CE350F351C65C6931D1038B9CBAFBA11F200983016705F96DC9B3077CE4EC7926481B0BAF7F208760C22AD69AAEBEC2A07BD960D001AD39DBF27832F986C3A694DEBDA4F9A5352816A5BC332293CD790450AE115E5A2D7B201000050D10310FE57CC9DEAD47342A98CEBB6473E5585A0F72C3077805C78EDF2FAB6B7CA46A7283359DB9E5E2D6A0DA42E9B3E73C9CA850F6547FBCCBAB69A1991719E219C0146F38420A07400E40218009102BA01F70E2D34C1BD48177457F76CDFF6A7CB9ECE8D9AF6B5A76B403C4CEA8528179D76FE92C75E2F177D86E5060089F793DC08CBFD91EBED5905E0D6E1EFB9E7D7A7A5B6CFD85E47BAE3011C23E02002F300CD00381750086086C86133C0DE8364005E045C774FF5CCDFB574A4B7105107A2E0A5C6FA8EA7771D9FE07A11339C70533919BF2C1900009ADBEACE27A31F928E3DCF1FB5EF5F7CF6E7B907375F17BCF6EE7D75845B29E3498110413A5C4415101B5A1020825072E79404821093BF0CFC4100084A10F09E889728E668EE2E58EFFAC69A27B702C0DAAE450B11059B003D09F0338D8B332F7B004C46D09549B782564FD7773314DE01E3B7441C09A91A04094862FC1322C971F14DE21E10A3062024800ECEDD1B657139A6A183C0C141C4BF5B59DFF1BD72D3A3952B00E8EC3B0E511616FCA5026D70D47110A69348883DB139314EE327E44E80313DC43F6240848E38C7A6BB570D3CCCC4E742CDBCBB2CF5586E035ED75A77906374BA8C5F20B9801A740F1404F6D379516290D871C47048CA3CA2EBA37827841FCEDEE785473FFD8937E5015014DAAF3D9BB02F89AA0110304FC87BF12E84FC10040ADB40AC0F72D13F2F5FF2E81B1E0013286B3A177D3E10AF226C7FF4CF7A09E4DEBD07C59C80981048E07527BD2EBAAFAF4E77FDD203604F23FE478EFF10AAAAEE27834F00AAA228F183095C09E5A94E8441B683DCF9DDC6F4A67FF000182FE5B72F3A8EC0DD8E7604291156168C250146413038E46E545FF4E5D50D9BBA7D1650C8CC6FAF6D20C33B6176841162A2D2B2F0AB141C28C081B2CB2C0C7FBCB6ADE610CF00632EF4D42E03ED76331D085122588E050B498A07EE08173E9072D59F3D77C9035B3D03EC2ED8EB38611189663377A0627F3AC4F8FD2CA0815F94285B93481071553119811497103198A394142008C004BA3FDE99DA7E434BF3D98107C0483EBFB5EEE32985FF06E21080026803D9769EB20827C9D14114639A158C2439192088314711A2E8E020231C1947A7FDC3CDC3564412B352C1593AFCB59B3C007635F3DB3FB91F037C3F6270485C6461BE82C7FE843B9E66204593DD41B15E2E3C09D4CD4E8AE2A430FFAEE2794D4104B25BA19D17059C51A75C7635113DDBBFA4306400C99F62F0A608BB706D7BFA2B3E06F84091E7C46B81F06BCC2B99C290544F8098706EE4AE6BAA7FF4CA217143E6842B89F01A9261D18286643549E4EB51A4D3CEAFEF782AFFD2ADBF39E1A3A954F84B92C78DA45AE54B46D2FF98B4AAB1AEF331CF00009A338B9792C165C984573C69862A50042882C2CBA4EEFAC08D38B600F6BC8A896AC6CB4C14EEDA27D5F7CCE0972E6CD8F40AC9FB04E634E20808023D240E75C0579B5B97CCAE7800AC6B4FCF32E03A80FB4914A8DD509500E27D67DA39FCF569E1F6B71DD58D64E1B758819F20107CF59C458FBBE1AF3BB93700971DF1FA94245553ACA6F1D316642FA8780038D829803B7160E68E40DEFD457FCE35D841C35FEEC91E7244001DC4A252401E08EE9896F6F4B45D14001680563DD200E28549E66F0620AE696E3D69DF8A060019FD24B1B9304A7D3751DB1CCABED9D2567F707FFCB0B1617F0BB2D70236BFA8E19F986F275949E8ACC1AFDD96492F03B814D27BA351D0C00206F767D0FDAD8A0D029B330B2F37567D7FA0B83FDAF41506DE1BBDE5E0EE320494AC01D491717C56D4D5E0A4B813E7F764EE61297C4EEA3B9808FE0CB4FEE2C4686B15493E03D04541943A74457DEBFFED0D1B847B177DC15730A4238BA37E228EC1242A3C80D4250E02E3926BB15B0112C62263E34952B014744B8500A425FD64635B9E8C7B952081E6D8FB8F002EAA2817D0D256BB4AC6B990A9309B09042926052011A42545A1C921B498004832C69CD1125B16967C8A202588567767DBA70EACAC1820D05F518100C74279A33FA1E280CD277B7998838A3CFDDC349EFF8324611FC95ACFD9150380B5AD4B3F02D961B1439F84B0BD644549A518331CDD49150300A57A1B44EE17F75C56AAF1630E50E24688E0D0E6CE051FAA1017A005046654B2E9070702A000B92318EDBF60CA03E017FF716695938E066028970E8FE2C612F1CA91611E2D9AFA0CD03B63DB7E06CC2A853A44E96000824888C7ADED4807531A001686F3011E36100555BA07102832E92F98A149AECD4C7A2128723A90B039A050AEAD5E139E4E524999DB8E256C5F00DBA62C009227B7025478FC3FC2F430208B29CD0002B611F8B58499A477018366468A0A36050A764E6900107A42C205F404F0C1A9A1E939B959EF4FBA0B1AAF34676AE691566F48D508EE9DC8E9A954F7EC8D2B4ED9B0DD1BB438D29CA9F918192E31040B1DDC13514EAF9CBF24F3C0A402E0F68DB587E542DE48E014C6FE3CDFB02331474655B734D6B75DECCD3571B2AE75D127A330F839A5A3498679CE889BA4A26E44A9ABB163EBF71A4F7FC51515002D99DAD341DD06700E6183D6C7014870341111216D0E34FDBC1575BFD93CE4463A6A0E92C27B00D5F81CE003723380CF35A633BD43667DC7A28B41DE4467963C953E68E9537020880890D6079AF6D72BEA5AC7FC6472417580E6B69A1300FE2BC53954DC843F78F95B244C8E94810C8E7196BDBBA5BDF6C8A1AE4E7301DB4FCCB779FBAF415FBDC38BA32DED8B9AA8E0BB2658BE6A3878DD5B204C1211880C973B8BD6B4B4D7CD9A700034671A029A7D9BD487018BA7FDB0199C2C6FF6F7650AEEE3802E5DBB71516AD09B1C2097BC3F590EF25F498A3C24396E6E5F7C04C8AB49552BE993E72EEB08A424C6CF26B953A05CD3C43380BAEB9D6909644967EC983C8C447E2E0A73733DBB17E86A371E1FC8B26788383CAE9891BB2B9C924C1E5931C0ECEB130E005AEA6B26CB33FD989D374104ACBA6C70B6E3650CC158387D9621BC3451B546EF978C275CBCEF19E74C3C00C423FB2D3A16FB73A00D5AD2511393784EE92AC050C3C8428AF30BD43959605F9A1500D143C7B37C1B03D20EF3262E500C018854B197CC0B5B0D1C4FF52E0E08236FD1717242912BA6616103E29EDC8A977169ADB83ED30A9BCA1310DC78348C514FC464044C361938E69EE3A8E282C0C9D29379D5577AACE9C50360D2E9CD4BE500C00781A5AD27EF023C03F82CC067015E3C031417DDDEF157781AE879BF5453279F05946A16E083401F04FA20D08B07809729910578A95800F820B0B4F5E483401F047AF12EC08B07800F023D007C10E883402F9E017C16E0B3002F9E012618DDDEF157781AE879BF5453279F05946A16E083401F04961E00343E64FB495FBAAEA0803D82149F9B5CE8F8E39391426FC98215376E9D178901F842FE1C6C150A5FD9666FD142273E7300DFDFC571E4A3E75C2A0600A8479C84E470BEB182588C8F4369F74160614120C93E119D89CE59B0CE271A0074A95FC5C7DE8E313C91440674CAED10ED1E1F0416E8EAA3AA5E8A1B2C7FA450413AEFDB32E10050D0FD2085F6FCE9DEA3108DE2CD0B2384A8FA494AF686377161B2B2FEE11CADF75780B62001C16E483F09B748288714A65D3FE10068AC7D3C47049713B655D26E0F4A14C47833496D702E77FD7975AD7DDEA4E30041EDE35B8C760DA077F346DEB5778ECF1F4D7692BD75F9E2CC2D454903572E6E7B8AD0192032FD916A12AFF6EF6528C45182C32F9C729736D677FDCE9B72FCB2A236D302B87341BC0A80BBD0B980E4CC6C871B2297FB62510B412BD399670CC1994ED94B1CB955122947894E7410B545C0AA200A2F6CAADBF4F264E7B55325081CC2BEE9AE07082E72CA5EE5C8ED8374DE2B3A8AEC14706A900BBFBABA7ED3DB1375DDDDCA6DED7F405AB585C25CC7F0A326CD065C67CEB4A3A9B663C47D01D7654E3C56A8BA437447D14785C366067F00E06F876F17DFAFF3CC1F32642A05051F1683434DAA8E987B5030D794CEB8F15C75DC059AD5754F0A4004E0D5E47BEC90F32CB06BF38FA6F3C5FF29007D005E4CBE27B310E4652ACA5E0280A7FDCA05804830B2F8D21E0815070029F50E8077095750CD7AEAFA7E258513029069AA03C0FD7EF61B0ED816073D1E01C999C17454CEC936AE1A2103983200683AF5DFFB10F17E38F478F303B1FD01839E03DDD3151104EE089EFF1903BE3470D85C654241884F550201133734A53B5EA808005C9A7EABCF145C02302B89042B120194E448C0D96381E1DB159406022BD2ADED705806228B7C8D5B82244DCD4AD1209E4BFA3BE266293E196571DAB9B51DDBF60A08F7B65A9A1F699887AA9DFF02DA1924AAA87C7E38BC3696EF2E62D29352C0D0E3E316C7F639E52F81E458CC424E4AD1C0F8767529451028D144A72CA52F35D677FE60AFB250A9CC8FE6F68663C0F79752C1C930CC27866544F16F1F1335AD20FB4BC9D1C602C4A74104A3CC53519C25623E871DD23A46A70E88DB40BD81E14BE69203AA9E72DAB921E776DC77E192FFDAEB876C975525666D7BDDB330B7000503C000E4D098EE1AD3A7D6B52D5BE8C2DE4D540E5050200144809B76E5AABA8DD7F942D0441ABFAD9EC0EE67EF44615D8CF619FF550850D5E5A2D78A590CF235870A0780970A07805F76F20CE0C503C08B0780179F0578F141A017EF02BC780078F100F000F041A007800F023D00CA62066B4F66BFA780F20600A9713D56986F3F5701144044C975A67EE37A1901C040322C7432934CFA0C830240D3174285870E713323813D78E8D60360448920445D85FB732528C83D53006CBA18F7111674A97827172188824D1E00132C2B1767E4C88D4326DB581120C031BA77CC1F30ED10A2FFD69877C4CA030D800867D97B3C008A2081C3060AEF8820C4E489128D6475411044120E556EDF9BC67A9D55E92E19F023CA90B40703BB799251F90EE6785FC79F8239E701500479FDB73B5F8BA42B81C8C5BBE7891A21BACB3F73176F5785BF5F5EF7E06B05390EA5D608783ADE0E2BDE7D6FF71C0300DAE622BBA17171973C008A20579CF7B864582F879BD11FA727F6C2E07DB4D4FF9280DB65F6CD42AFB5AAAEED1D0997027815200752102529699E7F92A707A45E29FA22DC2BCFF92CA088727EBAF35DF5CCBA42C87E03021C92FD11E3CDD2E418EF4F2C3AC0E1A786E06F9A6A33E3DAA62E65DD5D70D17952EE29C9C131796A20F9D7E59F0171EE2D38AD9866B6AEA9E1B7659539966D816C4DE7B166D1CCA369EE6263D525CEB9300E0DF43E94BDC55C6AFD4EC3A3172EEED8637FBCA67D416A9AED7F7AD6B9CF9BB98678DE0812B790EE6A396E5855D7F15639EAF1FF015841FD48A44C570F0000000049454E44AE426082'), $data[0]->getContent());
+ $this->assertEquals(pack('H*', '6956424F5277304B47676F414141414E53556845556741414144414141414177434149414141445959473751414141414358424957584D41414137454141414F784147564B7734624141414470556C45515652596865315A585567555552512B5A39646358624E4E4C4C4D314E6247303341724B4A585533677167484B336F776968376336442B71682F372F33346F67736A434C364B45777A622B4B54497A6F77536853574E63734C4E61734B4372536367304E79705A437935335477395934732B73366439787252505539444C4E7A7633504F64382B636D5876504C494161584B7A4C557355767461766A44775737387449596D535A7A5645526B6946722F7167316D576730614C516F65387634634636654C546441626F6B4A36653451334C37353075586F453453647A7837475539664D623166704874515941554F6159302F72636E5A67614159546F36344149554F696A72546B504D75614E71616E7347485A424A66597372556244776953674C597675662F37557038712F566857377543354C47344C494E673045584A7762682B423539736A4E5835444A6243696F544E64714E597871524531545A6F354F6D54374B58745046614D4B55665031497A5948544A67414541674C68304B5A6D6A3063676F6B4238416A702F39486E624B7A635149654B30444D4D5357787850515158583072324A49595344713577766D7430376C6A554E6B7171614B7832314E7A3463574E6C4D6941434167446E72346E5868544C48594D685135776E7543524276324A515041366C334A6741457A744742704C4143597A416278536D696F39734B64544A5A59796756523270437049586D7045524743556A455267597844414A7358336E6433667838386E454B476F6D4E304B5068786B4F5642382B55676B4731376F704B566B71425665796571657177474256717A78797153464A614F71544E47457849765253416F65314951394C53704F7A534D7166425A6F4E47716E467030544768786257617033624A323979526549675A4551724B2B31473470735675796C78743968766F6C49304B5A33537065494242736C6F626A35624F4D53574644573450395155413269324F735558667961727033575361696F7279586436353369707A2B3237482F564A723831634B74636E773837733150452F6349694C686D3332517070372B4770706D6A354D623842586D6E61307A512B367355776131676565486646735253424C3956554D445657494C2F47564C43763133554C506866513072346B7A4D55754B3368425749493143386F622B657A51454E385558476D5661724939625A37344B6A4F786F3969373064417A676257586C4D74626C357142306D6750537461704B4F794C617A4E366B434547624F6A6E49306668304F4B57454D327179504771427366722F6350354C756E4A674935696565755348716E4F6C32396E613565663435436F587A392B6F33344E5230732F5975436F4D4F62483250676C6C6B56434F426D7854744647745073432B396D68656B3076397A4B7251676B66514835665650374F64776E55486E2B36317456372F6B496B714B3833696F3338755261376E6E506B6C496A6A78535A704E2B634C703974753148325670582F594638324A464558487548372B57734954576177677269334A73466E6944502B75677878423839626875496843415172714C71345454782F38764354764B536F7172423132415864726E5942454146356A35586E3271576A687A613267446474424C3039777642767351414159454A5365466D397862597477652B504467414138397A6F636F6631784A565A5133502B4138457749412B7133696A634141414141456C46546B5375516D4343'), $data[0]->getThumb());
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetByAccountId()
+ {
+ $data = self::$service->getByAccountId(1);
+
+ $this->assertCount(2, $data);
+ $this->assertInstanceOf(FileData::class, $data[0]);
+ $this->assertEquals(4, $data[0]->getId());
+ $this->assertEquals('android.png', $data[0]->getName());
+ $this->assertEquals('image/png', $data[0]->getType());
+ $this->assertEquals('PNG', $data[0]->getExtension());
+ $this->assertEquals(4295, $data[0]->getSize());
+ $this->assertEquals(1, $data[0]->getAccountId());
+
+ $this->assertInstanceOf(FileData::class, $data[1]);
+ $this->assertEquals(1, $data[1]->getId());
+ $this->assertEquals('sysPass.xml', $data[1]->getName());
+ $this->assertEquals('text/xml', $data[1]->getType());
+ $this->assertEquals('XML', $data[1]->getExtension());
+ $this->assertEquals(1312, $data[1]->getSize());
+ $this->assertEquals(1, $data[1]->getAccountId());
+ $this->assertEquals(pack('H*', '3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C526F6F743E0A20203C4D6574613E0A202020203C47656E657261746F723E737973506173733C2F47656E657261746F723E0A202020203C56657273696F6E3E312E322E303C2F56657273696F6E3E0A202020203C54696D653E313433393332353330343C2F54696D653E0A202020203C557365722069643D2231223E61646D696E3C2F557365723E0A202020203C47726F75702069643D2231223E41646D696E733C2F47726F75703E0A202020203C486173683E36646232633238323731393136326630663136316531343731653734636531623C2F486173683E0A20203C2F4D6574613E0A20203C43617465676F726965733E0A202020203C43617465676F72792069643D2231223E0A2020202020203C6E616D653E485454503C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F43617465676F72793E0A20203C2F43617465676F726965733E0A20203C437573746F6D6572733E0A202020203C437573746F6D65722069643D2231223E0A2020202020203C6E616D653E476F6F676C6520496E632E3C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F437573746F6D65723E0A202020203C437573746F6D65722069643D2232223E0A2020202020203C6E616D653E4D6963726F736F667420496E633C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F437573746F6D65723E0A20203C2F437573746F6D6572733E0A20203C4163636F756E74733E0A202020203C4163636F756E742069643D2231223E0A2020202020203C6E616D653E476F6F676C653C2F6E616D653E0A2020202020203C637573746F6D657249643E313C2F637573746F6D657249643E0A2020202020203C63617465676F727949643E313C2F63617465676F727949643E0A2020202020203C6C6F67696E3E61646D696E3C2F6C6F67696E3E0A2020202020203C75726C3E382E382E382E383C2F75726C3E0A2020202020203C6E6F7465732F3E0A2020202020203C706173733E6C4E66513133634B6A384D592B79434F346652536B4773494334357247454C442F424E69345654614671593D3C2F706173733E0A2020202020203C7061737369763E454E6354743338503265346C643350395A553241767939664C466277386C42473947382F75414D785A6D343D3C2F7061737369763E0A202020203C2F4163636F756E743E0A202020203C4163636F756E742069643D2232223E0A2020202020203C6E616D653E4D6963726F736F66743C2F6E616D653E0A2020202020203C637573746F6D657249643E323C2F637573746F6D657249643E0A2020202020203C63617465676F727949643E313C2F63617465676F727949643E0A2020202020203C6C6F67696E3E726F6F743C2F6C6F67696E3E0A2020202020203C75726C3E342E342E342E343C2F75726C3E0A2020202020203C6E6F7465733E4E6F746173206465206D6963726F66736F66743C2F6E6F7465733E0A2020202020203C706173733E3352394F48632B53335A4E56684D795948352F784C476C76625246662F5367573348527261322B325349453D3C2F706173733E0A2020202020203C7061737369763E763637306A596B43547178635332344C4F65453077672B304330376A734C2F4635342B6E56484963544F773D3C2F7061737369763E0A202020203C2F4163636F756E743E0A20203C2F4163636F756E74733E0A3C2F526F6F743E0A'), $data[1]->getContent());
+ $this->assertEquals(pack('H*', '6E6F5F7468756D62'), $data[1]->getThumb());
+
+ $this->assertCount(0, self::$service->getByAccountId(10));
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Repositories\NoSuchItemException
+ */
+ public function testDelete()
+ {
+ self::$service
+ ->delete(1)
+ ->delete(3);
+
+ $this->assertEquals(1, $this->conn->getRowCount('AccountFile'));
+
+ $this->expectException(NoSuchItemException::class);
+
+ self::$service->delete(10);
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Services\ServiceException
+ */
+ public function testDeleteByIdBatch()
+ {
+ $this->assertEquals(2, self::$service->deleteByIdBatch([1, 3]));
+ $this->assertEquals(0, self::$service->deleteByIdBatch([]));
+
+ $this->assertEquals(1, $this->conn->getRowCount('AccountFile'));
+
+ $this->expectException(ServiceException::class);
+
+ self::$service->deleteByIdBatch([10]);
+ }
+
+ /**
+ * Returns the test dataset.
+ *
+ * @return IDataSet
+ */
+ protected function getDataSet()
+ {
+ return $this->createMySQLXMLDataSet(RESOURCE_DIR . DIRECTORY_SEPARATOR . 'datasets' . DIRECTORY_SEPARATOR . 'syspass_accountFile.xml');
+ }
+}
diff --git a/tests/Services/AccountHistoryServiceTest.php b/tests/Services/AccountHistoryServiceTest.php
new file mode 100644
index 00000000..b59273c7
--- /dev/null
+++ b/tests/Services/AccountHistoryServiceTest.php
@@ -0,0 +1,250 @@
+.
+ */
+
+namespace SP\Tests\Services;
+
+use PHPUnit\DbUnit\DataSet\IDataSet;
+use SP\DataModel\AccountHistoryData;
+use SP\DataModel\Dto\AccountHistoryCreateDto;
+use SP\DataModel\ItemSearchData;
+use SP\Repositories\NoSuchItemException;
+use SP\Services\Account\AccountHistoryService;
+use SP\Services\Account\AccountPasswordRequest;
+use SP\Services\ServiceException;
+use SP\Storage\Database\DatabaseConnectionData;
+use SP\Tests\DatabaseTestCase;
+use SP\Util\Util;
+use function SP\Tests\setupContext;
+
+/**
+ * Class AccountHistoryServiceTest
+ *
+ * @package SP\Tests\Services
+ */
+class AccountHistoryServiceTest extends DatabaseTestCase
+{
+ /**
+ * @var AccountHistoryService
+ */
+ private static $service;
+
+ /**
+ * @throws \DI\NotFoundException
+ * @throws \SP\Core\Context\ContextException
+ * @throws \DI\DependencyException
+ */
+ public static function setUpBeforeClass()
+ {
+ $dic = setupContext();
+
+ // Datos de conexión a la BBDD
+ self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
+
+ // Inicializar el servicio
+ self::$service = $dic->get(AccountHistoryService::class);
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetAll()
+ {
+ $data = self::$service->getAll();
+
+ $this->assertCount(5, $data);
+ $this->assertEquals(7, $data[0]->id);
+ $this->assertEquals('2018-06-13 20:14:23', $data[0]->dateEdit);
+ $this->assertEquals('2018-06-05 22:11:40', $data[0]->dateAdd);
+ $this->assertEquals('admin', $data[0]->userAdd);
+ $this->assertEquals('admin', $data[0]->userEdit);
+ }
+
+ /**
+ * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testCreate()
+ {
+ $result = self::$service->create(new AccountHistoryCreateDto(2, true, false, Util::generateRandomBytes()));
+ $this->assertEquals(8, $result);
+
+ $result = self::$service->create(new AccountHistoryCreateDto(2, true, true, Util::generateRandomBytes()));
+ $this->assertEquals(9, $result);
+
+ $result = self::$service->create(new AccountHistoryCreateDto(10, true, false, Util::generateRandomBytes()));
+ $this->assertEquals(0, $result);
+
+ $this->assertEquals(7, $this->conn->getRowCount('AccountHistory'));
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testSearch()
+ {
+ $itemSearchData = new ItemSearchData();
+ $itemSearchData->setLimitCount(10);
+ $itemSearchData->setSeachString('Google');
+
+ $result = self::$service->search($itemSearchData);
+ $data = $result->getDataAsArray();
+
+ $this->assertEquals(5, $result->getNumRows());
+ $this->assertCount(5, $data);
+ $this->assertEquals(7, $data[0]->id);
+
+ $itemSearchData->setSeachString('test');
+ $result = self::$service->search($itemSearchData);
+
+ $this->assertEquals(0, $result->getNumRows());
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetHistoryForAccount()
+ {
+ $data = self::$service->getHistoryForAccount(2);
+
+ $this->assertCount(1, $data);
+ $this->assertArrayHasKey(3, $data);
+ $this->assertEquals('2018-06-06 22:20:29 - admin', $data[3]);
+
+ $data = self::$service->getHistoryForAccount(1);
+
+ $this->assertCount(4, $data);
+ $this->assertArrayHasKey(4, $data);
+ $this->assertArrayHasKey(5, $data);
+ $this->assertArrayHasKey(6, $data);
+ $this->assertArrayHasKey(7, $data);
+ $this->assertEquals('2018-06-05 22:11:40 - admin', $data[4]);
+
+ $this->assertCount(0, self::$service->getHistoryForAccount(10));
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ public function testGetById()
+ {
+ $data = self::$service->getById(3);
+ /** @var AccountHistoryData $data */
+
+ $this->assertInstanceOf(AccountHistoryData::class, $data);
+ $this->assertEquals(3, $data->getId());
+ $this->assertEquals('2018-06-06 22:20:29', $data->getDateEdit());
+ $this->assertEquals('2018-06-05 22:49:34', $data->getDateAdd());
+ $this->assertEquals(1, $data->getUserId());
+ $this->assertEquals(1, $data->getUserEditId());
+
+ $this->expectException(NoSuchItemException::class);
+
+ self::$service->getById(1);
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Services\ServiceException
+ */
+ public function testDelete()
+ {
+ self::$service->delete(3);
+ self::$service->delete(4);
+
+ $this->expectException(ServiceException::class);
+
+ self::$service->delete(1);
+
+ $this->assertEquals(3, $this->conn->getRowCount('AccountHistory'));
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testDeleteByIdBatch()
+ {
+ $this->assertEquals(3, self::$service->deleteByIdBatch([1, 3, 4, 5]));
+ $this->assertEquals(0, self::$service->deleteByIdBatch([]));
+
+ $this->assertEquals(2, $this->conn->getRowCount('AccountHistory'));
+ }
+
+ /**
+ * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ public function testUpdatePasswordMasterPass()
+ {
+ $request = new AccountPasswordRequest();
+ $request->id = 3;
+ $request->pass = Util::generateRandomBytes();
+ $request->key = Util::generateRandomBytes();
+ $request->hash = Util::generateRandomBytes();
+
+ self::$service->updatePasswordMasterPass($request);
+
+ $data = self::$service->getById(3);
+
+ $this->assertEquals($request->pass, $data->getPass());
+ $this->assertEquals($request->key, $data->getKey());
+
+ $this->expectException(ServiceException::class);
+
+ $request->id = 10;
+
+ self::$service->updatePasswordMasterPass($request);
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ */
+ public function testGetAccountsPassData()
+ {
+ $data = self::$service->getAccountsPassData();
+
+ $this->assertCount(5, $data);
+ $this->assertEquals(3, $data[0]->id);
+ $this->assertEquals('Google', $data[0]->name);
+ $this->assertEquals(pack('H*', '646566353032303064396362643366376662646536326637663732663861383732623430613839386131643134333933663662623033316664343362366461643762626564643634386437363964346634616234386638336636653236396166623734636261383134313363626162326461393733343934613231653934666331616664633637313732316562356666396562646132613665313937626233333563613632383830393934333863643731333230383132316430366433303838'), $data[0]->pass);
+ $this->assertEquals(pack('H*', '6465663130303030646566353032303032636635623034396437656539356531653838663166613438643061616132663133613163663766346238316165663837326134373665316461653661353865316666626438346130383166303062633138646136373265653935643234626564336565303063333262646262303433336633356534323263616337613238363532336233313666316137333462616337343839346631333632643863376430373861373862396135633064396239653061353537626562666336636566623766363166376330393734356461623536373762303436313865343936383434663932666364303634316330303935636239363938336361336631363161623134663339643536636233653938333833613062396464356365383736333334376364363933313563306436343362623937366139383831376632346431303364316533353133306262393862353034353262346334663934663162323531383632356530653331346438343430323362666334306264616265376437386238663632326535353338636537663431626261616461613138646333333662623762636565333030656565333734616537356365303131363731323239383132383964346634383661376635303136303835336138663335653366393230383632386162373332343335633037656432616234'), $data[0]->key);
+ $this->assertEquals(pack('H*', '24327924313024787473754E325055766753482F306D7266426C73624F4163745667436A596371447143364C3354395172614E785A43345258475961'), $data[0]->mPassHash);
+ }
+
+ /**
+ * Returns the test dataset.
+ *
+ * @return IDataSet
+ */
+ protected function getDataSet()
+ {
+ return $this->createMySQLXMLDataSet(RESOURCE_DIR . DIRECTORY_SEPARATOR . 'datasets' . DIRECTORY_SEPARATOR . 'syspass_accountHistory.xml');
+ }
+}
diff --git a/tests/Services/AccountSearchServiceTest.php b/tests/Services/AccountSearchServiceTest.php
new file mode 100644
index 00000000..16137825
--- /dev/null
+++ b/tests/Services/AccountSearchServiceTest.php
@@ -0,0 +1,503 @@
+.
+ */
+
+namespace SP\Tests\Services;
+
+use PHPUnit\DbUnit\DataSet\IDataSet;
+use SP\Account\AccountSearchFilter;
+use SP\Account\AccountSearchItem;
+use SP\Core\Context\ContextInterface;
+use SP\DataModel\UserPreferencesData;
+use SP\Mvc\Model\QueryCondition;
+use SP\Services\Account\AccountSearchService;
+use SP\Services\User\UserLoginResponse;
+use SP\Storage\Database\DatabaseConnectionData;
+use SP\Storage\Database\QueryResult;
+use SP\Tests\DatabaseTestCase;
+use function SP\Tests\setupContext;
+
+/**
+ * Class AccountSearchServiceTest
+ *
+ * @package SP\Tests\Services
+ */
+class AccountSearchServiceTest extends DatabaseTestCase
+{
+ /**
+ * @var AccountSearchService
+ */
+ private static $service;
+ /**
+ * @var \Closure
+ */
+ private static $setUpUser;
+
+ /**
+ * @throws \DI\NotFoundException
+ * @throws \SP\Core\Context\ContextException
+ * @throws \DI\DependencyException
+ */
+ public static function setUpBeforeClass()
+ {
+ $dic = setupContext();
+
+ // Datos de conexión a la BBDD
+ self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
+
+ // Inicializar el servicio
+ self::$service = $dic->get(AccountSearchService::class);
+
+ $context = $dic->get(ContextInterface::class);
+
+ self::$setUpUser = function (UserLoginResponse $response) use ($context) {
+ $response->setLastUpdate(time());
+
+ $context->setUserData($response);
+ };
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ public function testProcessSearchResultsForUserAdmin()
+ {
+ $userData = new UserLoginResponse();
+ $userData->setId(1);
+ $userData->setUserGroupId(1);
+ $userData->setIsAdminApp(1);
+ $userData->setPreferences(new UserPreferencesData());
+
+ self::$setUpUser->call($this, $userData);
+
+ $this->checkCategoryById(1, [1]);
+ $this->checkNonExistantCategory();
+ $this->checkClientById(1, [1]);
+ $this->checkClientById(2, [2]);
+ $this->checkClientAndCategory(2, 2, [2]);
+ $this->checkClientAndCategory(2, 1, [2, 1], QueryCondition::CONDITION_OR);
+ $this->checkNonExistantClient();
+ $this->checkString('apple.com', [2]);
+ $this->checkString('aaaa', [1]);
+ $this->checkString('github');
+ $this->checkString('google', [1]);
+ $this->checkString('slack');
+ $this->checkString('is:private');
+ $this->checkString('not:private', [2, 1]);
+ $this->checkString('user:admin', [2, 1]);
+ $this->checkString('user:user_a', [2, 1]);
+ $this->checkString('owner:user_a');
+ $this->checkString('owner:user_b');
+ $this->checkString('group:Admins', [2, 1]);
+ $this->checkString('group:Usuarios', [2]);
+ $this->checkString('maingroup:Admins', [2, 1]);
+ $this->checkString('maingroup:Usuarios');
+ $this->checkString('file:"Clock 3"', [2]);
+ $this->checkString('file:"syspass"', [1]);
+ $this->checkString('id:1', [1]);
+ $this->checkString('id:3');
+ $this->checkFavorites(1, [1]);
+ $this->checkTags([1, 3], [2]);
+ $this->checkTags([1, 3], [2, 1], QueryCondition::CONDITION_OR);
+ $this->checkTags([2], [1]);
+ }
+
+ /**
+ * @param int $id Category Id
+ * @param array $accountsId
+ *
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ private function checkCategoryById($id, array $accountsId = [])
+ {
+ $rows = count($accountsId);
+
+ $searchFilter = new AccountSearchFilter();
+ $searchFilter->setLimitCount(10);
+ $searchFilter->setCategoryId($id);
+
+ // Comprobar un Id de categoría
+ $result = self::$service->processSearchResults($searchFilter);
+ $this->assertInstanceOf(QueryResult::class, $result);
+
+ if ($rows > 0) {
+ /** @var AccountSearchItem[] $data */
+ $data = $result->getDataAsArray();
+
+ $i = 0;
+
+ foreach ($data as $searchItem) {
+ $this->assertEquals($accountsId[$i], $searchItem->getAccountSearchVData()->getId());
+ $i++;
+ }
+ }
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ private function checkNonExistantCategory()
+ {
+ $searchFilter = new AccountSearchFilter();
+ $searchFilter->setLimitCount(10);
+ $searchFilter->setCategoryId(10);
+
+ $result = self::$service->processSearchResults($searchFilter);
+ $this->assertInstanceOf(QueryResult::class, $result);
+ $this->assertEquals(0, $result->getNumRows());
+ $this->assertCount(0, $result->getDataAsArray());
+ }
+
+ /**
+ * @param int $id Client Id
+ * @param array $accountsId
+ *
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ private function checkClientById($id, array $accountsId = [])
+ {
+ $rows = count($accountsId);
+
+ $searchFilter = new AccountSearchFilter();
+ $searchFilter->setLimitCount(10);
+ $searchFilter->setClientId($id);
+
+ $result = self::$service->processSearchResults($searchFilter);
+ $this->assertInstanceOf(QueryResult::class, $result);
+ $this->assertEquals($rows, $result->getNumRows());
+
+ if ($rows > 0) {
+ /** @var AccountSearchItem[] $data */
+ $data = $result->getDataAsArray();
+
+ $i = 0;
+
+ foreach ($data as $searchItem) {
+ $this->assertEquals($accountsId[$i], $searchItem->getAccountSearchVData()->getId());
+ $i++;
+ }
+ }
+ }
+
+ /**
+ * @param int $clientId
+ * @param int $categoryId
+ * @param array $accountsId
+ * @param string $operator
+ *
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ private function checkClientAndCategory($clientId, $categoryId, array $accountsId = [], $operator = null)
+ {
+ $rows = count($accountsId);
+
+ $searchFilter = new AccountSearchFilter();
+ $searchFilter->setLimitCount(10);
+ $searchFilter->setFilterOperator($operator);
+ $searchFilter->setClientId($clientId);
+ $searchFilter->setCategoryId($categoryId);
+
+ $result = self::$service->processSearchResults($searchFilter);
+ $this->assertInstanceOf(QueryResult::class, $result);
+ $this->assertEquals($rows, $result->getNumRows());
+
+ $i = 0;
+
+ /** @var AccountSearchItem $item */
+ foreach ($result->getDataAsArray() as $item) {
+ $this->assertEquals($accountsId[$i], $item->getAccountSearchVData()->getId());
+ $i++;
+ }
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ private function checkNonExistantClient()
+ {
+ $searchFilter = new AccountSearchFilter();
+ $searchFilter->setLimitCount(10);
+ $searchFilter->setClientId(10);
+
+ $result = self::$service->processSearchResults($searchFilter);
+ $this->assertInstanceOf(QueryResult::class, $result);
+ $this->assertEquals(0, $result->getNumRows());
+ $this->assertCount(0, $result->getDataAsArray());
+ }
+
+ /**
+ * @param string $string
+ * @param array $accountsId
+ *
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ private function checkString($string, array $accountsId = [])
+ {
+ $rows = count($accountsId);
+
+ $searchFilter = new AccountSearchFilter();
+ $searchFilter->setLimitCount(10);
+ $searchFilter->setTxtSearch($string);
+
+ $result = self::$service->processSearchResults($searchFilter);
+ $this->assertInstanceOf(QueryResult::class, $result);
+
+ $this->assertEquals($rows, $result->getNumRows());
+
+ $i = 0;
+
+ /** @var AccountSearchItem $item */
+ foreach ($result->getDataAsArray() as $item) {
+ $this->assertEquals($accountsId[$i], $item->getAccountSearchVData()->getId());
+
+ $i++;
+ }
+ }
+
+ /**
+ * @param int $rows Expected rows
+ * @param array $accountsId
+ *
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ private function checkFavorites($rows, array $accountsId = [])
+ {
+ $searchFilter = new AccountSearchFilter();
+ $searchFilter->setLimitCount(10);
+ $searchFilter->setSearchFavorites(true);
+
+ $result = self::$service->processSearchResults($searchFilter);
+
+ $this->assertInstanceOf(QueryResult::class, $result);
+ $this->assertEquals($rows, $result->getNumRows());
+
+ $i = 0;
+
+ /** @var AccountSearchItem $item */
+ foreach ($result->getDataAsArray() as $item) {
+ $this->assertEquals($accountsId[$i], $item->getAccountSearchVData()->getId());
+ $i++;
+ }
+ }
+
+ /**
+ * @param array $tagsId
+ * @param array $accountsId
+ * @param string $operator
+ *
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ private function checkTags(array $tagsId, array $accountsId = [], $operator = null)
+ {
+ $rows = count($accountsId);
+
+ $searchFilter = new AccountSearchFilter();
+ $searchFilter->setLimitCount(10);
+ $searchFilter->setFilterOperator($operator);
+ $searchFilter->setTagsId($tagsId);
+
+ $result = self::$service->processSearchResults($searchFilter);
+ $this->assertInstanceOf(QueryResult::class, $result);
+
+ /** @var AccountSearchItem[] $data */
+ $data = $result->getDataAsArray();
+
+ $this->assertEquals($rows, $result->getNumRows());
+ $this->assertCount($rows, $data);
+
+ $i = 0;
+
+ foreach ($data as $item) {
+ $this->assertEquals($accountsId[$i], $item->getAccountSearchVData()->getId());
+ $i++;
+ }
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ public function testProcessSearchResultsForUserDemo()
+ {
+ AccountSearchItem::$publicLinkEnabled = false;
+
+ $userData = new UserLoginResponse();
+ $userData->setId(2);
+ $userData->setUserGroupId(2);
+ $userData->setPreferences(new UserPreferencesData());
+
+ self::$setUpUser->call($this, $userData);
+
+ $this->checkCategoryById(1, [1]);
+ $this->checkNonExistantCategory();
+ $this->checkClientById(1, [1]);
+ $this->checkClientById(2, [2]);
+ $this->checkClientAndCategory(2, 2, [2]);
+ $this->checkClientAndCategory(2, 1, [2, 1], QueryCondition::CONDITION_OR);
+ $this->checkNonExistantClient();
+ $this->checkString('apple.com', [2]);
+ $this->checkString('github');
+ $this->checkString('google', [1]);
+ $this->checkString('slack');
+ $this->checkString('is:private');
+ $this->checkString('not:private', [2, 1]);
+ $this->checkString('user:admin', [2, 1]);
+ $this->checkString('user:user_a', [2, 1]);
+ $this->checkString('owner:user_a');
+ $this->checkString('owner:user_b');
+ $this->checkString('group:Admins', [2, 1]);
+ $this->checkString('group:Usuarios', [2]);
+ $this->checkString('maingroup:Admins', [2, 1]);
+ $this->checkString('maingroup:Usuarios');
+ $this->checkString('file:"Clock 3"', [2]);
+ $this->checkString('file:"syspass"', [1]);
+ $this->checkString('id:1', [1]);
+ $this->checkString('id:3');
+ $this->checkFavorites(1, [2]);
+ $this->checkTags([1, 3], [2]);
+ $this->checkTags([1, 3], [2, 1], QueryCondition::CONDITION_OR);
+ $this->checkTags([2], [1]);
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ public function testProcessSearchResultsForUserA()
+ {
+ AccountSearchItem::$publicLinkEnabled = false;
+
+ $userData = new UserLoginResponse();
+ $userData->setId(3);
+ $userData->setUserGroupId(3);
+ $userData->setPreferences(new UserPreferencesData());
+
+ self::$setUpUser->call($this, $userData);
+
+ $this->checkCategoryById(1, [1]);
+ $this->checkNonExistantCategory();
+ $this->checkClientById(1, [1]);
+ $this->checkClientById(2, [2, 3]);
+ $this->checkClientAndCategory(2, 2, [2, 3]);
+ $this->checkClientAndCategory(2, 1, [2, 3, 1], QueryCondition::CONDITION_OR);
+ $this->checkNonExistantClient();
+ $this->checkString('apple.com', [2]);
+ $this->checkString('github', [3]);
+ $this->checkString('google', [1]);
+ $this->checkString('slack', [4]);
+ $this->checkString('is:private', [3, 4]);
+ $this->checkString('user:admin', [2, 1]);
+ $this->checkString('user:user_a', [2, 3, 1, 4]);
+ $this->checkString('owner:user_a', [3, 4]);
+ $this->checkString('owner:user_b');
+ $this->checkString('group:Admins', [2, 1]);
+ $this->checkString('group:Usuarios', [2, 3, 4]);
+ $this->checkString('maingroup:Admins', [2, 1]);
+ $this->checkString('maingroup:Usuarios', [3, 4]);
+ $this->checkString('file:"Clock 3"', [2]);
+ $this->checkString('file:"syspass"', [1]);
+ $this->checkString('id:1', [1]);
+ $this->checkString('id:3', [3]);
+ $this->checkFavorites(2, [2, 1]);
+ $this->checkTags([1, 3], [2]);
+ $this->checkTags([1, 3], [2, 1], QueryCondition::CONDITION_OR);
+ $this->checkTags([2], [1]);
+ }
+
+ /**
+ * @throws \SP\Core\Exceptions\ConstraintException
+ * @throws \SP\Core\Exceptions\QueryException
+ * @throws \SP\Core\Exceptions\SPException
+ */
+ public function testProcessSearchResultsForUserB()
+ {
+ AccountSearchItem::$publicLinkEnabled = false;
+
+ $userData = new UserLoginResponse();
+ $userData->setId(4);
+ $userData->setUserGroupId(3);
+ $userData->setPreferences(new UserPreferencesData());
+
+ self::$setUpUser->call($this, $userData);
+
+ $this->checkCategoryById(1);
+ $this->checkNonExistantCategory();
+ $this->checkClientById(1);
+ $this->checkClientById(2, [2]);
+ $this->checkClientAndCategory(2, 2, [2]);
+ $this->checkClientAndCategory(2, 1, [2], QueryCondition::CONDITION_OR);
+ $this->checkNonExistantClient();
+ $this->checkString('apple.com', [2]);
+ $this->checkString('github');
+ $this->checkString('google');
+ $this->checkString('slack', [4]);
+ $this->checkString('is:private', [4]);
+ $this->checkString('not:private', [2]);
+ $this->checkString('user:admin', [2]);
+ $this->checkString('user:user_a', [2, 4]);
+ $this->checkString('owner:user_a', [4]);
+ $this->checkString('owner:user_b');
+ $this->checkString('group:Admins', [2]);
+ $this->checkString('group:Usuarios', [2, 4]);
+ $this->checkString('maingroup:Admins', [2]);
+ $this->checkString('maingroup:Usuarios', [4]);
+ $this->checkString('file:"Clock 3"', [2]);
+ $this->checkString('file:"syspass"');
+ $this->checkString('id:1');
+ $this->checkString('id:3');
+ $this->checkFavorites(0);
+ $this->checkTags([1, 3], [2]);
+ $this->checkTags([1, 3], [2], QueryCondition::CONDITION_OR);
+ $this->checkTags([2]);
+ }
+
+ /**
+ * Returns the test dataset.
+ *
+ * @return IDataSet
+ */
+ protected function getDataSet()
+ {
+ return $this->createMySQLXMLDataSet(RESOURCE_DIR . DIRECTORY_SEPARATOR . 'datasets' . DIRECTORY_SEPARATOR . 'syspass_accountSearch.xml');
+ }
+}
diff --git a/tests/TagRepositoryTestCase.php b/tests/TagRepositoryTestCase.php
deleted file mode 100644
index 64175fef..00000000
--- a/tests/TagRepositoryTestCase.php
+++ /dev/null
@@ -1,233 +0,0 @@
-.
- */
-
-namespace SP\Tests;
-
-use SP\Core\Exceptions\QueryException;
-use SP\DataModel\ItemSearchData;
-use SP\DataModel\TagData;
-use SP\Repositories\DuplicatedItemException;
-use SP\Repositories\Tag\TagRepository;
-use SP\Storage\DatabaseConnectionData;
-
-/**
- * Class TagRepositoryTest
- *
- * @package SP\Tests
- */
-class TagRepositoryTest extends DatabaseBaseTest
-{
- /**
- * @var TagRepository
- */
- private static $tagRepository;
-
- /**
- * @throws \DI\NotFoundException
- * @throws \SP\Core\Context\ContextException
- * @throws \DI\DependencyException
- */
- public static function setUpBeforeClass()
- {
- $dic = setupContext();
-
- // Datos de conexión a la BBDD
- self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
-
- // Inicializar el repositorio
- self::$tagRepository = $dic->get(TagRepository::class);
- }
-
- /**
- * Comprobar la búsqueda mediante texto
- */
- public function testSearch()
- {
- $searchItemData = new ItemSearchData();
- $searchItemData->setLimitCount(10);
- $searchItemData->setSeachString('www');
-
- $search = self::$tagRepository->search($searchItemData);
- $this->assertCount(2, $search);
- $this->assertArrayHasKey('count', $search);
- $this->assertEquals(1, $search['count']);
- $this->assertEquals(1, $search[0]->id);
-
- $searchItemData = new ItemSearchData();
- $searchItemData->setLimitCount(10);
- $searchItemData->setSeachString('prueba');
-
- $search = self::$tagRepository->search($searchItemData);
- $this->assertCount(1, $search);
- $this->assertArrayHasKey('count', $search);
- $this->assertEquals(0, $search['count']);
- }
-
- /**
- * Comprobar los resultados de obtener las etiquetas por Id
- */
- public function testGetById()
- {
- $tag = self::$tagRepository->getById(10);
-
- $this->assertCount(0, $tag);
-
- $tag = self::$tagRepository->getById(1);
-
- $this->assertEquals('www', $tag->getName());
-
- $tag = self::$tagRepository->getById(2);
-
- $this->assertEquals('windows', $tag->getName());
- }
-
- /**
- * Comprobar la obtención de todas las etiquetas
- */
- public function testGetAll()
- {
- $count = $this->conn->getRowCount('Tag');
-
- $results = self::$tagRepository->getAll();
-
- $this->assertCount($count, $results);
-
- $this->assertInstanceOf(TagData::class, $results[0]);
- $this->assertEquals('Linux', $results[0]->getName());
-
- $this->assertInstanceOf(TagData::class, $results[1]);
- $this->assertEquals('windows', $results[1]->getName());
-
- $this->assertInstanceOf(TagData::class, $results[2]);
- $this->assertEquals('www', $results[2]->getName());
- }
-
- /**
- * Comprobar la actualización de etiquetas
- *
- * @covers \SP\Repositories\Category\CategoryRepository::checkDuplicatedOnUpdate()
- * @throws \SP\Core\Exceptions\ConstraintException
- * @throws \SP\Core\Exceptions\QueryException
- * @throws \SP\Core\Exceptions\SPException
- */
- public function testUpdate()
- {
- $tagData = new TagData();
- $tagData->id = 1;
- $tagData->name = 'Servidor';
-
- self::$tagRepository->update($tagData);
-
- $category = self::$tagRepository->getById(1);
-
- $this->assertEquals($category->getName(), $tagData->name);
-
- // Comprobar la a actualización con un nombre duplicado comprobando su hash
- $tagData = new TagData();
- $tagData->id = 1;
- $tagData->name = ' linux.';
-
- $this->expectException(DuplicatedItemException::class);
-
- self::$tagRepository->update($tagData);
- }
-
- /**
- * Comprobar la eliminación de etiquetas
- *
- * @throws \SP\Core\Exceptions\SPException
- */
- public function testDeleteByIdBatch()
- {
- $this->assertEquals(0, self::$tagRepository->deleteByIdBatch([4]));
- $this->assertEquals(3, self::$tagRepository->deleteByIdBatch([1, 2, 3]));
-
- $this->assertEquals(0, $this->conn->getRowCount('Tag'));
- }
-
- /**
- * Comprobar la creación de etiquetas
- *
- * @covers \SP\Repositories\Category\CategoryRepository::checkDuplicatedOnAdd()
- * @throws DuplicatedItemException
- * @throws \SP\Core\Exceptions\SPException
- */
- public function testCreate()
- {
- $countBefore = $this->conn->getRowCount('Tag');
-
- $tagData = new TagData();
- $tagData->name = 'Core';
-
- $id = self::$tagRepository->create($tagData);
-
- // Comprobar que el Id devuelto corresponde con la etiqueta creada
- $tag = self::$tagRepository->getById($id);
-
- $this->assertEquals($tagData->name, $tag->getName());
-
- $countAfter = $this->conn->getRowCount('Tag');
-
- $this->assertEquals($countBefore + 1, $countAfter);
- }
-
- /**
- * Comprobar la eliminación de etiquetas por Id
- *
- * @throws QueryException
- * @throws \SP\Core\Exceptions\ConstraintException
- */
- public function testDelete()
- {
- $countBefore = $this->conn->getRowCount('Tag');
-
- $this->assertEquals(1, self::$tagRepository->delete(3));
-
- $countAfter = $this->conn->getRowCount('Tag');
-
- $this->assertEquals($countBefore - 1, $countAfter);
-
- // Comprobar la eliminación de etiquetas usadas
- $this->assertEquals(1, self::$tagRepository->delete(1));
- }
-
- /**
- * Comprobar la obtención de etiquetas por Id en lote
- */
- public function testGetByIdBatch()
- {
- $this->assertCount(3, self::$tagRepository->getByIdBatch([1, 2, 3]));
- $this->assertCount(3, self::$tagRepository->getByIdBatch([1, 2, 3, 4, 5]));
- $this->assertCount(0, self::$tagRepository->getByIdBatch([]));
- }
-
- /**
- * @throws QueryException
- * @throws \SP\Core\Exceptions\ConstraintException
- */
- public function testCheckInUse()
- {
- $this->assertTrue(self::$tagRepository->checkInUse(1));
- }
-}
diff --git a/tests/UserRepositoryTestCase.php b/tests/UserRepositoryTestCase.php
deleted file mode 100644
index d1edca38..00000000
--- a/tests/UserRepositoryTestCase.php
+++ /dev/null
@@ -1,306 +0,0 @@
-.
- */
-
-namespace SP\Tests;
-
-use DI\DependencyException;
-use SP\Core\Crypt\Hash;
-use SP\Core\Exceptions\ConstraintException;
-use SP\Core\Exceptions\QueryException;
-use SP\DataModel\UserData;
-use SP\DataModel\UserPreferencesData;
-use SP\Repositories\NoSuchItemException;
-use SP\Repositories\User\UserRepository;
-use SP\Services\User\UpdatePassRequest;
-use SP\Storage\DatabaseConnectionData;
-
-/**
- * Class UserRepositoryTest
- *
- * @package SP\Tests
- */
-class UserRepositoryTest extends DatabaseBaseTest
-{
-
- /**
- * @var UserRepository
- */
- private static $userRepository;
-
- /**
- * @throws DependencyException
- * @throws \DI\NotFoundException
- * @throws \SP\Core\Context\ContextException
- */
- public static function setUpBeforeClass()
- {
- $dic = setupContext();
-
- // Datos de conexión a la BBDD
- self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
-
- // Inicializar el repositorio
- self::$userRepository = $dic->get(UserRepository::class);
- }
-
- /**
- * Comprobar la actualización de usuarios
- *
- * @throws \SP\Core\Exceptions\ConstraintException
- * @throws \SP\Core\Exceptions\QueryException
- * @throws \SP\Core\Exceptions\SPException
- */
- public function testUpdate()
- {
- $userData = new UserData();
- $userData->setId(2);
- $userData->setName('Usuario Demo');
- $userData->setLogin('demo');
- $userData->setEmail('demo@syspass.org');
- $userData->setNotes('Usuario Demo');
- $userData->setUserGroupId(1);
- $userData->setUserProfileId(1);
- $userData->setIsAdminApp(1);
- $userData->setIsAdminAcc(1);
- $userData->setIsDisabled(1);
- $userData->setIsChangePass(1);
- $userData->setIsLdap(0);
-
- $this->assertEquals(1, self::$userRepository->update($userData));
-
- $userData = new UserData();
- $userData->setId(10);
-
- $this->expectException(QueryException::class);
-
- self::$userRepository->update($userData);
- }
-
- /**
- * Comprobar la modificación de las preferencias de usuario
- *
- * @throws QueryException
- * @throws \SP\Core\Exceptions\ConstraintException
- */
- public function testUpdatePreferencesById()
- {
- $preferences = new UserPreferencesData();
- $preferences->setLang('es_ED');
- $preferences->setAccountLink(true);
- $preferences->setOptionalActions(true);
- $preferences->setResultsAsCards(true);
- $preferences->setResultsPerPage(10);
-
- $this->assertTrue(self::$userRepository->updatePreferencesById(2, $preferences));
- }
-
- /**
- * Comprobar la obtención de los datos de un usuario
- *
- * @throws \SP\Core\Exceptions\SPException
- */
- public function testGetById()
- {
- $user = self::$userRepository->getById(2);
-
- $this->assertInstanceOf(UserData::class, $user);
- $this->assertEquals('sysPass Demo', $user->getName());
- $this->assertEquals('demo', $user->getLogin());
-
- $this->expectException(NoSuchItemException::class);
-
- self::$userRepository->getById(3);
- }
-
- /**
- * Comprobar si existe un usuario
- *
- * @throws QueryException
- * @throws \SP\Core\Exceptions\ConstraintException
- */
- public function testCheckExistsByLogin()
- {
- $this->assertTrue(self::$userRepository->checkExistsByLogin('demo'));
- $this->assertFalse(self::$userRepository->checkExistsByLogin('usuario'));
- }
-
- /**
- * Comprobar los datos de uso de un usuario
- */
- public function testGetUsageForUser()
- {
- $this->assertCount(1, self::$userRepository->getUsageForUser(2));
- }
-
- /**
- * Comprobar la actualización de la clave de un usuario por Id
- *
- * @throws QueryException
- * @throws \SP\Core\Exceptions\ConstraintException
- * @throws \SP\Core\Exceptions\SPException
- */
- public function testUpdatePassById()
- {
- $result = self::$userRepository->updatePassById(2, new UpdatePassRequest(Hash::hashKey('prueba123')));
-
- $this->assertTrue($result);
- }
-
- /**
- * Obtener los datos de los usuarios por Id en lote
- */
- public function testGetByIdBatch()
- {
- $users = self::$userRepository->getByIdBatch([1, 2, 5]);
-
- $this->assertCount(2, $users);
- $this->assertInstanceOf(UserData::class, $users[0]);
- $this->assertEquals('admin', $users[0]->getName());
- $this->assertInstanceOf(UserData::class, $users[1]);
- }
-
- /**
- * Obtener los datos de todos los usuarios
- */
- public function testGetAll()
- {
- $users = self::$userRepository->getAll();
-
- $this->assertCount(4, $users);
- $this->assertInstanceOf(UserData::class, $users[0]);
- $this->assertEquals('admin', $users[0]->getName());
- }
-
- /**
- * Actualizar un usuario desde el proceso de login
- *
- * @throws QueryException
- * @throws \SP\Core\Exceptions\ConstraintException
- */
- public function testUpdateOnLogin()
- {
- $userData = new UserData();
- $userData->setPass(Hash::hashKey('prueba123'));
- $userData->setName('prueba');
- $userData->setEmail('prueba@syspass.org');
- $userData->setIsLdap(1);
- $userData->setLogin('demo');
-
- $result = self::$userRepository->updateOnLogin($userData);
-
- $this->assertTrue($result);
- }
-
- /**
- * Eliminar usuarios en lote
- *
- * @throws QueryException
- * @throws \SP\Core\Exceptions\ConstraintException
- */
- public function testDeleteByIdBatch()
- {
- $result = self::$userRepository->deleteByIdBatch([1, 2, 5]);
-
- $this->assertCount(2, $result);
- }
-
- /**
- * Comprobar la obtención de los datos de un usuario
- *
- * @throws \SP\Core\Exceptions\SPException
- */
- public function testGetByLogin()
- {
- $user = self::$userRepository->getByLogin('demo');
-
- $this->assertInstanceOf(UserData::class, $user);
- $this->assertEquals('sysPass Demo', $user->getName());
- $this->assertEquals('demo', $user->getLogin());
-
- $this->expectException(NoSuchItemException::class);
-
- self::$userRepository->getByLogin('prueba');
- }
-
- /**
- * Comprobar la eliminación de un usuario
- *
- * @throws QueryException
- * @throws \SP\Core\Exceptions\ConstraintException
- */
- public function testDelete()
- {
- $result = self::$userRepository->delete(2);
-
- $this->assertEquals(1, $result);
-
- $this->expectException(ConstraintException::class);
-
- self::$userRepository->delete(1);
- }
-
- /**
- * Comprobar la obtención de los datos de usuarios
- */
- public function testGetBasicInfo()
- {
- $users = self::$userRepository->getBasicInfo();
-
- $this->assertCount(4, $users);
- $this->assertInstanceOf(UserData::class, $users[0]);
- }
-
- /**
- * Comprobar la modificación de los datos del último login
- *
- * @throws ConstraintException
- * @throws QueryException
- */
- public function testUpdateLastLoginById()
- {
- $result = self::$userRepository->updateLastLoginById(2);
-
- $this->assertTrue($result);
- }
-
- public function testSearch()
- {
-
- }
-
- public function testUpdateMasterPassById()
- {
-
- }
-
- public function testCreate()
- {
-
- }
-
- public function testGetUserEmailForGroup()
- {
-
- }
-}
diff --git a/tests/res/datasets/syspass_acl.xml b/tests/res/datasets/syspass_accountAcl.xml
similarity index 100%
rename from tests/res/datasets/syspass_acl.xml
rename to tests/res/datasets/syspass_accountAcl.xml
diff --git a/tests/res/datasets/syspass_favorite.xml b/tests/res/datasets/syspass_accountFavorite.xml
similarity index 100%
rename from tests/res/datasets/syspass_favorite.xml
rename to tests/res/datasets/syspass_accountFavorite.xml
diff --git a/tests/res/datasets/syspass_accountFile.xml b/tests/res/datasets/syspass_accountFile.xml
new file mode 100644
index 00000000..56057624
--- /dev/null
+++ b/tests/res/datasets/syspass_accountFile.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+ 1
+ 1
+ sysPass.xml
+ text/xml
+ 1312
+ 3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C526F6F743E0A20203C4D6574613E0A202020203C47656E657261746F723E737973506173733C2F47656E657261746F723E0A202020203C56657273696F6E3E312E322E303C2F56657273696F6E3E0A202020203C54696D653E313433393332353330343C2F54696D653E0A202020203C557365722069643D2231223E61646D696E3C2F557365723E0A202020203C47726F75702069643D2231223E41646D696E733C2F47726F75703E0A202020203C486173683E36646232633238323731393136326630663136316531343731653734636531623C2F486173683E0A20203C2F4D6574613E0A20203C43617465676F726965733E0A202020203C43617465676F72792069643D2231223E0A2020202020203C6E616D653E485454503C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F43617465676F72793E0A20203C2F43617465676F726965733E0A20203C437573746F6D6572733E0A202020203C437573746F6D65722069643D2231223E0A2020202020203C6E616D653E476F6F676C6520496E632E3C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F437573746F6D65723E0A202020203C437573746F6D65722069643D2232223E0A2020202020203C6E616D653E4D6963726F736F667420496E633C2F6E616D653E0A2020202020203C6465736372697074696F6E2F3E0A202020203C2F437573746F6D65723E0A20203C2F437573746F6D6572733E0A20203C4163636F756E74733E0A202020203C4163636F756E742069643D2231223E0A2020202020203C6E616D653E476F6F676C653C2F6E616D653E0A2020202020203C637573746F6D657249643E313C2F637573746F6D657249643E0A2020202020203C63617465676F727949643E313C2F63617465676F727949643E0A2020202020203C6C6F67696E3E61646D696E3C2F6C6F67696E3E0A2020202020203C75726C3E382E382E382E383C2F75726C3E0A2020202020203C6E6F7465732F3E0A2020202020203C706173733E6C4E66513133634B6A384D592B79434F346652536B4773494334357247454C442F424E69345654614671593D3C2F706173733E0A2020202020203C7061737369763E454E6354743338503265346C643350395A553241767939664C466277386C42473947382F75414D785A6D343D3C2F7061737369763E0A202020203C2F4163636F756E743E0A202020203C4163636F756E742069643D2232223E0A2020202020203C6E616D653E4D6963726F736F66743C2F6E616D653E0A2020202020203C637573746F6D657249643E323C2F637573746F6D657249643E0A2020202020203C63617465676F727949643E313C2F63617465676F727949643E0A2020202020203C6C6F67696E3E726F6F743C2F6C6F67696E3E0A2020202020203C75726C3E342E342E342E343C2F75726C3E0A2020202020203C6E6F7465733E4E6F746173206465206D6963726F66736F66743C2F6E6F7465733E0A2020202020203C706173733E3352394F48632B53335A4E56684D795948352F784C476C76625246662F5367573348527261322B325349453D3C2F706173733E0A2020202020203C7061737369763E763637306A596B43547178635332344C4F65453077672B304330376A734C2F4635342B6E56484963544F773D3C2F7061737369763E0A202020203C2F4163636F756E743E0A20203C2F4163636F756E74733E0A3C2F526F6F743E0A
+ XML
+ 6E6F5F7468756D62
+
+
+ 3
+ 2
+ Clock 3.jpg
+ image/jpeg
+ 4273
+ FFD8FFE000104A46494600010100000100010000FFDB0043000A07070807060A0808080B0A0A0B0E18100E0D0D0E1D15161118231F2524221F2221262B372F26293429212230413134393B3E3E3E252E4449433C48373D3E3BFFDB0043010A0B0B0E0D0E1C10101C3B2822283B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3BFFC00011080073007303012200021101031101FFC4001F0000010501010101010100000000000000000102030405060708090A0BFFC400B5100002010303020403050504040000017D01020300041105122131410613516107227114328191A1082342B1C11552D1F02433627282090A161718191A25262728292A3435363738393A434445464748494A535455565758595A636465666768696A737475767778797A838485868788898A92939495969798999AA2A3A4A5A6A7A8A9AAB2B3B4B5B6B7B8B9BAC2C3C4C5C6C7C8C9CAD2D3D4D5D6D7D8D9DAE1E2E3E4E5E6E7E8E9EAF1F2F3F4F5F6F7F8F9FAFFC4001F0100030101010101010101010000000000000102030405060708090A0BFFC400B51100020102040403040705040400010277000102031104052131061241510761711322328108144291A1B1C109233352F0156272D10A162434E125F11718191A262728292A35363738393A434445464748494A535455565758595A636465666768696A737475767778797A82838485868788898A92939495969798999AA2A3A4A5A6A7A8A9AAB2B3B4B5B6B7B8B9BAC2C3C4C5C6C7C8C9CAD2D3D4D5D6D7D8D9DAE2E3E4E5E6E7E8E9EAF2F3F4F5F6F7F8F9FAFFDA000C03010002110311003F00F1C44A9D12BACF86FE12B1F17EBF3E9FA84B711451DAB4CAD032AB6E0E8BDC1E30C6BD2C7C12F0C000FDBB5500F1CCB1F1FF008E500787A254E895EC137C29F09DB90BF6FD50B63BCB1E3FF40AA73FC3AF0D41D2F35138EDE6479FFD0281D8F3244A9D12BB997C1DA0424E2E6F40C1C6F91013FF008ED556F0FE8A84013DDB7246EDE981FA5016672E8953A256F1D1F498B21A69C7A7EF1791F9542B6FA57DA4C6AF70CA7852AEB953EA723A7F9ED82AE87CACCD44A9D12B6B4EB1D0E598C5793DC459C91209515540073BB238E9D7DFB77EA60F0169B23604978BFEF3A8FF00D96AD46EAE886ECEC7068953A2577CFE05D1221C5CDE7E2EBFFC4D2C3E0BD19DB027BCEBFDF4FF00E2693562ACCE1D12A744AEFE3F0168CCA3175779CF4DEBFF00C4D55D6FC23A7697A4CF7704D72D247B76891971CB01FDD1D8D211C784E28A9C271450064FC13017C5F779FF00A07BFF00E8C8EBD86FEF42444062A082339AF1FF0083C7CBF145E1F5B071FF009123AF45D718C876C4FB5D8F504F3DF3FA552571AEE655F6AA88C4EFC633DF9F4FF38AE72F75B9240543003773838ACBD73519AD55A5C79B133E0313D320F07F0CFEB5956167AD7886EA386C6DD9D64380501007A93EC3B9E82A5E9A2354BA9A7FDA924D3C7089BCC9A421515392C4F0001EA4D741A5783B53D59E28E5BCB7B21E63C522C7FE90C85319562A76AB73F74907827B576BE16F06693A069B6D24D6292EA18579669955E44908E42B738C72383F89AE5FC65E2DD1B4ABFBBB0D2E04BBBDBA3B2E859B7D9CC52A7219A540199B2402B9E3675539C9EA4277D8E8A4F87FE1AD8229ADE6B865EA5EE9C16FC88FD07F3AAE7C37A3A46E936956B09CE17C82D961EA4F1CFB74F7AF32D4FC69E24D6AE45C3EA725AE06D16FA73344871D4E4364FE24D64DC5AEA13E6799EEA4719E4CC493F98CD3524BA072F767A3EB9A269B65A734F6DA64B2EC23885D8C817FBC149C3638C8E38C9CF18A5D0EFF00504D303D85E5CEA16800D914D0B46EA0F20A33FDE5C718048E38C6307CDE2BDD5AD98449A9DFDB803210C8D8F5E0719FCAB7AC7C79A9DAC4A751B58AEADD005F3231B24278E4F38F4E303AF5A7CD17BAB1493E8CEE135F0EBF31646FEE30DAC3F02339FF00EB54B69AB02411267273C9C71D7FC2B8BD66E86A96B1EA9A44A9208D8AC9C152401D31F8FEA39F5ABA7F88964216401243C9EC3F3FCE9C9A295AC7AFE9DAB2B3E03A9EDEB9FF0038A7F89984BE1DBA2B9FE0E0741F3AD709A56AE721771C67DEBA6BDBE175A15C26EDD90B8E7FDA159A77339239609C515384E28A641CC7C2F6F27C4374C7FE7C9C7FE3E95D6788EF1E3F2E68E4C79520270718078CFF002AE3FC00DE56B172C0E3368C33FF00034ADBF115D99B4DB800E020DC467D083F8F4FD6A1CF9648DE11BC59CB5E5E99079780CA87A63A1F5FE7D2BD2FE1E6893D8E8F7926A901B77BD508A03324CAA3209CF55CE723041E33E98F30D1A279BC4C891DB8BA11CBBD9791B4671B8903800906BD16DFC6A24D5F5AB1F21A5874F412ACD0AE4B85505D0FFB5B836DF5C1E9B79DA2BAF7329B6F4441F113C5E34BB54F0DE8526C99D7FD22447667863C03B41EECD9EE49C11C65811C0E9FA5C6D6E4CCA5636FB88A705871827F4FE9C7599A39350D6EFAF5A21E6199A568FCE620BE49500E395CE4FE38C56EE8BA7CFA9195A5CA44AD90EC854631DB3E98E4D6136EF6467527CAAC8C2B6BA996ED628ECF6C6CA37F929C2C873C9EE38EB91D6B527D3B519E35104332EE71BCAE54E3D8E3D7F4CD7571580B5B23736D0111821C1050171904B658E147A93CF7F63A90D843241E62C73191B19591CA3020F207B8E71D8FAE306972DCC1BBEA91C29D3AFD6206E2D5C1DB97C2961D39AC2FB3C5A8C456D5D6DE58F21515970F1E7861C1E318FC735E81E2C33C76B6FA158999E5D537A33800AA460FCDB8F5F9B2147A024F6E6FDB681A635B2A0815664528C594292091938C74F9473D7803B5096BA0E2DC55D1E48967A8593B5EDA26C92303CD89548565EE303AF6E3DC1F4AAB72F079A2E6DD888E53C29C6548E307F9D7A06AFA525A4AD3DACB1DC3443FE59B6E7423271B723E6C838CF5E41C026B9BD6B4448DA19E3B79218351195B764E6DE451C8273DF923F1E2ABE2475D3A8A5B95F4AD41D1F05BDB935DFE9F7C6E2C1D3767701DFAF22BCB210D6F3946006D6C0AF4FD00E9EFA5E123FF004908BFBC0C704F1938CFF4A94ED63471BA2C84E28A9C271456A60709E0F668B529D97FE7D9B3FF007D2D5FD6C97B1B80A40CC47A8CFE03F3AABE141B2FE76C6716EDC7AFCCB56756007C99E3695248C8238E3D6B09FC475D27EE18DE149FCBD7C48A18F9B190483DBA93C7B815D26B9345A5787AE174D8961762A1B6E32E4B724FA9233C9F5AE2FC317BF66BE313B6CF3700673CE39C574B1CEDAC6911ACF0B40D2B2175739C6187F4CF5F6AE98BF70C64AD222D122B6B68079930D8A58C8CC4F453B71F98C01EA7DEBAB9F51D3A3B388ADE4769672B32B5C3BA84CC6FB4A61BAE5B2323A81D7BD57D2B4B4BE82789CB44F1CDB448002C854E415ED9CAA904E7A0E0D686A7A2D96A09069B3A36C91A4932589DAF907233EFCE3A707F1C36670BB735D9A7A75D473CB3CD6B7115DDAB287DF03F98030FBC0618E33F2E140EC4924B55F5DAC5C2BAFCBC3E1BEEF1DEB9883C07A34128789668E41C099362B7D72AA2B3FC41E15D43EC05EDB539EEB64AB2C91DCCACE190039072724727E5070413C669DC768B66BE876716ADA9DFEB971133ADCB7976E246253CA5C85214F40465B18EB21EE2B66F0C904C6EA286326300B313CB8C1CA0F43CA91D41EF8C0359FA035EC3A7D9C7E741796CB02076C95983E3E627390F93939F94F5FBD9AD2BD69C2AF9621F236389C312180DBF295C0C1E78EDC1F6C53889BD463E8B6324CD288143BAB2EEC6400D82481D3248049EA48EB5C9EB1671AE87A942CEE5ADD44DB0C646C08416F98F5CA9DBC76EBC9ADB96EB5B86DB4A4B2B4498BC71E7CD942EF22362C8C4E483F748201FBAD9C719A7E275945F6A08AD0FD9DB4D99A4C93E6670C0103A05C0E7BE40FC348EA690D25A1E6FA9DB3978E68D372B7DE715D1784E666B98E3C9DA4118FC0D518E3FF47891C00CA8A0827BE3A55CF07A63518863A0393FF0135125AA3AAFA1DB04E28A9C271455191C0F84E22DA84E07FCFBB7F35A9B538CF23F848E303353782E012EA770A549FF00456E3FE04B5A1ABD8853B994F049C63A0CF5AC66B5B9D149E963CAEDD92D3520CD8D8AC4648E9D466BAD8A78EEAD7FBEB282383D45739ADD93457AD9FE23BBF33EBF5CD555656884447DDE4EF63C607200E858FF00F5BDEAE32E812573D5744D4D1187971F9F35CC241DAB8FDEC6BCEF2385DDD466B56D5EEB55D28B4AD1C72B7EF2DA48D1B0B91953F30EA32467B8F98019C0E0FC2BA87F67CF1ADC305826DA30836F9583F21E4FF0F7FA91CD7A5DACC970AB8910C840390DF2C83FBC9EA0F5A6D7538AA4395E857B79E1B2D3D8AC53280CA0C288CEE3903200C9C720FD2B499D6352CEE14A8E598E001DCFB573735ECD75AD79715ABC535AF90BF3232EFF0033F89581F9828272A54721B046091B53DB5CCF0C96D22412C1226D6CB15CE7AF1838F6EB5266FCC9EE16D43C6F395462E12362DB4963D141F524553BF7B996F5ACA1B8245C28565E3302F24B8E3BF0307232467038365E0BEB95DA4C11AF0CAC3F7877020838207F9FA731691756B2CF2C10C7718015D6EA52196E72A0EE5209246307A01E9C53B0245F86EE16BDFB202C64D8640429DA406DA46EE9907A8EA3F1AC9F103DA4BA45FCCA1A65997C862A41187211B07D8296FA1CD6A9B38E395E6822DB712E43480918C84527382B9C2A751D17F3E3BC5FA844F15BDBB49E798010933F04E47CF230C0033D0638C138E0D6B15646B4E3AA67217C1DB524BA5CBC681891D94E38FE95BBE108C9BE89B6E0053EF9F96B1A43E6C691A9C87E49EBC5759E18B52B3A3E3B1ED8ED59BD59D2F63A709C515384E28AA3238FF87B0F99ADDC02323EC8DFFA125749AC5817048046327803FCF7AC3F875F2EBB3FBDA37FE8495DDDEDB89D58AF6E83DEA64AE8719599E3BE22D1FCC80944CB263803FAD71534263915C0C60FE15ED3AA69BF293D72781906B84D57409BCE0218C9573D1467DBA0E959EC6FCD7D4E7EDEF43210E76B28CFB56FE93E2A9ADAD5AD999E48882A8F1BE2587231FBB639C71ED8ACB97C31A9A056FB148075181CD236977969F2C96CEA18E7705E2AD484E299EB3A55F59EA519B9B2DB70D200B2C80059303270C0F279638038F9B8A9B559A16B54517BF660D345B9CB18C905C7CBBB8DA4F4F53C8182723C6F75C5B7EF632E1BAA953D0FAD6AD9F8BF5F8576AEA33B6C3D1E46603F5AABC5983A1AE87AE59CC2DED6DEDA59D9E458C2199D0AF98CA30493D33D4D538E04B1962BC796778CCCE33733BE22460CDFBB8C020904800E3217233800579ECFE3AF10CB095FB5AC60F24A2E08ACB9751D42FB1E75D4B264E797273EFCD3BC50952EACEE75CF19C30CA6CED1D4C8C7A0072E30072D93853B795E49E327A8AE4E667BC6796E1CBB483E625B939E302A82DAE4A796C43746C13D3B7D6B7EC34D92E6452FD8F1CF007A52736CD5251D86695A7B4CE18A119030A7B0F4AEEB4AB0F2D4498C6D1C67834DD2749DA8BBA31F980738AE8C5A88AD19B1CE001CFB8A4913265309C515384E28AA24E2FC0436EB731FFA766FFD096BD1490A84B0E4F53FD3F4AF1D44A9912811EA3716514EC0608EF8154DF4B8D633B10018E95C0A254E8949AB949B474B7164493F2671541F4F62DCAF1F9D5044A9D12A79116AA3436E3C3F6F70C1A58096EC7241F6E4566DE782D5D09B77287D1FA71F856DA254E894F9439EE7152785EE616FDE424AA9EBB78FE54F87C38E5C7C84AFE35DCA254E894B945CC72D63E1D20062A793926BA8D3B4658994ED23073D38AB08953A25525626E694168B1A804608E7AF14B72C0208C60E4FE9EB54912A744A6210271454E138A2803C95054E828A280274153A0A28A009D054C828A280274153A0A28A009D054E828A280274153A0A28A009D054E828A28025038A28A2803FFFD9
+ JPG
+ 6956424F5277304B47676F414141414E53556845556741414144414141414177434149414141445959473751414141414358424957584D41414137454141414F784147564B7734624141415666306C455156525968573135655A4263785A6C6E58692F7A6E58565864565631645864317477375575745553516B4C494C43435075415A387749793932494D78342F44456A4866483242473249326248472B50593849364E675448446D4C553961786A593951786A504D455944474B4E774A4B4D6B4953454C6D6970686270623671377572753771756C36392B37334D2F614E6141724F626B6645694D372B582B66752B373533352B304541414D595959347751516767525168424333524549496235613445657443434645594C666250524A4342415159513449786867686A435547436949515237316F524A4666505277522F424264432B4B48684B34617271332F45495968524678776842416D4747414D49495A4951786C323349454951555177685268416A4443474543434D4D4D59595153774168694169384D686442644258787733415177762B50517867696A4C723443435063726142724A372F6E4C6B486469566569784A674944434742534F4959436777414667684442426C4343474743454D41594C73654D3849666A527768314D345141414B71714F6F346A68416A444545496F6F6F69484955464959557858565955786A484555525977786D544A4B4A454949414142444A41474549674543763731554934494C50325159714B704B466258657367566D455A5145783145494943415959706B716C464B4D6F55796C5A5869455A466B474146424B6C3650536456335474496D4A43636159372F73496F636A7A44634E775864633054646431486365686C46617256644D304B61585430394F47596469323754694F5A375A6973526A6E584167784F7A75627A575A397A3931353438654A6B656D45416B4A49514B52686B452F6C4F5139643135595643634151516B45564755446344517768464962684530383859566B57516F674141494967694D5669375861376978514577616C335476712B4C306D53626475753638374F7A6761324B387379353978313365726C537231657A365354776A4F584B706664774738326D3771757A3039645242536548447333622F4B7666754F766659396E456B592B6D374D5736314555324536724454676D5846616F4564636A69636D7954436C315854654B6F6A414D7530384D41527748516453796243617A304138554153616E7A6F64684F444F7A6D4D3455466970566E544A3773575746456247386A746C362F384C35754B48303950524D545A795078395471596D33733341544168464A3565505849334E523466332B2F455A72502F4F32332F2F36787836737A732B5A6C732B474C754B5A3347715A45674354446D474534485A2B4C534769526E474B55534654582F6443544D455549775777366879527963576F536363463962326C3230576F765872773037666E63744E7A7164435879484E2F74544338754A524B785671746C3650727073366341414C46343874396566736B4C6845546736564D586137563665576756513871424E31376676577648497A2F3472696244587A372F33434F5050426147724A67765745733133335545436A675778564B76704D69534A47554B50597168516F7A2B2B3850665A35684143416B695741676877716A6562494A41324C5937666D4561516C79647230494136725535456269755A78454D4636707A5446626650487A34794B6D546F5276366E4C64394D44646253796653505957424B4D5368467930734C4D5269785A646650666A63433638382B65516A4F322F5A3838797A7A2B37617548747870707050784A724E52697975757046587734744B5573336E3836357245346F526C55515549596B69684169456B45645236495775375446434B2F4F4C515167765430336154736578326F734C73776F6A3758617A326D354E546C796956486C3337494C56736F3464503737377874327A315A7056582B684C4A707432533865384D312B4A584B6551566A30622F396B58372B2F50447752635050535662357737636562797859744C3035646432787063325363416D4845374D5665504971385844776752616647456F656C434349515151515253716E67644A36576E357564723538636E48624E6A57316174576945673470357A63757969485556364C6E506830755577354B6256486C6B396375726B6D614D4844763779756165662F70382F47786B5A615457616E757643434E7268596952414A705676742F774E4136566B496D6645556E356B78314C362F6C2B2F74483739326F5861504B52493057522F735331454B4B445145366D5936366D7935766F4F516F68416A4B484150416A727A627272654652524B5A454F376E2F464E757432732B3447586D5675726E2F316D6E2F6639317045704368776F7969616E71396B644C32334A796454365934372F7242536D653759566A4B546A714A676668707347393059656C463549506E31723339355A586E566E6C74765435524B576B4B5A6D4C353471664C2B3374763241416D3656536554316E7A66783552426A414641504F444C4C386C454B6F6B452B734A6E37304F637A387A4D4A5850464934634F5A424C7971524F48472F58617262642B636D6A313269656666737142414746693170755A544737372B68474B306562524C5133664F5463396C52726F586231315932486C594C62634F37686D744E70794A2B626D34746C4578366E6E3872463976336E706A554F48392B7935325967706C646E4C5A3836646E462B63615A7431585655416849684948624D6A49467873744968454D4561346B4D31684C4833366A6F3854332B4B2B642B444947486343486C527A655533563439556D2F642F2F2F757A41794D70503358336E594B483433452B656676432B2B316173585233727A5A79382B4E3767396A56626274346570556B4C6D6A694758746E2F713535317658712F556C706455464A7133456A57466C76706548476F742F636E503370792F647131726D655A6474313157345A424C64734E50637835704D566C706A48486878414B68434153516B4149513939627246595735325A714335584636757A4D7A4777515163666E69567771516D44693876546F2B6F314167502F323362385A584456674132763170705533376231786462482F7163642F5244302B6D4F75566F6252373534316A37353648484E75324379483644376665736E727A4F704A6737312B6579425A79547A373150375A763334354372694257583168717439764E5A724E56623752625463647341383658503659397552344D344A3764312B48514E56754E6F366650616A4B5A6D726F5943445466736E3778386F74766A3431444146565878413331766A2B3535304A6C664D334F6B5259303230366E4D6C347039665578576130336D6F7970415166583762795253537244557131572B39584C4C2F61552B7A503978556172766D513274322B35397456662F337237356932316D546D644B5A62765330685756556F676C79534D69534A5243524E4D4141435951416B4B78327A4564616E5471414A50625A6A32597364373843742F63664C4D61543256786B4436307938386941462B2F63303374742B386E53626B38636E7056444B584C4D654C78654B32585476634D446A7A337275796F5A574C77785343466558537A68336279304F4476336A7868552F632F636E684461734551344F72563754716A544E6E78726A506137576D6E4461616A6157597967674F6B366C3455736B43684342435247464D2B5035536256614C3749356C6163516E737554346771724A524B4A34312B31372F2B56666E6B2B56312B58792B542F3637443072746730634F58764D7432524D6A5778706150654F33662F387A4D2F763668743048436564375930497468744E344676486A78363761646675622F335674774E4D6C737A572B544E486567614C382B5056762F7A72627A3377366339634E377046384743364D706C4E3646616E66646664747779557937566D32415A515945774141454949536E426C636A4949677637656E454E78504A30424A4B6D704D642B323737337A376B4B716248767A6D335A73454A636D6F5552506E5237376A352F2F59716C2F344B6D6E2F756C502F2B514C332F757633336E306B622B374F446E5A6B386A6A624370307248747675767476482F6D62356D4A7278343033313531324D6B6C614E625056332F7A53562F373858312F38315A667566324437746B32567555735151736835665846685957472B504C53525549566A6A50734B52537A436E65745742335A4C4346467232664F4E70564E6E4A78392F2F4B66315A7550745977642F2B67395068726148644C356F31704C6C62456A525066666570387278343064502F5045396E3234754E6B362B66584C4E716D73555251746366334770636E3773374F42772B5937623730676B736B654F6E7641432F38632F66664C7734534F7052505A546E3767485258442F622F5A763237706C5958595763554B516947436F475570506F642F48456B4159442F623371647A6675583745626C6D746C72327755482F33334C6A72686F6C4D4B706E4D66767175507A49626A526465664B62426137662F385A32344A3737336B352B773273375969544F725375572B664738716C377668443234574B72573442346A6F5564543976396E2F6E372F32746162726851424A434B744D766557574F7A5A7676693566365065443848657648586A344F3938396565776452592F626475684746714B69347764724E6D7A6E694343436B53524A49592F6137626171716F68675256465557564555356443426737376E596F784E713933756D506C5372326D61567174646D35326E45526A4D3934364F724E2F2F7969736149644433686550514D4749524A3451777869596D4A70724E5A6841454F376465507A6B3532617857657849704A74484B7A4E7A3944333478674F4463784153563161625A6C706B612B47455552554B4937673838436E6D6B716D6F51685A626A71495A752B39373035495368304F4742667176644F6E72735451476956447139373958587079767A4C7A7A2F776875762F4A2B4549762F38365A3964662B3232672F746671382F4E47555371585A706575446970412F54352B2B36372B654E374A46564F5A644B546C3662657533514F4931424D706A7A5431425332642B2F65695A6C70505A6439363852785052626664634E757073684F45484942676D683538304D496F384A7830396E4D5971555368554C544E4D473532577A6D63316E624D6C565678526A6E532F6D4837766F6D704D44697A73306632373169316644366A6573793666544B56617565654F4B4A366C4C743757504837762F63357A397A3132654241695247687761484B67734C4E2B32355A587071326A544E77506351464C4645676B666F705A64656470754F45553848667368446B532B57356D74546F51437171766F51516F51497768676778446B48474B6D4B50444E335371464D414467394F64472F517056564E6A352B626E683432424F7776332B673762526C52576C5A6E573033587238775739327A5A302B375937712B4E33626D336151525378574D6444477A652F75757438362B492B764736644F6E6E332F752B56747632744D796D792F74657A57654B39792B3977386E33703963315475637A2B615A496F637568354152516F6A45424D4959515941674868346555676A6F7A36556B684E6F6473394732706935633449444E4C7A5A36536E3142464749556C51594B2B77362B735762746D6B2F642B386B41686A577A5757307537666A59446331324D7744635343564B2F61566B4B766E464278344977754148662F39444E776F765835363262573930644F76737A4D796D7A57734756677958683165346C686559337567314734373837733159497136704769584137445145416C75762F526A6F377051343577684256566638304175436746494B6D537045564A3264575A7166636379573554722F3849382F32374C6A2B6D4D6E54312B596E414163796F4B654F6E686343316E6C2F4B574D6B6B4368384C30414B584B67796E642B396A4D585A365A506E446A525738787632546769754C33556D702B757A396D754252464E46764D62726833744C52576E78736542487834392F4959516E7170714D53504A675958773875634D63516742496F524B62617444434D6B584336324F6D636B6B4173634B5041744473587658445866397757336D556B4F5856646479445433322B632F642F2B6A66505A624B5A6E7A6674396F574A5178794F446333427941756C34654768316647395467506F3330762F58706B3754554359744D3063366C3047504B7457376357436A33662F4D593343424B64646D752B4D714D6F436D4D4D6F797337656F77786B5352464E7A43544E6331676A4F5A797558684363367732526D4555324A32326154566144332F374F772F652B7A6B464B652B666E366A576C67435448766A796C3377654B6F626D4F45376F2B34486A4A685174644C31476F3947547959364E6A645557466F61476869696D756836666E706F64663239635A396F766E6E752B302B6E59646B66544E4633585779327A302B6C4555615449326F636F41304B4A706F63436133704D59637A33335344775659322B64666851344E754F32557A704D65614C3939352B527A6A52632F2F7258354F4A395078433151324438596D4C683438635361625447475048737575314A6359555864462F38494E4868387244592B2B64662F766F3856517938384E4866376835342B624230754454502F6E48766266732B65337262307850583571364E4C466C64424F45554658315643704479504C4F46572F63734A357A7357313031484D39332F4E4634454F4A4C74587274745042465069656C30316E6A78342B7967435871567865755762546C6C47662B37463444414E2B7A5971566A4E497743457A545A4C4B635343616154624E52623237644E48726F774B473171306475335874624745596A367A62466163797574622F3139572F742B64684E646D4E706476715370697351524A35727062495A4935346F443635457545746445434C4C436D55714A504C673042434530506639564471683651794B494A314D76507A6969344D442F5738645039707574567A547163347372426759386B314C59395333585631574E55334C35484C502F7650506E3376683339342B66767A566C2F6531577531644F33635669373067457051796D656D61724A30374D7A5A322B75787658332F7472626665676842434B45797A58536755597246597A45674163495634324C422B4863526B7A3032334A493359557130715378424266486273585533584D4D62546C7976705A4E7033676D4A7645565035304E476A70303664797154546A74555A366974585A69714B716D58794F5968526558686F614869346C4D766663503275644371645343555048446977734C44516B793171657170634B475A6A7557662F365A6D46536B5742344E4162723563473870314F57395856644337666B792F30447051354242686A4648455568427779436C556C5779704A4D5532343375357431314569573035495A61585A72464D4A61504659454471793448474A46497A3032744C61623337317632543668744B6C67616E5A6559425250704E2B39736B66762F7A384C7948676C753830374D37576E54752F2F4F662F4B6642424B5A4F666E624F2F2F2B686A4B71565774576F744E54535A6463796C574D4A49396D546A32545452354C6256584C3648526B625745454C757550504F77484F67434232726A5156756455776E44415341416949496B6563365951526B52596B4556356879384F416845595A66652B69685938666636532F31527A78714E557864316C565A5033506D76577533373242556B5342316D75376A333373306F63596231665A7666374D766C7A44654F766836777442383331367A646D5862627658323957667A5066464555704B56516D385264636D71545673324D366273336274586C6D565A6C7350414A5578756457773948676349746C7074414469474D41723832767838544E554378347272366F57787364646532646562376830716C74382F663747514B545A7172554B32744758307567766E4A35754C35736A516D6F756E7A712F734866726864782F576766664577392B724C3077724649626347526A75727A55584337333973566938314665574E62322F584462695363454678686876324C685259764A74742B324E4F4D6353616A6271495263536B384D776B6D576C756A43587A5757623758626B2B34784A6C74554A50432B4B4969595245496E78735176486A787A4A462F4C5872466931636330364263757857484C316974584470584A6F32624F545538642B392B6234653266662F7433727A635A435479344C494A633175645A596C46557445552F32395A665450626D2B636C6D6973682B4542474F4545494545526F4C37454F7170314F4C63544B7051557549646A344D656947525A3372527077376E78383747304151506832513643556852464B73574152304B456A414F375076757A7837372F38782F2F534664303133626B54456149435068683644724A5A4E774C50535A5434446E72316C31546139527A78594A6D71427253436F5865766D49356E6333324476525456564D3076565A764969675167496751776A6B584844702B6F4D5869696D35344559386C6B6C526D45714F5A54435A58794B31594E527850786E4B39505A4A434234624C6C6D755A5A6B7557695351465044414A394B48664158346E70387243625273557154694B713053456C6D5951676278344A6B466A69703649637941776C677146336D4B78704F7136466A4D7331324E4D6B56585644344E6C4B68636846455952674E7932585A30787968524D4661594169536D4633704B6D4B55526D3563462B585645447A323831326B3748345745304F546E5A617256637A2B3559446954594E4530512B5977614D55494375363270386B4A3173545251616E5361795A34734A6D786D626A61565343645336554B6846492F485A61624655386C454D68314C4A7067737937494D42554149495969494C4D6B71517A674D64556C4B78524E4C556252327A645A61645A374A426B564151694C794864653165656A346E71664C696D733767575558556873464A4A3741555251356F5438784E546C312B584B74767152706A41464A4348484E78765763637A3252544B52546264636547436F726371797672367872436361556F6546683256416F70595A6841414334482B517A616464316C336C7141454155525971696D4231545552513363505634544E456F41634B7A7A634254776959494173493545514557424167465530786B796E774F624E66783275307457362F64734758307A4A6B7A746D64626C6755415949785253714D6F536D65794B597154696252684A4250785A4B485178366969615270545A555652776A446B6E47756156712F5844634E596471684C4350752B54796B31545A504B71753237717377596B7752425571527A4B7275754A376D65344E7931624D4146414142774556655945414A41614E7432504237764C362B676A4C6D42303271314B70574B726D714D4D6162496765444A5A466F69564E646A6955534B55535543776A434D494169694B464A5664585A324E70564B63633452517643725833766F4B68486570666A425666596641776E684B2B77345151684A2B414E7041554F494D53514959774A4A56336A41464244512F61583551454C41424F447546416C6A33483337495951672F71687730473254712F7A2B565359624959515275754969687667444D6141724D48545641344151774668674C4341537147736E41674F4549567857476A44434742494A4C6D736979386F4975684C382F79747064444E43507049684367424742434D73494D5249776B68434747494945454B59454C67634C685951416F6B4369424443585869414D4D5141454177786867677452344951776D785A57634467436A444156314B316E426843727567544548587263683968434248454742434D594E636D384A58304C6973794547474941494959434978414E316B51413441412F4542522B564342455559414934546773752F646648346B51387558714B764241414141414D74744241474356377458793464484141414977473739594158306579662F33706F664B682F70666D546B2F774A4A373144734E344A75626741414141424A52553545726B4A6767673D3D
+
+
+ 4
+ 1
+ android.png
+ image/png
+ 4295
+ 89504E470D0A1A0A0000000D4948445200000080000000800806000000C33E61CB00000006624B474400FF00FF00FFA0BDA793000000097048597300000B1300000B1301009A9C180000000774494D4507DD011D0E180BE2306F78000010544944415478DAED5D6B745CD575FEBE7DEFC8961F3C0C01EC45480C2B8B0026A1D4206B2CB9C27181F208D074816D59069A16280B92A6246D42520A252D210FD2248426818418C9C63CD264C182BAE1154B1A4960CAB35E506A1E5D26501C9E768464CDDCF3F5C7BDA31796A59135F28CE66C2D594B9A19DF73F7FECEB71F67DF7388329096CCC293C1E997845174D1F2FACE374B7DBCCD1B17CF0F42DDDB1BED58F2E74B9E7DBB94C76AE5000069DA05A2CE8CA8EF94FA587FF6507D1503D71A018757D9EC334A7DBC650100B2E79F4C70B0E0336B338BFEA494C75A352DF70D1AE71AB8F9A5F51DCD1E001320AB163FB159C2CD12663A58D35D1DE9D9A538CE350F351C65C6931D1038B9CBAFBA11F200983016705F96DC9B3077CE4EC7926481B0BAF7F208760C22AD69AAEBEC2A07BD960D001AD39DBF27832F986C3A694DEBDA4F9A5352816A5BC332293CD790450AE115E5A2D7B201000050D10310FE57CC9DEAD47342A98CEBB6473E5585A0F72C3077805C78EDF2FAB6B7CA46A7283359DB9E5E2D6A0DA42E9B3E73C9CA850F6547FBCCBAB69A1991719E219C0146F38420A07400E40218009102BA01F70E2D34C1BD48177457F76CDFF6A7CB9ECE8D9AF6B5A76B403C4CEA8528179D76FE92C75E2F177D86E5060089F793DC08CBFD91EBED5905E0D6E1EFB9E7D7A7A5B6CFD85E47BAE3011C23E02002F300CD00381750086086C86133C0DE8364005E045C774FF5CCDFB574A4B7105107A2E0A5C6FA8EA7771D9FE07A11339C70533919BF2C1900009ADBEACE27A31F928E3DCF1FB5EF5F7CF6E7B907375F17BCF6EE7D75845B29E3498110413A5C4415101B5A1020825072E79404821093BF0CFC4100084A10F09E889728E668EE2E58EFFAC69A27B702C0DAAE450B11059B003D09F0338D8B332F7B004C46D09549B782564FD7773314DE01E3B7441C09A91A04094862FC1322C971F14DE21E10A3062024800ECEDD1B657139A6A183C0C141C4BF5B59DFF1BD72D3A3952B00E8EC3B0E511616FCA5026D70D47110A69348883DB139314EE327E44E80313DC43F6240848E38C7A6BB570D3CCCC4E742CDBCBB2CF5586E035ED75A77906374BA8C5F20B9801A740F1404F6D379516290D871C47048CA3CA2EBA37827841FCEDEE785473FFD8937E5015014DAAF3D9BB02F89AA0110304FC87BF12E84FC10040ADB40AC0F72D13F2F5FF2E81B1E0013286B3A177D3E10AF226C7FF4CF7A09E4DEBD07C59C80981048E07527BD2EBAAFAF4E77FDD203604F23FE478EFF10AAAAEE27834F00AAA228F183095C09E5A94E8441B683DCF9DDC6F4A67FF000182FE5B72F3A8EC0DD8E7604291156168C250146413038E46E545FF4E5D50D9BBA7D1650C8CC6FAF6D20C33B6176841162A2D2B2F0AB141C28C081B2CB2C0C7FBCB6ADE610CF00632EF4D42E03ED76331D085122588E050B498A07EE08173E9072D59F3D77C9035B3D03EC2ED8EB38611189663377A0627F3AC4F8FD2CA0815F94285B93481071553119811497103198A394142008C004BA3FDE99DA7E434BF3D98107C0483EBFB5EEE32985FF06E21080026803D9769EB20827C9D14114639A158C2439192088314711A2E8E020231C1947A7FDC3CDC3564412B352C1593AFCB59B3C007635F3DB3FB91F037C3F6270485C6461BE82C7FE843B9E66204593DD41B15E2E3C09D4CD4E8AE2A430FFAEE2794D4104B25BA19D17059C51A75C7635113DDBBFA4306400C99F62F0A608BB706D7BFA2B3E06F84091E7C46B81F06BCC2B99C290544F8098706EE4AE6BAA7FF4CA217143E6842B89F01A9261D18286643549E4EB51A4D3CEAFEF782AFFD2ADBF39E1A3A954F84B92C78DA45AE54B46D2FF98B4AAB1AEF331CF00009A338B9792C165C984573C69862A50042882C2CBA4EEFAC08D38B600F6BC8A896AC6CB4C14EEDA27D5F7CCE0972E6CD8F40AC9FB04E634E20808023D240E75C0579B5B97CCAE7800AC6B4FCF32E03A80FB4914A8DD509500E27D67DA39FCF569E1F6B71DD58D64E1B758819F20107CF59C458FBBE1AF3BB93700971DF1FA94245553ACA6F1D316642FA8780038D829803B7160E68E40DEFD457FCE35D841C35FEEC91E7244001DC4A252401E08EE9896F6F4B45D14001680563DD200E28549E66F0620AE696E3D69DF8A060019FD24B1B9304A7D3751DB1CCABED9D2567F707FFCB0B1617F0BB2D70236BFA8E19F986F275949E8ACC1AFDD96492F03B814D27BA351D0C00206F767D0FDAD8A0D029B330B2F37567D7FA0B83FDAF41506DE1BBDE5E0EE320494AC01D491717C56D4D5E0A4B813E7F764EE61297C4EEA3B9808FE0CB4FEE2C4686B15493E03D04541943A74457DEBFFED0D1B847B177DC15730A4238BA37E228EC1242A3C80D4250E02E3926BB15B0112C62263E34952B014744B8500A425FD64635B9E8C7B952081E6D8FB8F002EAA2817D0D256BB4AC6B990A9309B09042926052011A42545A1C921B498004832C69CD1125B16967C8A202588567767DBA70EACAC1820D05F518100C74279A33FA1E280CD277B7998838A3CFDDC349EFF8324611FC95ACFD9150380B5AD4B3F02D961B1439F84B0BD644549A518331CDD49150300A57A1B44EE17F75C56AAF1630E50E24688E0D0E6CE051FAA1017A005046654B2E9070702A000B92318EDBF60CA03E017FF716695938E066028970E8FE2C612F1CA91611E2D9AFA0CD03B63DB7E06CC2A853A44E96000824888C7ADED4807531A001686F3011E36100555BA07102832E92F98A149AECD4C7A2128723A90B039A050AEAD5E139E4E524999DB8E256C5F00DBA62C009227B7025478FC3FC2F430208B29CD0002B611F8B58499A477018366468A0A36050A764E6900107A42C205F404F0C1A9A1E939B959EF4FBA0B1AAF34676AE691566F48D508EE9DC8E9A954F7EC8D2B4ED9B0DD1BB438D29CA9F918192E31040B1DDC13514EAF9CBF24F3C0A402E0F68DB587E542DE48E014C6FE3CDFB02331474655B734D6B75DECCD3571B2AE75D127A330F839A5A3498679CE889BA4A26E44A9ABB163EBF71A4F7FC51515002D99DAD341DD06700E6183D6C7014870341111216D0E34FDBC1575BFD93CE4463A6A0E92C27B00D5F81CE003723380CF35A633BD43667DC7A28B41DE4467963C953E68E9537020880890D6079AF6D72BEA5AC7FC6472417580E6B69A1300FE2BC53954DC843F78F95B244C8E94810C8E7196BDBBA5BDF6C8A1AE4E7301DB4FCCB779FBAF415FBDC38BA32DED8B9AA8E0BB2658BE6A3878DD5B204C1211880C973B8BD6B4B4D7CD9A700034671A029A7D9BD487018BA7FDB0199C2C6FF6F7650AEEE3802E5DBB71516AD09B1C2097BC3F590EF25F498A3C24396E6E5F7C04C8AB49552BE993E72EEB08A424C6CF26B953A05CD3C43380BAEB9D6909644967EC983C8C447E2E0A73733DBB17E86A371E1FC8B26788383CAE9891BB2B9C924C1E5931C0ECEB130E005AEA6B26CB33FD989D374104ACBA6C70B6E3650CC158387D9621BC3451B546EF978C275CBCEF19E74C3C00C423FB2D3A16FB73A00D5AD2511393784EE92AC050C3C8428AF30BD43959605F9A1500D143C7B37C1B03D20EF3262E500C018854B197CC0B5B0D1C4FF52E0E08236FD1717242912BA6616103E29EDC8A977169ADB83ED30A9BCA1310DC78348C514FC464044C361938E69EE3A8E282C0C9D29379D5577AACE9C50360D2E9CD4BE500C00781A5AD27EF023C03F82CC067015E3C031417DDDEF157781AE879BF5453279F05946A16E083401F04FA20D08B07809729910578A95800F820B0B4F5E483401F047AF12EC08B07800F023D007C10E883402F9E017C16E0B3002F9E012618DDDEF157781AE879BF5453279F05946A16E083401F04961E00343E64FB495FBAAEA0803D82149F9B5CE8F8E39391426FC98215376E9D178901F842FE1C6C150A5FD9666FD142273E7300DFDFC571E4A3E75C2A0600A8479C84E470BEB182588C8F4369F74160614120C93E119D89CE59B0CE271A0074A95FC5C7DE8E313C91440674CAED10ED1E1F0416E8EAA3AA5E8A1B2C7FA450413AEFDB32E10050D0FD2085F6FCE9DEA3108DE2CD0B2384A8FA494AF686377161B2B2FEE11CADF75780B62001C16E483F09B748288714A65D3FE10068AC7D3C47049713B655D26E0F4A14C47833496D702E77FD7975AD7DDEA4E30041EDE35B8C760DA077F346DEB5778ECF1F4D7692BD75F9E2CC2D454903572E6E7B8AD0192032FD916A12AFF6EF6528C45182C32F9C729736D677FDCE9B72FCB2A236D302B87341BC0A80BBD0B980E4CC6C871B2297FB62510B412BD399670CC1994ED94B1CB955122947894E7410B545C0AA200A2F6CAADBF4F264E7B55325081CC2BEE9AE07082E72CA5EE5C8ED8374DE2B3A8AEC14706A900BBFBABA7ED3DB1375DDDDCA6DED7F405AB585C25CC7F0A326CD065C67CEB4A3A9B663C47D01D7654E3C56A8BA437447D14785C366067F00E06F876F17DFAFF3CC1F32642A05051F1683434DAA8E987B5030D794CEB8F15C75DC059AD5754F0A4004E0D5E47BEC90F32CB06BF38FA6F3C5FF29007D005E4CBE27B310E4652ACA5E0280A7FDCA05804830B2F8D21E0815070029F50E8077095750CD7AEAFA7E258513029069AA03C0FD7EF61B0ED816073D1E01C999C17454CEC936AE1A2103983200683AF5DFFB10F17E38F478F303B1FD01839E03DDD3151104EE089EFF1903BE3470D85C654241884F550201133734A53B5EA808005C9A7EABCF145C02302B89042B120194E448C0D96381E1DB159406022BD2ADED705806228B7C8D5B82244DCD4AD1209E4BFA3BE266293E196571DAB9B51DDBF60A08F7B65A9A1F699887AA9DFF02DA1924AAA87C7E38BC3696EF2E62D29352C0D0E3E316C7F639E52F81E458CC424E4AD1C0F8767529451028D144A72CA52F35D677FE60AFB250A9CC8FE6F68663C0F79752C1C930CC27866544F16F1F1335AD20FB4BC9D1C602C4A74104A3CC53519C25623E871DD23A46A70E88DB40BD81E14BE69203AA9E72DAB921E776DC77E192FFDAEB876C975525666D7BDDB330B7000503C000E4D098EE1AD3A7D6B52D5BE8C2DE4D540E5050200144809B76E5AABA8DD7F942D0441ABFAD9EC0EE67EF44615D8CF619FF550850D5E5A2D78A590CF235870A0780970A07805F76F20CE0C503C08B0780179F0578F141A017EF02BC780078F100F000F041A007800F023D00CA62066B4F66BFA780F20600A9713D56986F3F5701144044C975A67EE37A1901C040322C7432934CFA0C830240D3174285870E713323813D78E8D60360448920445D85FB732528C83D53006CBA18F7111674A97827172188824D1E00132C2B1767E4C88D4326DB581120C031BA77CC1F30ED10A2FFD69877C4CA030D800867D97B3C008A2081C3060AEF8820C4E489128D6475411044120E556EDF9BC67A9D55E92E19F023CA90B40703BB799251F90EE6785FC79F8239E701500479FDB73B5F8BA42B81C8C5BBE7891A21BACB3F73176F5785BF5F5EF7E06B05390EA5D608783ADE0E2BDE7D6FF71C0300DAE622BBA17171973C008A20579CF7B864582F879BD11FA727F6C2E07DB4D4FF9280DB65F6CD42AFB5AAAEED1D0997027815200752102529699E7F92A707A45E29FA22DC2BCFF92CA088727EBAF35DF5CCBA42C87E03021C92FD11E3CDD2E418EF4F2C3AC0E1A786E06F9A6A33E3DAA62E65DD5D70D17952EE29C9C131796A20F9D7E59F0171EE2D38AD9866B6AEA9E1B7659539966D816C4DE7B166D1CCA369EE6263D525CEB9300E0DF43E94BDC55C6AFD4EC3A3172EEED8637FBCA67D416A9AED7F7AD6B9CF9BB98678DE0812B790EE6A396E5855D7F15639EAF1FF015841FD48A44C570F0000000049454E44AE426082
+ PNG
+ 6956424F5277304B47676F414141414E53556845556741414144414141414177434149414141445959473751414141414358424957584D41414137454141414F784147564B7734624141414470556C45515652596865315A585567555552512B5A39646358624E4E4C4C4D314E6247303341724B4A585533677167484B336F776968376336442B71682F372F33346F67736A434C364B45777A622B4B54497A6F77536853574E63734C4E61734B4372536367304E79705A437935335477395934732B73366439787252505539444C4E7A7633504F64382B636D5876504C494161584B7A4C557355767461766A44775737387449596D535A7A5645526B6946722F7167316D576730614C516F65387634634636654C546441626F6B4A36653451334C37353075586F453453647A7837475539664D623166704874515941554F6159302F72636E5A67614159546F36344149554F696A72546B504D75614E71616E7347485A424A66597372556244776953674C597675662F37557038712F566857377543354C47344C494E673045584A7762682B423539736A4E5835444A6243696F544E64714E597871524531545A6F354F6D54374B58745046614D4B55665031497A5948544A67414541674C68304B5A6D6A3063676F6B4238416A702F39486E624B7A635149654B30444D4D5357787850515158583072324A49595344713577766D7430376C6A554E6B7171614B7832314E7A3463574E6C4D6941434167446E72346E5868544C48594D685135776E7543524276324A515041366C334A6741457A744742704C4143597A416278536D696F39734B64544A5A59796756523270437049586D7045524743556A455267597844414A7358336E6433667838386E454B476F6D4E304B5068786B4F5642382B55676B4731376F704B566B71425665796571657177474256717A78797153464A614F71544E47457849765253416F65314951394C53704F7A534D7166425A6F4E47716E467030544768786257617033624A323979526549675A4551724B2B31473470735675796C78743968766F6C49304B5A33537065494242736C6F626A35624F4D53574644573450395155413269324F735558667961727033575361696F7279586436353369707A2B3237482F564A723831634B74636E773837733150452F6349694C686D3332517070372B4770706D6A354D623842586D6E61307A512B367355776131676565486646735253424C3956554D445657494C2F47564C43763133554C506866513072346B7A4D55754B3368425749493143386F622B657A51454E385558476D5661724939625A37344B6A4F786F3969373064417A676257586C4D74626C357142306D6750537461704B4F794C617A4E366B434547624F6A6E49306668304F4B57454D327179504771427366722F6350354C756E4A674935696565755348716E4F6C32396E613565663435436F587A392B6F33344E5230732F5975436F4D4F62483250676C6C6B56434F426D7854744647745073432B396D68656B3076397A4B7251676B66514835665650374F64776E55486E2B36317456372F6B496B714B3833696F3338755261376E6E506B6C496A6A78535A704E2B634C703974753148325670582F594638324A464558487548372B57734954576177677269334A73466E6944502B75677878423839626875496843415172714C71345454782F38764354764B536F7172423132415864726E5942454146356A35586E3271576A687A613267446474424C3039777642767351414159454A5365466D397862597477652B504467414138397A6F636F6631784A565A5133502B4138457749412B7133696A634141414141456C46546B5375516D4343
+
+
+
+
diff --git a/tests/res/datasets/syspass_accountSearch.xml b/tests/res/datasets/syspass_accountSearch.xml
new file mode 100644
index 00000000..c2692e4b
--- /dev/null
+++ b/tests/res/datasets/syspass_accountSearch.xml
@@ -0,0 +1,213 @@
+
+
+
+
+
+ 1
+ 1
+ 1
+ 1
+ 1
+ Google
+ 1
+ admin
+ http://google.com
+ a
+ a
+ aaaa
+ 341
+ 35
+ 2018-03-25 09:54:07
+ 2018-04-02 21:38:25
+ 0
+ 0
+ 0
+ 0
+ 1522341709
+ 0
+ 0
+
+
+ 2
+ 1
+ 1
+ 1
+ 2
+ Apple
+ 2
+ admin
+ http://apple.com
+ a
+ a
+ bbbb
+ 341
+ 35
+ 2018-03-25 09:54:07
+ 2018-04-02 21:38:25
+ 0
+ 0
+ 0
+ 0
+ 1522341709
+ 0
+ 0
+
+
+ 3
+ 3
+ 3
+ 3
+ 2
+ Github
+ 2
+ admin
+ http://github.com
+ a
+ a
+ bbbb
+ 341
+ 35
+ 2018-03-25 09:54:07
+ 2018-04-02 21:38:25
+ 0
+ 0
+ 1
+ 0
+ 1522341709
+ 0
+ 0
+
+
+ 4
+ 3
+ 3
+ 3
+ 3
+ Slack
+ 2
+ admin
+ http://slack.com
+ a
+ a
+ bbbb
+ 341
+ 35
+ 2018-03-25 09:54:07
+ 2018-04-02 21:38:25
+ 0
+ 0
+ 0
+ 1
+ 1522341709
+ 0
+ 0
+
+
+
+
+ 1
+ 1
+ sysPass.xml
+ text/xml
+ 1312
+ a
+ XML
+ 6E6F5F7468756D62
+
+
+ 3
+ 2
+ Clock 3.jpg
+ image/jpeg
+ 4273
+ a
+ JPG
+ a
+
+
+ 4
+ 1
+ android.png
+ image/png
+ 4295
+ a
+ PNG
+ a
+
+
+
+
+ 1
+ 3
+
+
+ 2
+ 3
+
+
+ 1
+ 1
+
+
+ 2
+ 2
+
+
+
+
+ 1
+ 1
+
+
+ 1
+ 2
+
+
+ 2
+ 3
+
+
+ 2
+ 1
+
+
+
+
+ 1
+ 3
+ 1
+
+
+ 2
+ 3
+ 0
+
+
+
+
+ 1
+ 2
+ 1
+
+
+ 2
+ 3
+ 0
+
+
+
+
+ 1
+ 2
+
+
+ 3
+ 2
+
+
+ 2
+ 1
+
+
+
+
diff --git a/tests/res/imgs/add.png b/tests/res/imgs/add.png
new file mode 100644
index 00000000..60a7a291
Binary files /dev/null and b/tests/res/imgs/add.png differ