Merge branch 'hotfix/5.5.4'
This commit is contained in:
@@ -378,7 +378,8 @@ class Container
|
||||
{
|
||||
return new \Espo\Core\Utils\ClientManager(
|
||||
$this->get('config'),
|
||||
$this->get('themeManager')
|
||||
$this->get('themeManager'),
|
||||
$this->get('metadata')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class Record extends Base
|
||||
public function actionRead($params, $data, $request)
|
||||
{
|
||||
$id = $params['id'];
|
||||
$entity = $this->getRecordService()->readEntity($id);
|
||||
$entity = $this->getRecordService()->read($id);
|
||||
|
||||
if (empty($entity)) {
|
||||
throw new NotFound();
|
||||
@@ -95,7 +95,7 @@ class Record extends Base
|
||||
|
||||
$service = $this->getRecordService();
|
||||
|
||||
if ($entity = $service->createEntity($data)) {
|
||||
if ($entity = $service->create($data)) {
|
||||
return $entity->getValueMap();
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ class Record extends Base
|
||||
|
||||
$id = $params['id'];
|
||||
|
||||
if ($entity = $this->getRecordService()->updateEntity($id, $data)) {
|
||||
if ($entity = $this->getRecordService()->update($id, $data)) {
|
||||
return $entity->getValueMap();
|
||||
}
|
||||
|
||||
@@ -140,12 +140,12 @@ class Record extends Base
|
||||
throw new Forbidden("Max size should should not exceed " . $maxSizeLimit . ". Use offset and limit.");
|
||||
}
|
||||
|
||||
$result = $this->getRecordService()->findEntities($params);
|
||||
$result = $this->getRecordService()->find($params);
|
||||
|
||||
return array(
|
||||
return [
|
||||
'total' => $result['total'],
|
||||
'list' => isset($result['collection']) ? $result['collection']->getValueMapList() : $result['list']
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
public function getActionListKanban($params, $data, $request)
|
||||
@@ -195,7 +195,7 @@ class Record extends Base
|
||||
throw new Forbidden("Max size should should not exceed " . $maxSizeLimit . ". Use offset and limit.");
|
||||
}
|
||||
|
||||
$result = $this->getRecordService()->findLinkedEntities($id, $link, $params);
|
||||
$result = $this->getRecordService()->findLinked($id, $link, $params);
|
||||
|
||||
return array(
|
||||
'total' => $result['total'],
|
||||
@@ -211,7 +211,7 @@ class Record extends Base
|
||||
|
||||
$id = $params['id'];
|
||||
|
||||
if ($this->getRecordService()->deleteEntity($id)) {
|
||||
if ($this->getRecordService()->delete($id)) {
|
||||
return true;
|
||||
}
|
||||
throw new Error();
|
||||
@@ -262,9 +262,9 @@ class Record extends Base
|
||||
$params['format'] = $data->format;
|
||||
}
|
||||
|
||||
return array(
|
||||
return [
|
||||
'id' => $this->getRecordService()->export($params)
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
public function actionMassUpdate($params, $data, $request)
|
||||
@@ -363,7 +363,7 @@ class Record extends Base
|
||||
|
||||
$result = false;
|
||||
foreach ($foreignIdList as $foreignId) {
|
||||
if ($this->getRecordService()->linkEntity($id, $link, $foreignId)) {
|
||||
if ($this->getRecordService()->link($id, $link, $foreignId)) {
|
||||
$result = true;
|
||||
}
|
||||
}
|
||||
@@ -400,7 +400,7 @@ class Record extends Base
|
||||
|
||||
$result = false;
|
||||
foreach ($foreignIdList as $foreignId) {
|
||||
if ($this->getRecordService()->unlinkEntity($id, $link, $foreignId)) {
|
||||
if ($this->getRecordService()->unlink($id, $link, $foreignId)) {
|
||||
$result = $result || true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,42 +35,19 @@ class ClientManager
|
||||
|
||||
private $config;
|
||||
|
||||
private $metadata;
|
||||
|
||||
protected $mainHtmlFilePath = 'html/main.html';
|
||||
|
||||
protected $runScript = "app.start();";
|
||||
|
||||
protected $basePath = '';
|
||||
|
||||
protected $jsFileList = [
|
||||
'client/espo.min.js'
|
||||
];
|
||||
|
||||
protected $developerModeJsFileList = [
|
||||
'client/lib/jquery-2.1.4.min.js',
|
||||
'client/lib/underscore-min.js',
|
||||
'client/lib/es6-promise.min.js',
|
||||
'client/lib/backbone-min.js',
|
||||
'client/lib/handlebars.js',
|
||||
'client/lib/base64.js',
|
||||
'client/lib/jquery-ui.min.js',
|
||||
'client/lib/jquery.ui.touch-punch.min.js',
|
||||
'client/lib/moment.min.js',
|
||||
'client/lib/moment-timezone-with-data.min.js',
|
||||
'client/lib/jquery.timepicker.min.js',
|
||||
'client/lib/jquery.autocomplete.js',
|
||||
'client/lib/bootstrap.min.js',
|
||||
'client/lib/bootstrap-datepicker.js',
|
||||
'client/lib/bull.js',
|
||||
'client/lib/marked.min.js',
|
||||
'client/src/loader.js',
|
||||
'client/src/utils.js',
|
||||
'client/src/exceptions.js',
|
||||
];
|
||||
|
||||
public function __construct(Config $config, ThemeManager $themeManager)
|
||||
public function __construct(Config $config, ThemeManager $themeManager, Metadata $metadata)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->themeManager = $themeManager;
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
|
||||
protected function getThemeManager()
|
||||
@@ -83,6 +60,11 @@ class ClientManager
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
protected function getMetadata()
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
public function setBasePath($basePath)
|
||||
{
|
||||
$this->basePath = $basePath;
|
||||
@@ -116,11 +98,11 @@ class ClientManager
|
||||
|
||||
if ($isDeveloperMode) {
|
||||
$useCache = $this->getConfig()->get('useCacheInDeveloperMode');
|
||||
$jsFileList = $this->developerModeJsFileList;
|
||||
$jsFileList = $this->getMetadata()->get(['app', 'client', 'developerModeScriptList']);
|
||||
$loaderCacheTimestamp = 'null';
|
||||
} else {
|
||||
$useCache = $this->getConfig()->get('useCache');
|
||||
$jsFileList = $this->jsFileList;
|
||||
$jsFileList = $this->getMetadata()->get(['app', 'client', 'scriptList']);
|
||||
$loaderCacheTimestamp = $cacheTimestamp;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ class Metadata
|
||||
protected $frontendHiddenPathList = [
|
||||
['app', 'formula', 'functionClassNameMap'],
|
||||
['app', 'fileStorage', 'implementationClassNameMap'],
|
||||
['app', 'emailNotifications', 'handlerClassNameMap']
|
||||
['app', 'emailNotifications', 'handlerClassNameMap'],
|
||||
['app', 'client'],
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,23 +38,31 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
{
|
||||
public static $authRequired = true;
|
||||
|
||||
protected $allowedFileTypes = array(
|
||||
protected $allowedFileTypes = [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
);
|
||||
'image/webp',
|
||||
];
|
||||
|
||||
protected $imageSizes = array(
|
||||
'xxx-small' => array(18, 18),
|
||||
'xx-small' => array(32, 32),
|
||||
'x-small' => array(64, 64),
|
||||
'small' => array(128, 128),
|
||||
'medium' => array(256, 256),
|
||||
'large' => array(512, 512),
|
||||
'x-large' => array(864, 864),
|
||||
'xx-large' => array(1024, 1024),
|
||||
);
|
||||
protected $imageSizes = [
|
||||
'xxx-small' => [18, 18],
|
||||
'xx-small' => [32, 32],
|
||||
'x-small' => [64, 64],
|
||||
'small' => [128, 128],
|
||||
'medium' => [256, 256],
|
||||
'large' => [512, 512],
|
||||
'x-large' => [864, 864],
|
||||
'xx-large' => [1024, 1024],
|
||||
];
|
||||
|
||||
protected $fixOrientationFileTypeList = [
|
||||
'image/jpeg',
|
||||
];
|
||||
|
||||
protected $allowedRelatedTypeList = null;
|
||||
|
||||
protected $allowedFieldList = null;
|
||||
|
||||
public function run()
|
||||
{
|
||||
@@ -68,7 +76,7 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
$size = $_GET['size'];
|
||||
}
|
||||
|
||||
$this->show($id, $size);
|
||||
$this->show($id, $size, false);
|
||||
}
|
||||
|
||||
protected function show($id, $size, $disableAccessCheck = false)
|
||||
@@ -97,6 +105,18 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if ($this->allowedRelatedTypeList) {
|
||||
if (!in_array($attachment->get('relatedType'), $this->allowedRelatedTypeList)) {
|
||||
throw new NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->allowedFieldList) {
|
||||
if (!in_array($attachment->get('field'), $this->allowedFieldList)) {
|
||||
throw new NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($size)) {
|
||||
if (!empty($this->imageSizes[$size])) {
|
||||
$thumbFilePath = "data/upload/thumbs/{$sourceId}_{$size}";
|
||||
@@ -115,6 +135,9 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
case 'image/gif':
|
||||
imagegif($targetImage);
|
||||
break;
|
||||
case 'image/webp':
|
||||
imagewebp($targetImage);
|
||||
break;
|
||||
}
|
||||
$contents = ob_get_contents();
|
||||
ob_end_clean();
|
||||
@@ -181,7 +204,7 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
switch ($fileType) {
|
||||
case 'image/jpeg':
|
||||
$sourceImage = imagecreatefromjpeg($filePath);
|
||||
imagecopyresampled ($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight);
|
||||
imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight);
|
||||
break;
|
||||
case 'image/png':
|
||||
$sourceImage = imagecreatefrompng($filePath);
|
||||
@@ -195,10 +218,34 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
$sourceImage = imagecreatefromgif($filePath);
|
||||
imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight);
|
||||
break;
|
||||
case 'image/webp':
|
||||
$sourceImage = imagecreatefromwebp($filePath);
|
||||
imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight);
|
||||
break;
|
||||
}
|
||||
|
||||
if (in_array($fileType, $this->fixOrientationFileTypeList)) {
|
||||
$targetImage = $this->fixOrientation($targetImage, $filePath);
|
||||
}
|
||||
|
||||
return $targetImage;
|
||||
}
|
||||
|
||||
protected function getOrientation($filePath)
|
||||
{
|
||||
$orientation = 0;
|
||||
if (function_exists('exif_read_data')) {
|
||||
$targetImage = imagerotate($targetImage, array_values([0, 0, 0, 180, 0, 0, -90, 0, 90])[@exif_read_data($filePath)['Orientation'] ?: 0], 0);
|
||||
$orientation = @exif_read_data($filePath)['Orientation'];
|
||||
}
|
||||
return $orientation;
|
||||
}
|
||||
|
||||
protected function fixOrientation($targetImage, $filePath)
|
||||
{
|
||||
$orientation = $this->getOrientation($filePath);
|
||||
if ($orientation) {
|
||||
$angle = array_values([0, 0, 0, 180, 0, 0, -90, 0, 90])[$orientation];
|
||||
$targetImage = imagerotate($targetImage, $angle, 0);
|
||||
}
|
||||
|
||||
return $targetImage;
|
||||
|
||||
@@ -38,6 +38,10 @@ class LogoImage extends Image
|
||||
{
|
||||
public static $authRequired = false;
|
||||
|
||||
protected $allowedRelatedTypeList = ['Settings', 'Portal'];
|
||||
|
||||
protected $allowedFieldList = ['companyLogo'];
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->imageSizes['small-logo'] = array(181, 44);
|
||||
|
||||
@@ -35,6 +35,24 @@ use Espo\Core\Utils\Util;
|
||||
|
||||
class Attachment extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
protected $imageTypeList = [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
];
|
||||
|
||||
protected $imageThumbList = [
|
||||
'xxx-small',
|
||||
'xx-small',
|
||||
'x-small',
|
||||
'small',
|
||||
'medium',
|
||||
'large',
|
||||
'x-large',
|
||||
'xx-large',
|
||||
];
|
||||
|
||||
protected function init()
|
||||
{
|
||||
parent::init();
|
||||
@@ -42,6 +60,11 @@ class Attachment extends \Espo\Core\ORM\Repositories\RDB
|
||||
$this->addDependency('config');
|
||||
}
|
||||
|
||||
protected function getFileManager()
|
||||
{
|
||||
return $this->getInjection('container')->get('fileManager');
|
||||
}
|
||||
|
||||
protected function getFileStorageManager()
|
||||
{
|
||||
return $this->getInjection('container')->get('fileStorageManager');
|
||||
@@ -106,6 +129,20 @@ class Attachment extends \Espo\Core\ORM\Repositories\RDB
|
||||
|
||||
if ($duplicateCount === 0) {
|
||||
$this->getFileStorageManager()->unlink($entity);
|
||||
|
||||
if (in_array($entity->get('type'), $this->imageTypeList)) {
|
||||
$this->removeImageThumbs($entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function removeImageThumbs($entity)
|
||||
{
|
||||
foreach ($this->imageThumbList as $suffix) {
|
||||
$filePath = "data/upload/thumbs/".$entity->getSourceId()."_{$suffix}";
|
||||
if ($this->getFileManager()->isFile($filePath)) {
|
||||
$this->getFileManager()->removeFile($filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
|
||||
public function getIds(array $addressList = [])
|
||||
{
|
||||
$ids = array();
|
||||
$ids = [];
|
||||
if (!empty($addressList)) {
|
||||
$lowerAddressList = [];
|
||||
foreach ($addressList as $address) {
|
||||
@@ -72,8 +72,8 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
]
|
||||
])->find();
|
||||
|
||||
$ids = array();
|
||||
$exist = array();
|
||||
$ids = [];
|
||||
$exist = [];
|
||||
foreach ($eaCollection as $ea) {
|
||||
$ids[] = $ea->id;
|
||||
$exist[] = $ea->get('lower');
|
||||
@@ -96,7 +96,7 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
|
||||
public function getEmailAddressData(Entity $entity)
|
||||
{
|
||||
$data = array();
|
||||
$data = [];
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
$sql = "
|
||||
@@ -105,7 +105,7 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
JOIN email_address ON email_address.id = entity_email_address.email_address_id AND email_address.deleted = 0
|
||||
WHERE
|
||||
entity_email_address.entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_email_address.entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
entity_email_address.entity_type = ".$pdo->quote($entity->getEntityType())." AND
|
||||
entity_email_address.deleted = 0
|
||||
ORDER BY entity_email_address.primary DESC
|
||||
";
|
||||
@@ -249,40 +249,302 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
}
|
||||
}
|
||||
|
||||
public function storeEntityEmailAddress(Entity $entity)
|
||||
public function storeEntityEmailAddressData(Entity $entity)
|
||||
{
|
||||
$emailAddressValue = $entity->get('emailAddress');
|
||||
if (is_string($emailAddressValue)) {
|
||||
$emailAddressValue = trim($emailAddressValue);
|
||||
}
|
||||
$emailAddressData = null;
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
if ($entity->has('emailAddressData')) {
|
||||
$emailAddressData = $entity->get('emailAddressData');
|
||||
}
|
||||
$emailAddressValue = $entity->get('emailAddress');
|
||||
if (is_string($emailAddressValue)) {
|
||||
$emailAddressValue = trim($emailAddressValue);
|
||||
}
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
$emailAddressData = null;
|
||||
if ($entity->has('emailAddressData')) {
|
||||
$emailAddressData = $entity->get('emailAddressData');
|
||||
}
|
||||
|
||||
if ($emailAddressData !== null && is_array($emailAddressData)) {
|
||||
$previousEmailAddressData = array();
|
||||
if (!$entity->isNew()) {
|
||||
$previousEmailAddressData = $this->getEmailAddressData($entity);
|
||||
if (is_null($emailAddressData)) return;
|
||||
if (!is_array($emailAddressData)) return;
|
||||
|
||||
$keyList = [];
|
||||
$keyPreviousList = [];
|
||||
|
||||
$previousEmailAddressData = [];
|
||||
if (!$entity->isNew()) {
|
||||
$previousEmailAddressData = $this->getEmailAddressData($entity);
|
||||
}
|
||||
|
||||
$hash = (object) [];
|
||||
$hashPrevious = (object) [];
|
||||
|
||||
foreach ($emailAddressData as $row) {
|
||||
$key = trim($row->emailAddress);
|
||||
if (empty($key)) continue;
|
||||
$key = strtolower($key);
|
||||
$hash->$key = [
|
||||
'primary' => !empty($row->primary) ? true : false,
|
||||
'optOut' => !empty($row->optOut) ? true : false,
|
||||
'invalid' => !empty($row->invalid) ? true : false,
|
||||
'emailAddress' => trim($row->emailAddress)
|
||||
];
|
||||
$keyList[] = $key;
|
||||
}
|
||||
|
||||
if (
|
||||
$entity->has('emailAddressIsOptedOut')
|
||||
&&
|
||||
(
|
||||
$entity->isNew()
|
||||
||
|
||||
(
|
||||
$entity->hasFetched('emailAddressIsOptedOut')
|
||||
&&
|
||||
$entity->get('emailAddressIsOptedOut') !== $entity->getFetched('emailAddressIsOptedOut')
|
||||
)
|
||||
)
|
||||
) {
|
||||
if ($emailAddressValue) {
|
||||
$key = strtolower($emailAddressValue);
|
||||
if ($key && isset($hash->$key)) {
|
||||
$hash->$key['optOut'] = $entity->get('emailAddressIsOptedOut');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$hash = array();
|
||||
foreach ($emailAddressData as $row) {
|
||||
$key = trim($row->emailAddress);
|
||||
if (!empty($key)) {
|
||||
$key = strtolower($key);
|
||||
$hash[$key] = [
|
||||
'primary' => !empty($row->primary) ? true : false,
|
||||
'optOut' => !empty($row->optOut) ? true : false,
|
||||
'invalid' => !empty($row->invalid) ? true : false,
|
||||
'emailAddress' => trim($row->emailAddress)
|
||||
];
|
||||
foreach ($previousEmailAddressData as $row) {
|
||||
$key = $row->lower;
|
||||
if (empty($key)) continue;
|
||||
$hashPrevious->$key = [
|
||||
'primary' => $row->primary ? true : false,
|
||||
'optOut' => $row->optOut ? true : false,
|
||||
'invalid' => $row->invalid ? true : false,
|
||||
'emailAddress' => $row->emailAddress
|
||||
];
|
||||
$keyPreviousList[] = $key;
|
||||
}
|
||||
|
||||
$primary = false;
|
||||
|
||||
$toCreateList = [];
|
||||
$toUpdateList = [];
|
||||
$toRemoveList = [];
|
||||
|
||||
$revertData = [];
|
||||
|
||||
foreach ($keyList as $key) {
|
||||
$data = $hash->$key;
|
||||
|
||||
$new = true;
|
||||
$changed = false;
|
||||
|
||||
if ($hash->$key['primary']) {
|
||||
$primary = $key;
|
||||
}
|
||||
|
||||
if (property_exists($hashPrevious, $key)) {
|
||||
$new = false;
|
||||
$changed =
|
||||
$hash->$key['optOut'] != $hashPrevious->$key['optOut'] ||
|
||||
$hash->$key['invalid'] != $hashPrevious->$key['invalid'] ||
|
||||
$hash->$key['emailAddress'] !== $hashPrevious->$key['emailAddress'];
|
||||
|
||||
if ($hash->$key['primary']) {
|
||||
if ($hash->$key['primary'] == $hashPrevious->$key['primary']) {
|
||||
$primary = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($new) {
|
||||
$toCreateList[] = $key;
|
||||
}
|
||||
if ($changed) {
|
||||
$toUpdateList[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($keyPreviousList as $key) {
|
||||
if (!property_exists($hash, $key)) {
|
||||
$toRemoveList[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($toRemoveList as $address) {
|
||||
$emailAddress = $this->getByAddress($address);
|
||||
if ($emailAddress) {
|
||||
$query = "
|
||||
DELETE FROM entity_email_address
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityType())." AND
|
||||
email_address_id = ".$pdo->quote($emailAddress->id)."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($toUpdateList as $address) {
|
||||
$emailAddress = $this->getByAddress($address);
|
||||
if ($emailAddress) {
|
||||
$skipSave = $this->checkChangeIsForbidden($emailAddress, $entity);
|
||||
if (!$skipSave) {
|
||||
$emailAddress->set([
|
||||
'optOut' => $hash->$address['optOut'],
|
||||
'invalid' => $hash->$address['invalid'],
|
||||
'name' => $hash->$address['emailAddress']
|
||||
]);
|
||||
$this->save($emailAddress);
|
||||
} else {
|
||||
$revertData[$address] = [
|
||||
'optOut' => $emailAddress->get('optOut'),
|
||||
'invalid' => $emailAddress->get('invalid')
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($toCreateList as $address) {
|
||||
$emailAddress = $this->getByAddress($address);
|
||||
if (!$emailAddress) {
|
||||
$emailAddress = $this->get();
|
||||
|
||||
$emailAddress->set([
|
||||
'name' => $hash->$address['emailAddress'],
|
||||
'optOut' => $hash->$address['optOut'],
|
||||
'invalid' => $hash->$address['invalid'],
|
||||
]);
|
||||
$this->save($emailAddress);
|
||||
} else {
|
||||
$skipSave = $this->checkChangeIsForbidden($emailAddress, $entity);
|
||||
if (!$skipSave) {
|
||||
if (
|
||||
$emailAddress->get('optOut') != $hash->$address['optOut'] ||
|
||||
$emailAddress->get('invalid') != $hash->$address['invalid'] ||
|
||||
$emailAddress->get('emailAddress') != $hash->$address['emailAddress']
|
||||
) {
|
||||
$emailAddress->set([
|
||||
'optOut' => $hash->$address['optOut'],
|
||||
'invalid' => $hash->$address['invalid'],
|
||||
'name' => $hash->$address['emailAddress']
|
||||
]);
|
||||
$this->save($emailAddress);
|
||||
}
|
||||
} else {
|
||||
$revertData[$address] = [
|
||||
'optOut' => $emailAddress->get('optOut'),
|
||||
'invalid' => $emailAddress->get('invalid')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$query = "
|
||||
INSERT entity_email_address
|
||||
(entity_id, entity_type, email_address_id, `primary`)
|
||||
VALUES
|
||||
(
|
||||
".$pdo->quote($entity->id).",
|
||||
".$pdo->quote($entity->getEntityType()).",
|
||||
".$pdo->quote($emailAddress->id).",
|
||||
".$pdo->quote((int)($address === $primary))."
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE deleted = 0, `primary` = ".$pdo->quote((int)($address === $primary))."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
|
||||
if ($primary) {
|
||||
$emailAddress = $this->getByAddress($primary);
|
||||
if ($emailAddress) {
|
||||
$query = "
|
||||
UPDATE entity_email_address
|
||||
SET `primary` = 0
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityType())." AND
|
||||
`primary` = 1 AND
|
||||
deleted = 0
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
|
||||
$query = "
|
||||
UPDATE entity_email_address
|
||||
SET `primary` = 1
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityType())." AND
|
||||
email_address_id = ".$pdo->quote($emailAddress->id)." AND
|
||||
deleted = 0
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($revertData)) {
|
||||
foreach ($emailAddressData as $row) {
|
||||
if (!empty($revertData[$row->emailAddress])) {
|
||||
$row->optOut = $revertData[$row->emailAddress]['optOut'];
|
||||
$row->invalid = $revertData[$row->emailAddress]['invalid'];
|
||||
}
|
||||
}
|
||||
$entity->set('emailAddressData', $emailAddressData);
|
||||
}
|
||||
}
|
||||
|
||||
protected function storeEntityEmailAddressPrimary(Entity $entity)
|
||||
{
|
||||
if (!$entity->has('emailAddress')) return;
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$emailAddressValue = $entity->get('emailAddress');
|
||||
if (is_string($emailAddressValue)) {
|
||||
$emailAddressValue = trim($emailAddressValue);
|
||||
}
|
||||
|
||||
$entityRepository = $this->getEntityManager()->getRepository($entity->getEntityType());
|
||||
if (!empty($emailAddressValue)) {
|
||||
if ($emailAddressValue != $entity->getFetched('emailAddress')) {
|
||||
|
||||
$emailAddressNew = $this->where(['lower' => strtolower($emailAddressValue)])->findOne();
|
||||
$isNewEmailAddress = false;
|
||||
if (!$emailAddressNew) {
|
||||
$emailAddressNew = $this->get();
|
||||
$emailAddressNew->set('name', $emailAddressValue);
|
||||
if ($entity->has('emailAddressIsOptedOut')) {
|
||||
$emailAddressNew->set('optOut', !!$entity->get('emailAddressIsOptedOut'));
|
||||
}
|
||||
$this->save($emailAddressNew);
|
||||
$isNewEmailAddress = true;
|
||||
}
|
||||
|
||||
$emailAddressValueOld = $entity->getFetched('emailAddress');
|
||||
if (!empty($emailAddressValueOld)) {
|
||||
$emailAddressOld = $this->getByAddress($emailAddressValueOld);
|
||||
if ($emailAddressOld) {
|
||||
$entityRepository->unrelate($entity, 'emailAddresses', $emailAddressOld);
|
||||
}
|
||||
}
|
||||
$entityRepository->relate($entity, 'emailAddresses', $emailAddressNew);
|
||||
|
||||
if ($entity->has('emailAddressIsOptedOut')) {
|
||||
$this->markAddressOptedOut($emailAddressValue, !!$entity->get('emailAddressIsOptedOut'));
|
||||
}
|
||||
|
||||
$query = "
|
||||
UPDATE entity_email_address
|
||||
SET `primary` = 1
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityType())." AND
|
||||
email_address_id = ".$pdo->quote($emailAddressNew->id)."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
} else {
|
||||
if (
|
||||
$entity->has('emailAddressIsOptedOut')
|
||||
&&
|
||||
@@ -296,264 +558,33 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
)
|
||||
)
|
||||
) {
|
||||
if ($emailAddressValue) {
|
||||
$key = strtolower($emailAddressValue);
|
||||
if ($key && isset($hash[$key])) {
|
||||
$hash[$key]['optOut'] = $entity->get('emailAddressIsOptedOut');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$hashPrev = array();
|
||||
foreach ($previousEmailAddressData as $row) {
|
||||
$key = $row->lower;
|
||||
if (!empty($key)) {
|
||||
$hashPrev[$key] = array(
|
||||
'primary' => $row->primary ? true : false,
|
||||
'optOut' => $row->optOut ? true : false,
|
||||
'invalid' => $row->invalid ? true : false,
|
||||
'emailAddress' => $row->emailAddress
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$primary = false;
|
||||
$toCreate = array();
|
||||
$toUpdate = array();
|
||||
$toRemove = array();
|
||||
|
||||
$revertData = [];
|
||||
|
||||
foreach ($hash as $key => $data) {
|
||||
$new = true;
|
||||
$changed = false;
|
||||
|
||||
if ($hash[$key]['primary']) {
|
||||
$primary = $key;
|
||||
}
|
||||
|
||||
if (array_key_exists($key, $hashPrev)) {
|
||||
$new = false;
|
||||
$changed =
|
||||
$hash[$key]['optOut'] != $hashPrev[$key]['optOut'] ||
|
||||
$hash[$key]['invalid'] != $hashPrev[$key]['invalid'] ||
|
||||
$hash[$key]['emailAddress'] !== $hashPrev[$key]['emailAddress'];
|
||||
|
||||
if ($hash[$key]['primary']) {
|
||||
if ($hash[$key]['primary'] == $hashPrev[$key]['primary']) {
|
||||
$primary = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($new) {
|
||||
$toCreate[] = $key;
|
||||
}
|
||||
if ($changed) {
|
||||
$toUpdate[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($hashPrev as $key => $data) {
|
||||
if (!array_key_exists($key, $hash)) {
|
||||
$toRemove[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($toRemove as $address) {
|
||||
$emailAddress = $this->getByAddress($address);
|
||||
if ($emailAddress) {
|
||||
$query = "
|
||||
DELETE FROM entity_email_address
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
email_address_id = ".$pdo->quote($emailAddress->id)."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($toUpdate as $address) {
|
||||
$emailAddress = $this->getByAddress($address);
|
||||
if ($emailAddress) {
|
||||
$skipSave = $this->checkChangeIsForbidden($emailAddress, $entity);
|
||||
if (!$skipSave) {
|
||||
$emailAddress->set(array(
|
||||
'optOut' => $hash[$address]['optOut'],
|
||||
'invalid' => $hash[$address]['invalid'],
|
||||
'name' => $hash[$address]['emailAddress']
|
||||
));
|
||||
$this->save($emailAddress);
|
||||
} else {
|
||||
$revertData[$address] = [
|
||||
'optOut' => $emailAddress->get('optOut'),
|
||||
'invalid' => $emailAddress->get('invalid')
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($toCreate as $address) {
|
||||
$emailAddress = $this->getByAddress($address);
|
||||
if (!$emailAddress) {
|
||||
$emailAddress = $this->get();
|
||||
|
||||
$emailAddress->set(array(
|
||||
'name' => $hash[$address]['emailAddress'],
|
||||
'optOut' => $hash[$address]['optOut'],
|
||||
'invalid' => $hash[$address]['invalid'],
|
||||
));
|
||||
$this->save($emailAddress);
|
||||
} else {
|
||||
$skipSave = $this->checkChangeIsForbidden($emailAddress, $entity);
|
||||
if (!$skipSave) {
|
||||
if (
|
||||
$emailAddress->get('optOut') != $hash[$address]['optOut'] ||
|
||||
$emailAddress->get('invalid') != $hash[$address]['invalid'] ||
|
||||
$emailAddress->get('emailAddress') != $hash[$address]['emailAddress']
|
||||
) {
|
||||
$emailAddress->set(array(
|
||||
'optOut' => $hash[$address]['optOut'],
|
||||
'invalid' => $hash[$address]['invalid'],
|
||||
'name' => $hash[$address]['emailAddress']
|
||||
));
|
||||
$this->save($emailAddress);
|
||||
}
|
||||
} else {
|
||||
$revertData[$address] = [
|
||||
'optOut' => $emailAddress->get('optOut'),
|
||||
'invalid' => $emailAddress->get('invalid')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$query = "
|
||||
INSERT entity_email_address
|
||||
(entity_id, entity_type, email_address_id, `primary`)
|
||||
VALUES
|
||||
(
|
||||
".$pdo->quote($entity->id).",
|
||||
".$pdo->quote($entity->getEntityName()).",
|
||||
".$pdo->quote($emailAddress->id).",
|
||||
".$pdo->quote((int)($address === $primary))."
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE deleted = 0, `primary` = ".$pdo->quote((int)($address === $primary))."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
|
||||
if ($primary) {
|
||||
$emailAddress = $this->getByAddress($primary);
|
||||
if ($emailAddress) {
|
||||
$query = "
|
||||
UPDATE entity_email_address
|
||||
SET `primary` = 0
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
`primary` = 1 AND
|
||||
deleted = 0
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
|
||||
$query = "
|
||||
UPDATE entity_email_address
|
||||
SET `primary` = 1
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
email_address_id = ".$pdo->quote($emailAddress->id)." AND
|
||||
deleted = 0
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($revertData)) {
|
||||
foreach ($emailAddressData as $row) {
|
||||
if (!empty($revertData[$row->emailAddress])) {
|
||||
$row->optOut = $revertData[$row->emailAddress]['optOut'];
|
||||
$row->invalid = $revertData[$row->emailAddress]['invalid'];
|
||||
}
|
||||
}
|
||||
$entity->set('emailAddressData', $emailAddressData);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!$entity->has('emailAddress')) {
|
||||
return;
|
||||
}
|
||||
$entityRepository = $this->getEntityManager()->getRepository($entity->getEntityName());
|
||||
if (!empty($emailAddressValue)) {
|
||||
if ($emailAddressValue != $entity->getFetched('emailAddress')) {
|
||||
|
||||
$emailAddressNew = $this->where(array('lower' => strtolower($emailAddressValue)))->findOne();
|
||||
$isNewEmailAddress = false;
|
||||
if (!$emailAddressNew) {
|
||||
$emailAddressNew = $this->get();
|
||||
$emailAddressNew->set('name', $emailAddressValue);
|
||||
if ($entity->has('emailAddressIsOptedOut')) {
|
||||
$emailAddressNew->set('optOut', !!$entity->get('emailAddressIsOptedOut'));
|
||||
}
|
||||
$this->save($emailAddressNew);
|
||||
$isNewEmailAddress = true;
|
||||
}
|
||||
|
||||
$emailAddressValueOld = $entity->getFetched('emailAddress');
|
||||
if (!empty($emailAddressValueOld)) {
|
||||
$emailAddressOld = $this->getByAddress($emailAddressValueOld);
|
||||
if ($emailAddressOld) {
|
||||
$entityRepository->unrelate($entity, 'emailAddresses', $emailAddressOld);
|
||||
}
|
||||
}
|
||||
$entityRepository->relate($entity, 'emailAddresses', $emailAddressNew);
|
||||
|
||||
if ($entity->has('emailAddressIsOptedOut')) {
|
||||
$this->markAddressOptedOut($emailAddressValue, !!$entity->get('emailAddressIsOptedOut'));
|
||||
}
|
||||
|
||||
$query = "
|
||||
UPDATE entity_email_address
|
||||
SET `primary` = 1
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
email_address_id = ".$pdo->quote($emailAddressNew->id)."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
} else {
|
||||
if (
|
||||
$entity->has('emailAddressIsOptedOut')
|
||||
&&
|
||||
(
|
||||
$entity->isNew()
|
||||
||
|
||||
(
|
||||
$entity->hasFetched('emailAddressIsOptedOut')
|
||||
&&
|
||||
$entity->get('emailAddressIsOptedOut') !== $entity->getFetched('emailAddressIsOptedOut')
|
||||
)
|
||||
)
|
||||
) {
|
||||
$this->markAddressOptedOut($emailAddressValue, !!$entity->get('emailAddressIsOptedOut'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$emailAddressValueOld = $entity->getFetched('emailAddress');
|
||||
if (!empty($emailAddressValueOld)) {
|
||||
$emailAddressOld = $this->getByAddress($emailAddressValueOld);
|
||||
if ($emailAddressOld) {
|
||||
$entityRepository->unrelate($entity, 'emailAddresses', $emailAddressOld);
|
||||
}
|
||||
}
|
||||
$this->markAddressOptedOut($emailAddressValue, !!$entity->get('emailAddressIsOptedOut'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$emailAddressValueOld = $entity->getFetched('emailAddress');
|
||||
if (!empty($emailAddressValueOld)) {
|
||||
$emailAddressOld = $this->getByAddress($emailAddressValueOld);
|
||||
if ($emailAddressOld) {
|
||||
$entityRepository->unrelate($entity, 'emailAddresses', $emailAddressOld);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function storeEntityEmailAddress(Entity $entity)
|
||||
{
|
||||
$emailAddressData = null;
|
||||
if ($entity->has('emailAddressData')) {
|
||||
$emailAddressData = $entity->get('emailAddressData');
|
||||
}
|
||||
|
||||
if ($emailAddressData !== null) {
|
||||
$this->storeEntityEmailAddressData($entity);
|
||||
} else if ($entity->has('emailAddress')) {
|
||||
$this->storeEntityEmailAddressPrimary($entity);
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkChangeIsForbidden($entity, $excludeEntity)
|
||||
|
||||
@@ -96,7 +96,7 @@ class PhoneNumber extends \Espo\Core\ORM\Repositories\RDB
|
||||
JOIN phone_number ON phone_number.id = entity_phone_number.phone_number_id AND phone_number.deleted = 0
|
||||
WHERE
|
||||
entity_phone_number.entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_phone_number.entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
entity_phone_number.entity_type = ".$pdo->quote($entity->getEntityType())." AND
|
||||
entity_phone_number.deleted = 0
|
||||
ORDER BY entity_phone_number.primary DESC
|
||||
";
|
||||
@@ -193,247 +193,271 @@ class PhoneNumber extends \Espo\Core\ORM\Repositories\RDB
|
||||
}
|
||||
}
|
||||
|
||||
public function storeEntityPhoneNumber(Entity $entity)
|
||||
protected function storeEntityPhoneNumberData(Entity $entity)
|
||||
{
|
||||
$phoneNumberValue = trim($entity->get('phoneNumber'));
|
||||
$phoneNumberData = null;
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
if ($entity->has('phoneNumberData')) {
|
||||
$phoneNumberData = $entity->get('phoneNumberData');
|
||||
$phoneNumberData = null;
|
||||
if ($entity->has('phoneNumberData')) {
|
||||
$phoneNumberData = $entity->get('phoneNumberData');
|
||||
}
|
||||
|
||||
if (is_null($phoneNumberData)) return;
|
||||
if (!is_array($phoneNumberData)) return;
|
||||
|
||||
$keyList = [];
|
||||
$keyPreviousList = [];
|
||||
|
||||
$previousPhoneNumberData = [];
|
||||
if (!$entity->isNew()) {
|
||||
$previousPhoneNumberData = $this->getPhoneNumberData($entity);
|
||||
}
|
||||
|
||||
$hash = (object) [];
|
||||
$hashPrevious = (object) [];
|
||||
|
||||
foreach ($phoneNumberData as $row) {
|
||||
$key = trim($row->phoneNumber);
|
||||
if (empty($key)) continue;
|
||||
$hash->$key = [
|
||||
'primary' => $row->primary ? true : false,
|
||||
'type' => $row->type
|
||||
];
|
||||
$keyList[] = $key;
|
||||
}
|
||||
|
||||
foreach ($previousPhoneNumberData as $row) {
|
||||
$key = $row->phoneNumber;
|
||||
if (empty($key)) continue;
|
||||
$hashPrevious->$key = [
|
||||
'primary' => $row->primary ? true : false,
|
||||
'type' => $row->type
|
||||
];
|
||||
$keyPreviousList[] = $key;
|
||||
}
|
||||
|
||||
$primary = false;
|
||||
|
||||
$toCreateList = [];
|
||||
$toUpdateList = [];
|
||||
$toRemoveList = [];
|
||||
|
||||
$revertData = [];
|
||||
|
||||
foreach ($keyList as $key) {
|
||||
$data = $hash->$key;
|
||||
|
||||
$new = true;
|
||||
$changed = false;
|
||||
|
||||
if ($hash->$key['primary']) {
|
||||
$primary = $key;
|
||||
}
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
if ($phoneNumberData !== null && is_array($phoneNumberData)) {
|
||||
$previousPhoneNumberData = array();
|
||||
if (!$entity->isNew()) {
|
||||
$previousPhoneNumberData = $this->getPhoneNumberData($entity);
|
||||
}
|
||||
|
||||
$hash = array();
|
||||
foreach ($phoneNumberData as $row) {
|
||||
$key = trim($row->phoneNumber);
|
||||
if (!empty($key)) {
|
||||
$hash[$key] = array(
|
||||
'primary' => $row->primary ? true : false,
|
||||
'type' => $row->type
|
||||
);
|
||||
if (property_exists($hashPrevious, $key)) {
|
||||
$new = false;
|
||||
$changed = $hash->$key['type'] != $hashPrevious->$key['type'];
|
||||
if ($hash->$key['primary']) {
|
||||
if ($hash->$key['primary'] == $hashPrevious->$key['primary']) {
|
||||
$primary = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$hashPrev = array();
|
||||
foreach ($previousPhoneNumberData as $row) {
|
||||
$key = $row->phoneNumber;
|
||||
if (!empty($key)) {
|
||||
$hashPrev[$key] = array(
|
||||
'primary' => $row->primary ? true : false,
|
||||
'type' => $row->type
|
||||
);
|
||||
}
|
||||
if ($new) {
|
||||
$toCreateList[] = $key;
|
||||
}
|
||||
if ($changed) {
|
||||
$toUpdateList[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($keyPreviousList as $key) {
|
||||
if (!property_exists($hash, $key)) {
|
||||
$toRemoveList[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($toRemoveList as $number) {
|
||||
$phoneNumber = $this->getByNumber($number);
|
||||
if ($phoneNumber) {
|
||||
$query = "
|
||||
DELETE FROM entity_phone_number
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityType())." AND
|
||||
phone_number_id = ".$pdo->quote($phoneNumber->id)."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($toUpdateList as $number) {
|
||||
$phoneNumber = $this->getByNumber($number);
|
||||
if ($phoneNumber) {
|
||||
$skipSave = $this->checkChangeIsForbidden($phoneNumber, $entity);
|
||||
if (!$skipSave) {
|
||||
$phoneNumber->set([
|
||||
'type' => $hash->$number['type'],
|
||||
]);
|
||||
$this->save($phoneNumber);
|
||||
} else {
|
||||
$revertData[$number] = [
|
||||
'type' => $phoneNumber->get('type')
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$primary = false;
|
||||
$toCreate = array();
|
||||
$toUpdate = array();
|
||||
$toRemove = array();
|
||||
|
||||
$revertData = [];
|
||||
|
||||
foreach ($hash as $key => $data) {
|
||||
$new = true;
|
||||
$changed = false;
|
||||
|
||||
if ($hash[$key]['primary']) {
|
||||
$primary = $key;
|
||||
}
|
||||
|
||||
if (array_key_exists($key, $hashPrev)) {
|
||||
$new = false;
|
||||
$changed = $hash[$key]['type'] != $hashPrev[$key]['type'];
|
||||
if ($hash[$key]['primary']) {
|
||||
if ($hash[$key]['primary'] == $hashPrev[$key]['primary']) {
|
||||
$primary = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($new) {
|
||||
$toCreate[] = $key;
|
||||
}
|
||||
if ($changed) {
|
||||
$toUpdate[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($hashPrev as $key => $data) {
|
||||
if (!array_key_exists($key, $hash)) {
|
||||
$toRemove[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($toRemove as $number) {
|
||||
$phoneNumber = $this->getByNumber($number);
|
||||
if ($phoneNumber) {
|
||||
$query = "
|
||||
DELETE FROM entity_phone_number
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
phone_number_id = ".$pdo->quote($phoneNumber->id)."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($toUpdate as $number) {
|
||||
$phoneNumber = $this->getByNumber($number);
|
||||
if ($phoneNumber) {
|
||||
$skipSave = $this->checkChangeIsForbidden($phoneNumber, $entity);
|
||||
if (!$skipSave) {
|
||||
$phoneNumber->set(array(
|
||||
'type' => $hash[$number]['type'],
|
||||
));
|
||||
$this->save($phoneNumber);
|
||||
} else {
|
||||
$revertData[$number] = [
|
||||
'type' => $phoneNumber->get('type')
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($toCreate as $number) {
|
||||
$phoneNumber = $this->getByNumber($number);
|
||||
if (!$phoneNumber) {
|
||||
$phoneNumber = $this->get();
|
||||
|
||||
$phoneNumber->set(array(
|
||||
'name' => $number,
|
||||
'type' => $hash[$number]['type'],
|
||||
));
|
||||
$this->save($phoneNumber);
|
||||
} else {
|
||||
$skipSave = $this->checkChangeIsForbidden($phoneNumber, $entity);
|
||||
if (!$skipSave) {
|
||||
if ($phoneNumber->get('type') != $hash[$number]['type']) {
|
||||
$phoneNumber->set(array(
|
||||
'type' => $hash[$number]['type'],
|
||||
));
|
||||
$this->save($phoneNumber);
|
||||
}
|
||||
} else {
|
||||
$revertData[$number] = [
|
||||
'type' => $phoneNumber->get('type')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$query = "
|
||||
INSERT entity_phone_number
|
||||
(entity_id, entity_type, phone_number_id, `primary`)
|
||||
VALUES
|
||||
(
|
||||
".$pdo->quote($entity->id).",
|
||||
".$pdo->quote($entity->getEntityName()).",
|
||||
".$pdo->quote($phoneNumber->id).",
|
||||
".$pdo->quote((int)($number === $primary))."
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE deleted = 0, `primary` = ".$pdo->quote((int)($number === $primary))."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
|
||||
if ($primary) {
|
||||
$phoneNumber = $this->getByNumber($primary);
|
||||
if ($phoneNumber) {
|
||||
$query = "
|
||||
UPDATE entity_phone_number
|
||||
SET `primary` = 0
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
`primary` = 1 AND
|
||||
deleted = 0
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
|
||||
$query = "
|
||||
UPDATE entity_phone_number
|
||||
SET `primary` = 1
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
phone_number_id = ".$pdo->quote($phoneNumber->id)." AND
|
||||
deleted = 0
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($revertData)) {
|
||||
foreach ($phoneNumberData as $row) {
|
||||
if (!empty($revertData[$row->phoneNumber])) {
|
||||
$row->type = $revertData[$row->phoneNumber]['type'];
|
||||
}
|
||||
}
|
||||
$entity->set('phoneNumberData', $phoneNumberData);
|
||||
}
|
||||
foreach ($toCreateList as $number) {
|
||||
$phoneNumber = $this->getByNumber($number);
|
||||
if (!$phoneNumber) {
|
||||
$phoneNumber = $this->get();
|
||||
|
||||
$phoneNumber->set([
|
||||
'name' => $number,
|
||||
'type' => $hash->$number['type'],
|
||||
]);
|
||||
$this->save($phoneNumber);
|
||||
} else {
|
||||
if (!$entity->has('phoneNumber')) {
|
||||
return;
|
||||
}
|
||||
$entityRepository = $this->getEntityManager()->getRepository($entity->getEntityName());
|
||||
if (!empty($phoneNumberValue)) {
|
||||
if ($phoneNumberValue !== $entity->getFetched('phoneNumber')) {
|
||||
|
||||
$phoneNumberNew = $this->where(array('name' => $phoneNumberValue))->findOne();
|
||||
$isNewPhoneNumber = false;
|
||||
if (!$phoneNumberNew) {
|
||||
$phoneNumberNew = $this->get();
|
||||
$phoneNumberNew->set('name', $phoneNumberValue);
|
||||
$defaultType = $this->getEntityManager()->getEspoMetadata()->get('entityDefs.' . $entity->getEntityName() . '.fields.phoneNumber.defaultType');
|
||||
|
||||
$phoneNumberNew->set('type', $defaultType);
|
||||
|
||||
$this->save($phoneNumberNew);
|
||||
$isNewPhoneNumber = true;
|
||||
}
|
||||
|
||||
$phoneNumberValueOld = $entity->getFetched('phoneNumber');
|
||||
if (!empty($phoneNumberValueOld)) {
|
||||
$phoneNumberOld = $this->getByNumber($phoneNumberValueOld);
|
||||
if ($phoneNumberOld) {
|
||||
$entityRepository->unrelate($entity, 'phoneNumbers', $phoneNumberOld);
|
||||
}
|
||||
}
|
||||
$entityRepository->relate($entity, 'phoneNumbers', $phoneNumberNew);
|
||||
|
||||
$query = "
|
||||
UPDATE entity_phone_number
|
||||
SET `primary` = 1
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
phone_number_id = ".$pdo->quote($phoneNumberNew->id)."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
$skipSave = $this->checkChangeIsForbidden($phoneNumber, $entity);
|
||||
if (!$skipSave) {
|
||||
if ($phoneNumber->get('type') != $hash->$number['type']) {
|
||||
$phoneNumber->set([
|
||||
'type' => $hash->$number['type'],
|
||||
]);
|
||||
$this->save($phoneNumber);
|
||||
}
|
||||
} else {
|
||||
$phoneNumberValueOld = $entity->getFetched('phoneNumber');
|
||||
if (!empty($phoneNumberValueOld)) {
|
||||
$phoneNumberOld = $this->getByNumber($phoneNumberValueOld);
|
||||
if ($phoneNumberOld) {
|
||||
$entityRepository->unrelate($entity, 'phoneNumbers', $phoneNumberOld);
|
||||
}
|
||||
}
|
||||
$revertData[$number] = [
|
||||
'type' => $phoneNumber->get('type')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$query = "
|
||||
INSERT entity_phone_number
|
||||
(entity_id, entity_type, phone_number_id, `primary`)
|
||||
VALUES
|
||||
(
|
||||
".$pdo->quote($entity->id).",
|
||||
".$pdo->quote($entity->getEntityType()).",
|
||||
".$pdo->quote($phoneNumber->id).",
|
||||
".$pdo->quote((int)($number === $primary))."
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE deleted = 0, `primary` = ".$pdo->quote((int)($number === $primary))."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
|
||||
if ($primary) {
|
||||
$phoneNumber = $this->getByNumber($primary);
|
||||
if ($phoneNumber) {
|
||||
$query = "
|
||||
UPDATE entity_phone_number
|
||||
SET `primary` = 0
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityType())." AND
|
||||
`primary` = 1 AND
|
||||
deleted = 0
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
|
||||
$query = "
|
||||
UPDATE entity_phone_number
|
||||
SET `primary` = 1
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityType())." AND
|
||||
phone_number_id = ".$pdo->quote($phoneNumber->id)." AND
|
||||
deleted = 0
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($revertData)) {
|
||||
foreach ($phoneNumberData as $row) {
|
||||
if (!empty($revertData[$row->phoneNumber])) {
|
||||
$row->type = $revertData[$row->phoneNumber]['type'];
|
||||
}
|
||||
}
|
||||
$entity->set('phoneNumberData', $phoneNumberData);
|
||||
}
|
||||
}
|
||||
|
||||
protected function storeEntityPhoneNumberPrimary(Entity $entity)
|
||||
{
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
if (!$entity->has('phoneNumber')) return;
|
||||
$phoneNumberValue = trim($entity->get('phoneNumber'));
|
||||
|
||||
$entityRepository = $this->getEntityManager()->getRepository($entity->getEntityType());
|
||||
if (!empty($phoneNumberValue)) {
|
||||
if ($phoneNumberValue !== $entity->getFetched('phoneNumber')) {
|
||||
|
||||
$phoneNumberNew = $this->where(['name' => $phoneNumberValue])->findOne();
|
||||
$isNewPhoneNumber = false;
|
||||
if (!$phoneNumberNew) {
|
||||
$phoneNumberNew = $this->get();
|
||||
$phoneNumberNew->set('name', $phoneNumberValue);
|
||||
$defaultType = $this->getEntityManager()->getEspoMetadata()->get('entityDefs.' . $entity->getEntityType() . '.fields.phoneNumber.defaultType');
|
||||
|
||||
$phoneNumberNew->set('type', $defaultType);
|
||||
|
||||
$this->save($phoneNumberNew);
|
||||
$isNewPhoneNumber = true;
|
||||
}
|
||||
|
||||
$phoneNumberValueOld = $entity->getFetched('phoneNumber');
|
||||
if (!empty($phoneNumberValueOld)) {
|
||||
$phoneNumberOld = $this->getByNumber($phoneNumberValueOld);
|
||||
if ($phoneNumberOld) {
|
||||
$entityRepository->unrelate($entity, 'phoneNumbers', $phoneNumberOld);
|
||||
}
|
||||
}
|
||||
$entityRepository->relate($entity, 'phoneNumbers', $phoneNumberNew);
|
||||
|
||||
$query = "
|
||||
UPDATE entity_phone_number
|
||||
SET `primary` = 1
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityType())." AND
|
||||
phone_number_id = ".$pdo->quote($phoneNumberNew->id)."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
} else {
|
||||
$phoneNumberValueOld = $entity->getFetched('phoneNumber');
|
||||
if (!empty($phoneNumberValueOld)) {
|
||||
$phoneNumberOld = $this->getByNumber($phoneNumberValueOld);
|
||||
if ($phoneNumberOld) {
|
||||
$entityRepository->unrelate($entity, 'phoneNumbers', $phoneNumberOld);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function storeEntityPhoneNumber(Entity $entity)
|
||||
{
|
||||
$phoneNumberData = null;
|
||||
if ($entity->has('phoneNumberData')) {
|
||||
$phoneNumberData = $entity->get('phoneNumberData');
|
||||
}
|
||||
|
||||
if ($phoneNumberData !== null) {
|
||||
$this->storeEntityPhoneNumberData($entity);
|
||||
} else if ($entity->has('phoneNumber')) {
|
||||
$this->storeEntityPhoneNumberPrimary($entity);
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkChangeIsForbidden($entity, $excludeEntity)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"scriptList": [
|
||||
"client/espo.min.js"
|
||||
],
|
||||
"developerModeScriptList": [
|
||||
"client/lib/jquery-2.1.4.min.js",
|
||||
"client/lib/underscore-min.js",
|
||||
"client/lib/es6-promise.min.js",
|
||||
"client/lib/backbone-min.js",
|
||||
"client/lib/handlebars.js",
|
||||
"client/lib/base64.js",
|
||||
"client/lib/jquery-ui.min.js",
|
||||
"client/lib/jquery.ui.touch-punch.min.js",
|
||||
"client/lib/moment.min.js",
|
||||
"client/lib/moment-timezone-with-data.min.js",
|
||||
"client/lib/jquery.timepicker.min.js",
|
||||
"client/lib/jquery.autocomplete.js",
|
||||
"client/lib/bootstrap.min.js",
|
||||
"client/lib/bootstrap-datepicker.js",
|
||||
"client/lib/bull.js",
|
||||
"client/lib/marked.min.js",
|
||||
"client/src/loader.js",
|
||||
"client/src/utils.js",
|
||||
"client/src/exceptions.js"
|
||||
]
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
},
|
||||
{
|
||||
"name": "ifThen",
|
||||
"insertText": "ifThenElse(CONDITION, CONSEQUENT)"
|
||||
"insertText": "ifThen(CONDITION, CONSEQUENT)"
|
||||
},
|
||||
{
|
||||
"name": "string\\concatenate",
|
||||
@@ -16,10 +16,30 @@
|
||||
"name": "string\\substring",
|
||||
"insertText": "string\\substring(STRING, START, LENGTH)"
|
||||
},
|
||||
{
|
||||
"name": "string\\contains",
|
||||
"insertText": "string\\contains(STRING, NEEDLE)"
|
||||
},
|
||||
{
|
||||
"name": "string\\test",
|
||||
"insertText": "string\\test(STRING, REGULAR_EXPRESSION)"
|
||||
},
|
||||
{
|
||||
"name": "string\\length",
|
||||
"insertText": "string\\length(STRING)"
|
||||
},
|
||||
{
|
||||
"name": "string\\trim",
|
||||
"insertText": "string\\trim(STRING)"
|
||||
},
|
||||
{
|
||||
"name": "string\\lowerCase",
|
||||
"insertText": "string\\lowerCase(STRING)"
|
||||
},
|
||||
{
|
||||
"name": "string\\upperCase",
|
||||
"insertText": "string\\upperCase(STRING)"
|
||||
},
|
||||
{
|
||||
"name": "datetime\\today",
|
||||
"insertText": "datetime\\today()"
|
||||
@@ -32,6 +52,30 @@
|
||||
"name": "datetime\\format",
|
||||
"insertText": "datetime\\format(VALUE)"
|
||||
},
|
||||
{
|
||||
"name": "datetime\\date",
|
||||
"insertText": "datetime\\date(VALUE)"
|
||||
},
|
||||
{
|
||||
"name": "datetime\\month",
|
||||
"insertText": "datetime\\month(VALUE)"
|
||||
},
|
||||
{
|
||||
"name": "datetime\\year",
|
||||
"insertText": "datetime\\year(VALUE)"
|
||||
},
|
||||
{
|
||||
"name": "datetime\\hour",
|
||||
"insertText": "datetime\\hour(VALUE)"
|
||||
},
|
||||
{
|
||||
"name": "datetime\\minute",
|
||||
"insertText": "datetime\\minute(VALUE)"
|
||||
},
|
||||
{
|
||||
"name": "datetime\\dayOfWeek",
|
||||
"insertText": "datetime\\dayOfWeek(VALUE)"
|
||||
},
|
||||
{
|
||||
"name": "datetime\\addMinutes",
|
||||
"insertText": "datetime\\addMinutes(VALUE, MINUTES)"
|
||||
@@ -72,6 +116,14 @@
|
||||
"name": "number\\round",
|
||||
"insertText": "number\\round(VALUE, PRECISION)"
|
||||
},
|
||||
{
|
||||
"name": "number\\floor",
|
||||
"insertText": "number\\floor(VALUE)"
|
||||
},
|
||||
{
|
||||
"name": "number\\ceil",
|
||||
"insertText": "number\\ceil(VALUE)"
|
||||
},
|
||||
{
|
||||
"name": "entity\\isNew",
|
||||
"insertText": "entity\\isNew()"
|
||||
@@ -108,6 +160,14 @@
|
||||
"name": "entity\\isRelated",
|
||||
"insertText": "entity\\isRelated(LINK, ID)"
|
||||
},
|
||||
{
|
||||
"name": "entity\\sumRelated",
|
||||
"insertText": "entity\\sumRelated(LINK, FIELD, FILTER)"
|
||||
},
|
||||
{
|
||||
"name": "entity\\countRelated",
|
||||
"insertText": "entity\\countRelated(LINK, FILTER)"
|
||||
},
|
||||
{
|
||||
"name": "env\\userAttribute",
|
||||
"insertText": "env\\userAttribute(ATTRIBUTE)"
|
||||
|
||||
@@ -38,5 +38,10 @@
|
||||
"path": "client/lib/bootstrap-colorpicker.js",
|
||||
"exportsTo": "$",
|
||||
"exportsAs": "colorpicker"
|
||||
},
|
||||
"exif": {
|
||||
"path": "client/lib/exif-js.js",
|
||||
"exportsTo": "window",
|
||||
"exportsAs": "EXIF"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,13 @@ class Attachment extends Record
|
||||
|
||||
protected $inlineAttachmentFieldTypeList = ['wysiwyg'];
|
||||
|
||||
protected $imageTypeList = [
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
];
|
||||
|
||||
public function upload($fileData)
|
||||
{
|
||||
if (!$this->getAcl()->checkScope('Attachment', 'create')) {
|
||||
@@ -65,7 +72,7 @@ class Attachment extends Record
|
||||
return $attachment;
|
||||
}
|
||||
|
||||
public function createEntity($data)
|
||||
public function create($data)
|
||||
{
|
||||
if (!empty($data->file)) {
|
||||
$arr = explode(',', $data->file);
|
||||
@@ -127,7 +134,7 @@ class Attachment extends Record
|
||||
}
|
||||
}
|
||||
|
||||
$entity = parent::createEntity($data);
|
||||
$entity = parent::create($data);
|
||||
|
||||
if (!empty($data->file)) {
|
||||
$entity->clear('contents');
|
||||
@@ -322,7 +329,8 @@ class Attachment extends Record
|
||||
'png' => 'image/png',
|
||||
'jpg' => 'image/jpeg',
|
||||
'jpeg' => 'image/jpeg',
|
||||
'gif' => 'image/gif'
|
||||
'gif' => 'image/gif',
|
||||
'webp' => 'image/webp',
|
||||
];
|
||||
|
||||
$extension = preg_replace('#\?.*#', '', pathinfo($url, \PATHINFO_EXTENSION));
|
||||
@@ -334,7 +342,7 @@ class Attachment extends Record
|
||||
|
||||
if (!$type) return;
|
||||
|
||||
if (!in_array($type, ['image/png', 'image/jpeg', 'image/gif'])) {
|
||||
if (!in_array($type, $this->imageTypeList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -262,9 +262,9 @@ class Email extends Record
|
||||
return $this->streamService;
|
||||
}
|
||||
|
||||
public function createEntity($data)
|
||||
public function create($data)
|
||||
{
|
||||
$entity = parent::createEntity($data);
|
||||
$entity = parent::create($data);
|
||||
|
||||
if ($entity && $entity->get('status') == 'Sending') {
|
||||
$this->send($entity);
|
||||
|
||||
@@ -116,7 +116,7 @@ class EmailAccount extends Record
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
public function createEntity($data)
|
||||
public function create($data)
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
$count = $this->getEntityManager()->getRepository('EmailAccount')->where(array(
|
||||
@@ -127,7 +127,7 @@ class EmailAccount extends Record
|
||||
}
|
||||
}
|
||||
|
||||
$entity = parent::createEntity($data);
|
||||
$entity = parent::create($data);
|
||||
if ($entity) {
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
$entity->set('assignedUserId', $this->getUser()->id);
|
||||
|
||||
@@ -41,24 +41,6 @@ class InboundEmail extends \Espo\Services\Record
|
||||
|
||||
const PORTION_LIMIT = 20;
|
||||
|
||||
public function createEntity($data)
|
||||
{
|
||||
$entity = parent::createEntity($data);
|
||||
return $entity;
|
||||
}
|
||||
|
||||
public function getEntity($id = null)
|
||||
{
|
||||
$entity = parent::getEntity($id);
|
||||
return $entity;
|
||||
}
|
||||
|
||||
public function updateEntity($id, $data)
|
||||
{
|
||||
$entity = parent::updateEntity($id, $data);
|
||||
return $entity;
|
||||
}
|
||||
|
||||
protected function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
@@ -48,7 +48,7 @@ class Note extends Record
|
||||
return $entity;
|
||||
}
|
||||
|
||||
public function createEntity($data)
|
||||
public function create($data)
|
||||
{
|
||||
if (!empty($data->parentType) && !empty($data->parentId)) {
|
||||
$entity = $this->getEntityManager()->getEntity($data->parentType, $data->parentId);
|
||||
@@ -59,7 +59,7 @@ class Note extends Record
|
||||
}
|
||||
}
|
||||
|
||||
return parent::createEntity($data);
|
||||
return parent::create($data);
|
||||
}
|
||||
|
||||
protected function afterCreateEntity(Entity $entity, $data)
|
||||
@@ -197,20 +197,20 @@ class Note extends Record
|
||||
return true;
|
||||
}
|
||||
|
||||
public function linkEntity($id, $link, $foreignId)
|
||||
public function link($id, $link, $foreignId)
|
||||
{
|
||||
if ($link === 'teams' || $link === 'users') {
|
||||
throw new Forbidden();
|
||||
}
|
||||
return parant::linkEntity($id, $link, $foreignId);
|
||||
return parant::link($id, $link, $foreignId);
|
||||
}
|
||||
|
||||
public function unlinkEntity($id, $link, $foreignId)
|
||||
public function unlink($id, $link, $foreignId)
|
||||
{
|
||||
if ($link === 'teams' || $link === 'users') {
|
||||
throw new Forbidden();
|
||||
}
|
||||
return parant::unlinkEntity($id, $link, $foreignId);
|
||||
return parant::unlink($id, $link, $foreignId);
|
||||
}
|
||||
|
||||
public function processNoteAclJob($data)
|
||||
|
||||
@@ -261,7 +261,12 @@ class Record extends \Espo\Core\Services\Base
|
||||
$this->getEntityManager()->saveEntity($historyRecord);
|
||||
}
|
||||
|
||||
public function readEntity($id)
|
||||
public function readEntity($id) //TODO Remove in 5.8
|
||||
{
|
||||
return $this->read($id);
|
||||
}
|
||||
|
||||
public function read($id)
|
||||
{
|
||||
if (empty($id)) {
|
||||
throw new Error();
|
||||
@@ -313,6 +318,8 @@ class Record extends \Espo\Core\Services\Base
|
||||
if ($this->getUser()->isPortal()) return;
|
||||
if (!$this->getMetadata()->get(['scopes', $entity->getEntityType(), 'stream'])) return;
|
||||
|
||||
if (!$this->getAcl()->check($entity, 'stream')) return;
|
||||
|
||||
$data = $this->getStreamService()->getEntityFollowers($entity, 0, self::FOLLOWERS_LIMIT);
|
||||
if ($data) {
|
||||
$entity->set('followersIds', $data['idList']);
|
||||
@@ -787,7 +794,7 @@ class Record extends \Espo\Core\Services\Base
|
||||
}
|
||||
}
|
||||
|
||||
public function createEntity($data)
|
||||
public function createEntity($data) //TODO Remove in 5.8
|
||||
{
|
||||
return $this->create($data);
|
||||
}
|
||||
@@ -845,7 +852,7 @@ class Record extends \Espo\Core\Services\Base
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
public function updateEntity($id, $data)
|
||||
public function updateEntity($id, $data) //TODO Remove in 5.8
|
||||
{
|
||||
return $this->update($id, $data);
|
||||
}
|
||||
@@ -944,7 +951,7 @@ class Record extends \Espo\Core\Services\Base
|
||||
{
|
||||
}
|
||||
|
||||
public function deleteEntity($id)
|
||||
public function deleteEntity($id) //TODO Remove in 5.8
|
||||
{
|
||||
return $this->delete($id);
|
||||
}
|
||||
@@ -1285,7 +1292,7 @@ class Record extends \Espo\Core\Services\Base
|
||||
];
|
||||
}
|
||||
|
||||
public function linkEntity($id, $link, $foreignId)
|
||||
public function linkEntity($id, $link, $foreignId) //TODO Remove in 5.8
|
||||
{
|
||||
return $this->link($id, $link, $foreignId);
|
||||
}
|
||||
@@ -1342,7 +1349,7 @@ class Record extends \Espo\Core\Services\Base
|
||||
return true;
|
||||
}
|
||||
|
||||
public function unlinkEntity($id, $link, $foreignId)
|
||||
public function unlinkEntity($id, $link, $foreignId) //TODO Remove in 5.8
|
||||
{
|
||||
return $this->unlink($id, $link, $foreignId);
|
||||
}
|
||||
@@ -1403,7 +1410,7 @@ class Record extends \Espo\Core\Services\Base
|
||||
return true;
|
||||
}
|
||||
|
||||
public function linkEntityMass($id, $link, $where, $selectData = null)
|
||||
public function linkEntityMass($id, $link, $where, $selectData = null) //TODO Remove in 5.8
|
||||
{
|
||||
return $this->linkMass($id, $link, $where, $selectData);
|
||||
}
|
||||
@@ -1671,10 +1678,6 @@ class Record extends \Espo\Core\Services\Base
|
||||
{
|
||||
$entity = $this->getRepository()->get($id);
|
||||
|
||||
if (!$this->getAcl()->check($entity, 'read')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
if (empty($userId)) {
|
||||
$userId = $this->getUser()->id;
|
||||
}
|
||||
@@ -1724,7 +1727,7 @@ class Record extends \Espo\Core\Services\Base
|
||||
$idList = $params['ids'];
|
||||
foreach ($idList as $id) {
|
||||
$entity = $this->getEntity($id);
|
||||
if ($entity && $this->getAcl()->check($entity, 'stream')) {
|
||||
if ($entity) {
|
||||
if ($streamService->unfollowEntity($entity, $userId)) {
|
||||
$resultIdList[] = $entity->id;
|
||||
}
|
||||
@@ -2238,7 +2241,7 @@ class Record extends \Espo\Core\Services\Base
|
||||
{
|
||||
}
|
||||
|
||||
protected function findLinkedEntitiesFollowers($id, $params)
|
||||
protected function findLinkedFollowers($id, $params)
|
||||
{
|
||||
$maxSize = 0;
|
||||
|
||||
|
||||
@@ -174,21 +174,21 @@ class RecordTree extends Record
|
||||
}
|
||||
}
|
||||
|
||||
public function updateEntity($id, $data)
|
||||
public function update($id, $data)
|
||||
{
|
||||
if (!empty($data->parentId) && $data->parentId == $id) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
return parent::updateEntity($id, $data);
|
||||
return parent::update($id, $data);
|
||||
}
|
||||
|
||||
public function linkEntity($id, $link, $foreignId)
|
||||
public function link($id, $link, $foreignId)
|
||||
{
|
||||
if ($id == $foreignId ) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
return parent::linkEntity($id, $link, $foreignId);
|
||||
return parent::link($id, $link, $foreignId);
|
||||
}
|
||||
|
||||
public function getLastChildrenIdList($parentId = null)
|
||||
|
||||
@@ -242,7 +242,7 @@ class User extends Record
|
||||
}
|
||||
}
|
||||
|
||||
public function createEntity($data)
|
||||
public function create($data)
|
||||
{
|
||||
$newPassword = null;
|
||||
if (property_exists($data, 'password')) {
|
||||
@@ -250,7 +250,7 @@ class User extends Record
|
||||
$data->password = $this->hashPassword($data->password);
|
||||
}
|
||||
|
||||
$user = parent::createEntity($data);
|
||||
$user = parent::create($data);
|
||||
|
||||
if (!is_null($newPassword) && !empty($data->sendAccessInfo)) {
|
||||
if ($user->isActive()) {
|
||||
@@ -263,7 +263,7 @@ class User extends Record
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function updateEntity($id, $data)
|
||||
public function update($id, $data)
|
||||
{
|
||||
if ($id == 'system') {
|
||||
throw new Forbidden();
|
||||
@@ -280,7 +280,7 @@ class User extends Record
|
||||
unset($data->type);
|
||||
}
|
||||
|
||||
$user = parent::updateEntity($id, $data);
|
||||
$user = parent::update($id, $data);
|
||||
|
||||
if (!is_null($newPassword)) {
|
||||
try {
|
||||
@@ -576,7 +576,7 @@ class User extends Record
|
||||
$this->getMailSender()->send($email);
|
||||
}
|
||||
|
||||
public function deleteEntity($id)
|
||||
public function delete($id)
|
||||
{
|
||||
if ($id == 'system') {
|
||||
throw new Forbidden();
|
||||
@@ -584,7 +584,7 @@ class User extends Record
|
||||
if ($id == $this->getUser()->id) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
return parent::deleteEntity($id);
|
||||
return parent::delete($id);
|
||||
}
|
||||
|
||||
protected function checkEntityForMassRemove(Entity $entity)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -212,6 +212,11 @@ Espo.define('crm:views/dashlets/abstract/chart', ['views/dashlets/abstract/base'
|
||||
this.fetch(function (data) {
|
||||
this.chartData = this.prepareData(data);
|
||||
|
||||
if (this.isNoData()) {
|
||||
this.showNoData();
|
||||
return;
|
||||
}
|
||||
|
||||
this.adjustContainer();
|
||||
|
||||
setTimeout(function () {
|
||||
@@ -221,6 +226,10 @@ Espo.define('crm:views/dashlets/abstract/chart', ['views/dashlets/abstract/base'
|
||||
});
|
||||
},
|
||||
|
||||
isNoData: function () {
|
||||
return false;
|
||||
},
|
||||
|
||||
url: function () {},
|
||||
|
||||
prepareData: function (response) {
|
||||
@@ -239,6 +248,30 @@ Espo.define('crm:views/dashlets/abstract/chart', ['views/dashlets/abstract/base'
|
||||
|
||||
getDateFilter: function () {
|
||||
return this.getOption('dateFilter') || 'currentYear';
|
||||
},
|
||||
|
||||
showNoData: function () {
|
||||
var fontSize = this.getThemeManager().getParam('fontSize') || 14;
|
||||
this.$container.empty();
|
||||
var textFontSize = fontSize * 1.2;
|
||||
|
||||
var $text = $('<span>').html(this.translate('No Data')).addClass('text-muted');
|
||||
|
||||
var $div = $('<div>').css('text-align', 'center')
|
||||
.css('font-size', textFontSize + 'px')
|
||||
.css('display', 'table')
|
||||
.css('width', '100%')
|
||||
.css('height', '100%');
|
||||
|
||||
$text
|
||||
.css('display', 'table-cell')
|
||||
.css('vertical-align', 'middle')
|
||||
.css('padding-bottom', fontSize * 1.5 + 'px');
|
||||
|
||||
|
||||
$div.append($text);
|
||||
|
||||
this.$container.append($div);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -53,6 +53,10 @@ Espo.define('crm:views/dashlets/opportunities-by-lead-source', 'crm:views/dashle
|
||||
return data;
|
||||
},
|
||||
|
||||
isNoData: function () {
|
||||
return !this.chartData.length;
|
||||
},
|
||||
|
||||
setupDefaultOptions: function () {
|
||||
this.defaultOptions['dateFrom'] = this.defaultOptions['dateFrom'] || moment().format('YYYY') + '-01-01';
|
||||
this.defaultOptions['dateTo'] = this.defaultOptions['dateTo'] || moment().format('YYYY') + '-12-31';
|
||||
|
||||
@@ -52,6 +52,10 @@ Espo.define('crm:views/dashlets/sales-by-month', 'crm:views/dashlets/abstract/ch
|
||||
return 0;
|
||||
},
|
||||
|
||||
isNoData: function () {
|
||||
return !this.monthList.length;
|
||||
},
|
||||
|
||||
prepareData: function (response) {
|
||||
var monthList = this.monthList = response.keyList;
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
<li>vis.js by Almende B.V.</li>
|
||||
<li>Ace</li>
|
||||
<li>Marked by Christopher Jeffrey</li>
|
||||
<li>Exif.js by Jacob Seidelin</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{#if value}}<span class="fas fa-paperclip small text-soft"></span>{{/if}}
|
||||
{{#if value}}<span class="fas fa-paperclip small text-soft" title="{{translate 'hasAttachment' category='fields' scope='Email'}}"></span>{{/if}}
|
||||
@@ -334,15 +334,9 @@ Espo.define('views/fields/address', 'views/fields/base', function (Dep) {
|
||||
this.$country.attr('autocomplete', 'espo-country');
|
||||
}
|
||||
|
||||
this.controlStreetTextareaHeight();
|
||||
this.$street.on('input', function (e) {
|
||||
var numberOfLines = e.currentTarget.value.split('\n').length;
|
||||
var numberOfRows = this.$street.prop('rows');
|
||||
|
||||
if (numberOfRows < numberOfLines) {
|
||||
this.$street.prop('rows', numberOfLines);
|
||||
} else if (numberOfRows > numberOfLines) {
|
||||
this.$street.prop('rows', numberOfLines);
|
||||
}
|
||||
this.controlStreetTextareaHeight();
|
||||
}.bind(this));
|
||||
|
||||
var numberOfLines = this.$street.val().split('\n').length;
|
||||
@@ -350,6 +344,27 @@ Espo.define('views/fields/address', 'views/fields/base', function (Dep) {
|
||||
}
|
||||
},
|
||||
|
||||
controlStreetTextareaHeight: function (lastHeight) {
|
||||
var scrollHeight = this.$street.prop('scrollHeight');
|
||||
var clientHeight = this.$street.prop('clientHeight');
|
||||
|
||||
if (typeof lastHeight === 'undefined' && clientHeight === 0) {
|
||||
setTimeout(this.controlStreetTextareaHeight.bind(this), 10);
|
||||
return;
|
||||
}
|
||||
|
||||
if (clientHeight === lastHeight) return;
|
||||
|
||||
if (scrollHeight > clientHeight + 1) {
|
||||
var rows = this.$street.prop('rows');
|
||||
this.$street.attr('rows', rows + 1);
|
||||
this.controlStreetTextareaHeight(clientHeight);
|
||||
}
|
||||
if (this.$street.val().length === 0) {
|
||||
this.$street.attr('rows', 1);
|
||||
}
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ Espo.define('views/fields/attachment-multiple', 'views/fields/base', function (D
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
],
|
||||
|
||||
validations: ['ready', 'required'],
|
||||
@@ -284,11 +285,8 @@ Espo.define('views/fields/attachment-multiple', 'views/fields/base', function (D
|
||||
|
||||
var preview = name;
|
||||
|
||||
switch (type) {
|
||||
case 'image/png':
|
||||
case 'image/jpeg':
|
||||
case 'image/gif':
|
||||
preview = '<img src="' + this.getImageUrl(id, 'small') + '" title="' + name + '">';
|
||||
if (~this.previewTypeList.indexOf(type)) {
|
||||
preview = '<img src="' + this.getImageUrl(id, 'small') + '" title="' + name + '">';
|
||||
}
|
||||
|
||||
return preview;
|
||||
@@ -490,11 +488,8 @@ Espo.define('views/fields/attachment-multiple', 'views/fields/base', function (D
|
||||
},
|
||||
|
||||
isTypeIsImage: function (type) {
|
||||
switch (type) {
|
||||
case 'image/png':
|
||||
case 'image/jpeg':
|
||||
case 'image/gif':
|
||||
return true;
|
||||
if (~this.previewTypeList.indexOf(type)) {
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
},
|
||||
|
||||
@@ -46,6 +46,7 @@ Espo.define('views/fields/file', 'views/fields/link', function (Dep) {
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
],
|
||||
|
||||
defaultType: false,
|
||||
@@ -247,11 +248,8 @@ Espo.define('views/fields/file', 'views/fields/link', function (Dep) {
|
||||
name = Handlebars.Utils.escapeExpression(name);
|
||||
var preview = name;
|
||||
|
||||
switch (type) {
|
||||
case 'image/png':
|
||||
case 'image/jpeg':
|
||||
case 'image/gif':
|
||||
preview = '<a data-action="showImagePreview" data-id="' + id + '" href="' + this.getImageUrl(id) + '"><img src="'+this.getBasePath()+'?entryPoint=image&size='+this.previewSize+'&id=' + id + '" class="image-preview"></a>';
|
||||
if (~this.previewTypeList.indexOf(type)) {
|
||||
preview = '<a data-action="showImagePreview" data-id="' + id + '" href="' + this.getImageUrl(id) + '"><img src="'+this.getBasePath()+'?entryPoint=image&size='+this.previewSize+'&id=' + id + '" class="image-preview"></a>';
|
||||
}
|
||||
return preview;
|
||||
},
|
||||
@@ -260,11 +258,8 @@ Espo.define('views/fields/file', 'views/fields/link', function (Dep) {
|
||||
name = Handlebars.Utils.escapeExpression(name);
|
||||
var preview = name;
|
||||
|
||||
switch (type) {
|
||||
case 'image/png':
|
||||
case 'image/jpeg':
|
||||
case 'image/gif':
|
||||
preview = '<img src="' + this.getImageUrl(id, 'small') + '" title="' + name + '">';
|
||||
if (~this.previewTypeList.indexOf(type)) {
|
||||
preview = '<img src="' + this.getImageUrl(id, 'small') + '" title="' + name + '">';
|
||||
}
|
||||
|
||||
return preview;
|
||||
|
||||
@@ -181,7 +181,7 @@ Espo.define('views/fields/text', 'views/fields/base', function (Dep) {
|
||||
afterRender: function () {
|
||||
Dep.prototype.afterRender.call(this);
|
||||
|
||||
if (this.mode === 'detail' || this.mode === 'list') {
|
||||
if (this.isReadMode()) {
|
||||
$(window).off('resize.see-more-' + this.cid);
|
||||
|
||||
this.$textContainer = this.$el.find('> .complex-text-container');
|
||||
@@ -190,6 +190,10 @@ Espo.define('views/fields/text', 'views/fields/base', function (Dep) {
|
||||
|
||||
if (this.isCut()) {
|
||||
this.controlSeeMore();
|
||||
if (this.model.get(this.name) && this.$text.height() === 0) {
|
||||
this.$textContainer.addClass('cut');
|
||||
setTimeout(this.controlSeeMore.bind(this), 50);
|
||||
}
|
||||
|
||||
$(window).on('resize.see-more-' + this.cid, function () {
|
||||
this.controlSeeMore();
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('views/modals/image-preview', 'views/modal', function (Dep) {
|
||||
Espo.define('views/modals/image-preview', ['views/modal', 'lib!exif'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
@@ -40,6 +40,16 @@ Espo.define('views/modals/image-preview', 'views/modal', function (Dep) {
|
||||
|
||||
backdrop: true,
|
||||
|
||||
transformClassList: [
|
||||
'transform-flip',
|
||||
'transform-rotate-180',
|
||||
'transform-flip-and-rotate-180',
|
||||
'transform-flip-and-rotate-270',
|
||||
'transform-rotate-90',
|
||||
'transform-flip-and-rotate-90',
|
||||
'transform-rotate-270',
|
||||
],
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
name: this.options.name,
|
||||
@@ -81,9 +91,46 @@ Espo.define('views/modals/image-preview', 'views/modal', function (Dep) {
|
||||
return url;
|
||||
},
|
||||
|
||||
onImageLoad: function () {
|
||||
console.log(1);
|
||||
},
|
||||
|
||||
afterRender: function () {
|
||||
$container = this.$el.find('.image-container');
|
||||
$img = this.$el.find('.image-container img');
|
||||
$img = this.$img = this.$el.find('.image-container img');
|
||||
|
||||
$img.on('load', function () {
|
||||
var self = this;
|
||||
EXIF.getData($img.get(0), function () {
|
||||
var orientation = EXIF.getTag(this, 'Orientation');
|
||||
switch (orientation) {
|
||||
case 2:
|
||||
$img.addClass('transform-flip');
|
||||
break;
|
||||
case 3:
|
||||
$img.addClass('transform-rotate-180');
|
||||
break;
|
||||
case 4:
|
||||
$img.addClass('transform-rotate-180');
|
||||
$img.addClass('transform-flip');
|
||||
break;
|
||||
case 5:
|
||||
$img.addClass('transform-rotate-270');
|
||||
$img.addClass('transform-flip');
|
||||
break;
|
||||
case 6:
|
||||
$img.addClass('transform-rotate-90');
|
||||
break;
|
||||
case 7:
|
||||
$img.addClass('transform-rotate-90');
|
||||
$img.addClass('transform-flip');
|
||||
break;
|
||||
case 8:
|
||||
$img.addClass('transform-rotate-270');
|
||||
break;
|
||||
}
|
||||
});
|
||||
}.bind(this));
|
||||
|
||||
if (this.navigationEnabled) {
|
||||
$img.css('cursor', 'pointer');
|
||||
@@ -108,6 +155,11 @@ Espo.define('views/modals/image-preview', 'views/modal', function (Dep) {
|
||||
},
|
||||
|
||||
switchToNext: function () {
|
||||
|
||||
this.transformClassList.forEach(function (item) {
|
||||
this.$img.removeClass(item);
|
||||
}, this);
|
||||
|
||||
var index = -1;
|
||||
this.imageList.forEach(function (d, i) {
|
||||
if (d.id === this.options.id) {
|
||||
@@ -127,4 +179,3 @@ Espo.define('views/modals/image-preview', 'views/modal', function (Dep) {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2830,4 +2830,33 @@ a.field-info > span.fa-info-circle {
|
||||
.grid-auto-fill-md {
|
||||
grid-template-columns: repeat(auto-fill, minmax(@grid-column-width-medium, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
.transform-flip {
|
||||
-webkit-transform: scaleX(-1);
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.transform-rotate-90 {
|
||||
-webkit-transform: rotate(90deg);
|
||||
-moz-transform: rotate(90deg);
|
||||
-o-transform: rotate(90deg);
|
||||
-ms-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.transform-rotate-180 {
|
||||
-webkit-transform: rotate(180deg);
|
||||
-moz-transform: rotate(180deg);
|
||||
-o-transform: rotate(180deg);
|
||||
-ms-transform: rotate(180deg);
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.transform-rotate-270 {
|
||||
-webkit-transform: rotate(270deg);
|
||||
-moz-transform: rotate(270deg);
|
||||
-o-transform: rotate(270deg);
|
||||
-ms-transform: rotate(270deg);
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "espocrm",
|
||||
"version": "5.5.3",
|
||||
"version": "5.5.4",
|
||||
"description": "",
|
||||
"main": "index.php",
|
||||
"repository": {
|
||||
|
||||
Reference in New Issue
Block a user