mirror of
https://github.com/espocrm/espocrm.git
synced 2026-06-28 23:16:03 +00:00
Merge branch 'hotfix/5.6.6'
This commit is contained in:
@@ -284,6 +284,7 @@ class Sender
|
||||
$contents = $a->get('contents');
|
||||
} else {
|
||||
$fileName = $this->getEntityManager()->getRepository('Attachment')->getFilePath($a);
|
||||
if (!is_file($fileName)) continue;
|
||||
$contents = file_get_contents($fileName);
|
||||
}
|
||||
$attachment = new MimePart($contents);
|
||||
@@ -303,6 +304,7 @@ class Sender
|
||||
$contents = $a->get('contents');
|
||||
} else {
|
||||
$fileName = $this->getEntityManager()->getRepository('Attachment')->getFilePath($a);
|
||||
if (!is_file($fileName)) continue;
|
||||
$contents = file_get_contents($fileName);
|
||||
}
|
||||
$attachment = new MimePart($contents);
|
||||
|
||||
@@ -433,6 +433,8 @@ class Cleanup extends \Espo\Core\Jobs\Base
|
||||
$period = '-' . $this->getConfig()->get('cleanupDeletedRecordsPeriod', $this->cleanupDeletedRecordsPeriod);
|
||||
$datetime = new \DateTime($period);
|
||||
|
||||
$serviceFactory = $this->getServiceFactory();
|
||||
|
||||
$scopeList = array_keys($this->getMetadata()->get(['scopes']));
|
||||
foreach ($scopeList as $scope) {
|
||||
if (!$this->getMetadata()->get(['scopes', $scope, 'entity'])) continue;
|
||||
@@ -446,6 +448,15 @@ class Cleanup extends \Espo\Core\Jobs\Base
|
||||
if (!method_exists($repository, 'select')) continue;
|
||||
if (!method_exists($repository, 'deleteFromDb')) continue;
|
||||
|
||||
$hasCleanupMethod = false;
|
||||
$service = null;
|
||||
if ($serviceFactory->checkExists($scope)) {
|
||||
$service = $serviceFactory->create($scope);
|
||||
if (method_exists($service, 'cleanup')) {
|
||||
$hasCleanupMethod = true;
|
||||
}
|
||||
}
|
||||
|
||||
$whereClause = [
|
||||
'deleted' => 1,
|
||||
];
|
||||
@@ -458,6 +469,13 @@ class Cleanup extends \Espo\Core\Jobs\Base
|
||||
|
||||
$deletedEntityList = $repository->select(['id', 'deleted'])->where($whereClause)->find(['withDeleted' => true]);
|
||||
foreach ($deletedEntityList as $e) {
|
||||
if ($hasCleanupMethod) {
|
||||
try {
|
||||
$service->cleanup($e->id);
|
||||
} catch (\Throwable $e) {
|
||||
$GLOBALS['log']->error("Cleanup job: Cleanup scope {$scope}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
$this->cleanupDeletedEntity($e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1670,6 +1670,10 @@ abstract class Base
|
||||
|
||||
$sql = implode(' ' .$logicalOperator . ' ', $sqlList);
|
||||
|
||||
if (count($sqlList) > 1) {
|
||||
$sql = '(' . $sql . ')';
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[
|
||||
"portalRoles",
|
||||
"isActive"
|
||||
]
|
||||
@@ -0,0 +1,3 @@
|
||||
[
|
||||
"isActive"
|
||||
]
|
||||
@@ -118,6 +118,10 @@
|
||||
"view": "views/admin/dynamic-logic/conditions/field-types/base",
|
||||
"typeList": ["isEmpty", "isNotEmpty", "equals", "notEquals", "greaterThan", "lessThan", "greaterThanOrEquals", "lessThanOrEquals"]
|
||||
},
|
||||
"currency": {
|
||||
"view": "views/admin/dynamic-logic/conditions/field-types/base",
|
||||
"typeList": ["isEmpty", "isNotEmpty", "equals", "notEquals", "greaterThan", "lessThan", "greaterThanOrEquals", "lessThanOrEquals"]
|
||||
},
|
||||
"date": {
|
||||
"view": "views/admin/dynamic-logic/conditions/field-types/date",
|
||||
"typeList": ["isEmpty", "isNotEmpty", "isToday", "inFuture", "inPast", "equals", "notEquals"]
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
"list":"views/user/record/list"
|
||||
},
|
||||
"modalViews": {
|
||||
"detail": "views/user/modals/detail"
|
||||
"detail": "views/user/modals/detail",
|
||||
"massUpdate": "views/user/modals/mass-update"
|
||||
},
|
||||
"defaultSidePanel": {
|
||||
"detail": {
|
||||
|
||||
@@ -49,6 +49,12 @@ class Email extends \Espo\Core\SelectManagers\Base
|
||||
foreach ($params['where'] as $item) {
|
||||
if ($item['type'] === 'textFilter') {
|
||||
$skipIndex = true;
|
||||
break;
|
||||
} else {
|
||||
if (isset($item['attribute']) && $this->getSeed()->getAttributeParam($item['attribute'], 'type') === 'foreignId') {
|
||||
$skipIndex = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{{#unless fields}}
|
||||
{{#unless fieldList}}
|
||||
{{translate 'No fields available for Mass Update'}}
|
||||
{{else}}
|
||||
<div class="button-container">
|
||||
@@ -6,8 +6,8 @@
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-default dropdown-toggle select-field" data-toggle="dropdown" tabindex="-1">{{translate 'Select Field'}} <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu pull-left filter-list">
|
||||
{{#each ../fields}}
|
||||
<li data-name="{{./this}}"><a href="javascript:" data-name="{{./this}}" data-action="add-field">{{translate this scope=../../scope category='fields'}}</a></li>
|
||||
{{#each ../fieldList}}
|
||||
<li data-name="{{./this}}"><a href="javascript:" data-name="{{./this}}" data-action="add-field">{{translate this scope=../../entityType category='fields'}}</a></li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -95,7 +95,7 @@ Espo.define('views/admin/field-manager/fields/options-with-style', 'views/admin/
|
||||
}
|
||||
}
|
||||
var translated = this.getLanguage().translateOption(item, 'style', 'LayoutManager');
|
||||
var innerHtml = '<span class="check-icon fas fa-check pull-right'+hiddenPart+'"></span><div>'+translated+'</div>';
|
||||
var innerHtml = '<span class="check-icon fas fa-check pull-right'+hiddenPart+'"></span><div class="text-'+item+'">'+translated+'</div>';
|
||||
itemListHtml += '<li><a href="javascript:" data-action="selectOptionItemStyle" data-style="'+item+'" data-value="'+valueInternal+'">'+innerHtml+'</a></li>'
|
||||
}, this);
|
||||
|
||||
|
||||
@@ -220,9 +220,9 @@ Espo.define('views/fields/link-multiple', 'views/fields/base', function (Dep) {
|
||||
response.list.forEach(function(item) {
|
||||
list.push({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
name: item.name || item.id,
|
||||
data: item.id,
|
||||
value: item.name
|
||||
value: item.name || item.id,
|
||||
});
|
||||
}, this);
|
||||
return {
|
||||
|
||||
@@ -277,9 +277,9 @@ Espo.define('views/fields/link-parent', 'views/fields/base', function (Dep) {
|
||||
response.list.forEach(function(item) {
|
||||
list.push({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
name: item.name || item.id,
|
||||
data: item.id,
|
||||
value: item.name,
|
||||
value: item.name || item.id,
|
||||
attributes: item
|
||||
});
|
||||
}, this);
|
||||
|
||||
@@ -287,9 +287,9 @@ Espo.define('views/fields/link', 'views/fields/base', function (Dep) {
|
||||
response.list.forEach(function(item) {
|
||||
list.push({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
name: item.name || item.id,
|
||||
data: item.id,
|
||||
value: item.name,
|
||||
value: item.name || item.id,
|
||||
attributes: item
|
||||
});
|
||||
}, this);
|
||||
@@ -333,9 +333,9 @@ Espo.define('views/fields/link', 'views/fields/base', function (Dep) {
|
||||
response.list.forEach(function(item) {
|
||||
list.push({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
name: item.name || item.id,
|
||||
data: item.id,
|
||||
value: item.name
|
||||
value: item.name || item.id,
|
||||
});
|
||||
}, this);
|
||||
return {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('views/modals/mass-update', 'views/modal', function (Dep) {
|
||||
define('views/modals/mass-update', 'views/modal', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
@@ -34,10 +34,13 @@ Espo.define('views/modals/mass-update', 'views/modal', function (Dep) {
|
||||
|
||||
template: 'modals/mass-update',
|
||||
|
||||
layoutName: 'massUpdate',
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
scope: this.scope,
|
||||
fields: this.fields
|
||||
fieldList: this.fieldList,
|
||||
entityType: this.entityType,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -68,7 +71,9 @@ Espo.define('views/modals/mass-update', 'views/modal', function (Dep) {
|
||||
}
|
||||
];
|
||||
|
||||
this.scope = this.options.scope;
|
||||
this.entityType = this.options.entityType || this.options.scope;
|
||||
this.scope = this.options.scope || this.entityType;
|
||||
|
||||
this.ids = this.options.ids;
|
||||
this.where = this.options.where;
|
||||
this.selectData = this.options.selectData;
|
||||
@@ -76,15 +81,18 @@ Espo.define('views/modals/mass-update', 'views/modal', function (Dep) {
|
||||
|
||||
this.headerHtml = this.translate(this.scope, 'scopeNamesPlural') + ' » ' + this.translate('Mass Update');
|
||||
|
||||
var fobiddenList = this.getAcl().getScopeForbiddenFieldList(this.entityType, 'edit') || [];
|
||||
|
||||
this.wait(true);
|
||||
this.getModelFactory().create(this.scope, function (model) {
|
||||
this.getModelFactory().create(this.entityType, function (model) {
|
||||
this.model = model;
|
||||
this.getHelper().layoutManager.get(this.scope, 'massUpdate', function (layout) {
|
||||
this.getHelper().layoutManager.get(this.entityType, this.layoutName, function (layout) {
|
||||
layout = layout || [];
|
||||
this.fields = [];
|
||||
this.fieldList = [];
|
||||
layout.forEach(function (field) {
|
||||
if (~fobiddenList.indexOf(field)) return;
|
||||
if (model.hasField(field)) {
|
||||
this.fields.push(field);
|
||||
this.fieldList.push(field);
|
||||
}
|
||||
}, this);
|
||||
|
||||
@@ -92,7 +100,7 @@ Espo.define('views/modals/mass-update', 'views/modal', function (Dep) {
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
|
||||
this.fieldList = [];
|
||||
this.addedFieldList = [];
|
||||
},
|
||||
|
||||
addField: function (name) {
|
||||
@@ -107,7 +115,7 @@ Espo.define('views/modals/mass-update', 'views/modal', function (Dep) {
|
||||
}
|
||||
|
||||
this.notify('Loading...');
|
||||
var label = this.translate(name, 'fields', this.scope);
|
||||
var label = this.translate(name, 'fields', this.entityType);
|
||||
var html = '<div class="cell form-group col-sm-6" data-name="'+name+'"><label class="control-label">'+label+'</label><div class="field" data-name="'+name+'" /></div>';
|
||||
this.$el.find('.fields-container').append(html);
|
||||
|
||||
@@ -123,7 +131,7 @@ Espo.define('views/modals/mass-update', 'views/modal', function (Dep) {
|
||||
},
|
||||
mode: 'edit'
|
||||
}, function (view) {
|
||||
this.fieldList.push(name);
|
||||
this.addedFieldList.push(name);
|
||||
view.render();
|
||||
view.notify(false);
|
||||
}.bind(this));
|
||||
@@ -135,7 +143,7 @@ Espo.define('views/modals/mass-update', 'views/modal', function (Dep) {
|
||||
var self = this;
|
||||
|
||||
var attributes = {};
|
||||
this.fieldList.forEach(function (field) {
|
||||
this.addedFieldList.forEach(function (field) {
|
||||
var view = self.getView(field);
|
||||
_.extend(attributes, view.fetch());
|
||||
});
|
||||
@@ -143,7 +151,7 @@ Espo.define('views/modals/mass-update', 'views/modal', function (Dep) {
|
||||
this.model.set(attributes);
|
||||
|
||||
var notValid = false;
|
||||
this.fieldList.forEach(function (field) {
|
||||
this.addedFieldList.forEach(function (field) {
|
||||
var view = self.getView(field);
|
||||
notValid = view.validate() || notValid;
|
||||
});
|
||||
@@ -151,7 +159,7 @@ Espo.define('views/modals/mass-update', 'views/modal', function (Dep) {
|
||||
if (!notValid) {
|
||||
self.notify('Saving...');
|
||||
$.ajax({
|
||||
url: this.scope + '/action/massUpdate',
|
||||
url: this.entityType + '/action/massUpdate',
|
||||
type: 'PUT',
|
||||
data: JSON.stringify({
|
||||
attributes: attributes,
|
||||
@@ -178,12 +186,12 @@ Espo.define('views/modals/mass-update', 'views/modal', function (Dep) {
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
this.fieldList.forEach(function (field) {
|
||||
this.addedFieldList.forEach(function (field) {
|
||||
this.clearView(field);
|
||||
this.$el.find('.cell[data-name="'+field+'"]').remove();
|
||||
}, this);
|
||||
|
||||
this.fieldList = [];
|
||||
this.addedFieldList = [];
|
||||
|
||||
this.model.clear();
|
||||
|
||||
|
||||
@@ -795,12 +795,16 @@ define('views/record/list', 'view', function (Dep) {
|
||||
ids = this.checkedList;
|
||||
}
|
||||
|
||||
this.createView('massUpdate', 'views/modals/mass-update', {
|
||||
scope: this.entityType,
|
||||
var viewName = this.getMetadata().get(['clientDefs', this.entityType, 'modalViews', 'massUpdate']) ||
|
||||
'views/modals/mass-update';
|
||||
|
||||
this.createView('massUpdate', viewName, {
|
||||
scope: this.scope,
|
||||
entityType: this.entityType,
|
||||
ids: ids,
|
||||
where: this.collection.getWhere(),
|
||||
selectData: this.collection.data,
|
||||
byWhere: this.allResultIsChecked
|
||||
byWhere: this.allResultIsChecked,
|
||||
}, function (view) {
|
||||
view.render();
|
||||
view.notify(false);
|
||||
|
||||
44
client/src/views/user/modals/mass-update.js
Normal file
44
client/src/views/user/modals/mass-update.js
Normal file
@@ -0,0 +1,44 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2019 Yuri Kuznetsov, Taras Machyshyn, Oleksiy 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.
|
||||
************************************************************************/
|
||||
|
||||
define('views/user/modals/mass-update', 'views/modals/mass-update', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
setup: function () {
|
||||
|
||||
if (this.options.scope === 'ApiUser') {
|
||||
this.layoutName = 'massUpdateApi';
|
||||
} else if (this.options.scope === 'PortalUser') {
|
||||
this.layoutName = 'massUpdatePortal';
|
||||
}
|
||||
Dep.prototype.setup.call(this);
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
@@ -269,7 +269,26 @@ class QueryTest extends \PHPUnit\Framework\TestCase
|
||||
'withDeleted' => true,
|
||||
]);
|
||||
|
||||
$expectedSql = "SELECT note.id AS `id` FROM `note` LEFT JOIN `post` AS `post` ON post.name = 'test' OR post.name IS NULL";
|
||||
$expectedSql = "SELECT note.id AS `id` FROM `note` LEFT JOIN `post` AS `post` ON (post.name = 'test' OR post.name IS NULL)";
|
||||
|
||||
$this->assertEquals($expectedSql, $sql);
|
||||
}
|
||||
|
||||
public function testJoinConditions4()
|
||||
{
|
||||
$sql = $this->query->createSelectQuery('Note', [
|
||||
'select' => ['id'],
|
||||
'leftJoins' => [['post', 'post', [
|
||||
'name' => null,
|
||||
'OR' => [
|
||||
['name' => 'test'],
|
||||
['post.name' => null],
|
||||
]
|
||||
]]],
|
||||
'withDeleted' => true,
|
||||
]);
|
||||
|
||||
$expectedSql = "SELECT note.id AS `id` FROM `note` LEFT JOIN `post` AS `post` ON post.name IS NULL AND (post.name = 'test' OR post.name IS NULL)";
|
||||
|
||||
$this->assertEquals($expectedSql, $sql);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user