From 8bafcded509ececb12ac06befee3a04a0c25bf72 Mon Sep 17 00:00:00 2001
From: yuri
Date: Sat, 28 Sep 2019 11:20:42 +0300
Subject: [PATCH 01/44] portal role scope
---
.../Espo/Resources/metadata/scopes/PortalRole.json | 7 +++++++
application/Espo/Resources/metadata/scopes/Role.json | 8 +++++++-
2 files changed, 14 insertions(+), 1 deletion(-)
create mode 100644 application/Espo/Resources/metadata/scopes/PortalRole.json
diff --git a/application/Espo/Resources/metadata/scopes/PortalRole.json b/application/Espo/Resources/metadata/scopes/PortalRole.json
new file mode 100644
index 0000000000..a5280171da
--- /dev/null
+++ b/application/Espo/Resources/metadata/scopes/PortalRole.json
@@ -0,0 +1,7 @@
+{
+ "entity": true,
+ "layouts": false,
+ "tab": false,
+ "acl": false,
+ "customizable": false
+}
diff --git a/application/Espo/Resources/metadata/scopes/Role.json b/application/Espo/Resources/metadata/scopes/Role.json
index d22f18db45..a5280171da 100644
--- a/application/Espo/Resources/metadata/scopes/Role.json
+++ b/application/Espo/Resources/metadata/scopes/Role.json
@@ -1 +1,7 @@
-{"entity":true,"layouts":false,"tab":false,"acl":false,"customizable":false}
+{
+ "entity": true,
+ "layouts": false,
+ "tab": false,
+ "acl": false,
+ "customizable": false
+}
From 68615ba8bbc7b985d2fbd547ff61a846c8066ef0 Mon Sep 17 00:00:00 2001
From: yuri
Date: Sat, 28 Sep 2019 11:33:20 +0300
Subject: [PATCH 02/44] language hide labels by acl
---
application/Espo/Controllers/I18n.php | 8 +-
application/Espo/Services/Language.php | 133 +++++++++++++++++++++++++
2 files changed, 139 insertions(+), 2 deletions(-)
create mode 100644 application/Espo/Services/Language.php
diff --git a/application/Espo/Controllers/I18n.php b/application/Espo/Controllers/I18n.php
index cde4381417..ea8f5a1f52 100644
--- a/application/Espo/Controllers/I18n.php
+++ b/application/Espo/Controllers/I18n.php
@@ -33,9 +33,13 @@ class I18n extends \Espo\Core\Controllers\Base
{
public function actionRead($params, $data, $request)
{
- if ($request->get('default')) {
+ $default = $request->get('default') === 'true';
+
+ return $this->getServiceFactory()->create('Language')->getDataForFrontend($default);
+
+ /*if ($request->get('default')) {
return $this->getContainer()->get('defaultLanguage')->getAll();
}
- return $this->getContainer()->get('language')->getAll();
+ return $this->getContainer()->get('language')->getAll();*/
}
}
diff --git a/application/Espo/Services/Language.php b/application/Espo/Services/Language.php
new file mode 100644
index 0000000000..0b43d4be8a
--- /dev/null
+++ b/application/Espo/Services/Language.php
@@ -0,0 +1,133 @@
+addDependency('container');
+ $this->addDependency('metadata');
+ $this->addDependency('acl');
+ }
+
+ protected function getMetadata()
+ {
+ return $this->getInjection('metadata');
+ }
+
+ protected function getAcl()
+ {
+ return $this->getInjection('acl');
+ }
+
+ protected function getDefaultLanguage()
+ {
+ return $this->getInjection('container')->get('defaultLanguage');
+ }
+
+ protected function getLanguage()
+ {
+ return $this->getInjection('container')->get('language');
+ }
+
+ public function getDataForFrontend(bool $default = false)
+ {
+ if ($default) {
+ $languageObj = $this->getDefaultLanguage();
+ } else {
+ $languageObj = $this->getLanguage();
+ }
+ $data = $languageObj->getAll();
+
+ if ($this->getUser()->isSystem()) {
+ unset($data['Global']['scopeNames']);
+ unset($data['Global']['scopeNamesPlural']);
+ unset($data['Global']['dashlets']);
+ unset($data['Global']['links']);
+ unset($data['Global']['fields']);
+ unset($data['Global']['options']);
+
+ foreach ($data as $k => $item) {
+ if (in_array($k, ['Global', 'User'])) continue;
+ unset($data[$k]);
+ }
+ unset($data['User']['fields']);
+ unset($data['User']['links']);
+ unset($data['User']['options']);
+ unset($data['User']['filters']);
+ unset($data['User']['presetFilters']);
+ unset($data['User']['boolFilters']);
+ unset($data['User']['tooltips']);
+ } else {
+ $scopeList = array_keys($this->getMetadata()->get(['scopes'], []));
+
+ foreach ($scopeList as $scope) {
+ if (!$this->getAcl()->check($scope)) {
+ unset($data[$scope]);
+ unset($data['Global']['scopeNames'][$scope]);
+ unset($data['Global']['scopeNamesPlural'][$scope]);
+ } else {
+ foreach ($this->getAcl()->getScopeForbiddenFieldList($scope) as $field) {
+ if (isset($data[$scope]['fields'])) unset($data[$scope]['fields'][$field]);
+ if (isset($data[$scope]['options'])) unset($data[$scope]['options'][$field]);
+ if (isset($data[$scope]['links'])) unset($data[$scope]['links'][$field]);
+ }
+ }
+ }
+
+ if (!$this->getUser()->isAdmin()) {
+ unset($data['Admin']);
+ unset($data['LayoutManager']);
+ unset($data['EntityManager']);
+ unset($data['FieldManager']);
+ unset($data['Settings']);
+ unset($data['ApiUser']);
+ unset($data['DynamicLogic']);
+
+ $data['Settings'] = [
+ 'options' => [
+ 'weekStart' => $languageObj->get(['Settings', 'options', 'weekStart']),
+ ],
+ ];
+ $data['Admin'] = [
+ 'messages' => [
+ 'userHasNoEmailAddress' => $languageObj->translate('userHasNoEmailAddress', 'messages', 'Admin'),
+ ],
+ ];
+ $data['User']['fields']['password'] = $languageObj->translate('password', 'fields', 'User');
+ $data['User']['fields']['passwordConfirm'] = $languageObj->translate('passwordConfirm', 'fields', 'User');
+ }
+ }
+
+ return $data;
+ }
+}
From 4b25456acdf07d961ab2b36cff94763fc79b7a46 Mon Sep 17 00:00:00 2001
From: yuri
Date: Sat, 28 Sep 2019 11:55:31 +0300
Subject: [PATCH 03/44] fix teams select manager
---
application/Espo/SelectManagers/Team.php | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/application/Espo/SelectManagers/Team.php b/application/Espo/SelectManagers/Team.php
index b0119849d5..a2c4d1f175 100644
--- a/application/Espo/SelectManagers/Team.php
+++ b/application/Espo/SelectManagers/Team.php
@@ -43,6 +43,10 @@ class Team extends \Espo\Core\SelectManagers\Base
protected function accessOnlyTeam(&$result)
{
- $this->boolFilterOnlyMy($result);
+ $this->setDistinct(true, $result);
+ $this->addLeftJoin(['users', 'usersOnlyMyAccess'], $result);
+ $result['whereClause'][] = [
+ 'usersOnlyMyAccessMiddle.userId' => $this->getUser()->id
+ ];
}
}
From 1e4e8b3fcfd36f923be21b28de03f9c68b0c4253 Mon Sep 17 00:00:00 2001
From: yuri
Date: Sat, 28 Sep 2019 12:07:08 +0300
Subject: [PATCH 04/44] follow access
---
application/Espo/Hooks/Common/Stream.php | 6 ++---
application/Espo/Services/Record.php | 2 ++
application/Espo/Services/Stream.php | 32 ++++++++++++++++++++----
3 files changed, 32 insertions(+), 8 deletions(-)
diff --git a/application/Espo/Hooks/Common/Stream.php b/application/Espo/Hooks/Common/Stream.php
index 73e45c809c..885f2a4681 100644
--- a/application/Espo/Hooks/Common/Stream.php
+++ b/application/Espo/Hooks/Common/Stream.php
@@ -35,11 +35,11 @@ class Stream extends \Espo\Core\Hooks\Base
{
protected $streamService = null;
- protected $auditedFieldsCache = array();
+ protected $auditedFieldsCache = [];
- protected $hasStreamCache = array();
+ protected $hasStreamCache = [];
- protected $isLinkObservableInStreamCache = array();
+ protected $isLinkObservableInStreamCache = [];
protected $statusFields = null;
diff --git a/application/Espo/Services/Record.php b/application/Espo/Services/Record.php
index a502882d49..8cc82d5fc3 100644
--- a/application/Espo/Services/Record.php
+++ b/application/Espo/Services/Record.php
@@ -1857,6 +1857,7 @@ class Record extends \Espo\Core\Services\Base
public function follow($id, $userId = null)
{
$entity = $this->getRepository()->get($id);
+ if (!$entity) throw new NotFoundSilent();
if (!$this->getAcl()->check($entity, 'stream')) {
throw new Forbidden();
@@ -1872,6 +1873,7 @@ class Record extends \Espo\Core\Services\Base
public function unfollow($id, $userId = null)
{
$entity = $this->getRepository()->get($id);
+ if (!$entity) throw new NotFoundSilent();
if (empty($userId)) {
$userId = $this->getUser()->id;
diff --git a/application/Espo/Services/Stream.php b/application/Espo/Services/Stream.php
index f7665710f1..a89d9cac06 100644
--- a/application/Espo/Services/Stream.php
+++ b/application/Espo/Services/Stream.php
@@ -143,7 +143,8 @@ class Stream extends \Espo\Core\Services\Base
foreach ($userIdList as $i => $userId) {
$user = $this->getEntityManager()->getEntity('User', $userId);
- if (!$user){
+ if (!$user) {
+ unset($userIdList[$i]);
continue;
}
if (!$this->getAclManager()->check($user, $entity, 'stream')) {
@@ -165,10 +166,10 @@ class Stream extends \Espo\Core\Services\Base
$this->followEntityMass($entity, $userIdList);
- $noteList = $this->getEntityManager()->getRepository('Note')->where(array(
+ $noteList = $this->getEntityManager()->getRepository('Note')->where([
'parentType' => $entityType,
'parentId' => $entityId
- ))->order('number', 'ASC')->find();
+ ])->order('number', 'ASC')->find();
foreach ($noteList as $note) {
$this->getNotificationService()->notifyAboutNote($userIdList, $note);
@@ -197,9 +198,9 @@ class Stream extends \Espo\Core\Services\Base
return false;
}
- public function followEntityMass(Entity $entity, array $sourceUserIdList)
+ public function followEntityMass(Entity $entity, array $sourceUserIdList, bool $skipAclCheck = false)
{
- if (!$this->getMetadata()->get('scopes.' . $entity->getEntityName() . '.stream')) {
+ if (!$this->getMetadata()->get(['scopes', $entity->getEntityType(), 'stream'])) {
return false;
}
@@ -213,6 +214,27 @@ class Stream extends \Espo\Core\Services\Base
$userIdList = array_unique($userIdList);
+ if (!$skipAclCheck) {
+ foreach ($userIdList as $i => $userId) {
+ $user = $this->getEntityManager()->getRepository('User')
+ ->select(['id', 'type', 'isActive'])
+ ->where([
+ 'id' => $userId,
+ 'isActive' => true,
+ ])->findOne();
+
+ if (!$user) {
+ unset($userIdList[$i]);
+ continue;
+ }
+
+ if (!$this->getAclManager()->check($user, $entity, 'stream')) {
+ unset($userIdList[$i]);
+ }
+ }
+ $userIdList = array_values($userIdList);
+ }
+
if (empty($userIdList)) {
return;
}
From 882eeffdd5f4283559a1933b45964f1b6dcadd3f Mon Sep 17 00:00:00 2001
From: yuri
Date: Sat, 28 Sep 2019 12:16:17 +0300
Subject: [PATCH 05/44] modal backdrop fix
---
client/src/ui.js | 12 +++++++++++-
client/src/views/modal.js | 2 +-
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/client/src/ui.js b/client/src/ui.js
index 5f021669a4..0fc2fcb343 100644
--- a/client/src/ui.js
+++ b/client/src/ui.js
@@ -77,6 +77,10 @@ define('ui', [], function () {
this.id = 'dialog-' + Math.floor((Math.random() * 100000));
+ if (typeof this.backdrop === 'undefined') {
+ this.backdrop = 'static';
+ }
+
this.contents = '';
if (this.header) {
var headerClassName = '';
@@ -340,13 +344,19 @@ define('ui', [], function () {
Dialog: Dialog,
confirm: function (message, o, callback, context) {
+ o = o || {};
var confirmText = o.confirmText;
var cancelText = o.cancelText;
var confirmStyle = o.confirmStyle || 'danger';
+ var backdrop = o.backdrop;
+ if (typeof backdrop === 'undefined') {
+ backdrop = false;
+ }
+
return new Promise(function (resolve) {
var dialog = new Dialog({
- backdrop: ('backdrop' in o) ? o.backdrop : false,
+ backdrop: backdrop,
header: false,
className: 'dialog-confirm',
body: '' + message + '',
diff --git a/client/src/views/modal.js b/client/src/views/modal.js
index 52a3a968ba..7109fb5a9f 100644
--- a/client/src/views/modal.js
+++ b/client/src/views/modal.js
@@ -80,7 +80,7 @@ define('views/modal', 'view', function (Dep) {
this.options = this.options || {};
- this.backdrop = this.options.backdrop;
+ this.backdrop = this.options.backdrop || this.backdrop;
this.setSelector(this.containerSelector);
From 6e1d905db9ad78106fb3b9b4deb0bb51255dae5c Mon Sep 17 00:00:00 2001
From: yuri
Date: Sat, 28 Sep 2019 12:19:19 +0300
Subject: [PATCH 06/44] team role by default
---
application/Espo/Resources/metadata/app/acl.json | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/application/Espo/Resources/metadata/app/acl.json b/application/Espo/Resources/metadata/app/acl.json
index 711ab8ae6c..b7a5d5ea20 100644
--- a/application/Espo/Resources/metadata/app/acl.json
+++ b/application/Espo/Resources/metadata/app/acl.json
@@ -105,6 +105,10 @@
"read": "own",
"edit": "no"
},
+ "Team": {
+ "read": "team",
+ "edit": "no"
+ },
"Import": false,
"Webhook": false
},
From f2c769a0628d33188132cb8cd644e187323c610d Mon Sep 17 00:00:00 2001
From: yuri
Date: Sat, 28 Sep 2019 12:23:59 +0300
Subject: [PATCH 07/44] fix acl
---
application/Espo/Resources/metadata/app/acl.json | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/application/Espo/Resources/metadata/app/acl.json b/application/Espo/Resources/metadata/app/acl.json
index b7a5d5ea20..82956a4d8d 100644
--- a/application/Espo/Resources/metadata/app/acl.json
+++ b/application/Espo/Resources/metadata/app/acl.json
@@ -106,8 +106,7 @@
"edit": "no"
},
"Team": {
- "read": "team",
- "edit": "no"
+ "read": "team"
},
"Import": false,
"Webhook": false
From 3478aa772c30646f5b6b46ffeac302412b077837 Mon Sep 17 00:00:00 2001
From: yuri
Date: Sat, 28 Sep 2019 13:04:48 +0300
Subject: [PATCH 08/44] metadata hide by acl
---
application/Espo/Controllers/Metadata.php | 2 +-
application/Espo/Services/App.php | 3 +-
application/Espo/Services/Metadata.php | 92 +++++++++++++++++++
client/src/app.js | 2 +-
client/src/model.js | 8 +-
.../src/views/preferences/fields/time-zone.js | 5 +-
client/src/views/site/navbar.js | 3 +
7 files changed, 105 insertions(+), 10 deletions(-)
create mode 100644 application/Espo/Services/Metadata.php
diff --git a/application/Espo/Controllers/Metadata.php b/application/Espo/Controllers/Metadata.php
index 2d7980b4a7..e7455ab7f4 100644
--- a/application/Espo/Controllers/Metadata.php
+++ b/application/Espo/Controllers/Metadata.php
@@ -36,7 +36,7 @@ class Metadata extends \Espo\Core\Controllers\Base
public function actionRead($params, $data)
{
- return $this->getMetadata()->getAllForFrontend();
+ return $this->getServiceFactory()->create('Metadata')->getDataForFrontend();
}
public function getActionGet($params, $data, $request)
diff --git a/application/Espo/Services/App.php b/application/Espo/Services/App.php
index 5fc2261903..e495e0a365 100644
--- a/application/Espo/Services/App.php
+++ b/application/Espo/Services/App.php
@@ -116,7 +116,8 @@ class App extends \Espo\Core\Services\Base
'maxUploadSize' => $this->getMaxUploadSize() / 1024.0 / 1024.0,
'templateEntityTypeList' => $this->getTemplateEntityTypeList(),
'isRestrictedMode' => $this->getConfig()->get('restrictedMode'),
- 'passwordChangeForNonAdminDisabled' => $this->getConfig()->get('authenticationMethod', 'Espo') !== 'Espo'
+ 'passwordChangeForNonAdminDisabled' => $this->getConfig()->get('authenticationMethod', 'Espo') !== 'Espo',
+ 'timeZoneList' => $this->getMetadata()->get(['entityDefs', 'Settings', 'fields', 'timeZone', 'options'], []),
]
];
}
diff --git a/application/Espo/Services/Metadata.php b/application/Espo/Services/Metadata.php
new file mode 100644
index 0000000000..935765c9af
--- /dev/null
+++ b/application/Espo/Services/Metadata.php
@@ -0,0 +1,92 @@
+addDependency('metadata');
+ $this->addDependency('acl');
+ }
+
+ protected function getMetadata()
+ {
+ return $this->getInjection('metadata');
+ }
+
+ protected function getAcl()
+ {
+ return $this->getInjection('acl');
+ }
+
+ protected function getDefaultLanguage()
+ {
+ return $this->getInjection('container')->get('defaultLanguage');
+ }
+
+ protected function getLanguage()
+ {
+ return $this->getInjection('container')->get('language');
+ }
+
+ public function getDataForFrontend()
+ {
+ $data = $this->getMetadata()->getAllForFrontend();
+
+ if (!$this->getUser()->isAdmin()) {
+ $scopeList = array_keys($this->getMetadata()->get(['scopes'], []));
+ foreach ($scopeList as $scope) {
+ if (!$this->getAcl()->check($scope)) {
+ unset($data->entityDefs->$scope);
+ unset($data->clientDefs->$scope);
+ unset($data->entityAcl->$scope);
+ unset($data->scopes->$scope);
+ }
+ }
+
+ unset($data->entityDefs->Settings);
+
+ $dashletList = array_keys($this->getMetadata()->get(['dashlets'], []));
+
+ foreach ($dashletList as $item) {
+ $aclScope = $this->getMetadata()->get(['dashlets', $item, 'aclScope']);
+ if ($aclScope && !$this->getAcl()->check($aclScope)) {
+ unset($data->dashlets->$item);
+ }
+ }
+
+ unset($data->authenticationMethods);
+ unset($data->formula);
+ }
+
+ return $data;
+ }
+}
diff --git a/client/src/app.js b/client/src/app.js
index 773cb47d7f..bcccbcb40f 100644
--- a/client/src/app.js
+++ b/client/src/app.js
@@ -225,7 +225,7 @@ define(
this.fieldManager.defs = this.metadata.get('fields');
this.fieldManager.metadata = this.metadata;
- this.settings.defs = this.metadata.get('entityDefs.Settings');
+ this.settings.defs = this.metadata.get('entityDefs.Settings') || {};
this.user.defs = this.metadata.get('entityDefs.User');
this.preferences.defs = this.metadata.get('entityDefs.Preferences');
this.viewHelper.layoutManager.userId = this.user.id;
diff --git a/client/src/model.js b/client/src/model.js
index 06f9d245de..690f63c019 100644
--- a/client/src/model.js
+++ b/client/src/model.js
@@ -178,14 +178,14 @@ define('model', [], function () {
},
getFieldType: function (field) {
- if (('defs' in this) && ('fields' in this.defs) && (field in this.defs.fields)) {
+ if (this.defs && this.defs.fields && (field in this.defs.fields)) {
return this.defs.fields[field].type || null;
}
return null;
},
getFieldParam: function (field, param) {
- if (('defs' in this) && ('fields' in this.defs) && (field in this.defs.fields)) {
+ if (this.defs && this.defs.fields && (field in this.defs.fields)) {
if (param in this.defs.fields[field]) {
return this.defs.fields[field][param];
}
@@ -194,14 +194,14 @@ define('model', [], function () {
},
getLinkType: function (link) {
- if (('defs' in this) && ('links' in this.defs) && (link in this.defs.links)) {
+ if (this.defs && this.defs.links && (link in this.defs.links)) {
return this.defs.links[link].type || null;
}
return null;
},
getLinkParam: function (link, param) {
- if (('defs' in this) && ('links' in this.defs) && (link in this.defs.links)) {
+ if (this.defs && this.defs.links && (link in this.defs.links)) {
if (param in this.defs.links[link]) {
return this.defs.links[link][param];
}
diff --git a/client/src/views/preferences/fields/time-zone.js b/client/src/views/preferences/fields/time-zone.js
index 3368c2d21a..e298856a12 100644
--- a/client/src/views/preferences/fields/time-zone.js
+++ b/client/src/views/preferences/fields/time-zone.js
@@ -26,12 +26,12 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
-Espo.define('views/preferences/fields/time-zone', 'views/fields/enum', function (Dep) {
+define('views/preferences/fields/time-zone', 'views/fields/enum', function (Dep) {
return Dep.extend({
setupOptions: function () {
- this.params.options = Espo.Utils.clone(this.getConfig().getFieldParam('timeZone', 'options') || []);
+ this.params.options = Espo.Utils.clone(this.getHelper().getAppParam('timeZoneList')) || [];
this.params.options.unshift('');
this.translatedOptions = this.translatedOptions || {};
@@ -39,5 +39,4 @@ Espo.define('views/preferences/fields/time-zone', 'views/fields/enum', function
},
});
-
});
diff --git a/client/src/views/site/navbar.js b/client/src/views/site/navbar.js
index b0824c6d82..1c1141729e 100644
--- a/client/src/views/site/navbar.js
+++ b/client/src/views/site/navbar.js
@@ -206,6 +206,8 @@ define('views/site/navbar', 'view', function (Dep) {
var scopes = this.getMetadata().get('scopes') || {};
this.tabList = tabList.filter(function (scope) {
+ if (scope === '_delimiter_' || scope === 'Home') return true;
+ if (!scopes[scope]) return false;
if ((scopes[scope] || {}).disabled) return;
if ((scopes[scope] || {}).acl) {
return this.getAcl().check(scope);
@@ -214,6 +216,7 @@ define('views/site/navbar', 'view', function (Dep) {
}, this);
this.quickCreateList = this.getQuickCreateList().filter(function (scope) {
+ if (!scopes[scope]) return false;
if ((scopes[scope] || {}).disabled) return;
if ((scopes[scope] || {}).acl) {
return this.getAcl().check(scope, 'create');
From 6cfd5db8acf86489769a55f12ddf829e2f2adbdc Mon Sep 17 00:00:00 2001
From: yuri
Date: Sat, 28 Sep 2019 13:46:32 +0300
Subject: [PATCH 09/44] fix portal
---
application/Espo/Repositories/Portal.php | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/application/Espo/Repositories/Portal.php b/application/Espo/Repositories/Portal.php
index ac3f0c0fce..c593f78f75 100644
--- a/application/Espo/Repositories/Portal.php
+++ b/application/Espo/Repositories/Portal.php
@@ -74,18 +74,23 @@ class Portal extends \Espo\Core\ORM\Repositories\RDB
}
}
- protected function afterSave(Entity $entity, array $options = array())
+ protected function afterSave(Entity $entity, array $options = [])
{
parent::afterSave($entity, $options);
if ($entity->has('isDefault')) {
if ($entity->get('isDefault')) {
- $this->getConfig()->set('defaultPortalId', $entity->id);
- $this->getConfig()->save();
+ $defaultPortalId = $this->getConfig()->get('defaultPortalId');
+ if ($defaultPortalId !== $entity->id) {
+ $this->getConfig()->set('defaultPortalId', $entity->id);
+ $this->getConfig()->save();
+ }
} else {
if ($entity->isAttributeChanged('isDefault')) {
- $this->getConfig()->set('defaultPortalId', null);
- $this->getConfig()->save();
+ if ($entity->getFetched('isDefault')) {
+ $this->getConfig()->set('defaultPortalId', null);
+ $this->getConfig()->save();
+ }
}
}
}
From 1f334c2690ddd72e475820a117627d681ba1d84a Mon Sep 17 00:00:00 2001
From: yuri
Date: Sat, 28 Sep 2019 13:46:46 +0300
Subject: [PATCH 10/44] clear frontend cache on role change
---
application/Espo/Services/Portal.php | 18 +++++++++-
application/Espo/Services/PortalRole.php | 3 +-
application/Espo/Services/Role.php | 2 ++
application/Espo/Services/User.php | 46 ++++++++++++++++++++++--
4 files changed, 65 insertions(+), 4 deletions(-)
diff --git a/application/Espo/Services/Portal.php b/application/Espo/Services/Portal.php
index 951be43a6c..5cfc163477 100644
--- a/application/Espo/Services/Portal.php
+++ b/application/Espo/Services/Portal.php
@@ -35,6 +35,13 @@ class Portal extends Record
{
protected $getEntityBeforeUpdate = true;
+ protected function init()
+ {
+ parent::init();
+ $this->addDependency('fileManager');
+ $this->addDependency('dataManager');
+ }
+
public function loadAdditionalFields(Entity $entity)
{
parent::loadAdditionalFields($entity);
@@ -50,11 +57,20 @@ class Portal extends Record
protected function afterUpdateEntity(Entity $entity, $data)
{
$this->loadUrlField($entity);
+
+ if (property_exists($data, 'portalRolesIds')) {
+ $this->clearRolesCache();
+ }
}
protected function loadUrlField(Entity $entity)
{
$this->getRepository()->loadUrlField($entity);
}
-}
+ protected function clearRolesCache()
+ {
+ $this->getInjection('fileManager')->removeInDir('data/cache/application/acl-portal');
+ $this->getInjection('dataManager')->updateCacheTimestamp();
+ }
+}
diff --git a/application/Espo/Services/PortalRole.php b/application/Espo/Services/PortalRole.php
index efe52233be..60724eb8b6 100644
--- a/application/Espo/Services/PortalRole.php
+++ b/application/Espo/Services/PortalRole.php
@@ -37,6 +37,7 @@ class PortalRole extends Record
{
parent::init();
$this->addDependency('fileManager');
+ $this->addDependency('dataManager');
}
protected $forceSelectAllAttributes = true;
@@ -56,6 +57,6 @@ class PortalRole extends Record
protected function clearRolesCache()
{
$this->getInjection('fileManager')->removeInDir('data/cache/application/acl-portal');
+ $this->getInjection('dataManager')->updateCacheTimestamp();
}
}
-
diff --git a/application/Espo/Services/Role.php b/application/Espo/Services/Role.php
index d5ff531b98..3f60150ef9 100644
--- a/application/Espo/Services/Role.php
+++ b/application/Espo/Services/Role.php
@@ -37,6 +37,7 @@ class Role extends Record
{
parent::init();
$this->addDependency('fileManager');
+ $this->addDependency('dataManager');
}
protected $forceSelectAllAttributes = true;
@@ -56,5 +57,6 @@ class Role extends Record
protected function clearRolesCache()
{
$this->getInjection('fileManager')->removeInDir('data/cache/application/acl');
+ $this->getInjection('dataManager')->updateCacheTimestamp();
}
}
diff --git a/application/Espo/Services/User.php b/application/Espo/Services/User.php
index 52bc000fc2..f73a6f88ef 100644
--- a/application/Espo/Services/User.php
+++ b/application/Espo/Services/User.php
@@ -751,10 +751,28 @@ class User extends Record
{
parent::afterUpdateEntity($entity, $data);
- if (property_exists($data, 'rolesIds') || property_exists($data, 'teamsIds') || property_exists($data, 'type')) {
+ if (
+ property_exists($data, 'rolesIds') ||
+ property_exists($data, 'teamsIds') ||
+ property_exists($data, 'type') ||
+ property_exists($data, 'portalRolesIds') ||
+ property_exists($data, 'portalsIds')
+ ) {
$this->clearRoleCache($entity->id);
}
+ if (
+ property_exists($data, 'portalRolesIds')
+ ||
+ property_exists($data, 'portalsIds')
+ ||
+ property_exists($data, 'contactId')
+ ||
+ property_exists($data, 'accountsIds')
+ ) {
+ $this->clearPortalRolesCache();
+ }
+
if ($entity->isPortal() && $entity->get('contactId')) {
if (property_exists($data, 'firstName') || property_exists($data, 'lastName') || property_exists($data, 'salutationName')) {
$contact = $this->getEntityManager()->getEntity('Contact', $entity->get('contactId'));
@@ -775,6 +793,12 @@ class User extends Record
protected function clearRoleCache($id)
{
$this->getFileManager()->removeFile('data/cache/application/acl/' . $id . '.php');
+ $this->getContainer()->get('dataManager')->updateCacheTimestamp();
+ }
+
+ protected function clearPortalRolesCache()
+ {
+ $this->getInjection('fileManager')->removeInDir('data/cache/application/acl-portal');
}
public function massUpdate(array $params, $data)
@@ -792,11 +816,29 @@ class User extends Record
{
parent::afterMassUpdate($idList, $data);
- if (array_key_exists('rolesIds', $data) || array_key_exists('teamsIds', $data) || array_key_exists('type', $data)) {
+ if (
+ property_exists($data, 'rolesIds') ||
+ property_exists($data, 'teamsIds') ||
+ property_exists($data, 'type') ||
+ property_exists($data, 'portalRolesIds') ||
+ property_exists($data, 'portalsIds')
+ ) {
foreach ($idList as $id) {
$this->clearRoleCache($id);
}
}
+
+ if (
+ property_exists($data, 'portalRolesIds')
+ ||
+ property_exists($data, 'portalsIds')
+ ||
+ property_exists($data, 'contactId')
+ ||
+ property_exists($data, 'accountsIds')
+ ) {
+ $this->clearPortalRolesCache();
+ }
}
public function loadAdditionalFields(Entity $entity)
From e6d79e0847a4d11426e97759e59be2cd0a65f5b1 Mon Sep 17 00:00:00 2001
From: yuri
Date: Sat, 28 Sep 2019 14:14:00 +0300
Subject: [PATCH 11/44] dashboard layout fix
---
.../Resources/metadata/entityDefs/Portal.json | 3 +-
.../fields/dashboard-layout/detail.tpl | 4 +++
.../views/settings/fields/dashboard-layout.js | 30 ++++++++++++++++++-
3 files changed, 34 insertions(+), 3 deletions(-)
diff --git a/application/Espo/Resources/metadata/entityDefs/Portal.json b/application/Espo/Resources/metadata/entityDefs/Portal.json
index c0aeac3e5c..02632096d2 100644
--- a/application/Espo/Resources/metadata/entityDefs/Portal.json
+++ b/application/Espo/Resources/metadata/entityDefs/Portal.json
@@ -85,8 +85,7 @@
},
"dashboardLayout": {
"type": "jsonArray",
- "view": "views/settings/fields/dashboard-layout",
- "required": true
+ "view": "views/settings/fields/dashboard-layout"
},
"dashletsOptions": {
"type": "jsonObject",
diff --git a/client/res/templates/settings/fields/dashboard-layout/detail.tpl b/client/res/templates/settings/fields/dashboard-layout/detail.tpl
index 308bd56e45..4534610894 100644
--- a/client/res/templates/settings/fields/dashboard-layout/detail.tpl
+++ b/client/res/templates/settings/fields/dashboard-layout/detail.tpl
@@ -1,4 +1,8 @@
+{{#if isEmpty}}
+{{translate 'None'}}
+{{/if}}
+
diff --git a/client/modules/crm/res/templates/campaign/unsubscribe.tpl b/client/modules/crm/res/templates/campaign/unsubscribe.tpl
index 062d477ab3..dfd5d45a2e 100644
--- a/client/modules/crm/res/templates/campaign/unsubscribe.tpl
+++ b/client/modules/crm/res/templates/campaign/unsubscribe.tpl
@@ -6,7 +6,7 @@
{{translate 'unsubscribed' category='messages' scope='Campaign'}}
- {{translate 'Subscribe again' scope='Campaign'}}
+ {{translate 'Subscribe again' scope='Campaign'}}
diff --git a/client/modules/crm/src/views/campaign/subscribe-again.js b/client/modules/crm/src/views/campaign/subscribe-again.js
index 8cce5fcc27..f1d5bad20d 100644
--- a/client/modules/crm/src/views/campaign/subscribe-again.js
+++ b/client/modules/crm/src/views/campaign/subscribe-again.js
@@ -26,15 +26,23 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
-Espo.define('crm:views/campaign/subscribe-again', 'view', function (Dep) {
+define('crm:views/campaign/subscribe-again', 'view', function (Dep) {
return Dep.extend({
template: 'crm:campaign/subscribe-again',
data: function () {
+ var revertUrl;
+
+ var actionData = this.options.actionData;
+ if (actionData.hash && actionData.emailAddress)
+ revertUrl = '?entryPoint=unsubscribe&emailAddress=' + actionData.emailAddress + '&hash=' + actionData.hash;
+ else
+ revertUrl = '?entryPoint=unsubscribe&id=' + actionData.queueItemId;
+
var data = {
- actionData: this.options.actionData
+ revertUrl: revertUrl,
};
return data;
}
diff --git a/client/modules/crm/src/views/campaign/unsubscribe.js b/client/modules/crm/src/views/campaign/unsubscribe.js
index 4d5a974e83..7e073585e3 100644
--- a/client/modules/crm/src/views/campaign/unsubscribe.js
+++ b/client/modules/crm/src/views/campaign/unsubscribe.js
@@ -26,15 +26,23 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
-Espo.define('crm:views/campaign/unsubscribe', 'view', function (Dep) {
+define('crm:views/campaign/unsubscribe', 'view', function (Dep) {
return Dep.extend({
template: 'crm:campaign/unsubscribe',
data: function () {
+ var revertUrl;
+
+ var actionData = this.options.actionData;
+ if (actionData.hash && actionData.emailAddress)
+ revertUrl = '?entryPoint=subscribeAgain&emailAddress=' + actionData.emailAddress + '&hash=' + actionData.hash;
+ else
+ revertUrl = '?entryPoint=subscribeAgain&id=' + actionData.queueItemId;
+
var data = {
- actionData: this.options.actionData
+ revertUrl: revertUrl,
};
return data;
}
From a38fd487f4e1f18fd32fb3267757d5a091bac2c5 Mon Sep 17 00:00:00 2001
From: yuri
Date: Tue, 1 Oct 2019 15:43:22 +0300
Subject: [PATCH 29/44] lang fix
---
application/Espo/Services/Language.php | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/application/Espo/Services/Language.php b/application/Espo/Services/Language.php
index a416119550..7c140ec0a5 100644
--- a/application/Espo/Services/Language.php
+++ b/application/Espo/Services/Language.php
@@ -77,7 +77,7 @@ class Language extends \Espo\Core\Services\Base
unset($data['Global']['options']);
foreach ($data as $k => $item) {
- if (in_array($k, ['Global', 'User'])) continue;
+ if (in_array($k, ['Global', 'User', 'Campaign'])) continue;
unset($data[$k]);
}
unset($data['User']['fields']);
@@ -87,6 +87,12 @@ class Language extends \Espo\Core\Services\Base
unset($data['User']['presetFilters']);
unset($data['User']['boolFilters']);
unset($data['User']['tooltips']);
+
+ unset($data['Campaign']['fields']);
+ unset($data['Campaign']['links']);
+ unset($data['Campaign']['options']);
+ unset($data['Campaign']['tooltips']);
+ unset($data['Campaign']['presetFilters']);
} else {
$scopeList = array_keys($this->getMetadata()->get(['scopes'], []));
From 3fe4bc34ef67a5259566dc780cb497b58122526e Mon Sep 17 00:00:00 2001
From: yuri
Date: Tue, 1 Oct 2019 15:51:02 +0300
Subject: [PATCH 30/44] fix
---
.../Espo/Modules/Crm/EntryPoints/SubscribeAgain.php | 10 ++++++----
.../Espo/Modules/Crm/EntryPoints/Unsubscribe.php | 10 ++++++----
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/application/Espo/Modules/Crm/EntryPoints/SubscribeAgain.php b/application/Espo/Modules/Crm/EntryPoints/SubscribeAgain.php
index 6b22bd56ab..1f6e703ce4 100644
--- a/application/Espo/Modules/Crm/EntryPoints/SubscribeAgain.php
+++ b/application/Espo/Modules/Crm/EntryPoints/SubscribeAgain.php
@@ -182,11 +182,13 @@ class SubscribeAgain extends \Espo\Core\EntryPoints\Base
if ($ea) {
$entityList = $repository->getEntityListByAddressId($ea->id);
- $ea->set('optOut', false);
- $this->getEntityManager()->saveEntity($ea);
+ if ($ea->get('optOut')) {
+ $ea->set('optOut', false);
+ $this->getEntityManager()->saveEntity($ea);
- foreach ($entityList as $entity) {
- $this->getHookManager()->process($entity->getEntityType(), 'afterCancelOptOut', $entity, [], []);
+ foreach ($entityList as $entity) {
+ $this->getHookManager()->process($entity->getEntityType(), 'afterCancelOptOut', $entity, [], []);
+ }
}
$this->display([
diff --git a/application/Espo/Modules/Crm/EntryPoints/Unsubscribe.php b/application/Espo/Modules/Crm/EntryPoints/Unsubscribe.php
index d500c558d1..508a15973f 100644
--- a/application/Espo/Modules/Crm/EntryPoints/Unsubscribe.php
+++ b/application/Espo/Modules/Crm/EntryPoints/Unsubscribe.php
@@ -175,11 +175,13 @@ class Unsubscribe extends \Espo\Core\EntryPoints\Base
if ($ea) {
$entityList = $repository->getEntityListByAddressId($ea->id);
- $ea->set('optOut', true);
- $this->getEntityManager()->saveEntity($ea);
+ if (!$ea->get('optOut')) {
+ $ea->set('optOut', true);
+ $this->getEntityManager()->saveEntity($ea);
- foreach ($entityList as $entity) {
- $this->getHookManager()->process($entity->getEntityType(), 'afterOptOut', $entity, [], []);
+ foreach ($entityList as $entity) {
+ $this->getHookManager()->process($entity->getEntityType(), 'afterOptOut', $entity, [], []);
+ }
}
$this->display([
From 9d485624a88f447b72e6516862e333378393985c Mon Sep 17 00:00:00 2001
From: yuri
Date: Tue, 1 Oct 2019 16:00:21 +0300
Subject: [PATCH 31/44] fix
---
install/core/Installer.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/install/core/Installer.php b/install/core/Installer.php
index 0db8061f09..621f722fd0 100644
--- a/install/core/Installer.php
+++ b/install/core/Installer.php
@@ -260,7 +260,7 @@ class Installer
'siteUrl' => $siteUrl,
'passwordSalt' => $this->getPasswordHash()->generateSalt(),
'cryptKey' => $this->getContainer()->get('crypt')->generateKey(),
- 'hashSecretKey' => \Espo\Core\Utils\Util::generateSecretKey();
+ 'hashSecretKey' => \Espo\Core\Utils\Util::generateSecretKey(),
];
$owner = $this->getFileManager()->getPermissionUtils()->getDefaultOwner(true);
From 20ede11bdd8b6e825a5207a70b13924a9f739809 Mon Sep 17 00:00:00 2001
From: yuri
Date: Tue, 1 Oct 2019 16:40:03 +0300
Subject: [PATCH 32/44] css fix
---
frontend/less/espo/custom.less | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/frontend/less/espo/custom.less b/frontend/less/espo/custom.less
index 6cf1c12091..369bd1229e 100644
--- a/frontend/less/espo/custom.less
+++ b/frontend/less/espo/custom.less
@@ -2213,6 +2213,10 @@ h4.panel-title span.fas.color-icon {
}
.record .middle {
+ > .panel.hidden + .panel {
+ border-top-width: @panel-border-width;
+ }
+
margin-bottom: @line-height-computed;
}
@@ -2256,7 +2260,6 @@ h4.panel-title span.fas.color-icon {
.bottom {
.panel.hidden + .panel.sticked {
- margin-top: 0;
border-top-width: @panel-border-width;
}
}
From 73b00190f73ef45a75a52699e16a74cbad0904e5 Mon Sep 17 00:00:00 2001
From: yuri
Date: Tue, 1 Oct 2019 17:06:32 +0300
Subject: [PATCH 33/44] colorpicker fix
---
client/lib/bootstrap-colorpicker.js | 86 +++++++++++++-------------
client/src/views/fields/colorpicker.js | 12 +++-
2 files changed, 54 insertions(+), 44 deletions(-)
diff --git a/client/lib/bootstrap-colorpicker.js b/client/lib/bootstrap-colorpicker.js
index b2cdf560cf..ac22ed526c 100644
--- a/client/lib/bootstrap-colorpicker.js
+++ b/client/lib/bootstrap-colorpicker.js
@@ -1,5 +1,5 @@
/*!
- * Bootstrap Colorpicker v2.5.1
+ * Bootstrap Colorpicker v2.5.2
* https://itsjavi.com/bootstrap-colorpicker/
*
* Originally written by (c) 2012 Stefan Petre
@@ -38,14 +38,9 @@
val, predefinedColors, fallbackColor, fallbackFormat, hexNumberSignPrefix) {
this.fallbackValue = fallbackColor ?
(
- fallbackColor && (typeof fallbackColor.h !== 'undefined') ?
- fallbackColor :
- this.value = {
- h: 0,
- s: 0,
- b: 0,
- a: 1
- }
+ (typeof fallbackColor === 'string') ?
+ this.parse(fallbackColor) :
+ fallbackColor
) :
null;
@@ -480,6 +475,9 @@
* @returns {Object} Object containing h,s,b,a,format properties or FALSE if failed to parse
*/
parse: function(strVal) {
+ if (typeof strVal !== 'string') {
+ return this.fallbackValue;
+ }
if (arguments.length === 0) {
return false;
}
@@ -793,6 +791,8 @@
this.updateData(this.color);
}
+ this.disabled = false;
+
// Setup picker
var $picker = this.picker = $(this.options.template);
if (this.options.customClass) {
@@ -861,7 +861,7 @@
'keyup.colorpicker': $.proxy(this.keyup, this)
});
this.input.on({
- 'change.colorpicker': $.proxy(this.change, this)
+ 'input.colorpicker': $.proxy(this.change, this)
});
if (this.component === false) {
this.element.on({
@@ -1105,34 +1105,31 @@
return (this.input !== false);
},
isDisabled: function() {
- if (this.hasInput()) {
- return (this.input.prop('disabled') === true);
- }
- return false;
+ return this.disabled;
},
disable: function() {
if (this.hasInput()) {
this.input.prop('disabled', true);
- this.element.trigger({
- type: 'disable',
- color: this.color,
- value: this.getValue()
- });
- return true;
}
- return false;
+ this.disabled = true;
+ this.element.trigger({
+ type: 'disable',
+ color: this.color,
+ value: this.getValue()
+ });
+ return true;
},
enable: function() {
if (this.hasInput()) {
this.input.prop('disabled', false);
- this.element.trigger({
- type: 'enable',
- color: this.color,
- value: this.getValue()
- });
- return true;
}
- return false;
+ this.disabled = false;
+ this.element.trigger({
+ type: 'enable',
+ color: this.color,
+ value: this.getValue()
+ });
+ return true;
},
currentSlider: null,
mousePointer: {
@@ -1251,7 +1248,24 @@
return false;
},
change: function(e) {
- this.keyup(e);
+ this.color = this.createColor(this.input.val());
+ // Change format dynamically
+ // Only occurs if user choose the dynamic format by
+ // setting option format to false
+ if (this.color.origFormat && this.options.format === false) {
+ this.format = this.color.origFormat;
+ }
+ if (this.getValue(false) !== false) {
+ this.updateData();
+ this.updateComponent();
+ this.updatePicker();
+ }
+
+ this.element.trigger({
+ type: 'changeColor',
+ color: this.color,
+ value: this.input.val()
+ });
},
keyup: function(e) {
if ((e.keyCode === 38)) {
@@ -1264,20 +1278,8 @@
this.color.value.a = Math.round((this.color.value.a - 0.01) * 100) / 100;
}
this.update(true);
- } else {
- this.color = this.createColor(this.input.val());
- // Change format dynamically
- // Only occurs if user choose the dynamic format by
- // setting option format to false
- if (this.color.origFormat && this.options.format === false) {
- this.format = this.color.origFormat;
- }
- if (this.getValue(false) !== false) {
- this.updateData();
- this.updateComponent();
- this.updatePicker();
- }
}
+
this.element.trigger({
type: 'changeColor',
color: this.color,
diff --git a/client/src/views/fields/colorpicker.js b/client/src/views/fields/colorpicker.js
index 1e16b61554..04ecf541d0 100644
--- a/client/src/views/fields/colorpicker.js
+++ b/client/src/views/fields/colorpicker.js
@@ -26,7 +26,7 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
-Espo.define('views/fields/colorpicker', ['views/fields/varchar', 'lib!Colorpicker'], function (Dep, Colorpicker) {
+define('views/fields/colorpicker', ['views/fields/varchar', 'lib!Colorpicker'], function (Dep, Colorpicker) {
return Dep.extend({
@@ -46,10 +46,18 @@ Espo.define('views/fields/colorpicker', ['views/fields/varchar', 'lib!Colorpicke
afterRender: function () {
Dep.prototype.afterRender.call(this);
+
if (this.mode == 'edit') {
+ var isModal = !!this.$el.closest('.modal').length;
+
this.$element.parent().colorpicker({
- format: 'hex'
+ format: 'hex',
+ container: isModal ? this.$el : false,
});
+
+ if (isModal) {
+ this.$el.find('.colorpicker').css('position', 'relative').addClass('pull-right');
+ }
}
if (this.mode === 'edit') {
this.$element.on('change', function () {
From 57843f5f86d00f46db1a8674ccd289cfd5688307 Mon Sep 17 00:00:00 2001
From: yuri
Date: Tue, 1 Oct 2019 17:13:12 +0300
Subject: [PATCH 34/44] calendar apply color
---
client/modules/crm/src/views/calendar/calendar.js | 7 +++++++
client/modules/crm/src/views/calendar/timeline.js | 7 +++++++
2 files changed, 14 insertions(+)
diff --git a/client/modules/crm/src/views/calendar/calendar.js b/client/modules/crm/src/views/calendar/calendar.js
index 8ca427f4b5..87a6ac721d 100644
--- a/client/modules/crm/src/views/calendar/calendar.js
+++ b/client/modules/crm/src/views/calendar/calendar.js
@@ -149,6 +149,13 @@ Espo.define('crm:views/calendar/calendar', ['view', 'lib!full-calendar'], functi
this.enabledScopeList = [];
}
+ this.enabledScopeList.forEach(function (item) {
+ var color = this.getMetadata().get(['clientDefs', item, 'color']);
+ if (color) {
+ this.colors[item] = color;
+ }
+ }, this);
+
if (this.header) {
this.createView('modeButtons', 'crm:views/calendar/mode-buttons', {
el: this.getSelector() + ' .mode-buttons',
diff --git a/client/modules/crm/src/views/calendar/timeline.js b/client/modules/crm/src/views/calendar/timeline.js
index bd7946c3b7..49b72fa583 100644
--- a/client/modules/crm/src/views/calendar/timeline.js
+++ b/client/modules/crm/src/views/calendar/timeline.js
@@ -170,6 +170,13 @@ Espo.define('crm:views/calendar/timeline', ['view', 'lib!vis'], function (Dep, V
this.enabledScopeList = [];
}
+ this.enabledScopeList.forEach(function (item) {
+ var color = this.getMetadata().get(['clientDefs', item, 'color']);
+ if (color) {
+ this.colors[item] = color;
+ }
+ }, this);
+
if (this.options.calendarType) {
this.calendarType = this.options.calendarType;
} else {
From 3b880de16d695d6732bc5c34d1236f63e9672f64 Mon Sep 17 00:00:00 2001
From: yuri
Date: Wed, 2 Oct 2019 10:43:42 +0300
Subject: [PATCH 35/44] preferences fix
---
client/src/views/preferences/record/edit.js | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/client/src/views/preferences/record/edit.js b/client/src/views/preferences/record/edit.js
index f26471995f..eb7efdb1e5 100644
--- a/client/src/views/preferences/record/edit.js
+++ b/client/src/views/preferences/record/edit.js
@@ -134,6 +134,11 @@ define('views/preferences/record/edit', 'views/record/edit', function (Dep) {
this.hideField('assignmentEmailNotificationsIgnoreEntityTypeList');
} else {
hideNotificationPanel = false;
+
+ this.controlAssignmentEmailNotificationsVisibility();
+ this.listenTo(this.model, 'change:receiveAssignmentEmailNotifications', function () {
+ this.controlAssignmentEmailNotificationsVisibility();
+ }, this);
}
if ((this.getConfig().get('assignmentEmailNotificationsEntityList') || []).length === 0) {
@@ -233,6 +238,14 @@ define('views/preferences/record/edit', 'views/record/edit', function (Dep) {
}
},
+ controlAssignmentEmailNotificationsVisibility: function () {
+ if (this.model.get('receiveAssignmentEmailNotifications')) {
+ this.showField('assignmentEmailNotificationsIgnoreEntityTypeList');
+ } else {
+ this.hideField('assignmentEmailNotificationsIgnoreEntityTypeList');
+ }
+ },
+
actionReset: function () {
this.confirm(this.translate('resetPreferencesConfirmation', 'messages'), function () {
$.ajax({
From 00230f50d6a0d6f4113e894d61fa59c97a5c6d69 Mon Sep 17 00:00:00 2001
From: yuri
Date: Wed, 2 Oct 2019 10:46:19 +0300
Subject: [PATCH 36/44] remove notifications sound disabled
---
application/Espo/Resources/layouts/Settings/notifications.json | 3 +--
client/src/views/notification/badge.js | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/application/Espo/Resources/layouts/Settings/notifications.json b/application/Espo/Resources/layouts/Settings/notifications.json
index 78db9cb94b..b029926759 100644
--- a/application/Espo/Resources/layouts/Settings/notifications.json
+++ b/application/Espo/Resources/layouts/Settings/notifications.json
@@ -2,8 +2,7 @@
{
"label": "In-app Notifications",
"rows": [
- [{"name": "assignmentNotificationsEntityList"}, false],
- [{"name": "notificationSoundsDisabled"}, false]
+ [{"name": "assignmentNotificationsEntityList"}, false]
]
},
{
diff --git a/client/src/views/notification/badge.js b/client/src/views/notification/badge.js
index f5f294c9cb..31e3cf085f 100644
--- a/client/src/views/notification/badge.js
+++ b/client/src/views/notification/badge.js
@@ -49,7 +49,7 @@ define('views/notification/badge', 'view', function (Dep) {
setup: function () {
this.soundPath = this.getBasePath() + (this.getConfig().get('notificationSound') || this.soundPath);
- this.notificationSoundsDisabled = this.getConfig().get('notificationSoundsDisabled');
+ this.notificationSoundsDisabled = true;
this.useWebSocket = this.getConfig().get('useWebSocket');
From c752e8fc91d43bbff4cf4b899814ca66264ecba0 Mon Sep 17 00:00:00 2001
From: yuri
Date: Wed, 2 Oct 2019 11:44:28 +0300
Subject: [PATCH 37/44] job front end fixes
---
.../Espo/Resources/layouts/Job/detail.json | 28 +++++++++++++++++++
.../Resources/metadata/entityDefs/Job.json | 2 +-
client/src/views/admin/job/fields/name.js | 5 ++--
3 files changed, 31 insertions(+), 4 deletions(-)
create mode 100644 application/Espo/Resources/layouts/Job/detail.json
diff --git a/application/Espo/Resources/layouts/Job/detail.json b/application/Espo/Resources/layouts/Job/detail.json
new file mode 100644
index 0000000000..667eea760a
--- /dev/null
+++ b/application/Espo/Resources/layouts/Job/detail.json
@@ -0,0 +1,28 @@
+[
+ {
+ "label":"",
+ "rows":[
+ [{"name":"name"}, {"name": "status"}],
+ [{"name":"queue"}, {"name":"number"}]
+ ]
+ },
+ {
+ "label":"",
+ "rows":[
+ [{"name":"executeTime"}, {"name": "createdAt"}],
+ [{"name":"startedAt"}, {"name": "modifiedAt"}],
+ [{"name":"executedAt"}, false],
+ [{"name":"attempts"}, false],
+ [{"name":"failedAttempts"}, false]
+ ]
+ },
+ {
+ "label":"",
+ "rows":[
+ [{"name":"scheduledJob"}, {"name":"targetType"}],
+ [{"name":"serviceName"}, {"name":"targetId"}],
+ [{"name":"methodName"}, {"name":"job"}],
+ [{"name": "data", "fullWidth": true}]
+ ]
+ }
+]
diff --git a/application/Espo/Resources/metadata/entityDefs/Job.json b/application/Espo/Resources/metadata/entityDefs/Job.json
index 69bd930683..71d45b0bf2 100644
--- a/application/Espo/Resources/metadata/entityDefs/Job.json
+++ b/application/Espo/Resources/metadata/entityDefs/Job.json
@@ -104,7 +104,7 @@
"collection": {
"orderBy": "number",
"order": "desc",
- "textFilterFields": ["name", "methodName", "serviceName", "scheduledJob"]
+ "textFilterFields": ["id", "name", "methodName", "serviceName", "scheduledJob"]
},
"indexes": {
"executeTime": {
diff --git a/client/src/views/admin/job/fields/name.js b/client/src/views/admin/job/fields/name.js
index c3b073806e..54aca96003 100644
--- a/client/src/views/admin/job/fields/name.js
+++ b/client/src/views/admin/job/fields/name.js
@@ -26,12 +26,12 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
-Espo.define('views/admin/job/fields/name', 'views/fields/varchar', function (Dep) {
+define('views/admin/job/fields/name', 'views/fields/varchar', function (Dep) {
return Dep.extend({
getValueForDisplay: function () {
- if (this.mode == 'list' || this.mode == 'detail') {
+ if (this.mode == 'list' || this.mode == 'detail' || this.mode === 'listLink') {
if (!this.model.get('name')) {
return this.model.get('serviceName') + ': ' + this.model.get('methodName');
} else {
@@ -42,4 +42,3 @@ Espo.define('views/admin/job/fields/name', 'views/fields/varchar', function (Dep
});
});
-
From 2f93dfd653a7b41bed5b1b6e3b45eb8819ef71c9 Mon Sep 17 00:00:00 2001
From: yuri
Date: Wed, 2 Oct 2019 12:18:27 +0300
Subject: [PATCH 38/44] array displayAsList
---
client/src/views/fields/array.js | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/client/src/views/fields/array.js b/client/src/views/fields/array.js
index 75812f0799..ef4931c5fe 100644
--- a/client/src/views/fields/array.js
+++ b/client/src/views/fields/array.js
@@ -119,6 +119,9 @@ define('views/fields/array', ['views/fields/base', 'lib!Selectize'], function (D
this.setupTranslation();
}
+ this.displayAsLabel = this.params.displayAsLabel || this.displayAsLabel;
+ this.displayAsList = this.params.displayAsList || this.displayAsList;
+
if (this.params.isSorted && this.translatedOptions) {
this.params.options = Espo.Utils.clone(this.params.options);
this.params.options = this.params.options.sort(function (v1, v2) {
@@ -390,7 +393,10 @@ define('views/fields/array', ['views/fields/base', 'lib!Selectize'], function (D
}, this)
- if (this.params.displayAsLabel) {
+ if (this.displayAsList) {
+ if (!list.length) return '';
+ return '' + list.join('
') + '
';
+ } else if (this.displayAsLabel) {
return list.join(' ');
} else {
return list.join(', ')
From 43fed19d0776965e17a58c5d325c1fb4c49a8e7d Mon Sep 17 00:00:00 2001
From: yuri
Date: Wed, 2 Oct 2019 14:58:20 +0300
Subject: [PATCH 39/44] formula password functions
---
.../Functions/PasswordGroup/GenerateType.php | 54 +++++++++++++++++
.../Functions/PasswordGroup/HashType.php | 60 +++++++++++++++++++
.../Espo/Core/Formula/FormulaTest.php | 24 ++++++++
3 files changed, 138 insertions(+)
create mode 100644 application/Espo/Core/Formula/Functions/PasswordGroup/GenerateType.php
create mode 100644 application/Espo/Core/Formula/Functions/PasswordGroup/HashType.php
diff --git a/application/Espo/Core/Formula/Functions/PasswordGroup/GenerateType.php b/application/Espo/Core/Formula/Functions/PasswordGroup/GenerateType.php
new file mode 100644
index 0000000000..a5b9c211d5
--- /dev/null
+++ b/application/Espo/Core/Formula/Functions/PasswordGroup/GenerateType.php
@@ -0,0 +1,54 @@
+addDependency('config');
+ }
+
+ public function process(\StdClass $item)
+ {
+ $config = $this->getInjection('config');
+
+ $length = $config->get('passwordGenerateLength', 10);
+ $letterCount = $config->get('passwordGenerateLetterCount', 4);
+ $numberCount = $config->get('passwordGenerateNumberCount', 2);
+
+ $password = \Espo\Core\Utils\Util::generatePassword($length, $letterCount, $numberCount, true);
+
+ return $password;
+ }
+}
diff --git a/application/Espo/Core/Formula/Functions/PasswordGroup/HashType.php b/application/Espo/Core/Formula/Functions/PasswordGroup/HashType.php
new file mode 100644
index 0000000000..463092b5b8
--- /dev/null
+++ b/application/Espo/Core/Formula/Functions/PasswordGroup/HashType.php
@@ -0,0 +1,60 @@
+addDependency('config');
+ }
+
+ public function process(\StdClass $item)
+ {
+ $args = $item->value ?? [];
+
+ if (!is_array($args)) throw new Error();
+ if (count($args) < 1)
+ throw new Error("Formula: password\\hash: no argument.");
+
+ $password = $this->evaluate($args[0]);
+
+ if (!is_string($password))
+ throw new Error("Formula: password\\hash: bad argument.");
+
+ $passwordHash = new \Espo\Core\Utils\PasswordHash($this->getInjection('config'));
+ $hash = $passwordHash->hash($password);
+
+ return $hash;
+ }
+}
diff --git a/tests/integration/Espo/Core/Formula/FormulaTest.php b/tests/integration/Espo/Core/Formula/FormulaTest.php
index ef6fbc5220..3b59e07577 100644
--- a/tests/integration/Espo/Core/Formula/FormulaTest.php
+++ b/tests/integration/Espo/Core/Formula/FormulaTest.php
@@ -296,4 +296,28 @@ class FormulaTest extends \tests\integration\Core\BaseTestCase
$result = $fm->run($script, $contact);
$this->assertEquals('1', $result);
}
+
+ public function testPasswordGenerate()
+ {
+ $fm = $this->getContainer()->get('formulaManager');
+
+ $script = "password\\generate()";
+ $result = $fm->run($script);
+ $this->assertTrue(is_string($result));
+ }
+
+ public function testPasswordHash()
+ {
+ $fm = $this->getContainer()->get('formulaManager');
+
+ $script1 = "password\\hash('1')";
+ $result1 = $fm->run($script1);
+
+ $script2 = "password\\hash('2')";
+ $result2 = $fm->run($script2);
+
+ $this->assertTrue(is_string($result1));
+
+ $this->assertTrue($result1 !== $result);
+ }
}
From 9b2ac56563129958fb5ef6cabb9a36806345f865 Mon Sep 17 00:00:00 2001
From: yuri
Date: Thu, 3 Oct 2019 10:27:29 +0300
Subject: [PATCH 40/44] email use index fix
---
application/Espo/SelectManagers/Email.php | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/application/Espo/SelectManagers/Email.php b/application/Espo/SelectManagers/Email.php
index 317c03cd80..52a25a1cf9 100644
--- a/application/Espo/SelectManagers/Email.php
+++ b/application/Espo/SelectManagers/Email.php
@@ -52,8 +52,10 @@ class Email extends \Espo\Core\SelectManagers\Base
break;
} else {
if (isset($item['attribute'])) {
- $skipIndex = true;
- break;
+ if (!in_array($item['attribute'], ['teams', 'users', 'status'])) {
+ $skipIndex = true;
+ break;
+ }
}
}
}
@@ -61,9 +63,6 @@ class Email extends \Espo\Core\SelectManagers\Base
if ($folderId === 'important' || $folderId === 'drafts') {
$skipIndex = true;
}
- if (!$skipIndex && $this->hasLinkJoined('teams', $result)) {
- $skipIndex = true;
- }
if (!$skipIndex) {
$result['useIndexList'] = ['dateSent'];
}
From a5433ec82a199620bcdfc29bf89d83ab45024c26 Mon Sep 17 00:00:00 2001
From: yuri
Date: Thu, 3 Oct 2019 13:09:54 +0300
Subject: [PATCH 41/44] stream use index
---
application/Espo/Resources/metadata/entityDefs/Note.json | 3 +++
application/Espo/Services/Stream.php | 2 ++
2 files changed, 5 insertions(+)
diff --git a/application/Espo/Resources/metadata/entityDefs/Note.json b/application/Espo/Resources/metadata/entityDefs/Note.json
index b5f6968613..1e46923360 100644
--- a/application/Espo/Resources/metadata/entityDefs/Note.json
+++ b/application/Espo/Resources/metadata/entityDefs/Note.json
@@ -155,6 +155,9 @@
"parentAndSuperParent": {
"type": "index",
"columns": ["parentId", "parentType", "superParentId", "superParentType"]
+ },
+ "createdByNumber": {
+ "columns": ["createdById", "number"]
}
}
}
diff --git a/application/Espo/Services/Stream.php b/application/Espo/Services/Stream.php
index a89d9cac06..3df5ed1cff 100644
--- a/application/Espo/Services/Stream.php
+++ b/application/Espo/Services/Stream.php
@@ -386,6 +386,7 @@ class Stream extends \Espo\Core\Services\Base
'orderBy' => 'number',
'order' => 'DESC',
'limit' => $sqLimit,
+ 'useIndexList' => ['createdByNumber'],
];
if ($user->isPortal()) {
@@ -483,6 +484,7 @@ class Stream extends \Espo\Core\Services\Base
'orderBy' => 'number',
'order' => 'DESC',
'limit' => $sqLimit,
+ 'useIndexList' => ['createdByNumber'],
];
if ($user->isPortal()) {
From 850f6ad41e0d40c4dc892e3abfabd9cbd57ff51b Mon Sep 17 00:00:00 2001
From: yuri
Date: Thu, 3 Oct 2019 13:12:51 +0300
Subject: [PATCH 42/44] cs fix
---
application/Espo/Services/Stream.php | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/application/Espo/Services/Stream.php b/application/Espo/Services/Stream.php
index 3df5ed1cff..496220cefe 100644
--- a/application/Espo/Services/Stream.php
+++ b/application/Espo/Services/Stream.php
@@ -61,7 +61,7 @@ class Stream extends \Espo\Core\Services\Base
protected $emailsWithContentEntityList = ['Case'];
- protected $auditedFieldsCache = array();
+ protected $auditedFieldsCache = [];
private $notificationService = null;
@@ -106,7 +106,7 @@ class Stream extends \Espo\Core\Services\Base
protected function getStatusStyles()
{
if (empty($this->statusStyles)) {
- $this->statusStyles = $this->getMetadata()->get('entityDefs.Note.statusStyles', array());
+ $this->statusStyles = $this->getMetadata()->get('entityDefs.Note.statusStyles', []);
}
return $this->statusStyles;
}
@@ -115,7 +115,7 @@ class Stream extends \Espo\Core\Services\Base
{
if (is_null($this->statusFields)) {
$this->statusFields = array();
- $scopes = $this->getMetadata()->get('scopes', array());
+ $scopes = $this->getMetadata()->get('scopes', []);
foreach ($scopes as $scope => $data) {
if (empty($data['statusField'])) continue;
$this->statusFields[$scope] = $data['statusField'];
From 415eff0486ab46634efa7558c63b1aced830bdda Mon Sep 17 00:00:00 2001
From: yuri
Date: Thu, 3 Oct 2019 13:41:53 +0300
Subject: [PATCH 43/44] fix stream portal user
---
application/Espo/Services/Stream.php | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/application/Espo/Services/Stream.php b/application/Espo/Services/Stream.php
index 496220cefe..d05924de00 100644
--- a/application/Espo/Services/Stream.php
+++ b/application/Espo/Services/Stream.php
@@ -1662,17 +1662,30 @@ class Stream extends \Espo\Core\Services\Base
{
$ignoreScopeList = [];
$scopes = $this->getMetadata()->get('scopes', []);
+
+ $aclManager = $this->getAclManager();
+
+ if ($user->isPortal() && !$this->getUser()->isPortal()) {
+ $aclManager = new \Espo\Core\Portal\AclManager($this->getInjection('container'));
+
+ $portals = $user->get('portals');
+ if (count($portals)) {
+ $aclManager->setPortal($portals[0]);
+ }
+ }
+
foreach ($scopes as $scope => $item) {
if (empty($item['entity'])) continue;
if (empty($item['object'])) continue;
if (
- !$this->getAclManager()->checkScope($user, $scope, 'read')
+ !$aclManager->checkScope($user, $scope, 'read')
||
- !$this->getAclManager()->checkScope($user, $scope, 'stream')
+ !$aclManager->checkScope($user, $scope, 'stream')
) {
$ignoreScopeList[] = $scope;
}
}
+
return $ignoreScopeList;
}
From 98e69436d9766da67293f40877ee88c3b8f29f43 Mon Sep 17 00:00:00 2001
From: yuri
Date: Thu, 3 Oct 2019 13:42:17 +0300
Subject: [PATCH 44/44] sum related support children
---
.../Functions/EntityGroup/SumRelatedType.php | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/application/Espo/Core/Formula/Functions/EntityGroup/SumRelatedType.php b/application/Espo/Core/Formula/Functions/EntityGroup/SumRelatedType.php
index b0ef65a2cf..c136914da1 100644
--- a/application/Espo/Core/Formula/Functions/EntityGroup/SumRelatedType.php
+++ b/application/Espo/Core/Formula/Functions/EntityGroup/SumRelatedType.php
@@ -97,7 +97,21 @@ class SumRelatedType extends \Espo\Core\Formula\Functions\Base
$selectParams['select'] = [[$foreignLink . '.id', 'foreignId'], 'SUM:' . $field];
- $foreignSelectManager->addJoin($foreignLink, $selectParams);
+ if ($entity->getRelationType($link) === 'hasChildren') {
+ $foreignSelectManager->addJoin([
+ $entity->getEntityType(),
+ $foreignLink,
+ [
+ $foreignLink . '.id:' => $foreignLink . 'Id',
+ 'deleted' => false,
+ $foreignLink . '.id!=' => null,
+ ]
+ ], $selectParams);
+ $selectParams['whereClause'][] = [$foreignLink . 'Type' => $entity->getEntityType()];
+
+ } else {
+ $foreignSelectManager->addJoin($foreignLink, $selectParams);
+ }
$selectParams['groupBy'] = [$foreignLink . '.id'];