Compare commits

...

28 Commits
6.0.1 ... 6.0.4

Author SHA1 Message Date
Yuri Kuznetsov
83332178a0 fix acl check command 2020-11-12 15:05:03 +02:00
Yuri Kuznetsov
fb33c2acf1 fix task panel layout 2020-11-10 12:48:40 +02:00
Yuri Kuznetsov
3c5914b5d9 fix text filter by foreign field 2020-11-10 09:22:20 +02:00
Taras Machyshyn
8c48f72a3c Command fix 2020-11-09 15:16:30 +02:00
Taras Machyshyn
a8ce780718 Upgrade fix 2020-11-04 10:23:07 +02:00
Yuri Kuznetsov
31eff86578 fix link search blur 2020-11-03 16:44:20 +02:00
Yuri Kuznetsov
892f9f01f6 export xlsx currency format 2020-11-03 10:43:33 +02:00
Yuri Kuznetsov
860a58847d currency format 10 $ 2020-11-03 10:03:12 +02:00
Yuri Kuznetsov
1ed90d2306 v 2020-11-02 12:55:01 +02:00
Yuri Kuznetsov
aff0b350f3 fix portal runner 2020-11-02 12:54:13 +02:00
Yuri Kuznetsov
651b0be5ed add log to slim 2020-10-31 13:38:11 +02:00
Yuri Kuznetsov
cead33c09d template manager image 2020-10-30 09:26:37 +02:00
Yuri Kuznetsov
80602c084f fix pdf page number 2020-10-29 16:34:49 +02:00
Yuri Kuznetsov
b0420b8b93 fix email folder 2020-10-28 13:19:49 +02:00
Yuri Kuznetsov
b47018cbab hide email menu items in portal 2020-10-28 11:58:44 +02:00
Yuri Kuznetsov
ea69ab6eaf v 2020-10-28 11:12:51 +02:00
Eymen Elkum
92887401b2 address view remove duplicated codes (#1823) 2020-10-28 11:10:52 +02:00
Yuri Kuznetsov
df0bda6324 Merge branch 'hotfix/6.0.3' of github.com:espocrm/espocrm into hotfix/6.0.3 2020-10-28 11:05:37 +02:00
Yuri Kuznetsov
9d67808496 fix tester 2020-10-28 11:02:24 +02:00
Yuri Kuznetsov
cf33a98f20 fix activities and select manager 2020-10-27 17:04:49 +02:00
Yuri Kuznetsov
afbda344ec fix export specific fields 2020-10-27 14:25:47 +02:00
Yuri Kuznetsov
1079597584 fix 2fa 2020-10-27 14:13:00 +02:00
Yuri Kuznetsov
af9b411a4c diff all patch versions 2020-10-27 12:07:39 +02:00
Yuri Kuznetsov
cd49d951d8 v 2020-10-27 11:59:55 +02:00
Yuri Kuznetsov
7d63c114aa fix export all fields 2020-10-27 11:06:52 +02:00
Yuri Kuznetsov
af6f05ba07 formula fix logical operator priority 2020-10-27 10:31:42 +02:00
Yuri Kuznetsov
46f8eb0cdb formula fix logical not 2020-10-27 10:23:03 +02:00
Pomazan Bogdan
c543bb5a5b Update Admin.json (#1814) 2020-10-26 15:36:46 +02:00
32 changed files with 177 additions and 77 deletions

View File

@@ -39,6 +39,7 @@ use Espo\Core\{
Api\ResponseWrapper,
Api\RouteProcessor,
Utils\Route,
Utils\Log,
};
use Slim\{
@@ -63,12 +64,15 @@ class Api implements ApplicationRunner
protected $injectableFactory;
protected $applicationUser;
protected $routeUtil;
protected $log;
public function __construct(InjectableFactory $injectableFactory, ApplicationUser $applicationUser, Route $routeUtil)
{
public function __construct(
InjectableFactory $injectableFactory, ApplicationUser $applicationUser, Route $routeUtil, Log $log
) {
$this->injectableFactory = $injectableFactory;
$this->applicationUser = $applicationUser;
$this->routeUtil = $routeUtil;
$this->log = $log;
}
public function run()
@@ -85,7 +89,7 @@ class Api implements ApplicationRunner
$this->addRoute($slim, $item);
}
$slim->addErrorMiddleware(false, true, true);
$slim->addErrorMiddleware(false, true, true, $this->log);
$slim->run();
}

View File

@@ -368,7 +368,7 @@ class Authentication
if ($code) {
if (!$impl->verifyCode($loggedUser, $code)) {
Result::fail('Code not verified');
return Result::fail('Code not verified');
}
return $result;

View File

@@ -103,7 +103,7 @@ class CommandManager
$skipIndex = 1;
if (isset($argv[0]) && $argv[0] === 'command.php') {
if (isset($argv[0]) && preg_match('/command\.php$/', $argv[0])) {
$skipIndex = 2;
}

View File

@@ -48,37 +48,57 @@ class AclCheck implements Command
$id = $options['id'] ?? null;
$action = $options['action'] ?? null;
if (empty($userId)) return null;
if (empty($scope)) return null;
if (empty($id)) return null;
if (empty($userId)) {
return null;
}
if (empty($scope)) {
return null;
}
if (empty($id)) {
return null;
}
$container = $this->container;
$entityManager = $container->get('entityManager');
$user = $entityManager->getEntity('User', $userId);
if (!$user) return null;
if (!$user) {
return null;
}
if ($user->isPortal()) {
$portalIdList = $user->getLinkMultipleIdList('portals');
foreach ($portalIdList as $portalId) {
$application = new PortalApplication($portalId);
$containerPortal = $application->getContainer();
$entityManager = $containerPortal->get('entityManager');
$user = $entityManager->getEntity('User', $userId);
if (!$user) return null;
if (!$user) {
return null;
}
$result = $this->check($user, $scope, $id, $action, $containerPortal);
if ($result) {
return 'true';
}
}
return null;
}
if ($this->check($user, $scope, $id, $action, $container)) {
return 'true';
}
return null;
}
protected function check($user, $scope, $id, $action, $container)
@@ -86,7 +106,10 @@ class AclCheck implements Command
$entityManager = $container->get('entityManager');
$entity = $entityManager->getEntity($scope, $id);
if (!$entity) return false;
if (!$entity) {
return false;
}
$aclManager = $container->get('aclManager');

View File

@@ -78,7 +78,7 @@ class Upgrade implements Command
$versionInfo = $this->getVersionInfo($toVersion);
$nextVersion = $versionInfo->nextVersion ?? null;
$lastVersion = $infoData->lastVersion ?? null;
$lastVersion = $versionInfo->lastVersion ?? null;
$packageFile = $this->getPackageFile($params, $versionInfo);

View File

@@ -38,6 +38,6 @@ class NotType extends BaseFunction
{
public function process(ArgumentList $args)
{
return !$this->evaluate($args);
return !$this->evaluate($args[0]);
}
}

View File

@@ -40,7 +40,8 @@ class Parser
{
protected $priorityList = [
['='],
['||', '&&'],
['||'],
['&&'],
['==', '!=', '>', '<', '>=', '<='],
['+', '-'],
['*', '/', '%'],

View File

@@ -120,11 +120,11 @@ class Tcpdf extends \TCPDF
$html = $this->headerHtml;
if ($this->useGroupNumbers) {
$html = str_replace('{pageNumber}', '{:png:}', $html);
$html = str_replace('{pageAbsoluteNumber}', '{:pnp:}', $html);
$html = str_replace('{pageNumber}', '{{:png:}}', $html);
$html = str_replace('{pageAbsoluteNumber}', '{{:pnp:}}', $html);
} else {
$html = str_replace('{pageNumber}', '{:pnp:}', $html);
$html = str_replace('{pageAbsoluteNumber}', '{:pnp:}', $html);
$html = str_replace('{pageNumber}', '{{:pnp:}', $html);
$html = str_replace('{pageAbsoluteNumber}', '{{:pnp:}}', $html);
}
if ($this->isUnicodeFont()) {
@@ -148,11 +148,11 @@ class Tcpdf extends \TCPDF
$html = $this->footerHtml;
if ($this->useGroupNumbers) {
$html = str_replace('{pageNumber}', '{:png:}', $html);
$html = str_replace('{pageAbsoluteNumber}', '{:pnp:}', $html);
$html = str_replace('{pageNumber}', '{{:png:}}', $html);
$html = str_replace('{pageAbsoluteNumber}', '{{:pnp:}}', $html);
} else {
$html = str_replace('{pageNumber}', '{:pnp:}', $html);
$html = str_replace('{pageAbsoluteNumber}', '{:pnp:}', $html);
$html = str_replace('{pageNumber}', '{{:pnp:}}', $html);
$html = str_replace('{pageAbsoluteNumber}', '{{:pnp:}}', $html);
}
if ($this->isUnicodeFont()) {

View File

@@ -34,12 +34,13 @@ use Espo\Core\{
InjectableFactory,
ApplicationUser,
Portal\Utils\Route,
Utils\Log,
};
class Api extends ApiBase
{
public function __construct(InjectableFactory $injectableFactory, ApplicationUser $applicationUser, Route $routeUtil)
public function __construct(InjectableFactory $injectableFactory, ApplicationUser $applicationUser, Route $routeUtil, Log $log)
{
parent::__construct($injectableFactory, $applicationUser, $routeUtil);
parent::__construct($injectableFactory, $applicationUser, $routeUtil, $log);
}
}

View File

@@ -2506,6 +2506,14 @@ class SelectManager
$attributeType = $seed->getAttributeType($foreignField);
} else {
$attributeType = $seed->getAttributeType($field);
if ($attributeType === 'foreign') {
$link = $seed->getAttributeParam($field, 'relation');
if ($link) {
$this->addLeftJoin($link, $result);
}
}
}
if ($attributeType === 'int') {
@@ -2686,11 +2694,6 @@ class SelectManager
$selectParams1['havingClause'][] = $selectParams2['havingClause'];
}
if (!empty($selectParams2['leftJoins'])) {
foreach ($selectParams2['leftJoins'] as $item) {
$this->addLeftJoin($item, $selectParams1);
}
}
if (!empty($selectParams2['joins'])) {
foreach ($selectParams2['joins'] as $item) {
@@ -2698,6 +2701,16 @@ class SelectManager
}
}
if (!empty($selectParams2['leftJoins'])) {
foreach ($selectParams2['leftJoins'] as $item) {
if ($this->hasJoin($item, $selectParams1)) {
continue;
}
$this->addLeftJoin($item, $selectParams1);
}
}
if (isset($selectParams2['select'])) {
$selectParams1['select'] = $selectParams2['select'];
}

View File

@@ -873,7 +873,7 @@ class Activities implements
$service->handleListParams($params);
$selectParams = $selectManager->getSelectParams($params, false, true);
$selectParams = $selectManager->getSelectParams($params, false, true, true);
$offset = $selectParams['offset'];
$limit = $selectParams['limit'];

View File

@@ -144,7 +144,8 @@
},
"currencyFormat": {
"1": "10 USD",
"2": "$10"
"2": "$10",
"3": "10 $"
},
"personNameFormat": {
"firstLast": "First Last",

View File

@@ -185,7 +185,7 @@
"uninstallConfirmation": "Ви впевнені, що хочете видалити розширення?",
"cronIsNotConfigured": "Заплановані завдання не працюють. Отже, вхідні електронні листи, сповіщення та нагадування не працюють. Будь ласка, дотримуйтесь інструкцій (https://www.espocrm.com/documentation/administration/server-configuration/#user-content-setup-a-crontab), щоб налаштувати cron job.",
"newExtensionVersionIsAvailable": "Нова {extensionName} версія {latestVersion} доступна.",
"upgradeVersion": "EspoCRM буде оновлено до версії **{версія}**. Будьте терплячі, оскільки це може зайняти деякий час.",
"upgradeVersion": "EspoCRM буде оновлено до версії **{version}**. Будьте терплячі, оскільки це може зайняти деякий час.",
"upgradeDone": "EspoCRM оновлено до версії **{version}**.",
"downloadUpgradePackage": "Завантажте апгрейд [звідси]({url})",
"upgradeInfo": "Перегляньте [документацію]({url}) про те, як оновити EspoCRM.\n",
@@ -257,4 +257,4 @@
"noteStatus": "Повідомлення про оновлення статусу",
"passwordChangeLink": "Посилання на зміну паролю"
}
}
}

View File

@@ -65,7 +65,10 @@
"parent": false
},
"EmailFolder": {
"assignedUser": false
"assignedUser": {
"read": "yes",
"edit": "no"
}
},
"Email": {
"inboundEmails": false,

View File

@@ -53,11 +53,21 @@
{
"label":"Folders",
"link":"#EmailFolder",
"configCheck": "!emailFoldersDisabled"
"configCheck": "!emailFoldersDisabled",
"accessDataList": [
{
"inPortalDisabled": true
}
]
},
{
"label":"Filters",
"link":"#EmailFilter"
"link":"#EmailFilter",
"accessDataList": [
{
"inPortalDisabled": true
}
]
}
]
},

View File

@@ -496,7 +496,7 @@
},
"currencyFormat": {
"type": "enumInt",
"options": [1, 2]
"options": [1, 2, 3]
},
"currencyDecimalPlaces": {
"type": "int",

View File

@@ -162,8 +162,6 @@ class Email extends \Espo\Core\Select\SelectManager
$result['whereClause'][] = [
'usersMiddle.userId' => $this->getUser()->id
];
$this->addUsersColumns($result);
}
protected function boolFilterOnlyMy(&$result)

View File

@@ -44,6 +44,10 @@ class Attachment extends Record
protected $inlineAttachmentFieldTypeList = ['wysiwyg'];
protected $adminOnlyHavingInlineAttachmentsEntityTypeList = [
'TemplateManager',
];
protected $imageTypeList = [
'image/png',
'image/jpeg',
@@ -160,12 +164,24 @@ class Attachment extends Record
protected function checkAttachmentField($relatedEntityType, $field, $role = 'Attachment')
{
if (
$this->getUser()->isAdmin()
&&
$role === 'Inline Attachment'
&&
in_array($relatedEntityType, $this->adminOnlyHavingInlineAttachmentsEntityTypeList)
) {
return;
}
$fieldType = $this->getMetadata()->get(['entityDefs', $relatedEntityType, 'fields', $field, 'type']);
if (!$fieldType) {
throw new Error("Field '{$field}' does not exist.");
}
$attachmentFieldTypeListParam = lcfirst(str_replace(' ', '', $role)) . 'FieldTypeList';
if (!in_array($fieldType, $this->$attachmentFieldTypeListParam)) {
throw new Error("Field type '{$fieldType}' is not allowed for {$role}.");
}

View File

@@ -131,6 +131,8 @@ class Export
$collection = null;
$exportAllFields = !array_key_exists('fieldList', $params);
if (array_key_exists('collection', $params)) {
$collection = $params['collection'];
} else {
@@ -162,9 +164,7 @@ class Export
}
}
if (isset($searchParams['select']) && is_string($searchParams['select'])) {
$searchParams['select'] = explode(',', $searchParams['select']);
}
unset($searchParams['select']);
$selectParams = $selectManager->getSelectParams($searchParams, true, true, true);
}
@@ -218,15 +218,12 @@ class Export
}
}
if (!array_key_exists('fieldList', $params)) {
$exportAllFields = true;
if ($exportAllFields) {
$fieldDefs = $this->metadata->get(['entityDefs', $this->entityType, 'fields'], []);
$fieldList = array_keys($fieldDefs);
array_unshift($fieldList, 'id');
} else {
$exportAllFields = false;
$fieldList = $params['fieldList'];
}

View File

@@ -350,21 +350,24 @@ class Xlsx
} else if ($type == 'currency') {
if (array_key_exists($name.'Currency', $row) && array_key_exists($name, $row)) {
$sheet->setCellValue("$col$rowNumber", $row[$name] ? $row[$name] : '');
$currency = $row[$name . 'Currency'];
$currencySymbol = $this->getMetadata()->get(['app', 'currency', 'symbolMap', $currency], '');
$sheet->getStyle("$col$rowNumber")
->getNumberFormat()
->setFormatCode('[$'.$currencySymbol.'-409]#,##0.00;-[$'.$currencySymbol.'-409]#,##0.00');
->setFormatCode(
$this->getCurrencyFormatCode($currency)
);
}
} else if ($type == 'currencyConverted') {
if (array_key_exists($name, $row)) {
$currency = $this->getConfig()->get('defaultCurrency');
$currencySymbol = $this->getMetadata()->get(['app', 'currency', 'symbolMap', $currency], '');
$sheet->getStyle("$col$rowNumber")
->getNumberFormat()
->setFormatCode('[$'.$currencySymbol.'-409]#,##0.00;-[$'.$currencySymbol.'-409]#,##0.00');
->setFormatCode(
$this->getCurrencyFormatCode($currency)
);
$sheet->setCellValue("$col$rowNumber", $row[$name] ? $row[$name] : '');
}
@@ -663,4 +666,17 @@ class Xlsx
return $xlsx;
}
protected function getCurrencyFormatCode(string $currency) : string
{
$currencySymbol = $this->getMetadata()->get(['app', 'currency', 'symbolMap', $currency], '');
$currencyFormat = $this->getConfig()->get('currencyFormat') ?? 2;
if ($currencyFormat == 3) {
return '#,##0.00_-"' . $currencySymbol . '"';
}
return '[$'.$currencySymbol.'-409]#,##0.00;-[$'.$currencySymbol.'-409]#,##0.00';
}
}

View File

@@ -68,14 +68,14 @@ define('crm:views/record/panels/tasks', 'views/record/panels/relationship', func
name: 'name',
link: true,
},
{
name: 'isOverdue'
}
],
[
{
name: 'isOverdue'
},
{name: 'assignedUser'},
{name: 'status'},
{name: 'dateEnd'},
{name: 'status'},
]
]
},

View File

@@ -0,0 +1,5 @@
{{#if isNotEmpty}}
{{value}} {{currencySymbol}}
{{else}}
{{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}}
{{/if}}

View File

@@ -0,0 +1,3 @@
{{#if isNotEmpty}}
<span title="{{currencySymbol}}{{value}}">{{value}} {{currencySymbol}}</span>
{{/if}}

View File

@@ -356,11 +356,6 @@ define('views/fields/address', 'views/fields/base', function (Dep) {
this.$country.attr('autocomplete', 'espo-country');
}
this.controlStreetTextareaHeight();
this.$street.on('input', function (e) {
this.controlStreetTextareaHeight();
}.bind(this));
var cityList = this.getConfig().get('addressCityList') || [];
if (cityList.length) {
this.$city.autocomplete({
@@ -394,11 +389,6 @@ define('views/fields/address', 'views/fields/base', function (Dep) {
this.$city.attr('autocomplete', 'espo-city');
}
this.controlStreetTextareaHeight();
this.$street.on('input', function (e) {
this.controlStreetTextareaHeight();
}.bind(this));
var stateList = this.getConfig().get('addressStateList') || [];
if (stateList.length) {
this.$state.autocomplete({

View File

@@ -26,7 +26,7 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
Espo.define('views/fields/currency', 'views/fields/float', function (Dep) {
define('views/fields/currency', 'views/fields/float', function (Dep) {
return Dep.extend({
@@ -40,12 +40,16 @@ Espo.define('views/fields/currency', 'views/fields/float', function (Dep) {
detailTemplate2: 'fields/currency/detail-2',
detailTemplate3: 'fields/currency/detail-3',
listTemplate: 'fields/currency/list',
listTemplate1: 'fields/currency/list-1',
listTemplate2: 'fields/currency/list-2',
listTemplate3: 'fields/currency/list-3',
detailTemplateNoCurrency: 'fields/currency/detail-no-currency',
maxDecimalPlaces: 3,

View File

@@ -253,10 +253,6 @@ define('views/fields/link-parent', 'views/fields/base', function (Dep) {
e.currentTarget.value = this.model.get(this.nameName);
}
}.bind(this));
} else if (this.mode == 'search') {
this.$elementName.on('blur', function (e) {
e.currentTarget.value = '';
}.bind(this));
}
if (!this.autocompleteDisabled) {

View File

@@ -260,10 +260,6 @@ define('views/fields/link', 'views/fields/base', function (Dep) {
e.currentTarget.value = this.model.get(this.nameName);
}
}.bind(this));
} else if (this.mode == 'search') {
this.$elementName.on('blur', function (e) {
e.currentTarget.value = '';
}.bind(this));
}
var $elementName = this.$elementName;

View File

@@ -93,7 +93,12 @@ class Diff
if (!~tag.indexOf('beta') && !~tag.indexOf('alpha')) {
versionFromList.push(tag);
break;
var patchVersionNumberI = tag.split('.')[2];
if (patchVersionNumberI === '0') {
break;
}
}
}
}

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "espocrm",
"version": "6.0.1",
"version": "6.0.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "espocrm",
"version": "6.0.1",
"version": "6.0.4",
"description": "",
"main": "index.php",
"repository": {

View File

@@ -146,7 +146,7 @@ class Tester
{
$configData = $this->getTestConfigData();
if ($configData[$optionName] === $data) {
if (array_key_exists($optionName, $configData) && $configData[$optionName] === $data) {
return true;
}

View File

@@ -434,4 +434,22 @@ class EvaluatorTest extends \PHPUnit\Framework\TestCase
$this->assertEquals('test', $result);
}
public function testNegate1()
{
$expression = "!string\contains('hello', 'test')";
$result = $this->evaluator->process($expression);
$this->assertTrue($result);
}
public function testLogicalProority()
{
$expression = "0 && 0 || 1";
$result = $this->evaluator->process($expression);
$this->assertTrue($result);
}
}