config writer
This commit is contained in:
@@ -41,6 +41,7 @@ use Espo\Core\{
|
||||
Api\Request,
|
||||
DataManager,
|
||||
Utils\Config,
|
||||
Utils\Config\ConfigWriter,
|
||||
};
|
||||
|
||||
class EntityManager
|
||||
@@ -49,13 +50,20 @@ class EntityManager
|
||||
protected $dataManager;
|
||||
protected $config;
|
||||
protected $entityManagerTool;
|
||||
protected $configWriter;
|
||||
|
||||
public function __construct(User $user, DataManager $dataManager, Config $config, EntityManagerTool $entityManagerTool)
|
||||
{
|
||||
public function __construct(
|
||||
User $user,
|
||||
DataManager $dataManager,
|
||||
Config $config,
|
||||
EntityManagerTool $entityManagerTool,
|
||||
ConfigWriter $configWriter
|
||||
) {
|
||||
$this->user = $user;
|
||||
$this->dataManager = $dataManager;
|
||||
$this->config = $config;
|
||||
$this->entityManagerTool = $entityManagerTool;
|
||||
$this->configWriter = $configWriter;
|
||||
|
||||
$this->checkControllerAccess();
|
||||
}
|
||||
@@ -131,8 +139,10 @@ class EntityManager
|
||||
|
||||
if (!in_array($name, $tabList)) {
|
||||
$tabList[] = $name;
|
||||
$this->config->set('tabList', $tabList);
|
||||
$this->config->save();
|
||||
|
||||
$this->configWriter->set('tabList', $tabList);
|
||||
|
||||
$this->configWriter->save();
|
||||
}
|
||||
|
||||
$this->dataManager->rebuild();
|
||||
@@ -184,15 +194,19 @@ class EntityManager
|
||||
|
||||
if ($result) {
|
||||
$tabList = $this->config->get('tabList', []);
|
||||
|
||||
if (($key = array_search($name, $tabList)) !== false) {
|
||||
unset($tabList[$key]);
|
||||
$tabList = array_values($tabList);
|
||||
}
|
||||
$this->config->set('tabList', $tabList);
|
||||
$this->config->save();
|
||||
|
||||
$this->configWriter->set('tabList', $tabList);
|
||||
|
||||
$this->configWriter->save();
|
||||
|
||||
$this->dataManager->clearCache();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
@@ -206,11 +220,11 @@ class EntityManager
|
||||
$data = get_object_vars($data);
|
||||
|
||||
$paramList = [
|
||||
'entity',
|
||||
'link',
|
||||
'linkForeign',
|
||||
'label',
|
||||
'linkType',
|
||||
'entity',
|
||||
'link',
|
||||
'linkForeign',
|
||||
'label',
|
||||
'linkType',
|
||||
];
|
||||
|
||||
$additionalParamList = [
|
||||
@@ -222,10 +236,11 @@ class EntityManager
|
||||
$params = [];
|
||||
|
||||
foreach ($paramList as $item) {
|
||||
if (empty($data[$item])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$params[$item] = filter_var($data[$item], \FILTER_SANITIZE_STRING);
|
||||
if (empty($data[$item])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$params[$item] = filter_var($data[$item], \FILTER_SANITIZE_STRING);
|
||||
}
|
||||
|
||||
foreach ($additionalParamList as $item) {
|
||||
@@ -272,12 +287,12 @@ class EntityManager
|
||||
$data = get_object_vars($data);
|
||||
|
||||
$paramList = [
|
||||
'entity',
|
||||
'entityForeign',
|
||||
'link',
|
||||
'linkForeign',
|
||||
'label',
|
||||
'labelForeign',
|
||||
'entity',
|
||||
'entityForeign',
|
||||
'link',
|
||||
'linkForeign',
|
||||
'label',
|
||||
'labelForeign',
|
||||
];
|
||||
|
||||
$additionalParamList = [];
|
||||
@@ -331,8 +346,8 @@ class EntityManager
|
||||
$data = get_object_vars($data);
|
||||
|
||||
$paramList = [
|
||||
'entity',
|
||||
'link',
|
||||
'entity',
|
||||
'link',
|
||||
];
|
||||
|
||||
$d = [];
|
||||
@@ -382,6 +397,7 @@ class EntityManager
|
||||
}
|
||||
|
||||
$this->entityManagerTool->resetToDefaults($data->scope);
|
||||
|
||||
$this->dataManager->clearCache();
|
||||
|
||||
return true;
|
||||
|
||||
@@ -29,55 +29,57 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\{
|
||||
Exceptions\Forbidden,
|
||||
ServiceFactory,
|
||||
Api\Request,
|
||||
};
|
||||
|
||||
class Integration extends \Espo\Core\Controllers\Record
|
||||
use Espo\{
|
||||
Entities\User,
|
||||
};
|
||||
|
||||
class Integration
|
||||
{
|
||||
protected $serviceFactory;
|
||||
|
||||
protected $user;
|
||||
|
||||
public function __construct(ServiceFactory $serviceFactory, User $user)
|
||||
{
|
||||
$this->serviceFactory = $serviceFactory;
|
||||
$this->user = $user;
|
||||
|
||||
$this->checkControllerAccess();
|
||||
}
|
||||
|
||||
protected function checkControllerAccess()
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
public function actionIndex($params, $data, $request)
|
||||
public function getActionRead(Request $request)
|
||||
{
|
||||
return false;
|
||||
$entity = $this->serviceFactory
|
||||
->create('Integration')
|
||||
->read($request->getRouteParam('id'));
|
||||
|
||||
return $entity->getValueMap();
|
||||
}
|
||||
|
||||
public function actionRead($params, $data, $request)
|
||||
public function putActionUpdate(Request $request)
|
||||
{
|
||||
$entity = $this->getEntityManager()->getEntity('Integration', $params['id']);
|
||||
return $entity->toArray();
|
||||
return $this->patchActionPatch($request);
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data, $request)
|
||||
public function patchActionPatch(Request $request)
|
||||
{
|
||||
return $this->actionPatch($params, $data, $request);
|
||||
}
|
||||
$entity = $this->serviceFactory
|
||||
->create('Integration')
|
||||
->update($request->getRouteParam('id'), $request->getParsedBody());
|
||||
|
||||
public function actionPatch($params, $data, $request)
|
||||
{
|
||||
if (!$request->isPut() && !$request->isPatch()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$entity = $this->getEntityManager()->getEntity('Integration', $params['id']);
|
||||
$entity->set($data);
|
||||
$this->getEntityManager()->saveEntity($entity);
|
||||
|
||||
$integrationsConfigData = $this->getConfig()->get('integrations');
|
||||
|
||||
if (!$integrationsConfigData || !($integrationsConfigData instanceof \StdClass)) {
|
||||
$integrationsConfigData = (object)[];
|
||||
}
|
||||
$integrationName = $params['id'];
|
||||
|
||||
$integrationsConfigData->$integrationName = $entity->get('enabled');
|
||||
$this->getConfig()->set('integrations', $integrationsConfigData);
|
||||
|
||||
$this->getConfig()->save();
|
||||
|
||||
return $entity->toArray();
|
||||
return $entity->getValueMap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ use Espo\Core\{
|
||||
Utils\Metadata,
|
||||
Utils\Util,
|
||||
Utils\Config,
|
||||
Utils\Config\ConfigWriter,
|
||||
Utils\File\Manager as FileManager,
|
||||
Utils\Metadata\OrmMetadataData,
|
||||
HookManager,
|
||||
@@ -50,6 +51,7 @@ use Throwable;
|
||||
class DataManager
|
||||
{
|
||||
protected $config;
|
||||
protected $configWriter;
|
||||
protected $entityManager;
|
||||
protected $fileManager;
|
||||
protected $metadata;
|
||||
@@ -62,6 +64,7 @@ class DataManager
|
||||
public function __construct(
|
||||
EntityManager $entityManager,
|
||||
Config $config,
|
||||
ConfigWriter $configWriter,
|
||||
FileManager $fileManager,
|
||||
Metadata $metadata,
|
||||
OrmMetadataData $ormMetadataData,
|
||||
@@ -70,6 +73,7 @@ class DataManager
|
||||
) {
|
||||
$this->entityManager = $entityManager;
|
||||
$this->config = $config;
|
||||
$this->configWriter = $configWriter;
|
||||
$this->fileManager = $fileManager;
|
||||
$this->metadata = $metadata;
|
||||
$this->ormMetadataData = $ormMetadataData;
|
||||
@@ -125,8 +129,8 @@ class DataManager
|
||||
$result = false;
|
||||
|
||||
$GLOBALS['log']->error(
|
||||
'Fault to rebuild database schema. Details: '. $e->getMessage() .
|
||||
' at ' . $e->getFile() . ':' . $e->getLine()
|
||||
"Fault to rebuild database schema. Details: ". $e->getMessage() .
|
||||
" at " . $e->getFile() . ":" . $e->getLine()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -134,21 +138,27 @@ class DataManager
|
||||
throw new Error("Error while rebuilding database. See log file for details.");
|
||||
}
|
||||
|
||||
$config = $this->config;
|
||||
|
||||
$databaseType = strtolower($schema->getDatabaseHelper()->getDatabaseType());
|
||||
|
||||
if (!$config->get('actualDatabaseType') || $config->get('actualDatabaseType') != $databaseType) {
|
||||
$config->set('actualDatabaseType', $databaseType);
|
||||
if (
|
||||
!$this->config->get('actualDatabaseType') ||
|
||||
$this->config->get('actualDatabaseType') !== $databaseType
|
||||
) {
|
||||
$this->configWriter->set('actualDatabaseType', $databaseType);
|
||||
}
|
||||
|
||||
$databaseVersion = $schema->getDatabaseHelper()->getDatabaseVersion();
|
||||
|
||||
if (!$config->get('actualDatabaseVersion') || $config->get('actualDatabaseVersion') != $databaseVersion) {
|
||||
$config->set('actualDatabaseVersion', $databaseVersion);
|
||||
if (
|
||||
!$this->config->get('actualDatabaseVersion') ||
|
||||
$this->config->get('actualDatabaseVersion') !== $databaseVersion
|
||||
) {
|
||||
$this->configWriter->set('actualDatabaseVersion', $databaseVersion);
|
||||
}
|
||||
|
||||
$this->updateCacheTimestamp();
|
||||
$this->configWriter->updateCacheTimestamp();
|
||||
|
||||
$this->configWriter->save();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,10 +269,9 @@ class DataManager
|
||||
*/
|
||||
public function updateCacheTimestamp()
|
||||
{
|
||||
$this->config->updateCacheTimestamp();
|
||||
$this->configWriter->updateCacheTimestamp();
|
||||
|
||||
/* Fix rebuildDatabase() method when remove this line. */
|
||||
$this->config->save();
|
||||
$this->configWriter->save();
|
||||
}
|
||||
|
||||
protected function populateConfigParameters()
|
||||
@@ -270,15 +279,13 @@ class DataManager
|
||||
$this->setFullTextConfigParameters();
|
||||
$this->setCryptKeyConfigParameter();
|
||||
|
||||
$this->config->save();
|
||||
$this->configWriter->save();
|
||||
}
|
||||
|
||||
protected function setFullTextConfigParameters()
|
||||
{
|
||||
$config = $this->config;
|
||||
|
||||
$platform = $config->get('database.platform') ?? null;
|
||||
$driver = $config->get('database.driver') ?? '';
|
||||
$platform = $this->config->get('database.platform') ?? null;
|
||||
$driver = $this->config->get('database.driver') ?? '';
|
||||
|
||||
if ($platform !== 'Mysql' && strpos($driver, 'mysql') === false) {
|
||||
return;
|
||||
@@ -300,7 +307,7 @@ class DataManager
|
||||
$fullTextSearchMinLength = intval($row['Value']);
|
||||
}
|
||||
|
||||
$config->set('fullTextSearchMinLength', $fullTextSearchMinLength);
|
||||
$this->configWriter->set('fullTextSearchMinLength', $fullTextSearchMinLength);
|
||||
}
|
||||
|
||||
protected function setCryptKeyConfigParameter()
|
||||
@@ -311,7 +318,7 @@ class DataManager
|
||||
|
||||
$cryptKey = Util::generateSecretKey();
|
||||
|
||||
$this->config->set('cryptKey', $cryptKey);
|
||||
$this->configWriter->set('cryptKey', $cryptKey);
|
||||
}
|
||||
|
||||
protected function disableHooks()
|
||||
|
||||
@@ -77,7 +77,10 @@ class Application extends BaseApplication
|
||||
$portal = $entityManager->getEntity('Portal', $portalId);
|
||||
|
||||
if (!$portal) {
|
||||
$portal = $entityManager->getRepository('Portal')->where(['customId' => $portalId])->findOne();
|
||||
$portal = $entityManager
|
||||
->getRepository('Portal')
|
||||
->where(['customId' => $portalId])
|
||||
->findOne();
|
||||
}
|
||||
|
||||
if (!$portal) {
|
||||
|
||||
@@ -31,18 +31,31 @@ namespace Espo\Core\Portal;
|
||||
|
||||
use Espo\Entities\Portal as PortalEntity;
|
||||
|
||||
use Espo\Core\Container as BaseContainer;
|
||||
use Espo\Core\{
|
||||
Container as BaseContainer,
|
||||
Exceptions\Error,
|
||||
};
|
||||
|
||||
class Container extends BaseContainer
|
||||
{
|
||||
protected $portalIsSet = false;
|
||||
|
||||
public function setPortal(PortalEntity $portal)
|
||||
{
|
||||
if ($this->portalIsSet) {
|
||||
throw new Error("Can't set portal second time.");
|
||||
}
|
||||
|
||||
$this->portalIsSet = true;
|
||||
|
||||
$this->setForced('portal', $portal);
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($this->get('portal')->getSettingsAttributeList() as $attribute) {
|
||||
$data[$attribute] = $this->get('portal')->get($attribute);
|
||||
}
|
||||
|
||||
$this->get('config')->setPortalParameters($data);
|
||||
|
||||
$this->get('aclManager')->setPortal($portal);
|
||||
|
||||
@@ -29,37 +29,103 @@
|
||||
|
||||
namespace Espo\Core\Portal\Utils;
|
||||
|
||||
use Espo\Core\Utils\Config as BaseConfig;
|
||||
use Espo\Core\{
|
||||
Exceptions\Error,
|
||||
Utils\Config as BaseConfig,
|
||||
};
|
||||
|
||||
class Config extends BaseConfig
|
||||
{
|
||||
protected $portalParamsSet = false;
|
||||
|
||||
protected $portalData = [];
|
||||
|
||||
protected $portalParamList = [
|
||||
'companyLogoId',
|
||||
'tabList',
|
||||
'quickCreateList',
|
||||
'dashboardLayout',
|
||||
'dashletsOptions',
|
||||
'theme',
|
||||
'language',
|
||||
'timeZone',
|
||||
'dateFormat',
|
||||
'timeFormat',
|
||||
'weekStart',
|
||||
'defaultCurrency',
|
||||
];
|
||||
|
||||
public function get(string $name, $default = null)
|
||||
{
|
||||
if (array_key_exists($name, $this->portalData)) {
|
||||
return $this->portalData[$name];
|
||||
}
|
||||
|
||||
return parent::get($name, $default);
|
||||
}
|
||||
|
||||
public function has(string $name) : bool
|
||||
{
|
||||
if (array_key_exists($name, $this->portalData)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::has($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override parameters for a portal.
|
||||
* Override parameters for a portal. Can be called only once.
|
||||
*/
|
||||
public function setPortalParameters(array $data = [])
|
||||
{
|
||||
if (empty($data['language'])) unset($data['language']);
|
||||
if (empty($data['theme'])) unset($data['theme']);
|
||||
if (empty($data['timeZone'])) unset($data['timeZone']);
|
||||
if (empty($data['dateFormat'])) unset($data['dateFormat']);
|
||||
if (empty($data['timeFormat'])) unset($data['timeFormat']);
|
||||
if (empty($data['defaultCurrency'])) unset($data['defaultCurrency']);
|
||||
if (isset($data['weekStart']) && $data['weekStart'] === -1) unset($data['weekStart']);
|
||||
if (array_key_exists('weekStart', $data) && is_null($data['weekStart'])) unset($data['weekStart']);
|
||||
if ($this->portalParamsSet) {
|
||||
throw new Error("Can't set portal params second time.");
|
||||
}
|
||||
|
||||
$this->portalParamsSet = true;
|
||||
|
||||
if (empty($data['language'])) {
|
||||
unset($data['language']);
|
||||
}
|
||||
|
||||
if (empty($data['theme'])) {
|
||||
unset($data['theme']);
|
||||
}
|
||||
|
||||
if (empty($data['timeZone'])) {
|
||||
unset($data['timeZone']);
|
||||
}
|
||||
|
||||
if (empty($data['dateFormat'])) {
|
||||
unset($data['dateFormat']);
|
||||
}
|
||||
|
||||
if (empty($data['timeFormat'])) {
|
||||
unset($data['timeFormat']);
|
||||
}
|
||||
|
||||
if (empty($data['defaultCurrency'])) {
|
||||
unset($data['defaultCurrency']);
|
||||
}
|
||||
|
||||
if (isset($data['weekStart']) && $data['weekStart'] === -1) {
|
||||
unset($data['weekStart']);
|
||||
}
|
||||
|
||||
if (array_key_exists('weekStart', $data) && is_null($data['weekStart'])) {
|
||||
unset($data['weekStart']);
|
||||
}
|
||||
|
||||
if ($this->get('webSocketInPortalDisabled')) {
|
||||
$this->set('useWebSocket', false, true);
|
||||
$this->portalData['useWebSocket'] = false;
|
||||
}
|
||||
|
||||
foreach ($data as $attribute => $value) {
|
||||
$this->set($attribute, $value, true);
|
||||
if (!in_array($attribute, $this->portalParamList)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->portalData[$attribute] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save is disabled.
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,14 @@ use Espo\Core\Utils\System;
|
||||
use Espo\Core\Utils\Json;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
use Espo\Core\{
|
||||
Container,
|
||||
Upgrades\ActionManager,
|
||||
Utils\File\ZipArchive,
|
||||
Utils\Config\ConfigWriter,
|
||||
Utils\Database\Helper as DatabaseHelper,
|
||||
};
|
||||
|
||||
use Composer\Semver\Semver;
|
||||
|
||||
use Throwable;
|
||||
@@ -89,13 +97,13 @@ abstract class Base
|
||||
|
||||
protected $vendorDirName = 'vendor';
|
||||
|
||||
public function __construct(\Espo\Core\Container $container, \Espo\Core\Upgrades\ActionManager $actionManager)
|
||||
public function __construct(Container $container, ActionManager $actionManager)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->actionManager = $actionManager;
|
||||
$this->params = $actionManager->getParams();
|
||||
|
||||
$this->zipUtil = new \Espo\Core\Utils\File\ZipArchive($container->get('fileManager'));
|
||||
$this->zipUtil = new ZipArchive($container->get('fileManager'));
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
@@ -136,7 +144,7 @@ abstract class Base
|
||||
protected function getDatabaseHelper()
|
||||
{
|
||||
if (!isset($this->databaseHelper)) {
|
||||
$this->databaseHelper = new \Espo\Core\Utils\Database\Helper($this->getConfig());
|
||||
$this->databaseHelper = new DatabaseHelper($this->getConfig());
|
||||
}
|
||||
|
||||
return $this->databaseHelper;
|
||||
@@ -157,6 +165,11 @@ abstract class Base
|
||||
return $this->getContainer()->get('entityManager');
|
||||
}
|
||||
|
||||
public function createConfigWriter() : ConfigWriter
|
||||
{
|
||||
return $this->getContainer()->get('injectableFactory')->create(ConfigWriter::class);
|
||||
}
|
||||
|
||||
public function throwErrorAndRemovePackage($errorMessage = '', $deletePackage = true, $systemRebuild = true)
|
||||
{
|
||||
if ($deletePackage) {
|
||||
@@ -224,7 +237,10 @@ abstract class Base
|
||||
|
||||
//check php version
|
||||
if (isset($manifest['php'])) {
|
||||
$res &= $this->checkVersions($manifest['php'], System::getPhpVersion(), 'Your PHP version ({version}) is not supported. Required version: {requiredVersion}.');
|
||||
$res &= $this->checkVersions(
|
||||
$manifest['php'], System::getPhpVersion(),
|
||||
'Your PHP version ({version}) is not supported. Required version: {requiredVersion}.'
|
||||
);
|
||||
}
|
||||
|
||||
//check database version
|
||||
@@ -235,15 +251,25 @@ abstract class Base
|
||||
|
||||
if (isset($manifest['database'][$databaseTypeLc])) {
|
||||
$databaseVersion = $databaseHelper->getDatabaseVersion();
|
||||
|
||||
if ($databaseVersion) {
|
||||
$res &= $this->checkVersions($manifest['database'][$databaseTypeLc], $databaseVersion, 'Your '. $databaseType .' version ({version}) is not supported. Required version: {requiredVersion}.');
|
||||
$res &= $this->checkVersions(
|
||||
$manifest['database'][$databaseTypeLc],
|
||||
$databaseVersion,
|
||||
'Your '. $databaseType .
|
||||
' version ({version}) is not supported. Required version: {requiredVersion}.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//check acceptableVersions
|
||||
if (isset($manifest['acceptableVersions'])) {
|
||||
$res &= $this->checkVersions($manifest['acceptableVersions'], $this->getConfig()->get('version'), 'Your EspoCRM version ({version}) is not supported. Required version: {requiredVersion}.');
|
||||
$res &= $this->checkVersions(
|
||||
$manifest['acceptableVersions'],
|
||||
$this->getConfig()->get('version'),
|
||||
'Your EspoCRM version ({version}) is not supported. Required version: {requiredVersion}.'
|
||||
);
|
||||
}
|
||||
|
||||
//check dependencies
|
||||
@@ -291,6 +317,7 @@ abstract class Base
|
||||
|
||||
/** check package type */
|
||||
$type = strtolower( $this->getParams('name') );
|
||||
|
||||
$manifestType = isset($manifest['type']) ? strtolower($manifest['type']) : $this->defaultPackageType;
|
||||
|
||||
if (!in_array($manifestType, $this->packageTypes)) {
|
||||
@@ -298,7 +325,9 @@ abstract class Base
|
||||
}
|
||||
|
||||
if ($type != $manifestType) {
|
||||
$this->throwErrorAndRemovePackage('Wrong package type. You cannot install '.$manifestType.' package via '.ucfirst($type).' Manager.');
|
||||
$this->throwErrorAndRemovePackage(
|
||||
'Wrong package type. You cannot install '.$manifestType.' package via '.ucfirst($type).' Manager.'
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -352,11 +381,13 @@ abstract class Base
|
||||
$scriptNames = $this->getParams('scriptNames');
|
||||
|
||||
$scriptName = $scriptNames[$type];
|
||||
|
||||
if (!isset($scriptName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$beforeInstallScript = Util::concatPath( array($packagePath, self::SCRIPTS, $scriptName) ) . '.php';
|
||||
|
||||
if (file_exists($beforeInstallScript)) {
|
||||
return $beforeInstallScript;
|
||||
}
|
||||
@@ -411,13 +442,19 @@ abstract class Base
|
||||
protected function getDeleteFileList()
|
||||
{
|
||||
if (!isset($this->data['deleteFileList'])) {
|
||||
$deleteFileList = array();
|
||||
$deleteFileList = [];
|
||||
|
||||
$deleteList = array_merge(
|
||||
$this->getDeleteList('delete'),
|
||||
$this->getDeleteList('deleteBeforeCopy'),
|
||||
$this->getDeleteList('vendor')
|
||||
);
|
||||
|
||||
$deleteList = array_merge($this->getDeleteList('delete'), $this->getDeleteList('deleteBeforeCopy'), $this->getDeleteList('vendor'));
|
||||
foreach ($deleteList as $key => $itemPath) {
|
||||
if (is_dir($itemPath)) {
|
||||
$fileList = $this->getFileManager()->getFileList($itemPath, true, '', true, true);
|
||||
$fileList = $this->concatStringWithArray($itemPath, $fileList);
|
||||
|
||||
$deleteFileList = array_merge($deleteFileList, $fileList);
|
||||
|
||||
continue;
|
||||
@@ -452,6 +489,7 @@ abstract class Base
|
||||
{
|
||||
if (!isset($this->data['fileList'])) {
|
||||
$packagePath = $this->getPackagePath();
|
||||
|
||||
$this->data['fileList'] = $this->getFileList($packagePath);
|
||||
}
|
||||
|
||||
@@ -462,6 +500,7 @@ abstract class Base
|
||||
{
|
||||
if (!isset($this->data['restoreFileList'])) {
|
||||
$backupPath = $this->getPath('backupPath');
|
||||
|
||||
$this->data['restoreFileList'] = $this->getFileList($backupPath, true);
|
||||
}
|
||||
|
||||
@@ -478,6 +517,7 @@ abstract class Base
|
||||
protected function getFileDirs($parentDirPath = null)
|
||||
{
|
||||
$dirNames = $this->getParams('customDirNames');
|
||||
|
||||
$paths = array(self::FILES, $dirNames['before'], $dirNames['after']);
|
||||
|
||||
if (isset($parentDirPath)) {
|
||||
@@ -501,6 +541,7 @@ abstract class Base
|
||||
$fileList = array();
|
||||
|
||||
$paths = $this->getFileDirs($dirPath);
|
||||
|
||||
foreach ($paths as $filesPath) {
|
||||
if (file_exists($filesPath)) {
|
||||
$files = $this->getFileManager()->getFileList($filesPath, true, '', true, true);
|
||||
@@ -518,8 +559,9 @@ abstract class Base
|
||||
return $fileList;
|
||||
}
|
||||
|
||||
protected function copy($sourcePath, $destPath, $recursively = false, array $fileList = null, $copyOnlyFiles = false)
|
||||
{
|
||||
protected function copy(
|
||||
$sourcePath, $destPath, $recursively = false, array $fileList = null, $copyOnlyFiles = false
|
||||
) {
|
||||
try {
|
||||
$res = $this->getFileManager()->copy($sourcePath, $destPath, $recursively, $fileList, $copyOnlyFiles);
|
||||
}
|
||||
@@ -565,18 +607,23 @@ abstract class Base
|
||||
case 'before':
|
||||
case 'after':
|
||||
$dirNames = $this->getParams('customDirNames');
|
||||
|
||||
$dirPath = $dirNames[$type];
|
||||
|
||||
break;
|
||||
|
||||
case 'vendor':
|
||||
$dirNames = $this->getParams('customDirNames');
|
||||
|
||||
if (isset($dirNames['vendor'])) {
|
||||
$dirPath = $dirNames['vendor'];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$dirPath = self::FILES;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -596,11 +643,13 @@ abstract class Base
|
||||
|
||||
$packagePath = $this->getPackagePath();
|
||||
$dirNames = $this->getParams('customDirNames');
|
||||
|
||||
if (!isset($dirNames['vendor'])) {
|
||||
return $list;
|
||||
}
|
||||
|
||||
$filesPath = Util::concatPath($packagePath, $dirNames['vendor']);
|
||||
|
||||
if (!file_exists($filesPath)) {
|
||||
return $list;
|
||||
}
|
||||
@@ -608,10 +657,12 @@ abstract class Base
|
||||
switch ($type) {
|
||||
case 'copy':
|
||||
$list = $this->getFileManager()->getFileList($filesPath, true, '', true, true);
|
||||
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
$list = $this->getFileManager()->getFileList($filesPath, false, '', null, true);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -628,11 +679,13 @@ abstract class Base
|
||||
$packagePath = $this->getPackagePath();
|
||||
|
||||
$manifestPath = Util::concatPath($packagePath, $this->manifestName);
|
||||
|
||||
if (!file_exists($manifestPath)) {
|
||||
$this->throwErrorAndRemovePackage('It\'s not an Installation package.');
|
||||
}
|
||||
|
||||
$manifestJson = $this->getFileManager()->getContents($manifestPath);
|
||||
|
||||
$this->data['manifest'] = Json::decode($manifestJson, true);
|
||||
|
||||
if (!$this->data['manifest']) {
|
||||
@@ -686,7 +739,7 @@ abstract class Base
|
||||
}
|
||||
|
||||
/**
|
||||
* Unzip a package archieve
|
||||
* Unzip a package archive.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -706,7 +759,7 @@ abstract class Base
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete temporary package files
|
||||
* Delete temporary package files.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
@@ -719,7 +772,7 @@ abstract class Base
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete temporary package archive
|
||||
* Delete temporary package archive.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
@@ -750,7 +803,7 @@ abstract class Base
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an action. For ex., execute uninstall action in install
|
||||
* Execute an action. For ex., execute uninstall action in install.
|
||||
*
|
||||
* @param string $actionName
|
||||
* @param string $data
|
||||
@@ -800,11 +853,15 @@ abstract class Base
|
||||
$fullFileList = array_merge([$backupPath], $this->getDeleteFileList(), $this->getCopyFileList());
|
||||
|
||||
$result = $this->getFileManager()->isWritableList($fullFileList);
|
||||
|
||||
if (!$result) {
|
||||
$permissionDeniedList = $this->getFileManager()->getLastPermissionDeniedList();
|
||||
|
||||
$delimiter = $this->isCli() ? "\n" : "<br>";
|
||||
$this->throwErrorAndRemovePackage("Permission denied: " . $delimiter . implode($delimiter, $permissionDeniedList), false, false);
|
||||
|
||||
$this->throwErrorAndRemovePackage(
|
||||
"Permission denied: " . $delimiter . implode($delimiter, $permissionDeniedList), false, false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -842,6 +899,8 @@ abstract class Base
|
||||
protected function enableMaintenanceMode()
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
$configWriter = $this->createConfigWriter();
|
||||
|
||||
$configParamName = $this->getTemporaryConfigParamName();
|
||||
$parentConfigParamName = $this->getTemporaryConfigParamName(true);
|
||||
|
||||
@@ -855,36 +914,41 @@ abstract class Base
|
||||
'useCache' => $config->get('useCache'),
|
||||
];
|
||||
|
||||
$config->set($configParamName, $actualParams);
|
||||
// @todo Maybe to romove this line?
|
||||
$configWriter->set($configParamName, $actualParams);
|
||||
|
||||
$save = false;
|
||||
|
||||
if (!$actualParams['maintenanceMode']) {
|
||||
$config->set('maintenanceMode', true);
|
||||
$configWriter->set('maintenanceMode', true);
|
||||
|
||||
$save = true;
|
||||
}
|
||||
|
||||
if (!$actualParams['cronDisabled']) {
|
||||
$config->set('cronDisabled', true);
|
||||
$configWriter->set('cronDisabled', true);
|
||||
|
||||
$save = true;
|
||||
}
|
||||
|
||||
if ($actualParams['useCache']) {
|
||||
$config->set('useCache', false);
|
||||
$configWriter->set('useCache', false);
|
||||
|
||||
$save = true;
|
||||
}
|
||||
|
||||
if ($save) {
|
||||
$config->save();
|
||||
$configWriter->save();
|
||||
}
|
||||
}
|
||||
|
||||
protected function disableMaintenanceMode($force = false)
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
$configWriter = $this->createConfigWriter();
|
||||
|
||||
$configParamList = [
|
||||
$this->getTemporaryConfigParamName()
|
||||
$this->getTemporaryConfigParamName(),
|
||||
];
|
||||
|
||||
if ($force && $this->getTemporaryConfigParamName(true)) {
|
||||
@@ -901,16 +965,17 @@ abstract class Base
|
||||
|
||||
foreach ($config->get($configParamName, []) as $paramName => $paramValue) {
|
||||
if ($config->get($paramName) != $paramValue) {
|
||||
$config->set($paramName, $paramValue);
|
||||
$configWriter->set($paramName, $paramValue);
|
||||
}
|
||||
}
|
||||
|
||||
$config->remove($configParamName);
|
||||
$configWriter->remove($configParamName);
|
||||
|
||||
$save = true;
|
||||
}
|
||||
|
||||
if ($save) {
|
||||
$config->save();
|
||||
$configWriter->save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -920,6 +985,7 @@ abstract class Base
|
||||
|
||||
if ($isParentProcess) {
|
||||
$processId = $this->getParentProcessId();
|
||||
|
||||
if (!$processId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,8 +45,11 @@ class Install extends \Espo\Core\Upgrades\Actions\Base\Install
|
||||
{
|
||||
$manifest = $this->getManifest();
|
||||
|
||||
$this->getConfig()->set('version', $manifest['version']);
|
||||
$this->getConfig()->save();
|
||||
$configWriter = $this->createConfigWriter();
|
||||
|
||||
$configWriter->set('version', $manifest['version']);
|
||||
|
||||
$configWriter->save();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,15 +29,21 @@
|
||||
|
||||
namespace Espo\Core\Utils;
|
||||
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
Utils\Config\ConfigWriter,
|
||||
};
|
||||
|
||||
class ApiKey
|
||||
{
|
||||
private $config;
|
||||
|
||||
public function __construct(Config $config)
|
||||
private $configWriter;
|
||||
|
||||
public function __construct(Config $config, ConfigWriter $configWriter)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->configWriter = $configWriter;
|
||||
}
|
||||
|
||||
public static function hash(string $secretKey, string $string = '') : string
|
||||
@@ -74,9 +80,9 @@ class ApiKey
|
||||
|
||||
$apiSecretKeys->$id = $secretKey;
|
||||
|
||||
$this->config->set('apiSecretKeys', $apiSecretKeys);
|
||||
$this->configWriter->set('apiSecretKeys', $apiSecretKeys);
|
||||
|
||||
$this->config->save();
|
||||
$this->configWriter->save();
|
||||
}
|
||||
|
||||
public function removeSecretKeyForUserId(string $id)
|
||||
@@ -89,7 +95,8 @@ class ApiKey
|
||||
|
||||
unset($apiSecretKeys->$id);
|
||||
|
||||
$this->config->set('apiSecretKeys', $apiSecretKeys);
|
||||
$this->config->save();
|
||||
$this->configWriter->set('apiSecretKeys', $apiSecretKeys);
|
||||
|
||||
$this->configWriter->save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ use Espo\Core\{
|
||||
use StdClass;
|
||||
|
||||
/**
|
||||
* Reads and writes the main config file.
|
||||
* Access to the application config parameters.
|
||||
*/
|
||||
class Config
|
||||
{
|
||||
@@ -69,6 +69,11 @@ class Config
|
||||
$this->fileManager = $fileManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* A path to the config file.
|
||||
*
|
||||
* @todo Move to ConfigData.
|
||||
*/
|
||||
public function getConfigPath() : string
|
||||
{
|
||||
return $this->configPath;
|
||||
@@ -125,7 +130,18 @@ class Config
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a parameter or multiple parameters.
|
||||
* Re-load data.
|
||||
*
|
||||
* @todo Get rid of this method. Use ConfigData as a dependency.
|
||||
* `$configData->update();`
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
$this->loadConfig(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since version 6.2.0
|
||||
*/
|
||||
public function set($name, $value = null, bool $dontMarkDirty = false)
|
||||
{
|
||||
@@ -151,7 +167,7 @@ class Config
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a parameter..
|
||||
* @deprecated since version 6.2.0
|
||||
*/
|
||||
public function remove(string $name) : bool
|
||||
{
|
||||
@@ -167,7 +183,7 @@ class Config
|
||||
}
|
||||
|
||||
/**
|
||||
* Save config changes to the file.
|
||||
* @deprecated since version 6.2.0
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
@@ -233,6 +249,9 @@ class Config
|
||||
|
||||
/**
|
||||
* Get system default config parameters.
|
||||
*
|
||||
* @deprecated
|
||||
* @todo Move to `Espo\Core\Utils\Config\ConfigDefaults`.
|
||||
*/
|
||||
public function getDefaults() : array
|
||||
{
|
||||
@@ -289,8 +308,7 @@ class Config
|
||||
/**
|
||||
* Update cache timestamp.
|
||||
*
|
||||
* @param $returnOnlyValue - To return an array with timestamp.
|
||||
* @return bool | array
|
||||
* @deprecated
|
||||
*/
|
||||
public function updateCacheTimestamp(bool $returnOnlyValue = false)
|
||||
{
|
||||
@@ -305,31 +323,55 @@ class Config
|
||||
return $this->set($timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Remove.
|
||||
* @deprecated
|
||||
*/
|
||||
public function getAdminOnlyItemList() : array
|
||||
{
|
||||
return $this->get('adminItems', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Remove.
|
||||
* @deprecated
|
||||
*/
|
||||
public function getSuperAdminOnlyItemList() : array
|
||||
{
|
||||
return $this->get('superAdminItems', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Remove.
|
||||
* @deprecated
|
||||
*/
|
||||
public function getSystemOnlyItemList() : array
|
||||
{
|
||||
return $this->get('systemItems', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Remove.
|
||||
* @deprecated
|
||||
*/
|
||||
public function getSuperAdminOnlySystemItemList() : array
|
||||
{
|
||||
return $this->get('superAdminSystemItems', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Remove.
|
||||
* @deprecated
|
||||
*/
|
||||
public function getUserOnlyItemList() : array
|
||||
{
|
||||
return $this->get('userItems', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Move to another class `Espo\Core\Utils\Config\ApplicationConfigProvider`.
|
||||
* @deprecated
|
||||
*/
|
||||
public function getSiteUrl() : string
|
||||
{
|
||||
return rtrim($this->get('siteUrl'), '/');
|
||||
|
||||
@@ -34,6 +34,8 @@ use Espo\Core\{
|
||||
Utils\Config,
|
||||
};
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class ConfigFileManager
|
||||
{
|
||||
protected $fileManager;
|
||||
@@ -55,9 +57,23 @@ class ConfigFileManager
|
||||
return $this->fileManager->isFile($filePath);
|
||||
}
|
||||
|
||||
public function putPhpContents(string $path, $data, bool $useRenaming = false)
|
||||
protected function putPhpContentsInternal(string $path, array $data, bool $useRenaming = false)
|
||||
{
|
||||
return $this->fileManager->putPhpContents($path, $data, true, $useRenaming);
|
||||
$result = $this->fileManager->putPhpContents($path, $data, true, $useRenaming);
|
||||
|
||||
if ($result === false) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public function putPhpContents(string $path, array $data)
|
||||
{
|
||||
$this->putPhpContentsInternal($path, $data, true);
|
||||
}
|
||||
|
||||
public function putPhpContentsNoRenaming(string $path, array $data)
|
||||
{
|
||||
$this->putPhpContentsInternal($path, $data, false);
|
||||
}
|
||||
|
||||
public function getPhpContents(string $path)
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Config;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
Exceptions\Error,
|
||||
};
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Writes into the config.
|
||||
*/
|
||||
class ConfigWriter
|
||||
{
|
||||
private $changedData = [];
|
||||
|
||||
private $removeParamList = [];
|
||||
|
||||
protected $associativeArrayAttributeList = [
|
||||
'currencyRates',
|
||||
'database',
|
||||
'logger',
|
||||
'defaultPermissions',
|
||||
];
|
||||
|
||||
private $cacheTimestampParam = 'cacheTimestamp';
|
||||
|
||||
protected $config;
|
||||
|
||||
protected $fileManager;
|
||||
|
||||
protected $helper;
|
||||
|
||||
public function __construct(Config $config, ConfigWriterFileManager $fileManager, ConfigWriterHelper $helper)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->fileManager = $fileManager;
|
||||
$this->helper = $helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a parameter.
|
||||
*/
|
||||
public function set(string $name, $value)
|
||||
{
|
||||
if (in_array($name, $this->associativeArrayAttributeList) && is_object($value)) {
|
||||
$value = (array) $value;
|
||||
}
|
||||
|
||||
$this->changedData[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set multiple parameters.
|
||||
*/
|
||||
public function setMultiple(array $params)
|
||||
{
|
||||
foreach ($params as $name => $value) {
|
||||
$this->set($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a parameter.
|
||||
*/
|
||||
public function remove(string $name)
|
||||
{
|
||||
$this->removeParamList[] = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save config changes to the file.
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$changedData = $this->changedData;
|
||||
|
||||
if (!isset($changedData[$this->cacheTimestampParam])) {
|
||||
$changedData[$this->cacheTimestampParam] = $this->generateCacheTimestamp();
|
||||
}
|
||||
|
||||
$configPath = $this->config->getConfigPath();
|
||||
|
||||
if (!$this->fileManager->isFile($configPath)) {
|
||||
throw new Error("Config file '{$configPath}' was not found.");
|
||||
}
|
||||
|
||||
$data = $this->fileManager->getPhpContents($configPath);
|
||||
|
||||
if (!is_array($data)) {
|
||||
$data = $this->fileManager->getPhpContents($configPath);
|
||||
}
|
||||
|
||||
if (!is_array($data)) {
|
||||
throw new Error("Could not read config.");
|
||||
}
|
||||
|
||||
foreach ($changedData as $key => $value) {
|
||||
$data[$key] = $value;
|
||||
}
|
||||
|
||||
foreach ($this->removeParamList as $key) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
|
||||
if (!is_array($data)) {
|
||||
throw new Error("Invalid config data while saving.");
|
||||
}
|
||||
|
||||
$data['microtime'] = $microtime = $this->helper->generateMicrotime();
|
||||
|
||||
try {
|
||||
$this->fileManager->putPhpContents($configPath, $data);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
throw new Error("Could not save config.");
|
||||
}
|
||||
|
||||
$reloadedData = $this->fileManager->getPhpContents($configPath);
|
||||
|
||||
if (
|
||||
!is_array($reloadedData) ||
|
||||
$microtime !== ($reloadedData['microtime'] ?? null)
|
||||
) {
|
||||
try {
|
||||
$this->fileManager->putPhpContentsNoRenaming($configPath, $data);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
throw new Error("Could not save config.");
|
||||
}
|
||||
}
|
||||
|
||||
$this->changedData = [];
|
||||
$this->removeParamList = [];
|
||||
|
||||
$this->config->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the cache timestamp.
|
||||
*
|
||||
* @todo Remove? Saving re-writes the cache timestamp anyway.
|
||||
*/
|
||||
public function updateCacheTimestamp()
|
||||
{
|
||||
$this->set($this->cacheTimestampParam, $this->generateCacheTimestamp());
|
||||
}
|
||||
|
||||
protected function generateCacheTimestamp() : int
|
||||
{
|
||||
return $this->helper->generateCacheTimestamp();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Config;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\File\Manager as FileManager,
|
||||
Utils\Config,
|
||||
};
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class ConfigWriterFileManager
|
||||
{
|
||||
private $fileManager;
|
||||
|
||||
public function __construct(?Config $config = null, ?array $defaultPermissions = null)
|
||||
{
|
||||
$defaultPermissionsToSet = null;
|
||||
|
||||
if ($defaultPermissions) {
|
||||
$defaultPermissionsToSet = $defaultPermissions;
|
||||
}
|
||||
else if ($config) {
|
||||
$defaultPermissionsToSet = $config->get('defaultPermissions');
|
||||
}
|
||||
|
||||
$this->fileManager = new FileManager($defaultPermissionsToSet);
|
||||
}
|
||||
|
||||
public function setConfig(Config $config)
|
||||
{
|
||||
$this->fileManager = new FileManager(
|
||||
$config->get('defaultPermissions')
|
||||
);
|
||||
}
|
||||
|
||||
public function isFile(string $filePath) : bool
|
||||
{
|
||||
return $this->fileManager->isFile($filePath);
|
||||
}
|
||||
|
||||
protected function putPhpContentsInternal(string $path, array $data, bool $useRenaming = false)
|
||||
{
|
||||
$result = $this->fileManager->putPhpContents($path, $data, true, $useRenaming);
|
||||
|
||||
if ($result === false) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public function putPhpContents(string $path, array $data)
|
||||
{
|
||||
$this->putPhpContentsInternal($path, $data, true);
|
||||
}
|
||||
|
||||
public function putPhpContentsNoRenaming(string $path, array $data)
|
||||
{
|
||||
$this->putPhpContentsInternal($path, $data, false);
|
||||
}
|
||||
|
||||
public function getPhpContents(string $path)
|
||||
{
|
||||
return $this->fileManager->getPhpContents($path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Config;
|
||||
|
||||
class ConfigWriterHelper
|
||||
{
|
||||
public function generateCacheTimestamp() : int
|
||||
{
|
||||
return time();
|
||||
}
|
||||
|
||||
public function generateMicrotime() : float
|
||||
{
|
||||
return microtime(true);
|
||||
}
|
||||
}
|
||||
@@ -43,12 +43,11 @@ class Portal extends \Espo\Core\ORM\Entity
|
||||
'dateFormat',
|
||||
'timeFormat',
|
||||
'weekStart',
|
||||
'defaultCurrency'
|
||||
'defaultCurrency',
|
||||
];
|
||||
|
||||
public function getSettingsAttributeList()
|
||||
{
|
||||
return $this->settingsAttributeList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,28 +32,34 @@ namespace Espo\Hooks\Integration;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
Utils\Config\ConfigWriter,
|
||||
};
|
||||
|
||||
class GoogleMaps
|
||||
{
|
||||
protected $config;
|
||||
protected $configWriter;
|
||||
|
||||
public function __construct(Config $config)
|
||||
public function __construct(ConfigWriter $configWriter)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->configWriter = $configWriter;
|
||||
}
|
||||
|
||||
public function afterSave(Entity $entity)
|
||||
{
|
||||
if ($entity->id === 'GoogleMaps') {
|
||||
if (!$entity->get('enabled') || !$entity->get('apiKey')) {
|
||||
$this->config->set('googleMapsApiKey', null);
|
||||
$this->config->save();
|
||||
return;
|
||||
}
|
||||
$this->config->set('googleMapsApiKey', $entity->get('apiKey'));
|
||||
$this->config->save();
|
||||
if ($entity->id !== 'GoogleMaps') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$entity->get('enabled') || !$entity->get('apiKey')) {
|
||||
$this->configWriter->set('googleMapsApiKey', null);
|
||||
|
||||
$this->configWriter->save();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->configWriter->set('googleMapsApiKey', $entity->get('apiKey'));
|
||||
|
||||
$this->configWriter->save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Hooks\Portal;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
Utils\Config\ConfigWriter,
|
||||
};
|
||||
|
||||
class WriteConfig
|
||||
{
|
||||
protected $config;
|
||||
|
||||
protected $configWriter;
|
||||
|
||||
public function __construct(Config $config, ConfigWriter $configWriter)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->configWriter = $configWriter;
|
||||
}
|
||||
|
||||
public function afterSave(Entity $entity)
|
||||
{
|
||||
if (!$entity->has('isDefault')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($entity->get('isDefault')) {
|
||||
$defaultPortalId = $this->config->get('defaultPortalId');
|
||||
|
||||
if ($defaultPortalId === $entity->id) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->configWriter->set('defaultPortalId', $entity->id);
|
||||
|
||||
$this->configWriter->save();
|
||||
}
|
||||
|
||||
if ($entity->isAttributeChanged('isDefault') && $entity->getFetched('isDefault')) {
|
||||
|
||||
$this->configWriter->set('defaultPortalId', null);
|
||||
|
||||
$this->configWriter->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,11 +31,12 @@ namespace Espo\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Repositories\Database;
|
||||
|
||||
use Espo\Core\Di;
|
||||
|
||||
class Portal extends \Espo\Core\Repositories\Database implements
|
||||
class Portal extends Database implements
|
||||
|
||||
Di\ConfigAware
|
||||
{
|
||||
use Di\ConfigSetter;
|
||||
@@ -67,26 +68,4 @@ class Portal extends \Espo\Core\Repositories\Database implements
|
||||
$entity->set('url', $url);
|
||||
}
|
||||
}
|
||||
|
||||
protected function afterSave(Entity $entity, array $options = [])
|
||||
{
|
||||
parent::afterSave($entity, $options);
|
||||
|
||||
if ($entity->has('isDefault')) {
|
||||
if ($entity->get('isDefault')) {
|
||||
$defaultPortalId = $this->config->get('defaultPortalId');
|
||||
if ($defaultPortalId !== $entity->id) {
|
||||
$this->config->set('defaultPortalId', $entity->id);
|
||||
$this->config->save();
|
||||
}
|
||||
} else {
|
||||
if ($entity->isAttributeChanged('isDefault')) {
|
||||
if ($entity->getFetched('isDefault')) {
|
||||
$this->config->set('defaultPortalId', null);
|
||||
$this->config->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,16 +29,28 @@
|
||||
|
||||
namespace Espo\Services;
|
||||
|
||||
use Espo\Core\Di;
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
Utils\Config\ConfigWriter,
|
||||
Di,
|
||||
};
|
||||
|
||||
class AdminNotifications implements
|
||||
|
||||
Di\ConfigAware,
|
||||
Di\EntityManagerAware
|
||||
{
|
||||
use Di\ConfigSetter;
|
||||
use Di\EntityManagerSetter;
|
||||
|
||||
protected $config;
|
||||
|
||||
protected $configWriter;
|
||||
|
||||
public function __construct(Config $config, ConfigWriter $configWriter)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->configWriter = $configWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Job for checking a new version of EspoCRM.
|
||||
*/
|
||||
@@ -51,32 +63,36 @@ class AdminNotifications implements
|
||||
}
|
||||
|
||||
$latestRelease = $this->getLatestRelease();
|
||||
|
||||
if (empty($latestRelease['version'])) {
|
||||
$config->set('latestVersion', $latestRelease['version']);
|
||||
$config->save();
|
||||
$this->configWriter->set('latestVersion', $latestRelease['version']);
|
||||
|
||||
$this->configWriter->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($config->get('latestVersion') != $latestRelease['version']) {
|
||||
$config->set('latestVersion', $latestRelease['version']);
|
||||
$this->configWriter->set('latestVersion', $latestRelease['version']);
|
||||
|
||||
if (!empty($latestRelease['notes'])) {
|
||||
//todo: create notification
|
||||
// @todo Create a notification.
|
||||
}
|
||||
|
||||
$config->save();
|
||||
$this->configWriter->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!empty($latestRelease['notes'])) {
|
||||
//todo: find and modify notification
|
||||
// @todo Find and modify notification.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Job for cheking a new version of installed extensions.
|
||||
* Job for checking a new version of installed extensions.
|
||||
*/
|
||||
public function jobCheckNewExtensionVersion()
|
||||
{
|
||||
@@ -103,6 +119,7 @@ class AdminNotifications implements
|
||||
|
||||
while ($row = $sth->fetch()) {
|
||||
$url = !empty($row['checkVersionUrl']) ? $row['checkVersionUrl'] : null;
|
||||
|
||||
$extensionName = $row['name'];
|
||||
|
||||
$latestRelease = $this->getLatestRelease($url, [
|
||||
@@ -117,11 +134,13 @@ class AdminNotifications implements
|
||||
$latestExtensionVersions = $config->get('latestExtensionVersions', []);
|
||||
|
||||
$save = false;
|
||||
|
||||
foreach ($latestReleases as $extensionName => $extensionData) {
|
||||
|
||||
if (empty($latestExtensionVersions[$extensionName])) {
|
||||
$latestExtensionVersions[$extensionName] = $extensionData['version'];
|
||||
$save = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -133,6 +152,7 @@ class AdminNotifications implements
|
||||
}
|
||||
|
||||
$save = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -142,37 +162,51 @@ class AdminNotifications implements
|
||||
}
|
||||
|
||||
if ($save) {
|
||||
$config->set('latestExtensionVersions', $latestExtensionVersions);
|
||||
$config->save();
|
||||
$this->configWriter->set('latestExtensionVersions', $latestExtensionVersions);
|
||||
|
||||
$this->configWriter->save();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getLatestRelease(?string $url = null, array $requestData = [], string $urlPath = 'release/latest')
|
||||
{
|
||||
if (function_exists('curl_version')) {
|
||||
$ch = curl_init();
|
||||
protected function getLatestRelease(
|
||||
?string $url = null, array $requestData = [], string $urlPath = 'release/latest'
|
||||
) : ?array {
|
||||
|
||||
$requestUrl = $url ? trim($url) : base64_decode('aHR0cHM6Ly9zLmVzcG9jcm0uY29tLw==');
|
||||
$requestUrl = (substr($requestUrl, -1) == '/') ? $requestUrl : $requestUrl . '/';
|
||||
$requestUrl .= empty($requestData) ? $urlPath . '/' : $urlPath . '/?' . http_build_query($requestData);
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $requestUrl);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
|
||||
|
||||
$result = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($httpCode === 200) {
|
||||
$data = json_decode($result, true);
|
||||
if (is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
if (!function_exists('curl_version')) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
$requestUrl = $url ? trim($url) : base64_decode('aHR0cHM6Ly9zLmVzcG9jcm0uY29tLw==');
|
||||
$requestUrl = (substr($requestUrl, -1) == '/') ? $requestUrl : $requestUrl . '/';
|
||||
|
||||
$requestUrl .= empty($requestData) ?
|
||||
$urlPath . '/' :
|
||||
$urlPath . '/?' . http_build_query($requestData);
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $requestUrl);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
|
||||
|
||||
$result = curl_exec($ch);
|
||||
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
if ($httpCode !== 200) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = json_decode($result, true);
|
||||
|
||||
if (!is_array($data)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ use Espo\Core\Exceptions\{
|
||||
use Espo\Core\{
|
||||
DataManager,
|
||||
Utils\Config,
|
||||
Utils\Config\ConfigWriter,
|
||||
Acl,
|
||||
};
|
||||
|
||||
@@ -45,55 +46,81 @@ use StdClass;
|
||||
class CurrencyRate
|
||||
{
|
||||
protected $config;
|
||||
protected $configWriter;
|
||||
protected $dataManager;
|
||||
protected $acl;
|
||||
|
||||
public function __construct(Config $config, DataManager $dataManager, Acl $acl) {
|
||||
public function __construct(Config $config, ConfigWriter $configWriter, DataManager $dataManager, Acl $acl)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->configWriter = $configWriter;
|
||||
$this->dataManager = $dataManager;
|
||||
$this->acl = $acl;
|
||||
}
|
||||
|
||||
public function get() : StdClass
|
||||
{
|
||||
if (!$this->acl->check('Currency')) throw new Forbidden();
|
||||
if ($this->acl->getLevel('Currency', 'read') !== 'yes') throw new Forbidden();
|
||||
if (!$this->acl->check('Currency')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
return (object) ($this->config->get('currencyRates') ?? []);
|
||||
if ($this->acl->getLevel('Currency', 'read') !== 'yes') {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
return (object) (
|
||||
$this->config->get('currencyRates') ?? []
|
||||
);
|
||||
}
|
||||
|
||||
public function set(StdClass $rates) : StdClass
|
||||
{
|
||||
if (!$this->acl->check('Currency')) throw new Forbidden();
|
||||
if ($this->acl->getLevel('Currency', 'edit') !== 'yes') throw new Forbidden();
|
||||
if (!$this->acl->check('Currency')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
if ($this->acl->getLevel('Currency', 'edit') !== 'yes') {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$config = $this->config;
|
||||
|
||||
$currencyList = $config->get('currencyList') ?? [];
|
||||
|
||||
foreach (get_object_vars($rates) as $key => $value) {
|
||||
if (!is_string($key) || !in_array($key, $currencyList)) {
|
||||
unset($rates->$key);
|
||||
|
||||
continue;
|
||||
}
|
||||
if (!is_numeric($value) || is_string($value)) throw new BadRequest();
|
||||
if ($value < 0) throw new BadRequest();
|
||||
|
||||
if (!is_numeric($value) || is_string($value)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
if ($value < 0) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($currencyList as $currency) {
|
||||
if ($currency == $config->get('baseCurrency')) continue;
|
||||
if ($currency == $config->get('baseCurrency')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($rates->$currency)) {
|
||||
$rates->$currency = $config->get('currencyRates.' . $currency) ?? 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
$data = (object) ['currencyRates' => $rates];
|
||||
$this->configWriter->set('currencyRates', $rates);
|
||||
|
||||
$config->setData($data);
|
||||
$config->save();
|
||||
$this->configWriter->save();
|
||||
|
||||
$this->dataManager->rebuildDatabase([]);
|
||||
|
||||
return (object) ($config->get('currencyRates') ?? []);
|
||||
return (object) (
|
||||
$config->get('currencyRates') ?? []
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Services;
|
||||
|
||||
use Espo\{
|
||||
Core\Exceptions\Forbidden,
|
||||
Core\Exceptions\NotFound,
|
||||
Core\Utils\Config,
|
||||
Core\Utils\Config\ConfigWriter,
|
||||
ORM\EntityManager,
|
||||
ORM\Entity,
|
||||
Entities\User,
|
||||
};
|
||||
|
||||
use StdClass;
|
||||
|
||||
class Integration
|
||||
{
|
||||
protected $entityManager;
|
||||
|
||||
protected $user;
|
||||
|
||||
protected $config;
|
||||
|
||||
protected $configWriter;
|
||||
|
||||
public function __construct(
|
||||
EntityManager $entityManager, User $user, Config $config, ConfigWriter $configWriter
|
||||
) {
|
||||
$this->entityManager = $entityManager;
|
||||
$this->user = $user;
|
||||
$this->config = $config;
|
||||
$this->configWriter = $configWriter;
|
||||
}
|
||||
|
||||
protected function processAccessCheck()
|
||||
{
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
public function read(string $id) : Entity
|
||||
{
|
||||
$this->processAccessCheck();
|
||||
|
||||
$entity = $this->entityManager->getEntity('Integration', $id);
|
||||
|
||||
if (!$entity) {
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
public function update(string $id, StdClass $data) : Entity
|
||||
{
|
||||
$this->processAccessCheck();
|
||||
|
||||
$entity = $this->entityManager->getEntity('Integration', $id);
|
||||
|
||||
if (!$entity) {
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
$entity->set($data);
|
||||
|
||||
$this->entityManager->saveEntity($entity);
|
||||
|
||||
$integrationsConfigData = $this->config->get('integrations') ?? (object) [];
|
||||
|
||||
if (!($integrationsConfigData instanceof StdClass)) {
|
||||
$integrationsConfigData = (object) [];
|
||||
}
|
||||
|
||||
$integrationName = $id;
|
||||
|
||||
$integrationsConfigData->$integrationName = $entity->get('enabled');
|
||||
|
||||
$this->configWriter->set('integrations', $integrationsConfigData);
|
||||
|
||||
$this->configWriter->save();
|
||||
|
||||
return $entity;
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@
|
||||
namespace Espo\Services;
|
||||
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
@@ -43,6 +42,7 @@ use Espo\Core\{
|
||||
Utils\Metadata,
|
||||
Utils\FieldUtil,
|
||||
Utils\Config,
|
||||
Utils\Config\ConfigWriter,
|
||||
DataManager,
|
||||
Utils\FieldValidatorManager,
|
||||
Currency\DatabasePopulator as CurrencyDatabasePopulator,
|
||||
@@ -52,6 +52,7 @@ class Settings
|
||||
{
|
||||
protected $applicationState;
|
||||
protected $config;
|
||||
protected $configWriter;
|
||||
protected $fieldUtil;
|
||||
protected $metadata;
|
||||
protected $acl;
|
||||
@@ -63,6 +64,7 @@ class Settings
|
||||
public function __construct(
|
||||
ApplicationState $applicationState,
|
||||
Config $config,
|
||||
ConfigWriter $configWriter,
|
||||
Metadata $metadata,
|
||||
Acl $acl,
|
||||
FieldUtil $fieldUtil,
|
||||
@@ -73,6 +75,7 @@ class Settings
|
||||
) {
|
||||
$this->applicationState = $applicationState;
|
||||
$this->config = $config;
|
||||
$this->configWriter = $configWriter;
|
||||
$this->metadata = $metadata;
|
||||
$this->acl = $acl;
|
||||
$this->fieldUtil = $fieldUtil;
|
||||
@@ -114,7 +117,9 @@ class Settings
|
||||
|
||||
if ($this->applicationState->isPortal()) {
|
||||
$portal = $this->applicationState->getPortal();
|
||||
|
||||
$this->entityManager->getRepository('Portal')->loadUrlField($portal);
|
||||
|
||||
$data->siteUrl = $portal->get('url');
|
||||
}
|
||||
|
||||
@@ -124,6 +129,7 @@ class Settings
|
||||
|
||||
if ($user->isSystem()) {
|
||||
$globalItemList = $this->getGlobalItemList();
|
||||
|
||||
foreach (get_object_vars($data) as $item => $value) {
|
||||
if (!in_array($item, $globalItemList)) {
|
||||
unset($data->$item);
|
||||
@@ -145,21 +151,30 @@ class Settings
|
||||
'streamEmailNotificationsTypeList',
|
||||
'emailKeepParentTeamsEntityList',
|
||||
];
|
||||
$scopeList = array_keys($this->metadata->get(['entityDefs'], []));
|
||||
foreach ($scopeList as $scope) {
|
||||
if (!$this->metadata->get(['scopes', $scope, 'acl'])) continue;
|
||||
if (!$this->acl->check($scope)) {
|
||||
foreach ($entityTypeListParamList as $param) {
|
||||
$list = $data->$param ?? [];
|
||||
foreach ($list as $i => $item) {
|
||||
if ($item === $scope) {
|
||||
unset($list[$i]);
|
||||
}
|
||||
}
|
||||
$list = array_values($list);
|
||||
|
||||
$data->$param = $list;
|
||||
$scopeList = array_keys($this->metadata->get(['entityDefs'], []));
|
||||
|
||||
foreach ($scopeList as $scope) {
|
||||
if (!$this->metadata->get(['scopes', $scope, 'acl'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->acl->check($scope)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($entityTypeListParamList as $param) {
|
||||
$list = $data->$param ?? [];
|
||||
|
||||
foreach ($list as $i => $item) {
|
||||
if ($item === $scope) {
|
||||
unset($list[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
$list = array_values($list);
|
||||
|
||||
$data->$param = $list;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,6 +218,7 @@ class Settings
|
||||
foreach ($this->config->getSuperAdminOnlyItemList() as $item) {
|
||||
$ignoreItemList[] = $item;
|
||||
}
|
||||
|
||||
foreach ($this->config->getSuperAdminOnlySystemItemList() as $item) {
|
||||
$ignoreItemList[] = $item;
|
||||
}
|
||||
@@ -213,7 +229,9 @@ class Settings
|
||||
}
|
||||
|
||||
$entity = $this->entityManager->getEntity('Settings');
|
||||
|
||||
$entity->set($data);
|
||||
|
||||
$this->processValidation($entity, $data);
|
||||
|
||||
if (
|
||||
@@ -222,13 +240,11 @@ class Settings
|
||||
$this->dataManager->clearCache();
|
||||
}
|
||||
|
||||
$this->config->setData($data);
|
||||
$this->configWriter->setMultiple(
|
||||
get_object_vars($data)
|
||||
);
|
||||
|
||||
$result = $this->config->save();
|
||||
|
||||
if ($result === false) {
|
||||
throw new Error('Cannot save settings');
|
||||
}
|
||||
$this->configWriter->save();
|
||||
|
||||
if (isset($data->personNameFormat)) {
|
||||
$this->dataManager->clearCache();
|
||||
@@ -237,8 +253,6 @@ class Settings
|
||||
if (isset($data->defaultCurrency) || isset($data->baseCurrency) || isset($data->currencyRates)) {
|
||||
$this->populateDatabaseWithCurrencyRates();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function populateDatabaseWithCurrencyRates()
|
||||
@@ -254,9 +268,13 @@ class Settings
|
||||
unset($data->webSocketUrl);
|
||||
}
|
||||
|
||||
if ($user->isSystem()) return;
|
||||
if ($user->isSystem()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($user->isAdmin()) return;
|
||||
if ($user->isAdmin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!$this->acl->checkScope('Email', 'create')
|
||||
@@ -290,6 +308,7 @@ class Settings
|
||||
$itemList = $this->config->getUserOnlyItemList();
|
||||
|
||||
$fieldDefs = $this->metadata->get(['entityDefs', 'Settings', 'fields']);
|
||||
|
||||
foreach ($fieldDefs as $field => $fieldParams) {
|
||||
if (!empty($fieldParams['onlyUser'])) {
|
||||
foreach ($this->fieldUtil->getAttributeList('Settings', $field) as $attribute) {
|
||||
@@ -306,6 +325,7 @@ class Settings
|
||||
$itemList = $this->config->getSystemOnlyItemList();
|
||||
|
||||
$fieldDefs = $this->metadata->get(['entityDefs', 'Settings', 'fields']);
|
||||
|
||||
foreach ($fieldDefs as $field => $fieldParams) {
|
||||
if (!empty($fieldParams['onlySystem'])) {
|
||||
foreach ($this->fieldUtil->getAttributeList('Settings', $field) as $attribute) {
|
||||
@@ -322,6 +342,7 @@ class Settings
|
||||
$itemList = $this->config->get('globalItems', []);
|
||||
|
||||
$fieldDefs = $this->metadata->get(['entityDefs', 'Settings', 'fields']);
|
||||
|
||||
foreach ($fieldDefs as $field => $fieldParams) {
|
||||
if (!empty($fieldParams['global'])) {
|
||||
foreach ($this->fieldUtil->getAttributeList('Settings', $field) as $attribute) {
|
||||
@@ -338,7 +359,10 @@ class Settings
|
||||
$fieldList = $this->fieldUtil->getEntityTypeFieldList('Settings');
|
||||
|
||||
foreach ($fieldList as $field) {
|
||||
if (!$this->isFieldSetInData($data, $field)) continue;
|
||||
if (!$this->isFieldSetInData($data, $field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->processValidationField($entity, $field, $data);
|
||||
}
|
||||
}
|
||||
@@ -352,7 +376,10 @@ class Settings
|
||||
|
||||
foreach ($validationList as $type) {
|
||||
$value = $this->fieldUtil->getEntityTypeFieldParam('Settings', $field, $type);
|
||||
if (is_null($value) && !in_array($type, $mandatoryValidationList)) continue;
|
||||
|
||||
if (is_null($value) && !in_array($type, $mandatoryValidationList)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$fieldValidatorManager->check($entity, $field, $type, $data)) {
|
||||
throw new BadRequest("Not valid data. Field: '{$field}', type: {$type}.");
|
||||
@@ -363,13 +390,17 @@ class Settings
|
||||
protected function isFieldSetInData($data, $field)
|
||||
{
|
||||
$attributeList = $this->fieldUtil->getActualAttributeList('Settings', $field);
|
||||
|
||||
$isSet = false;
|
||||
|
||||
foreach ($attributeList as $attribute) {
|
||||
if (property_exists($data, $attribute)) {
|
||||
$isSet = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $isSet;
|
||||
}
|
||||
}
|
||||
|
||||
+76
-20
@@ -32,6 +32,9 @@ use Espo\Core\{
|
||||
Utils\Util,
|
||||
Utils\Config\ConfigFileManager,
|
||||
Utils\Config,
|
||||
Utils\Config\ConfigWriter,
|
||||
Utils\Config\ConfigWriterFileManager,
|
||||
Utils\Config\ConfigWriterHelper,
|
||||
Utils\Database\Helper as DatabaseHelper,
|
||||
Utils\PasswordHash,
|
||||
Utils\SystemRequirements,
|
||||
@@ -97,7 +100,9 @@ class Installer
|
||||
protected function initialize()
|
||||
{
|
||||
$fileManager = new ConfigFileManager();
|
||||
|
||||
$config = new Config($fileManager);
|
||||
|
||||
$configPath = $config->getConfigPath();
|
||||
|
||||
if (!file_exists($configPath)) {
|
||||
@@ -105,13 +110,22 @@ class Installer
|
||||
}
|
||||
|
||||
$data = include('data/config.php');
|
||||
|
||||
$configWriter = new ConfigWriter(
|
||||
$config,
|
||||
new ConfigWriterFileManager(null, $data['defaultPermissions'] ?? null),
|
||||
new ConfigWriterHelper()
|
||||
);
|
||||
|
||||
$defaultData = $config->getDefaults();
|
||||
|
||||
//save default data if not exists, check by keys
|
||||
if (!Util::arrayKeysExists(array_keys($defaultData), $data)) {
|
||||
$defaultData = array_replace_recursive($defaultData, $data);
|
||||
$config->set($defaultData);
|
||||
$config->save();
|
||||
|
||||
$configWriter->setMultiple($defaultData);
|
||||
|
||||
$configWriter->save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +144,11 @@ class Installer
|
||||
return $this->app->getContainer()->get('config');
|
||||
}
|
||||
|
||||
public function createConfigWriter() : ConfigWriter
|
||||
{
|
||||
return $this->app->getContainer()->get('injectableFactory')->create(ConfigWriter::class);
|
||||
}
|
||||
|
||||
protected function getSystemHelper()
|
||||
{
|
||||
return $this->systemHelper;
|
||||
@@ -154,7 +173,9 @@ class Installer
|
||||
{
|
||||
if (!isset($this->passwordHash)) {
|
||||
$config = $this->getConfig();
|
||||
$this->passwordHash = new PasswordHash($config);
|
||||
$configWriter = $this->createConfigWriter();
|
||||
|
||||
$this->passwordHash = new PasswordHash($config, $configWriter);
|
||||
}
|
||||
|
||||
return $this->passwordHash;
|
||||
@@ -192,8 +213,10 @@ class Installer
|
||||
if (!isset($this->language)) {
|
||||
try {
|
||||
$this->language = $this->app->getContainer()->get('defaultLanguage');
|
||||
} catch (Throwable $e) {
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
echo "Error: " . $e->getMessage();
|
||||
|
||||
$GLOBALS['log']->error($e->getMessage());
|
||||
|
||||
die;
|
||||
@@ -227,6 +250,7 @@ class Installer
|
||||
public function getSystemRequirementList($type, $requiredOnly = false, array $additionalData = null)
|
||||
{
|
||||
$systemRequirementManager = new SystemRequirements($this->app->getContainer());
|
||||
|
||||
return $systemRequirementManager->getRequiredListByType($type, $requiredOnly, $additionalData);
|
||||
}
|
||||
|
||||
@@ -240,9 +264,11 @@ class Installer
|
||||
catch (Exception $e) {
|
||||
if ($isCreateDatabase && $e->getCode() == '1049') {
|
||||
$modParams = $params;
|
||||
|
||||
unset($modParams['dbname']);
|
||||
|
||||
$pdo = $this->getDatabaseHelper()->createPdoConnection($modParams);
|
||||
|
||||
$pdo->query("CREATE DATABASE IF NOT EXISTS `". $params['dbname'] ."`");
|
||||
|
||||
return $this->checkDatabaseConnection($params, false);
|
||||
@@ -279,25 +305,31 @@ class Installer
|
||||
'siteUrl' => !empty($saveData['siteUrl']) ? $saveData['siteUrl'] : $this->getSystemHelper()->getBaseUrl(),
|
||||
'passwordSalt' => $this->getPasswordHash()->generateSalt(),
|
||||
'cryptKey' => $this->getContainer()->get('crypt')->generateKey(),
|
||||
'hashSecretKey' => \Espo\Core\Utils\Util::generateSecretKey(),
|
||||
'hashSecretKey' => Util::generateSecretKey(),
|
||||
];
|
||||
|
||||
if (empty($saveData['defaultPermissions']['user'])) {
|
||||
$saveData['defaultPermissions']['user'] = $this->getFileManager()->getPermissionUtils()->getDefaultOwner(true);
|
||||
$saveData['defaultPermissions']['user'] = $this->getFileManager()
|
||||
->getPermissionUtils()
|
||||
->getDefaultOwner(true);
|
||||
}
|
||||
|
||||
if (empty($saveData['defaultPermissions']['group'])) {
|
||||
$saveData['defaultPermissions']['group'] = $this->getFileManager()->getPermissionUtils()->getDefaultGroup(true);
|
||||
$saveData['defaultPermissions']['group'] = $this->getFileManager()
|
||||
->getPermissionUtils()
|
||||
->getDefaultGroup(true);
|
||||
}
|
||||
|
||||
if (!empty($saveData['defaultPermissions']['user'])) {
|
||||
$data['defaultPermissions']['user'] = $saveData['defaultPermissions']['user'];
|
||||
}
|
||||
|
||||
if (!empty($saveData['defaultPermissions']['group'])) {
|
||||
$data['defaultPermissions']['group'] = $saveData['defaultPermissions']['group'];
|
||||
}
|
||||
|
||||
$data = array_merge($data, $initData);
|
||||
|
||||
$result = $this->saveConfig($data);
|
||||
|
||||
return $result;
|
||||
@@ -305,12 +337,13 @@ class Installer
|
||||
|
||||
public function saveConfig($data)
|
||||
{
|
||||
$config = $this->app->getContainer()->get('config');
|
||||
$configWriter = $this->createConfigWriter();
|
||||
|
||||
$config->set($data);
|
||||
$result = $config->save();
|
||||
$configWriter->setMultiple($data);
|
||||
|
||||
return $result;
|
||||
$configWriter->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function buildDatabase()
|
||||
@@ -446,13 +479,16 @@ class Installer
|
||||
);
|
||||
|
||||
$data = array_intersect_key($preferences, array_flip($permittedSettingList));
|
||||
|
||||
if (empty($data)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$entity = $this->getEntityManager()->getEntity('Preferences', '1');
|
||||
|
||||
if ($entity) {
|
||||
$entity->set($data);
|
||||
|
||||
return $this->getEntityManager()->saveEntity($entity);
|
||||
}
|
||||
|
||||
@@ -479,12 +515,16 @@ class Installer
|
||||
/** END: afterInstall scripts */
|
||||
|
||||
$installerConfig = $this->getInstallerConfig();
|
||||
|
||||
$installerConfig->set('isInstalled', true);
|
||||
|
||||
$installerConfig->save();
|
||||
|
||||
$config = $this->app->getContainer()->get('config');
|
||||
$config->set('isInstalled', true);
|
||||
$result &= $config->save();
|
||||
$configWriter = $this->createConfigWriter();
|
||||
|
||||
$configWriter->set('isInstalled', true);
|
||||
|
||||
$configWriter->save();
|
||||
|
||||
return $result;
|
||||
}
|
||||
@@ -505,10 +545,12 @@ class Installer
|
||||
switch ($fieldName) {
|
||||
case 'defaultCurrency':
|
||||
$settingDefs['defaultCurrency']['options'] = $this->getCurrencyList();
|
||||
|
||||
break;
|
||||
|
||||
case 'language':
|
||||
$settingDefs['language']['options'] = $this->getLanguageList(false);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -526,8 +568,11 @@ class Installer
|
||||
$defaultSettings = $this->getDefaultSettings();
|
||||
|
||||
$normalizedParams = [];
|
||||
|
||||
foreach ($params as $name => $value) {
|
||||
if (!isset($defaultSettings[$name])) continue;
|
||||
if (!isset($defaultSettings[$name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paramDefs = $defaultSettings[$name];
|
||||
$paramType = isset($paramDefs['type']) ? $paramDefs['type'] : 'varchar';
|
||||
@@ -539,23 +584,32 @@ class Installer
|
||||
case 'enum':
|
||||
if (isset($paramDefs['options']) && array_key_exists($value, $paramDefs['options'])) {
|
||||
$normalizedParams[$name] = $value;
|
||||
} else if (array_key_exists('default', $paramDefs)) {
|
||||
$normalizedParams[$name] = $paramDefs['default'];
|
||||
$GLOBALS['log']->warning('Incorrect value ['. $value .'] for Settings parameter ['. $name .']. Use default value ['. $paramDefs['default'] .'].');
|
||||
}
|
||||
else if (array_key_exists('default', $paramDefs)) {
|
||||
$normalizedParams[$name] = $paramDefs['default'];
|
||||
|
||||
$GLOBALS['log']->warning(
|
||||
'Incorrect value ['. $value .'] for Settings parameter ['. $name .']. ' .
|
||||
'Use default value ['. $paramDefs['default'] .'].'
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'bool':
|
||||
$normalizedParams[$name] = (bool) $value;
|
||||
|
||||
break;
|
||||
|
||||
case 'int':
|
||||
$normalizedParams[$name] = (int) $value;
|
||||
|
||||
break;
|
||||
|
||||
case 'varchar':
|
||||
default:
|
||||
$normalizedParams[$name] = $value;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -573,7 +627,8 @@ class Installer
|
||||
}
|
||||
|
||||
if ($optionLabel == $name) {
|
||||
$optionLabel = array();
|
||||
$optionLabel = [];
|
||||
|
||||
foreach ($settingDefs['options'] as $key => $value) {
|
||||
$optionLabel[$value] = $value;
|
||||
}
|
||||
@@ -603,7 +658,8 @@ class Installer
|
||||
|
||||
try {
|
||||
$result &= $sth->execute();
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$GLOBALS['log']->warning('Error executing the query: ' . $query);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace tests\integration\Espo\Currency;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Config\ConfigWriter,
|
||||
};
|
||||
|
||||
class CurrencyTest extends \tests\integration\Core\BaseTestCase
|
||||
{
|
||||
public function testSetCurrencyRates()
|
||||
{
|
||||
$app = $this->createApplication();
|
||||
|
||||
$configWriter = $app->getContainer()->get('injectableFactory')->create(ConfigWriter::class);
|
||||
|
||||
$configWriter->set('currencyList', ['USD', 'EUR']);
|
||||
$configWriter->set('defaultCurrency', 'USD');
|
||||
$configWriter->set('baseCurrency', 'USD');
|
||||
|
||||
$configWriter->set('currencyRates', [
|
||||
'EUR' => 1.2,
|
||||
]);
|
||||
|
||||
$configWriter->save();
|
||||
|
||||
$service = $app->getContainer()->get('serviceFactory')->create('CurrencyRate');
|
||||
|
||||
$newRates = $service->set(
|
||||
(object) [
|
||||
'EUR' => 1.3,
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(1.3, $newRates->EUR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace tests\unit\Espo\Core\Utils;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
Utils\Config\ConfigWriter,
|
||||
Utils\Config\ConfigWriterFileManager,
|
||||
Utils\Config\ConfigWriterHelper,
|
||||
};
|
||||
|
||||
class ConfigWriterTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->fileManager = $this->createMock(ConfigWriterFileManager::class);
|
||||
|
||||
$this->config = $this->createMock(Config::class);
|
||||
|
||||
$this->helper = $this->createMock(ConfigWriterHelper::class);
|
||||
|
||||
$this->configWriter = new ConfigWriter($this->config, $this->fileManager, $this->helper);
|
||||
|
||||
$this->configPath = 'somepath';
|
||||
|
||||
$this->config
|
||||
->expects($this->any())
|
||||
->method('getConfigPath')
|
||||
->willReturn($this->configPath);
|
||||
}
|
||||
|
||||
public function testSave1()
|
||||
{
|
||||
$this->configWriter->set('k1', 'v1');
|
||||
|
||||
$this->configWriter->setMass([
|
||||
'k2' => 'v2',
|
||||
'k3' => 'v3',
|
||||
]);
|
||||
|
||||
$this->configWriter->remove('k4');
|
||||
|
||||
$previousData = [
|
||||
'k3' => 'e3',
|
||||
'k4' => 'e4',
|
||||
'microtime' => 0.0,
|
||||
'cacheTimestamp' => 0,
|
||||
];
|
||||
|
||||
$newData = [
|
||||
'k1' => 'v1',
|
||||
'k2' => 'v2',
|
||||
'k3' => 'v3',
|
||||
'microtime' => 1.0,
|
||||
'cacheTimestamp' => 1,
|
||||
];
|
||||
|
||||
$this->helper
|
||||
->expects($this->once())
|
||||
->method('generateMicrotime')
|
||||
->willReturn(1.0);
|
||||
|
||||
$this->helper
|
||||
->expects($this->once())
|
||||
->method('generateCacheTimestamp')
|
||||
->willReturn(1);
|
||||
|
||||
$this->config
|
||||
->expects($this->once())
|
||||
->method('update');
|
||||
|
||||
$this->fileManager
|
||||
->expects($this->at(0))
|
||||
->method('isFile')
|
||||
->with($this->configPath)
|
||||
->willReturn(true);
|
||||
|
||||
$this->fileManager
|
||||
->expects($this->at(1))
|
||||
->method('getPhpContents')
|
||||
->with($this->configPath)
|
||||
->willReturn($previousData);
|
||||
|
||||
$this->fileManager
|
||||
->expects($this->at(2))
|
||||
->method('putPhpContents')
|
||||
->with($this->configPath, $newData);
|
||||
|
||||
$this->fileManager
|
||||
->expects($this->at(3))
|
||||
->method('getPhpContents')
|
||||
->with($this->configPath)
|
||||
->willReturn($previousData);
|
||||
|
||||
$this->configWriter->save();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user