Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e9208602f6 | |||
| e1d7733848 | |||
| b08f7de0cb | |||
| d83f02010a | |||
| 88bc592fcd | |||
| 9c2a125365 | |||
| e79e75c0d5 | |||
| 2187073e2b | |||
| 3c36e81502 | |||
| f8bafa5221 | |||
| 00a0cb1394 | |||
| 3a37f8421d | |||
| 2dbde4e2c8 | |||
| 98084e9314 | |||
| 2946969e3a | |||
| 75c3891654 | |||
| c0866c8fea | |||
| 5d3a785a49 | |||
| 4bcf88dcee | |||
| 022d9a42ec | |||
| ac80f67533 | |||
| 83fa22852a | |||
| 7ffd8a54a1 | |||
| 739cb5e98f | |||
| f5e1b7175e | |||
| 81cb2aaeb8 | |||
| 01ba132a62 | |||
| 4b31173355 | |||
| 34cd265fc1 | |||
| 93f8ef9daa | |||
| 81ffbc8e6d | |||
| 061dda1a1e | |||
| 41d8605e17 | |||
| 13a2ba47e7 | |||
| 4c598d19b5 | |||
| 7d4227c98d | |||
| 1102e9f1e8 | |||
| 607ee9a080 | |||
| e30838cf27 | |||
| 790355fb63 | |||
| 371fbf9864 | |||
| e3ac8c3f67 | |||
| 2087894c3a | |||
| 5c00a7ad43 | |||
| fe0dcc5342 | |||
| f05381cc43 | |||
| a9a30d7237 | |||
| 5312c1d141 | |||
| a97d516c4f | |||
| 16c24abb55 | |||
| ed897e9b97 | |||
| b4b222c1d7 | |||
| a68d711249 | |||
| d6834f7f97 | |||
| 20818659e8 | |||
| 1c668ce983 | |||
| a9dacd74c6 | |||
| b7c9ddc4e6 | |||
| d5ee599f9f |
@@ -190,6 +190,7 @@ module.exports = function (grunt) {
|
||||
'extension.php',
|
||||
'websocket.php',
|
||||
'command.php',
|
||||
'oauth-callback.php',
|
||||
'index.php',
|
||||
'LICENSE.txt',
|
||||
'.htaccess',
|
||||
|
||||
@@ -121,6 +121,8 @@ class FieldManager extends \Espo\Core\Controllers\Base
|
||||
|
||||
$this->getContainer()->get('fieldManager')->resetToDefault($data->scope, $data->name);
|
||||
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
|
||||
$this->getContainer()->get('dataManager')->rebuildMetadata();
|
||||
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* 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.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Exceptions;
|
||||
|
||||
class ConflictSilent extends Conflict
|
||||
{
|
||||
public $logLevel = 'notice';
|
||||
}
|
||||
@@ -65,7 +65,7 @@ class AddLinkMultipleIdType extends \Espo\Core\Formula\Functions\Base
|
||||
}
|
||||
} else {
|
||||
if (!is_string($id)) {
|
||||
throw new Error();
|
||||
return;
|
||||
}
|
||||
$this->getEntity()->addLinkMultipleId($link, $id);
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ class Sender
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function send(Email $email, $params = [], &$message = null, $attachmentList = [])
|
||||
public function send(Email $email, $params = [], $message = null, $attachmentList = [])
|
||||
{
|
||||
if (!$message) {
|
||||
$message = new Message();
|
||||
|
||||
@@ -197,10 +197,10 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
protected function afterMassRelate(Entity $entity, $relationName, array $params = [], array $options = [])
|
||||
{
|
||||
if (!$this->hooksDisabled && empty($options['skipHooks'])) {
|
||||
$hookData = array(
|
||||
$hookData = [
|
||||
'relationName' => $relationName,
|
||||
'relationParams' => $params
|
||||
);
|
||||
'relationParams' => $params,
|
||||
];
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterMassRelate', $entity, $options, $hookData);
|
||||
}
|
||||
}
|
||||
@@ -215,14 +215,24 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
{
|
||||
parent::afterRelate($entity, $relationName, $foreign, $data, $options);
|
||||
|
||||
if ($foreign instanceof Entity) {
|
||||
$foreignEntity = $foreign;
|
||||
if (!$this->hooksDisabled && empty($options['skipHooks'])) {
|
||||
$hookData = array(
|
||||
if (!$this->hooksDisabled && empty($options['skipHooks'])) {
|
||||
if (is_string($foreign)) {
|
||||
$foreignId = $foreign;
|
||||
$foreignEntityType = $entity->getRelationParam($relationName, 'entity');
|
||||
if ($foreignEntityType) {
|
||||
$foreign = $this->getEntityManager()->getEntity($foreignEntityType);
|
||||
$foreign->id = $foreignId;
|
||||
$foreign->setAsFetched();
|
||||
}
|
||||
}
|
||||
|
||||
if ($foreign instanceof Entity) {
|
||||
$hookData = [
|
||||
'relationName' => $relationName,
|
||||
'relationData' => $data,
|
||||
'foreignEntity' => $foreignEntity
|
||||
);
|
||||
'foreignEntity' => $foreign,
|
||||
'foreignId' => $foreign->id,
|
||||
];
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterRelate', $entity, $options, $hookData);
|
||||
}
|
||||
}
|
||||
@@ -232,13 +242,23 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
{
|
||||
parent::afterUnrelate($entity, $relationName, $foreign, $options);
|
||||
|
||||
if ($foreign instanceof Entity) {
|
||||
$foreignEntity = $foreign;
|
||||
if (!$this->hooksDisabled && empty($options['skipHooks'])) {
|
||||
$hookData = array(
|
||||
if (!$this->hooksDisabled && empty($options['skipHooks'])) {
|
||||
if (is_string($foreign)) {
|
||||
$foreignId = $foreign;
|
||||
$foreignEntityType = $entity->getRelationParam($relationName, 'entity');
|
||||
if ($foreignEntityType) {
|
||||
$foreign = $this->getEntityManager()->getEntity($foreignEntityType);
|
||||
$foreign->id = $foreignId;
|
||||
$foreign->setAsFetched();
|
||||
}
|
||||
}
|
||||
|
||||
if ($foreign instanceof Entity) {
|
||||
$hookData = [
|
||||
'relationName' => $relationName,
|
||||
'foreignEntity' => $foreignEntity
|
||||
);
|
||||
'foreignEntity' => $foreign,
|
||||
'foreignId' => $foreign->id,
|
||||
];
|
||||
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterUnrelate', $entity, $options, $hookData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +144,12 @@ class Auth
|
||||
|
||||
$createTokenSecret = $this->request->headers->get('Espo-Authorization-Create-Token-Secret') === 'true';
|
||||
|
||||
if ($createTokenSecret) {
|
||||
if ($this->getConfig()->get('authTokenSecretDisabled')) {
|
||||
$createTokenSecret = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$isByTokenOnly) {
|
||||
$this->checkFailedAttemptsLimit($username);
|
||||
}
|
||||
@@ -269,9 +275,8 @@ class Auth
|
||||
|
||||
if ($createTokenSecret) {
|
||||
$secret = $this->generateToken();
|
||||
//$authToken->set('secret', $secret);
|
||||
|
||||
setcookie('auth-token-secret', $secret, strtotime('+1000 days'), '/', '', false, true);
|
||||
$authToken->set('secret', $secret);
|
||||
$this->setSecretInCookie($secret);
|
||||
}
|
||||
|
||||
if ($this->isPortal()) {
|
||||
@@ -353,10 +358,16 @@ class Auth
|
||||
|
||||
public function destroyAuthToken($token)
|
||||
{
|
||||
$authToken = $this->getEntityManager()->getRepository('AuthToken')->select(['id', 'isActive'])->where(['token' => $token])->findOne();
|
||||
$authToken = $this->getEntityManager()->getRepository('AuthToken')->select(['id', 'isActive', 'secret'])->where(['token' => $token])->findOne();
|
||||
if ($authToken) {
|
||||
$authToken->set('isActive', false);
|
||||
$this->getEntityManager()->saveEntity($authToken);
|
||||
if ($authToken->get('secret')) {
|
||||
$sentSecret = $_COOKIE['auth-token-secret'] ?? null;
|
||||
if ($sentSecret === $authToken->get('secret')) {
|
||||
setcookie('auth-token-secret', null, -1, '/');
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -398,4 +409,19 @@ class Auth
|
||||
$authLogRecord->set('denialReason', $denialReason);
|
||||
$this->getEntityManager()->saveEntity($authLogRecord);
|
||||
}
|
||||
|
||||
protected function setSecretInCookie(string $secret)
|
||||
{
|
||||
if (version_compare(\PHP_VERSION, '7.3.0') < 0) {
|
||||
setcookie('auth-token-secret', $secret, strtotime('+1000 days'), '/', '', false, true);
|
||||
return;
|
||||
}
|
||||
|
||||
setcookie('auth-token-secret', $secret, [
|
||||
'expires' => strtotime('+1000 days'),
|
||||
'path' => '/',
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ namespace Espo\Core\Utils\Database\DBAL\Schema;
|
||||
|
||||
class Column extends \Doctrine\DBAL\Schema\Column
|
||||
{
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
@@ -42,6 +41,7 @@ class Column extends \Doctrine\DBAL\Schema\Column
|
||||
*/
|
||||
protected $_unique = false;
|
||||
|
||||
protected $_quoted = true;
|
||||
|
||||
/**
|
||||
* @param boolean $unique
|
||||
@@ -85,4 +85,4 @@ class Column extends \Doctrine\DBAL\Schema\Column
|
||||
), $this->_platformOptions, $this->_customSchemaOptions);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
namespace Espo\Core\Utils\Database\DBAL\Schema;
|
||||
|
||||
use Doctrine\DBAL\Schema\Index as DBALIndex;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
|
||||
class Index extends \Doctrine\DBAL\Schema\Index
|
||||
{
|
||||
@@ -79,4 +80,16 @@ class Index extends \Doctrine\DBAL\Schema\Index
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getQuotedColumns(AbstractPlatform $platform)
|
||||
{
|
||||
$columns = array();
|
||||
|
||||
foreach ($this->_columns as $column) {
|
||||
$column->_quoted = true;
|
||||
$columns[] = $column->getQuotedName($platform);
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ use Doctrine\DBAL\Schema\SchemaException;
|
||||
|
||||
class Table extends \Doctrine\DBAL\Schema\Table
|
||||
{
|
||||
protected $_quoted = true;
|
||||
|
||||
/**
|
||||
* @param string $columnName
|
||||
* @param string $typeName
|
||||
@@ -81,4 +83,4 @@ class Table extends \Doctrine\DBAL\Schema\Table
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ class Converter
|
||||
'orderBy' => 'orderBy',
|
||||
'where' => 'where',
|
||||
'storeArrayValues' => 'storeArrayValues',
|
||||
'binary' => 'binary',
|
||||
);
|
||||
|
||||
protected $idParams = array(
|
||||
|
||||
@@ -408,9 +408,15 @@ class Converter
|
||||
$dbFieldParams['unsigned'] = true;
|
||||
}
|
||||
|
||||
if (isset($fieldParams['binary']) && $fieldParams['binary']) {
|
||||
$dbFieldParams['platformOptions'] = array(
|
||||
'collation' => 'utf8mb4_bin',
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($fieldParams['utf8mb3']) && $fieldParams['utf8mb3']) {
|
||||
$dbFieldParams['platformOptions'] = array(
|
||||
'collation' => 'utf8_unicode_ci',
|
||||
'collation' => (isset($fieldParams['binary']) && $fieldParams['binary']) ? 'utf8_bin' : 'utf8_unicode_ci',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class EntityManager
|
||||
|
||||
private $linkForbiddenNameList = ['posts', 'stream', 'subscription', 'followers', 'action', 'null', 'false', 'true'];
|
||||
|
||||
private $forbiddenEntityTypeNameList = ['PortalUser', 'ApiUser', 'Timeline', 'About', 'Admin', 'Null', 'False', 'True'];
|
||||
private $forbiddenEntityTypeNameList = ['Common', 'PortalUser', 'ApiUser', 'Timeline', 'About', 'Admin', 'Null', 'False', 'True'];
|
||||
|
||||
public function __construct(Metadata $metadata, Language $language, File\Manager $fileManager, Config $config, Container $container = null)
|
||||
{
|
||||
|
||||
@@ -271,7 +271,7 @@ class FieldManager
|
||||
|
||||
$entityDefs = $this->normalizeDefs($scope, $name, $fieldDefs);
|
||||
|
||||
if (!empty($entityDefs)) {
|
||||
if (!empty((array) $entityDefs)) {
|
||||
$result &= $this->saveCustomEntityDefs($scope, $entityDefs);
|
||||
$this->isChanged = true;
|
||||
}
|
||||
@@ -430,13 +430,15 @@ class FieldManager
|
||||
return $this->getMetadata()->get('entityDefs'.'.'.$scope.'.fields.'.$name, $default);
|
||||
}
|
||||
|
||||
protected function getCustomFieldDefs($scope, $name)
|
||||
protected function getCustomFieldDefs($scope, $name, $default = null)
|
||||
{
|
||||
$customDefs = $this->getMetadata()->getCustom('entityDefs', $scope, (object) []);
|
||||
|
||||
if (isset($customDefs->fields->$name)) {
|
||||
return (array) $customDefs->fields->$name;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
protected function saveCustomEntityDefs($scope, $newDefs)
|
||||
@@ -529,43 +531,32 @@ class FieldManager
|
||||
}
|
||||
}
|
||||
|
||||
$actualCustomFieldDefs = $this->getCustomFieldDefs($scope, $name);
|
||||
$actualCustomFieldDefs = $this->getCustomFieldDefs($scope, $name, []);
|
||||
$actualFieldDefs = $this->getFieldDefs($scope, $name, []);
|
||||
$permittedParamList = array_keys($params);
|
||||
|
||||
$filteredFieldDefs = $actualCustomFieldDefs ? $actualCustomFieldDefs : [];
|
||||
$filteredFieldDefs = !empty($actualCustomFieldDefs) ? $actualCustomFieldDefs : [];
|
||||
|
||||
foreach ($fieldDefs as $paramName => $paramValue) {
|
||||
if (in_array($paramName, $permittedParamList)) {
|
||||
|
||||
$defaultParamValue = null;
|
||||
|
||||
switch ($params[$paramName]['type']) {
|
||||
case 'bool':
|
||||
$fieldDefsDefaultValue = array_key_exists('default', $params[$paramName]) ? $params[$paramName]['default'] : false;
|
||||
|
||||
$actualValue = array_key_exists($paramName, $actualFieldDefs) ? $actualFieldDefs[$paramName] : $fieldDefsDefaultValue;
|
||||
|
||||
if (!Util::areValuesEqual($actualValue, $paramValue)) {
|
||||
$filteredFieldDefs[$paramName] = $paramValue;
|
||||
}
|
||||
$defaultParamValue = false;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (!array_key_exists('default', $params[$paramName]) && !array_key_exists($paramName, $actualFieldDefs)) {
|
||||
$filteredFieldDefs[$paramName] = $paramValue;
|
||||
break;
|
||||
}
|
||||
$actualValue = array_key_exists($paramName, $actualFieldDefs) ? $actualFieldDefs[$paramName] : $defaultParamValue;
|
||||
|
||||
if (array_key_exists('default', $params[$paramName])) {
|
||||
$actualValue = $params[$paramName]['default'];
|
||||
}
|
||||
if (!array_key_exists($paramName, $actualCustomFieldDefs) && !Util::areValuesEqual($actualValue, $paramValue)) {
|
||||
$filteredFieldDefs[$paramName] = $paramValue;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (array_key_exists($paramName, $actualFieldDefs)) {
|
||||
$actualValue = $actualFieldDefs[$paramName];
|
||||
}
|
||||
|
||||
if (!Util::areValuesEqual($actualValue, $paramValue)) {
|
||||
$filteredFieldDefs[$paramName] = $paramValue;
|
||||
}
|
||||
break;
|
||||
if (array_key_exists($paramName, $actualCustomFieldDefs)) {
|
||||
$filteredFieldDefs[$paramName] = $paramValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -593,7 +584,7 @@ class FieldManager
|
||||
* @param string $scope
|
||||
* @param string $fieldName
|
||||
* @param array $fieldDefs
|
||||
* @return array
|
||||
* @return object
|
||||
*/
|
||||
protected function normalizeDefs($scope, $fieldName, array $fieldDefs)
|
||||
{
|
||||
|
||||
@@ -354,7 +354,7 @@ class Language
|
||||
|
||||
$cacheFile = $this->getCacheFile($language);
|
||||
|
||||
if (!$this->useCache || !file_exists($cacheFile)) {
|
||||
if (!$this->useCache || !file_exists($cacheFile) || $reload) {
|
||||
|
||||
$paths = $this->paths;
|
||||
|
||||
@@ -368,11 +368,12 @@ class Language
|
||||
|
||||
$data = $this->getUnifier()->unify('i18n', $paths, true);
|
||||
|
||||
if (is_array($data))
|
||||
if (is_array($data)) {
|
||||
$this->sanitizeData($data);
|
||||
}
|
||||
|
||||
if ($language != $this->defaultLanguage) {
|
||||
$data = Util::merge($this->getDefaultLanguageData(), $data);
|
||||
$data = Util::merge($this->getDefaultLanguageData($reload), $data);
|
||||
}
|
||||
|
||||
$this->data[$language] = $data;
|
||||
@@ -399,11 +400,9 @@ class Language
|
||||
if (is_array($subData)) {
|
||||
$this->sanitizeData($subData);
|
||||
} else {
|
||||
$subData = htmlspecialchars($subData);
|
||||
if (is_string($subData)) {
|
||||
$subData = str_replace('<', '<', $subData);
|
||||
$subData = str_replace('>', '>', $subData);
|
||||
$subData = str_replace('"', '"', $subData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,4 +733,80 @@ class Util
|
||||
|
||||
return mb_strtolower($firstChar) . $then;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize Html code
|
||||
* @param string $text
|
||||
* @param array $permittedHtmlTags - Allows only html tags without parameters like <p></p>, <br>, etc.
|
||||
* @return string
|
||||
*/
|
||||
public static function sanitizeHtml($text, $permittedHtmlTags = ['p', 'br', 'b', 'strong', 'pre'])
|
||||
{
|
||||
if (is_array($text)) {
|
||||
foreach ($text as $key => &$value) {
|
||||
$value = self::sanitizeHtml($value, $permittedHtmlTags);
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
$sanitized = htmlspecialchars($text, \ENT_QUOTES | \ENT_HTML5, 'UTF-8');
|
||||
|
||||
foreach ($permittedHtmlTags as $htmlTag) {
|
||||
$sanitized = preg_replace('/<(\/)?(' . $htmlTag . ')>/i', '<$1$2>', $sanitized);
|
||||
}
|
||||
|
||||
return $sanitized;
|
||||
}
|
||||
|
||||
public static function urlAddParam($url, $paramName, $paramValue)
|
||||
{
|
||||
$urlQuery = parse_url($url, \PHP_URL_QUERY);
|
||||
|
||||
if (!$urlQuery) {
|
||||
$params = [
|
||||
$paramName => $paramValue
|
||||
];
|
||||
|
||||
$url = trim($url);
|
||||
$url = preg_replace('/\/\?$/', '', $url);
|
||||
$url = preg_replace('/\/$/', '', $url);
|
||||
|
||||
return $url . '/?' . http_build_query($params);
|
||||
}
|
||||
|
||||
parse_str($urlQuery, $params);
|
||||
|
||||
if (!isset($params[$paramName]) || $params[$paramName] != $paramValue) {
|
||||
$params[$paramName] = $paramValue;
|
||||
|
||||
return str_replace($urlQuery, http_build_query($params), $url);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
public static function urlRemoveParam($url, $paramName, $suffix = '')
|
||||
{
|
||||
$urlQuery = parse_url($url, \PHP_URL_QUERY);
|
||||
|
||||
if ($urlQuery) {
|
||||
parse_str($urlQuery, $params);
|
||||
|
||||
if (isset($params[$paramName])) {
|
||||
unset($params[$paramName]);
|
||||
|
||||
$newUrl = str_replace($urlQuery, http_build_query($params), $url);
|
||||
|
||||
if (empty($params)) {
|
||||
$newUrl = preg_replace('/\/\?$/', '', $newUrl);
|
||||
$newUrl = preg_replace('/\/$/', '', $newUrl);
|
||||
$newUrl .= $suffix;
|
||||
}
|
||||
|
||||
return $newUrl;
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,17 @@ use Espo\ORM\Entity;
|
||||
|
||||
class Lead extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
public function afterSave(Entity $entity, array $options = array())
|
||||
public function beforeSave(Entity $entity, array $options = [])
|
||||
{
|
||||
if (!$entity->get('convertedAt') && $entity->get('status') === 'Converted' && $entity->isAttributeChanged('status')) {
|
||||
$convertedAt = date('Y-m-d H:i:s');
|
||||
$entity->set('convertedAt', $convertedAt);
|
||||
}
|
||||
|
||||
parent::beforeSave($entity, $options);
|
||||
}
|
||||
|
||||
public function afterSave(Entity $entity, array $options = [])
|
||||
{
|
||||
parent::afterSave($entity, $options);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"createdAccount": "Account",
|
||||
"createdContact": "Contact",
|
||||
"createdOpportunity": "Opportunity",
|
||||
"convertedAt": "Converted At",
|
||||
"campaign": "Campaign",
|
||||
"targetLists": "Target Lists",
|
||||
"targetList": "Target List",
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
"recordViews":{
|
||||
"detail":"crm:views/lead/record/detail"
|
||||
},
|
||||
"defaultSidePanelFieldList": [
|
||||
":assignedUser",
|
||||
"teams",
|
||||
"convertedAt"
|
||||
],
|
||||
"sidePanels":{
|
||||
"detail":[
|
||||
{
|
||||
@@ -132,6 +137,26 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"convertedAt": {
|
||||
"visible": {
|
||||
"conditionGroup": [
|
||||
{
|
||||
"type": "and",
|
||||
"value": [
|
||||
{
|
||||
"type": "equals",
|
||||
"attribute": "status",
|
||||
"value": "Converted"
|
||||
},
|
||||
{
|
||||
"type": "isNotEmpty",
|
||||
"attribute": "convertedAt"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"panels": {
|
||||
|
||||
@@ -100,6 +100,12 @@
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
"convertedAt": {
|
||||
"type": "datetime",
|
||||
"layoutDetailDisabled": true,
|
||||
"layoutMassUpdateDisabled": true,
|
||||
"readOnly": true
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "datetime",
|
||||
"readOnly": true
|
||||
|
||||
@@ -739,7 +739,7 @@ class Activities extends \Espo\Core\Services\Base
|
||||
$orderBy = null;
|
||||
$order = null;
|
||||
if (!empty($selectParams['orderBy'])) {
|
||||
$order = $selectParams['order'];
|
||||
$order = $selectParams['order'] ?? null;
|
||||
$orderBy = $selectParams['orderBy'];
|
||||
}
|
||||
|
||||
|
||||
@@ -1082,7 +1082,7 @@ abstract class Base
|
||||
if (!empty($item[1])) {
|
||||
$orderInternal = $item[1];
|
||||
}
|
||||
$arr[] = $this->getOrderPart($entity, $orderByInternal, $orderInternal, false, $params);
|
||||
$arr[] = $this->getOrderPart($entity, $orderByInternal, $orderInternal, $useColumnAlias, $params);
|
||||
}
|
||||
}
|
||||
return implode(", ", $arr);
|
||||
@@ -1090,7 +1090,11 @@ abstract class Base
|
||||
|
||||
if (strpos($orderBy, 'LIST:') === 0) {
|
||||
list($l, $field, $list) = explode(':', $orderBy);
|
||||
$fieldPath = $this->getFieldPathForOrderBy($entity, $field, $params);
|
||||
if ($useColumnAlias) {
|
||||
$fieldPath = '`'. $this->sanitizeSelectAlias($field) . '`';
|
||||
} else {
|
||||
$fieldPath = $this->getFieldPathForOrderBy($entity, $field, $params);
|
||||
}
|
||||
$listQuoted = [];
|
||||
$list = array_reverse(explode(',', $list));
|
||||
foreach ($list as $i => $listItem) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"action": "Action",
|
||||
"createdAt": "Date",
|
||||
"user": "User",
|
||||
"userType": "User Type",
|
||||
"target": "Target",
|
||||
"targetType": "Target Type",
|
||||
"authToken": "Auth Token",
|
||||
|
||||
@@ -91,7 +91,6 @@
|
||||
"massEmailOpenTracking": "Email Open Tracking",
|
||||
"activitiesEntityList": "Activities Entity List",
|
||||
"historyEntityList": "History Entity List",
|
||||
"b2cMode": "B2C Mode",
|
||||
"currencyFormat": "Currency Format",
|
||||
"currencyDecimalPlaces": "Currency Decimal Places",
|
||||
"aclStrictMode": "ACL Strict Mode",
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
"target",
|
||||
"createdAt",
|
||||
"ipAddress",
|
||||
"user"
|
||||
"user",
|
||||
"userType"
|
||||
]
|
||||
@@ -15,15 +15,7 @@
|
||||
[{"name": "exportDelimiter"}, {"name":"autoFollowEntityTypeList"}],
|
||||
[
|
||||
{
|
||||
"name": "signature",
|
||||
"params": {
|
||||
"toolbar": [
|
||||
["style", ["bold", "italic", "underline", "clear"]],
|
||||
["color", ["color"]],
|
||||
["height", ["height"]],
|
||||
["misc",["codeview"]]
|
||||
]
|
||||
}
|
||||
"name": "signature"
|
||||
},
|
||||
{
|
||||
"name": "defaultReminders"
|
||||
|
||||
@@ -45,7 +45,8 @@
|
||||
},
|
||||
{
|
||||
"label":"Folders",
|
||||
"link":"#EmailFolder"
|
||||
"link":"#EmailFolder",
|
||||
"configCheck": "!emailFoldersDisabled"
|
||||
},
|
||||
{
|
||||
"label":"Filters",
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
"user": {
|
||||
"type": "link"
|
||||
},
|
||||
"userType": {
|
||||
"type": "foreign",
|
||||
"link": "user",
|
||||
"field": "type",
|
||||
"view": "views/fields/foreign-enum",
|
||||
"notStorable": true
|
||||
},
|
||||
"ipAddress": {
|
||||
"type": "varchar",
|
||||
"maxLength": "39"
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
},
|
||||
"signature": {
|
||||
"type": "wysiwyg",
|
||||
"view": "views/fields/wysiwyg"
|
||||
"view": "views/preferences/fields/signature"
|
||||
},
|
||||
"defaultReminders": {
|
||||
"type": "jsonArray",
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
{
|
||||
"name": "rows",
|
||||
"type": "int",
|
||||
"default": 30,
|
||||
"min": 1
|
||||
},
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ class Email extends \Espo\Core\SelectManagers\Base
|
||||
$skipIndex = true;
|
||||
break;
|
||||
} else {
|
||||
if (isset($item['attribute']) && $this->getSeed()->getAttributeParam($item['attribute'], 'type') === 'foreignId') {
|
||||
if (isset($item['attribute'])) {
|
||||
$skipIndex = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -41,5 +41,10 @@ class EmailFilter extends Record
|
||||
if (!$this->getAcl()->check($entity, 'edit')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
if ($entity->get('isGlobal')) {
|
||||
$entity->set('parentId', null);
|
||||
$entity->set('parentType', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ class InboundEmail extends \Espo\Services\Record
|
||||
'isActive' => true,
|
||||
'teamsMiddle.teamId' => $teamIdList
|
||||
),
|
||||
'distrinct' => true,
|
||||
'distinct' => true,
|
||||
'joins' => ['teams']
|
||||
));
|
||||
foreach ($userList as $user) {
|
||||
@@ -922,7 +922,7 @@ class InboundEmail extends \Espo\Services\Record
|
||||
|
||||
public function getSmtpParamsFromAccount(\Espo\Entities\InboundEmail $emailAccount)
|
||||
{
|
||||
$smtpParams = array();
|
||||
$smtpParams = [];
|
||||
$smtpParams['server'] = $emailAccount->get('smtpHost');
|
||||
if ($smtpParams['server']) {
|
||||
$smtpParams['port'] = $emailAccount->get('smtpPort');
|
||||
@@ -933,7 +933,10 @@ class InboundEmail extends \Espo\Services\Record
|
||||
if ($emailAccount->get('fromName')) {
|
||||
$smtpParams['fromName'] = $emailAccount->get('fromName');
|
||||
}
|
||||
if (array_key_exists('password', $smtpParams)) {
|
||||
if ($emailAccount->get('emailAddress')) {
|
||||
$smtpParams['fromAddress'] = $emailAccount->get('emailAddress');
|
||||
}
|
||||
if (array_key_exists('password', $smtpParams) && is_string($smtpParams['password'])) {
|
||||
$smtpParams['password'] = $this->getCrypt()->decrypt($smtpParams['password']);
|
||||
}
|
||||
return $smtpParams;
|
||||
|
||||
@@ -38,6 +38,7 @@ use \Espo\Core\Exceptions\Conflict;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\NotFoundSilent;
|
||||
use \Espo\Core\Exceptions\ForbiddenSilent;
|
||||
use \Espo\Core\Exceptions\ConflictSilent;
|
||||
|
||||
use \Espo\Core\Utils\Util;
|
||||
|
||||
@@ -830,7 +831,7 @@ class Record extends \Espo\Core\Services\Base
|
||||
'reason' => 'Duplicate',
|
||||
'data' => $data
|
||||
];
|
||||
throw new Conflict(json_encode($reason));
|
||||
throw new ConflictSilent(json_encode($reason));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +154,8 @@ Espo.define('crm:views/contact/fields/accounts', 'views/fields/link-multiple-wit
|
||||
},
|
||||
|
||||
addLinkHtml: function (id, name) {
|
||||
name = name || id;
|
||||
|
||||
if (this.mode == 'search') {
|
||||
return Dep.prototype.addLinkHtml.call(this, id, name);
|
||||
}
|
||||
|
||||
@@ -43,8 +43,7 @@ Espo.define('crm:views/lead/record/panels/converted-to', 'views/record/panels/si
|
||||
if (this.getAcl().check('Opportunity') && !this.getMetadata().get('scopes.Opportunity.disabled')) {
|
||||
this.fieldList.push('createdOpportunity');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -98,6 +98,12 @@ Espo.define('crm:views/meeting/detail', 'views/detail', function (Dep) {
|
||||
|
||||
if (!contactIdList.length && !leadIdList.length && !userIdList.length) {
|
||||
show = false;
|
||||
} else if (
|
||||
userIdList.length === 1 && userIdList[0] === this.getUser().id
|
||||
&&
|
||||
this.model.getLinkMultipleColumn('users', 'status', this.getUser().id) === 'Accepted'
|
||||
) {
|
||||
show = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
<img src="{{url}}" style="max-width: 100%;">
|
||||
</div>
|
||||
|
||||
{{#if size}}
|
||||
<div class="margin">
|
||||
{{translate 'Original'}}: <a href="{{originalUrl}}" target="_blank">{{name}}</a>
|
||||
<div class="original-link-container margin{{#unless showOriginalLink}} hidden{{/unless}}">
|
||||
<a href="{{originalUrl}}" target="_blank">{{translate 'Original'}}</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<ul class="dropdown-menu pull-left">
|
||||
{{#each dropdownItemList}}
|
||||
{{#if this}}
|
||||
<li class="{{#if hidden}}hidden{{/if}}"><a href="javascript:" class="action" data-action="{{name}}">{{#if html}}{{{html}}}{{else}}{{translate label scope=../../../entityType}}{{/if}}</a></li>
|
||||
<li class="{{#if hidden}}hidden{{/if}}"><a href="javascript:" class="action" data-action="{{name}}" {{#each data}} data-{{@key}}="{{./this}}"{{/each}}>{{#if html}}{{{html}}}{{else}}{{translate label scope=../../../entityType}}{{/if}}</a></li>
|
||||
{{else}}
|
||||
{{#unless @first}}
|
||||
{{#unless @last}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="navbar navbar-inverse" role="navigation">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-action="toggleCollapsable"">
|
||||
<button type="button" class="navbar-toggle" data-action="toggleCollapsable">
|
||||
<span class="fas fa-bars"></span>
|
||||
</button>
|
||||
<div class="navbar-logo-container"><a class="navbar-brand nav-link" href="#"><img src="{{logoSrc}}" class="logo"></span></a></div>
|
||||
|
||||
@@ -116,7 +116,8 @@ define('language', ['ajax'], function (Ajax) {
|
||||
},
|
||||
|
||||
load: function (callback, disableCache, loadDefault) {
|
||||
this.once('sync', callback);
|
||||
if (callback)
|
||||
this.once('sync', callback);
|
||||
|
||||
if (!disableCache) {
|
||||
if (this.loadFromCache(loadDefault)) {
|
||||
@@ -129,7 +130,7 @@ define('language', ['ajax'], function (Ajax) {
|
||||
},
|
||||
|
||||
fetch: function (disableCache, loadDefault) {
|
||||
Ajax.getRequest(this.url, {default: loadDefault}).then(function (data) {
|
||||
return Ajax.getRequest(this.url, {default: loadDefault}).then(function (data) {
|
||||
this.data = data;
|
||||
if (!disableCache) {
|
||||
this.storeToCache(loadDefault);
|
||||
|
||||
@@ -46,19 +46,22 @@ define('metadata', [], function () {
|
||||
load: function (callback, disableCache, sync) {
|
||||
var sync = (typeof sync == 'undefined') ? false: sync;
|
||||
this.off('sync');
|
||||
this.once('sync', callback);
|
||||
|
||||
if (callback)
|
||||
this.once('sync', callback);
|
||||
|
||||
if (!disableCache) {
|
||||
if (this.loadFromCache()) {
|
||||
this.trigger('sync');
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.fetch(sync);
|
||||
return this.fetch(sync);
|
||||
},
|
||||
|
||||
fetch: function (sync) {
|
||||
var self = this;
|
||||
this.ajax({
|
||||
return this.ajax({
|
||||
url: this.url,
|
||||
type: 'GET',
|
||||
dataType: 'JSON',
|
||||
|
||||
@@ -33,22 +33,58 @@ define('utils', [], function () {
|
||||
handleAction: function (viewObject, e) {
|
||||
var $target = $(e.currentTarget);
|
||||
var action = $target.data('action');
|
||||
|
||||
var fired = false;
|
||||
if (action) {
|
||||
var data = $target.data();
|
||||
var method = 'action' + Espo.Utils.upperCaseFirst(action);
|
||||
if (typeof viewObject[method] == 'function') {
|
||||
viewObject[method].call(viewObject, data, e);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
fired = true;
|
||||
} else if (data.handler) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
fired = true;
|
||||
require(data.handler, function (Handler) {
|
||||
var handler = new Handler(viewObject);
|
||||
handler[method].call(handler, data, e);
|
||||
});
|
||||
}
|
||||
|
||||
if (fired) {
|
||||
var $dropdown = $target.closest('.dropdown-menu');
|
||||
if ($dropdown.length) {
|
||||
var $dropdownToggle = $dropdown.parent().find('[data-toggle="dropdown"]');
|
||||
if ($dropdownToggle.length) {
|
||||
$dropdownToggle.dropdown('toggle');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
checkActionAvailability: function (helper, item) {
|
||||
var config = helper.config;
|
||||
|
||||
if (item.configCheck) {
|
||||
var configCheck = item.configCheck;
|
||||
var opposite = false;
|
||||
if (configCheck.substr(0, 1) === '!') {
|
||||
opposite = true;
|
||||
configCheck = configCheck.substr(1);
|
||||
}
|
||||
var configCheckResult = config.getByPath(configCheck.split('.'));
|
||||
if (opposite) {
|
||||
configCheckResult = !configCheckResult;
|
||||
}
|
||||
if (!configCheckResult) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
checkActionAccess: function (acl, obj, item, isPrecise) {
|
||||
var hasAccess = true;
|
||||
if (item.acl) {
|
||||
|
||||
@@ -314,13 +314,15 @@ define('view-helper', ['lib!client/lib/purify.min.js'], function () {
|
||||
text = text.replace(item.regex, item.value);
|
||||
});
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (options.inline) {
|
||||
text = marked.inlineLexer(text, []);
|
||||
} else {
|
||||
text = marked(text);
|
||||
}
|
||||
|
||||
text = DOMPurify.sanitize(text);
|
||||
text = DOMPurify.sanitize(text).toString();
|
||||
|
||||
text = text.replace(/<a href="mailto:(.*)"/gm, '<a href="javascript:" data-email-address="$1" data-action="mailTo"');
|
||||
|
||||
|
||||
@@ -424,8 +424,9 @@ Espo.define('views/admin/field-manager/edit', ['view', 'model'], function (Dep,
|
||||
}.bind(this)),
|
||||
new Promise(function (resolve) {
|
||||
this.getLanguage().load(function () {
|
||||
this.getLanguage().storeToCache();
|
||||
resolve();
|
||||
}, true);
|
||||
}.bind(this), true);
|
||||
}.bind(this))
|
||||
]).then(function () {
|
||||
this.trigger('after:save');
|
||||
@@ -501,6 +502,7 @@ Espo.define('views/admin/field-manager/edit', ['view', 'model'], function (Dep,
|
||||
}.bind(this)),
|
||||
new Promise(function (resolve) {
|
||||
this.getLanguage().load(function () {
|
||||
this.getLanguage().storeToCache();
|
||||
resolve();
|
||||
}.bind(this), true);
|
||||
}.bind(this))
|
||||
@@ -513,8 +515,7 @@ Espo.define('views/admin/field-manager/edit', ['view', 'model'], function (Dep,
|
||||
}.bind(this));
|
||||
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -45,6 +45,8 @@ Espo.define('views/email-template/record/detail', 'views/record/detail', functio
|
||||
if (!bodyView) return;
|
||||
|
||||
if (this.model.get('isHtml')) {
|
||||
var $anchor = $(window.getSelection().anchorNode);
|
||||
if (!$anchor.closest('.note-editing-area').length) return;
|
||||
bodyView.$summernote.summernote('insertText', tag);
|
||||
} else {
|
||||
var $body = bodyView.$element;
|
||||
|
||||
@@ -203,10 +203,6 @@ Espo.define('views/email/fields/email-address-varchar', ['views/fields/varchar',
|
||||
},
|
||||
|
||||
addAddress: function (address, name, type, id) {
|
||||
if (name) {
|
||||
name = this.getHelper().escapeString(name);
|
||||
}
|
||||
|
||||
if (this.justAddedAddress) {
|
||||
this.deleteAddress(this.justAddedAddress);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('views/email/list', 'views/list', function (Dep) {
|
||||
define('views/email/list', 'views/list', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
@@ -65,13 +65,18 @@ Espo.define('views/email/list', 'views/list', function (Dep) {
|
||||
}
|
||||
|
||||
this.foldersDisabled = this.foldersDisabled ||
|
||||
this.getMetadata().get(['scopes', this.folderScope, 'disabled']) ||
|
||||
!this.getAcl().checkScope(this.folderScope);
|
||||
this.getConfig().get('emailFoldersDisabled') ||
|
||||
this.getMetadata().get(['scopes', this.folderScope, 'disabled']) ||
|
||||
!this.getAcl().checkScope(this.folderScope);
|
||||
|
||||
var params = this.options.params || {};
|
||||
|
||||
this.selectedFolderId = params.folder || this.defaultFolderId;
|
||||
|
||||
if (this.foldersDisabled) {
|
||||
this.selectedFolderId = null;
|
||||
}
|
||||
|
||||
this.applyFolder();
|
||||
},
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ Espo.define('views/fields/link-multiple-with-columns', 'views/fields/link-multip
|
||||
},
|
||||
|
||||
getDetailLinkHtml: function (id, name) {
|
||||
name = name || this.nameHash[id];
|
||||
name = name || this.nameHash[id] || id;
|
||||
|
||||
var roleHtml = '';
|
||||
|
||||
|
||||
@@ -123,6 +123,8 @@ Espo.define('views/fields/link-multiple-with-primary', 'views/fields/link-multip
|
||||
},
|
||||
|
||||
addLinkHtml: function (id, name) {
|
||||
name = name || id;
|
||||
|
||||
if (this.mode == 'search') {
|
||||
return Dep.prototype.addLinkHtml.call(this, id, name);
|
||||
}
|
||||
@@ -130,7 +132,7 @@ Espo.define('views/fields/link-multiple-with-primary', 'views/fields/link-multip
|
||||
var $container = this.$el.find('.link-container');
|
||||
var $el = $('<div class="form-inline list-group-item link-with-role clearfix link-group-item-with-primary">').addClass('link-' + id).attr('data-id', id);
|
||||
|
||||
var nameHtml = '<div>' + this.getHelper().escapeString(name) + ' ' + '</div>';
|
||||
var nameHtml = '<div>' + this.getHelper().escapeString(name) || id + ' ' + '</div>';
|
||||
var removeHtml = '<a href="javascript:" class="pull-right" data-id="' + id + '" data-action="clearLink"><span class="fas fa-times"></a>';
|
||||
|
||||
$left = $('<div>');
|
||||
|
||||
@@ -70,7 +70,7 @@ Espo.define('views/fields/link-multiple-with-role', 'views/fields/link-multiple'
|
||||
},
|
||||
|
||||
getDetailLinkHtml: function (id, name) {
|
||||
name = name || this.nameHash[id];
|
||||
name = name || this.nameHash[id] || id;
|
||||
if (!name && id) {
|
||||
name = this.translate(this.foreignScope, 'scopeNames');
|
||||
}
|
||||
@@ -158,6 +158,8 @@ Espo.define('views/fields/link-multiple-with-role', 'views/fields/link-multiple'
|
||||
},
|
||||
|
||||
addLinkHtml: function (id, name) {
|
||||
name = name || id;
|
||||
|
||||
if (this.mode == 'search') {
|
||||
return Dep.prototype.addLinkHtml.call(this, id, name);
|
||||
}
|
||||
|
||||
@@ -307,6 +307,8 @@ Espo.define('views/fields/link-multiple', 'views/fields/base', function (Dep) {
|
||||
},
|
||||
|
||||
addLinkHtml: function (id, name) {
|
||||
name = name || id;
|
||||
|
||||
var $container = this.$el.find('.link-container');
|
||||
var $el = $('<div />').addClass('link-' + id).addClass('list-group-item').attr('data-id', id);
|
||||
$el.html(this.getHelper().escapeString(name || id) + ' ');
|
||||
|
||||
@@ -26,13 +26,13 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('views/fields/link-one', 'views/fields/link', function (Dep) {
|
||||
define('views/fields/link-one', 'views/fields/link', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
readOnly: true,
|
||||
|
||||
searchTypeList: ['is', 'isOneOf'],
|
||||
searchTypeList: ['is', 'isEmpty', 'isNotEmpty', 'isOneOf'],
|
||||
|
||||
fetchSearch: function () {
|
||||
var type = this.$el.find('select.search-type').val();
|
||||
@@ -46,12 +46,12 @@ Espo.define('views/fields/link-one', 'views/fields/link', function (Dep) {
|
||||
data: {
|
||||
type: type,
|
||||
oneOfIdList: this.searchData.oneOfIdList,
|
||||
oneOfNameHash: this.searchData.oneOfNameHash
|
||||
}
|
||||
oneOfNameHash: this.searchData.oneOfNameHash,
|
||||
},
|
||||
};
|
||||
return data;
|
||||
|
||||
} else {
|
||||
} else if (type == 'is' || !type) {
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
@@ -61,8 +61,26 @@ Espo.define('views/fields/link-one', 'views/fields/link', function (Dep) {
|
||||
value: value,
|
||||
data: {
|
||||
type: type,
|
||||
nameValue: this.$el.find('[data-name="' + this.nameName + '"]').val()
|
||||
}
|
||||
nameValue: this.$el.find('[data-name="' + this.nameName + '"]').val(),
|
||||
},
|
||||
};
|
||||
return data;
|
||||
|
||||
} else if (type === 'isEmpty') {
|
||||
var data = {
|
||||
type: 'isNotLinked',
|
||||
data: {
|
||||
type: type,
|
||||
},
|
||||
};
|
||||
return data;
|
||||
|
||||
} else if (type === 'isNotEmpty') {
|
||||
var data = {
|
||||
type: 'isLinked',
|
||||
data: {
|
||||
type: type,
|
||||
},
|
||||
};
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ Espo.define('views/fields/link-parent', 'views/fields/base', function (Dep) {
|
||||
},
|
||||
|
||||
select: function (model) {
|
||||
this.$elementName.val(model.get('name'));
|
||||
this.$elementName.val(model.get('name') || model.id);
|
||||
this.$elementId.val(model.get('id'));
|
||||
this.trigger('change');
|
||||
},
|
||||
|
||||
@@ -167,11 +167,11 @@ Espo.define('views/fields/link', 'views/fields/base', function (Dep) {
|
||||
},
|
||||
|
||||
select: function (model) {
|
||||
this.$elementName.val(model.get('name'));
|
||||
this.$elementName.val(model.get('name') || model.id);
|
||||
this.$elementId.val(model.get('id'));
|
||||
if (this.mode === 'search') {
|
||||
this.searchData.idValue = model.get('id');
|
||||
this.searchData.nameValue = model.get('name');
|
||||
this.searchData.nameValue = model.get('name') || model.id;
|
||||
}
|
||||
this.trigger('change');
|
||||
},
|
||||
|
||||
@@ -32,7 +32,7 @@ define('views/fields/multi-enum', ['views/fields/array', 'lib!Selectize'], funct
|
||||
|
||||
type: 'multiEnum',
|
||||
|
||||
listTemplate: 'fields//array/list',
|
||||
listTemplate: 'fields/array/list',
|
||||
|
||||
detailTemplate: 'fields/array/detail',
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ define('views/fields/wysiwyg', ['views/fields/text', 'lib!Summernote'], function
|
||||
|
||||
this.useIframe = this.params.useIframe || this.useIframe;
|
||||
|
||||
this.toolbar = this.params.toolbar || [
|
||||
this.toolbar = this.params.toolbar || this.toolbar || [
|
||||
['style', ['style']],
|
||||
['style', ['bold', 'italic', 'underline', 'clear']],
|
||||
['fontsize', ['fontsize']],
|
||||
@@ -71,7 +71,7 @@ define('views/fields/wysiwyg', ['views/fields/text', 'lib!Summernote'], function
|
||||
['para', ['ul', 'ol', 'paragraph']],
|
||||
['height', ['height']],
|
||||
['table', ['table', 'espoLink', 'espoImage', 'hr']],
|
||||
['misc',['codeview', 'fullscreen']]
|
||||
['misc', ['codeview', 'fullscreen']]
|
||||
];
|
||||
|
||||
this.buttons = {};
|
||||
@@ -110,8 +110,8 @@ define('views/fields/wysiwyg', ['views/fields/text', 'lib!Summernote'], function
|
||||
} else {
|
||||
this.lastHtmlValue = this.model.get(this.name);
|
||||
var value = this.htmlToPlain(this.model.get(this.name));
|
||||
this.model.set(this.name, value, {skipReRender: true});
|
||||
this.disableWysiwygMode();
|
||||
this.model.set(this.name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -368,6 +368,8 @@ define('views/fields/wysiwyg', ['views/fields/text', 'lib!Summernote'], function
|
||||
keyMap.pc['CTRL+K'] = 'espoLink.show';
|
||||
keyMap.mac['CMD+K'] = 'espoLink.show';
|
||||
|
||||
var toolbar = this.toolbar;
|
||||
|
||||
var options = {
|
||||
espoView: this,
|
||||
lang: this.getConfig().get('language'),
|
||||
@@ -408,7 +410,7 @@ define('views/fields/wysiwyg', ['views/fields/text', 'lib!Summernote'], function
|
||||
onCreateLink: function (link) {
|
||||
return link;
|
||||
},
|
||||
toolbar: this.toolbar,
|
||||
toolbar: toolbar,
|
||||
buttons: this.buttons,
|
||||
dialogsInBody: this.$el,
|
||||
codeviewFilter: true,
|
||||
@@ -710,6 +712,81 @@ define('views/fields/wysiwyg', ['views/fields/text', 'lib!Summernote'], function
|
||||
}
|
||||
},
|
||||
|
||||
'fullscreen': function (context) {
|
||||
var ui = $.summernote.ui;
|
||||
var options = context.options;
|
||||
var self = options.espoView;
|
||||
var lang = options.langInfo;
|
||||
|
||||
this.$window = $(window);
|
||||
this.$scrollbar = $('html, body');
|
||||
|
||||
this.initialize = function () {
|
||||
this.$editor = context.layoutInfo.editor;
|
||||
this.$toolbar = context.layoutInfo.toolbar;
|
||||
this.$editable = context.layoutInfo.editable;
|
||||
this.$codable = context.layoutInfo.codable;
|
||||
|
||||
this.$modal = self.$el.closest('.modal');
|
||||
this.isInModal = this.$modal.length > 0;
|
||||
};
|
||||
|
||||
this.resizeTo = function (size) {
|
||||
this.$editable.css('height', size.h);
|
||||
this.$codable.css('height', size.h);
|
||||
if (this.$codable.data('cmeditor')) {
|
||||
this.$codable.data('cmeditor').setsize(null, size.h);
|
||||
}
|
||||
};
|
||||
|
||||
this.onResize = function () {
|
||||
this.resizeTo({
|
||||
h: this.$window.height() - this.$toolbar.outerHeight(),
|
||||
});
|
||||
};
|
||||
|
||||
this.isFullscreen = function () {
|
||||
return this.$editor.hasClass('fullscreen');
|
||||
};
|
||||
|
||||
this.destroy = function () {
|
||||
this.$window.off('resize.summernote' + self.cid);
|
||||
if (this.isInModal) {
|
||||
this.$modal.css('overflow-y', '');
|
||||
} else {
|
||||
this.$scrollbar.css('overflow', '');
|
||||
}
|
||||
}
|
||||
|
||||
this.toggle = function () {
|
||||
this.$editor.toggleClass('fullscreen');
|
||||
if (this.isFullscreen()) {
|
||||
this.$editable.data('orgHeight', this.$editable.css('height'));
|
||||
this.$editable.data('orgMaxHeight', this.$editable.css('maxHeight'));
|
||||
this.$editable.css('maxHeight', '');
|
||||
this.$window.on('resize.summernote' + self.cid, this.onResize.bind(this)).trigger('resize');
|
||||
if (this.isInModal) {
|
||||
this.$modal.css('overflow-y', 'hidden');
|
||||
} else {
|
||||
this.$scrollbar.css('overflow', 'hidden');
|
||||
}
|
||||
this._isFullscreen = true;
|
||||
} else {
|
||||
this.$window.off('resize.summernote' + self.cid);
|
||||
this.resizeTo({ h: this.$editable.data('orgHeight') });
|
||||
this.$editable.css('maxHeight', this.$editable.css('orgMaxHeight'));
|
||||
if (this.isInModal) {
|
||||
this.$modal.css('overflow-y', '');
|
||||
} else {
|
||||
this.$scrollbar.css('overflow', '');
|
||||
}
|
||||
this._isFullscreen = false;
|
||||
}
|
||||
|
||||
context.invoke('toolbar.updateFullscreen', this.isFullscreen());
|
||||
};
|
||||
},
|
||||
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -87,15 +87,15 @@ define('views/main', 'view', function (Dep) {
|
||||
if (this.menu) {
|
||||
['buttons', 'actions', 'dropdown'].forEach(function (type) {
|
||||
(this.menu[type] || []).forEach(function (item) {
|
||||
item = Espo.Utils.clone(item);
|
||||
menu[type] = menu[type] || [];
|
||||
if (item.configCheck) {
|
||||
if (!this.getConfig().getByPath(item.configCheck.split('.'))) return;
|
||||
}
|
||||
if (Espo.Utils.checkActionAccess(this.getAcl(), this.model || this.scope, item)) {
|
||||
menu[type].push(item);
|
||||
}
|
||||
|
||||
if (!Espo.Utils.checkActionAvailability(this.getHelper(), item)) return;
|
||||
if (!Espo.Utils.checkActionAccess(this.getAcl(), this.model || this.scope, item)) return;
|
||||
|
||||
item.name = item.name || item.action;
|
||||
item.action = item.action || this.name;
|
||||
menu[type].push(item);
|
||||
}, this);
|
||||
}, this);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ Espo.define('views/modals/image-preview', ['views/modal', 'lib!exif'], function
|
||||
name: this.options.name,
|
||||
url: this.getImageUrl(),
|
||||
originalUrl: this.getOriginalImageUrl(),
|
||||
size: this.size
|
||||
showOriginalLink: this.size,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -99,7 +99,9 @@ Espo.define('views/modals/image-preview', ['views/modal', 'lib!exif'], function
|
||||
|
||||
$img.on('load', function () {
|
||||
var self = this;
|
||||
EXIF.getData($img.get(0), function () {
|
||||
var imgEl = $img.get(0);
|
||||
|
||||
EXIF.getData(imgEl, function () {
|
||||
var orientation = EXIF.getTag(this, 'Orientation');
|
||||
switch (orientation) {
|
||||
case 2:
|
||||
@@ -128,6 +130,10 @@ Espo.define('views/modals/image-preview', ['views/modal', 'lib!exif'], function
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if (imgEl.naturalWidth > imgEl.clientWidth) {
|
||||
this.$el.find('.original-link-container').removeClass('hidden');
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
if (this.navigationEnabled) {
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/************************************************************************
|
||||
* 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/preferences/fields/signature', 'views/fields/wysiwyg', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
toolbar: [
|
||||
["style", ["bold", "italic", "underline", "clear"]],
|
||||
["color", ["color"]],
|
||||
["height", ["height"]],
|
||||
['table', ['espoLink']],
|
||||
["misc",["codeview", "fullscreen"]]
|
||||
],
|
||||
|
||||
});
|
||||
});
|
||||
@@ -254,6 +254,56 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
name: 'viewFollowers'
|
||||
});
|
||||
}
|
||||
|
||||
if (this.type === 'detail') {
|
||||
this.additionalActionsDefs = {};
|
||||
|
||||
var additionalActionList = [];
|
||||
(this.getMetadata().get(['clientDefs', this.scope, this.type + 'ActionList']) || []).forEach(function (item) {
|
||||
if (typeof item === 'string') {
|
||||
item = {
|
||||
name: item,
|
||||
};
|
||||
}
|
||||
var item = Espo.Utils.clone(item);
|
||||
var name = item.name;
|
||||
|
||||
if (!item.label) item.html = this.translate(name, 'actions', this.scope);
|
||||
|
||||
this.addDropdownItem(item);
|
||||
|
||||
if (!Espo.Utils.checkActionAvailability(this.getHelper(), item)) return;
|
||||
|
||||
additionalActionList.push(item);
|
||||
|
||||
var viewObject = this;
|
||||
if (item.initFunction && item.data.handler) {
|
||||
this.wait(new Promise(function (resolve) {
|
||||
require(item.data.handler, function (Handler) {
|
||||
var handler = new Handler(viewObject);
|
||||
handler[item.initFunction].call(handler);
|
||||
resolve();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
if (!Espo.Utils.checkActionAccess(this.getAcl(), this.model, item, true)) {
|
||||
item.hidden = true;
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (additionalActionList.length) {
|
||||
this.listenTo(this.model, 'sync', function () {
|
||||
additionalActionList.forEach(function (item) {
|
||||
if (Espo.Utils.checkActionAccess(this.getAcl(), this.model, item, true)) {
|
||||
this.showActionItem(item.name);
|
||||
} else {
|
||||
this.hideActionItem(item.name);
|
||||
}
|
||||
}, this);
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
disableActionItems: function () {
|
||||
@@ -1518,7 +1568,7 @@ define('views/record/detail', ['views/record/base', 'view-record-helper'], funct
|
||||
}
|
||||
|
||||
this.getRouter().navigate(url, {trigger: true});
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -908,20 +908,10 @@ define('views/record/list', 'view', function (Dep) {
|
||||
|
||||
(this.getMetadata().get(['clientDefs', this.scope, 'massActionList']) || []).forEach(function (item) {
|
||||
var defs = this.getMetadata().get(['clientDefs', this.scope, 'massActionDefs', item]) || {};
|
||||
var acl = defs.acl;
|
||||
var aclScope = defs.aclScope;
|
||||
if (acl || aclScope) {
|
||||
if (!this.getAcl().check(aclScope || this.scope, acl)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var configCheck = defs.configCheck;
|
||||
if (configCheck) {
|
||||
var arr = configCheck.split('.');
|
||||
if (!this.getConfig().getByPath(arr)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Espo.Utils.checkActionAvailability(this.getHelper(), defs)) return;
|
||||
if (!Espo.Utils.checkActionAccess(this.getAcl(), null, defs)) return;
|
||||
|
||||
this.massActionList.push(item);
|
||||
}, this);
|
||||
|
||||
@@ -937,20 +927,10 @@ define('views/record/list', 'view', function (Dep) {
|
||||
if (this.collection.url !== this.entityType) return;
|
||||
if (~this.massActionList.indexOf(item)) {
|
||||
var defs = this.getMetadata().get(['clientDefs', this.scope, 'massActionDefs', item]) || {};
|
||||
var acl = defs.acl;
|
||||
var aclScope = defs.aclScope;
|
||||
if (acl || aclScope) {
|
||||
if (!this.getAcl().check(aclScope || this.scope, acl)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var configCheck = defs.configCheck;
|
||||
if (configCheck) {
|
||||
var arr = configCheck.split('.');
|
||||
if (!this.getConfig().getByPath(arr)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Espo.Utils.checkActionAvailability(this.getHelper(), defs)) return;
|
||||
if (!Espo.Utils.checkActionAccess(this.getAcl(), null, defs)) return;
|
||||
|
||||
this.checkAllResultMassActionList.push(item);
|
||||
}
|
||||
}, this);
|
||||
|
||||
@@ -82,11 +82,9 @@ define('views/record/panels-container', 'view', function (Dep) {
|
||||
applyAccessToActions: function (actionList) {
|
||||
if (!actionList) return;
|
||||
actionList.forEach(function (item) {
|
||||
if (item.configCheck) {
|
||||
if (!this.getConfig().getByPath(item.configCheck.split('.'))) {
|
||||
item.hidden = true;
|
||||
return;
|
||||
}
|
||||
if (!Espo.Utils.checkActionAvailability(this.getHelper(), item)) {
|
||||
item.hidden = true;
|
||||
return;
|
||||
}
|
||||
if (Espo.Utils.checkActionAccess(this.getAcl(), this.model, item, true)) {
|
||||
if (item.isHiddenByAcl) {
|
||||
|
||||
@@ -233,7 +233,7 @@
|
||||
|
||||
ul.tabs {
|
||||
> li > a > span.full-label {
|
||||
display: inline;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1179,6 +1179,10 @@ select[multiple].input-sm {
|
||||
height: 90px !important;
|
||||
}
|
||||
|
||||
optgroup {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.input-group-btn > select.form-control {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
@@ -35,4 +35,4 @@ $smarty->assign('cronHelp', $cronMessage['command']);
|
||||
$installer->setSuccess();
|
||||
|
||||
// clean session
|
||||
session_unset();
|
||||
session_unset();
|
||||
|
||||
@@ -98,8 +98,4 @@ service apache2 restart',
|
||||
}
|
||||
}',
|
||||
],
|
||||
|
||||
'blog' => 'http://blog.espocrm.com',
|
||||
'twitter' => 'https://twitter.com/espocrm',
|
||||
'forum' => 'http://forum.espocrm.com',
|
||||
];
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"labels": {
|
||||
"headerTitle": "EspoCRM Installation",
|
||||
"Main page title": "Welcome to EspoCRM",
|
||||
"Main page header": "",
|
||||
"Start page title": "License Agreement",
|
||||
@@ -48,7 +49,9 @@
|
||||
"Success": "Success",
|
||||
"Fail": "Fail",
|
||||
"is recommended": "is recommended",
|
||||
"extension is missing": "extension is missing"
|
||||
"extension is missing": "extension is missing",
|
||||
"Crontab setup instructions": "Without running Scheduled jobs inbound emails, notifications and reminders will not be working. Here you can read {SETUP_INSTRUCTIONS}.",
|
||||
"Setup instructions": "setup instructions"
|
||||
},
|
||||
"fields": {
|
||||
"Choose your language": "Choose your language",
|
||||
@@ -82,7 +85,7 @@
|
||||
"smtpPassword": "Password"
|
||||
},
|
||||
"messages": {
|
||||
"Bad init Permission": "Permission denied for \"{*}\" directory. Please set 775 for \"{*}\" or just execute this command in the terminal <pre><b>{C}</b></pre>\n\tOperation not permitted? Try this one: {CSU}",
|
||||
"Bad init Permission": "Permission denied for \"{*}\" directory. Please set 775 for \"{*}\" or just execute this command in the terminal <pre><b>{C}</b></pre> Operation is not permitted? Try this one: {CSU}",
|
||||
"Some errors occurred!": "Some errors occurred!",
|
||||
"phpVersion": "Your PHP version is not supported by EspoCRM, please update to PHP {minVersion} at least",
|
||||
"requiredMysqlVersion": "Your MySQL version is not supported by EspoCRM, please update to MySQL {minVersion} at least",
|
||||
@@ -102,8 +105,8 @@
|
||||
"Ajax failed": "An unexpected error occurred",
|
||||
"Cannot create user": "Cannot create a user",
|
||||
"Permission denied": "Permission denied",
|
||||
"permissionInstruction": "<br>Run this in Terminal<pre><b>\"{C}\"</b></pre>",
|
||||
"operationNotPermitted" : "Operation not permitted? Try this: <br>{CSU}",
|
||||
"permissionInstruction": "<br>Run this command in Terminal:<pre><b>\"{C}\"</b></pre>",
|
||||
"operationNotPermitted" : "Operation is not permitted? Try this one: <br><br>{CSU}",
|
||||
"Permission denied to": "Permission denied",
|
||||
"Can not save settings": "Can not save settings",
|
||||
"Cannot save preferences": "Cannot save preferences",
|
||||
|
||||
+17
-29
@@ -2,48 +2,36 @@
|
||||
<form id="nav">
|
||||
<div class="row">
|
||||
<div class=" col-md-13">
|
||||
<div class="panel-body" align="center">
|
||||
<div class="message">
|
||||
{$langs['labels']['Congratulation! Welcome to EspoCRM']}
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="likes">
|
||||
<p>
|
||||
{$langs['labels']['share']}
|
||||
{$langs['labels']['Congratulation! Welcome to EspoCRM']}
|
||||
</p>
|
||||
<br>
|
||||
|
||||
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
|
||||
<div class="g-plusone" data-size="standard" data-count="true" data-href='http://www.espocrm.com'></div>
|
||||
</div>
|
||||
|
||||
<div class="more-information">
|
||||
{assign var="blogLink" value="<a target=\"_blank\" href=\"{$config['blog']}\">{$langs['labels']['blog']}</a>"}
|
||||
{assign var="twitterLink" value="<a target=\"_blank\" href=\"{$config['twitter']}\">{$langs['labels']['twitter']}</a>"}
|
||||
{assign var="forumLink" value="<a target=\"_blank\" href=\"{$config['forum']}\">{$langs['labels']['forum']}</a>"}
|
||||
{if $cronHelp}
|
||||
<div class="cron-help">
|
||||
{$cronTitle}
|
||||
<pre>
|
||||
{$cronHelp}
|
||||
</pre>
|
||||
|
||||
{assign var="message" value="{$langs['labels']['More Information']|replace:'{BLOG}':$blogLink}"}
|
||||
{assign var="message" value="{$message|replace:'{TWITTER}':$twitterLink}"}
|
||||
{assign var="message" value="{$message|replace:'{FORUM}':$forumLink}"}
|
||||
<p>
|
||||
{assign var="link" value="<a target=\"_blank\" href=\"https://www.espocrm.com/documentation/administration/server-configuration/#user-content-setup-a-crontab\">{$langs['labels']['Setup instructions']}</a>"}
|
||||
|
||||
{assign var="message" value="{$langs['labels']['Crontab setup instructions']|replace:'{SETUP_INSTRUCTIONS}':$link}"}
|
||||
{$message}
|
||||
</p>
|
||||
|
||||
{$message}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{if $cronHelp}
|
||||
<div class="cron-help">
|
||||
{$cronTitle}
|
||||
<pre>
|
||||
{$cronHelp}
|
||||
</pre>
|
||||
</div>
|
||||
{/if}
|
||||
<footer class="modal-footer">
|
||||
<button class="btn btn-primary" type="button" id="start">{$langs['labels']['Go to EspoCRM']}</button>
|
||||
</footer>
|
||||
@@ -56,4 +44,4 @@
|
||||
var installScript = new InstallScript({action: 'finish', langs: langs});
|
||||
})
|
||||
{/literal}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>EspoCRM Installation</title>
|
||||
<title>{$langs['labels']['headerTitle']}</title>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<meta content="utf-8" http-equiv="encoding">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
|
||||
<script type="text/javascript" src="../client/lib/jquery-2.1.4.min.js"></script>
|
||||
<script type="text/javascript" src="../client/lib/purify.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/install.js"></script>
|
||||
<link href="../client/css/espo/hazyblue.css" rel="stylesheet">
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell cell-website pull-right" align="right">
|
||||
<a target="_blank" href="https://www.espocrm.com/documentation/administration/installation/" style="font-weight:bold;">{$langs['labels']['Installation Guide']}</a>
|
||||
<a target="_blank" href="https://www.espocrm.com/documentation/administration/installation/" style="font-weight:600;">{$langs['labels']['Installation Guide']}</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -44,4 +44,3 @@
|
||||
})
|
||||
{/literal}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
</table>
|
||||
|
||||
<div class="cell cell-website pull-right" align="right">
|
||||
<a target="_blank" href="https://www.espocrm.com/documentation/administration/server-configuration/" style="font-weight:bold;">{$langs['labels']['Configuration Instructions']}</a>
|
||||
<a target="_blank" href="https://www.espocrm.com/documentation/administration/server-configuration/" style="font-weight:600;">{$langs['labels']['Configuration Instructions']}</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -72,13 +72,19 @@ select[name="user-lang"] {
|
||||
}
|
||||
|
||||
.cron-help {
|
||||
margin: 20px;
|
||||
margin-top: 40px;
|
||||
color: #ad4846;
|
||||
}
|
||||
|
||||
.cron-help pre {
|
||||
margin-top: 15px;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.cron-help p {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.table {
|
||||
@@ -107,7 +113,7 @@ select[name="user-lang"] {
|
||||
|
||||
span.remark {
|
||||
color: #a94442;
|
||||
font-weight: bold;
|
||||
font-weight: 600;
|
||||
}
|
||||
span.ok {
|
||||
color: #87c956;
|
||||
@@ -115,8 +121,7 @@ span.ok {
|
||||
|
||||
.more-information {
|
||||
line-height: 1.5;
|
||||
font-size: 16px;
|
||||
margin-top: 70px;
|
||||
margin-top: 40px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -54,6 +54,7 @@ $userLang = (!empty($_SESSION['install']['user-lang']))? $_SESSION['install']['u
|
||||
require_once 'core/Language.php';
|
||||
$language = new Language();
|
||||
$langs = $language->get($userLang);
|
||||
$sanitizedLangs = \Espo\Core\Utils\Util::sanitizeHtml($langs);
|
||||
//END: get user selected language
|
||||
|
||||
$config = include('core/config.php');
|
||||
@@ -63,13 +64,13 @@ $systemHelper = new SystemHelper();
|
||||
|
||||
$systemConfig = include('application/Espo/Core/defaults/systemConfig.php');
|
||||
if (isset($systemConfig['requiredPhpVersion']) && version_compare(PHP_VERSION, $systemConfig['requiredPhpVersion'], '<')) {
|
||||
die(str_replace('{minVersion}', $systemConfig['requiredPhpVersion'], $langs['messages']['phpVersion']) . '.');
|
||||
die(str_replace('{minVersion}', $systemConfig['requiredPhpVersion'], $sanitizedLangs['messages']['phpVersion']) . '.');
|
||||
}
|
||||
|
||||
if (!$systemHelper->initWritable()) {
|
||||
$dir = $systemHelper->getWritableDir();
|
||||
|
||||
$message = $langs['messages']['Bad init Permission'];
|
||||
$message = $sanitizedLangs['messages']['Bad init Permission'];
|
||||
$message = str_replace('{*}', $dir, $message);
|
||||
$message = str_replace('{C}', $systemHelper->getPermissionCommands(array($dir, ''), '775'), $message);
|
||||
$message = str_replace('{CSU}', $systemHelper->getPermissionCommands(array($dir, ''), '775', true), $message);
|
||||
@@ -102,7 +103,7 @@ $smarty->caching = false;
|
||||
$smarty->setTemplateDir('install/core/tpl');
|
||||
|
||||
$smarty->assign("version", $installer->getVersion());
|
||||
$smarty->assign("langs", $langs);
|
||||
$smarty->assign("langs", $sanitizedLangs);
|
||||
$smarty->assign("langsJs", json_encode($langs));
|
||||
|
||||
// include actions and set tpl name
|
||||
|
||||
+30
-8
@@ -79,6 +79,8 @@ var InstallScript = function(opt) {
|
||||
];
|
||||
this.checkIndex = 0;
|
||||
this.checkError = false;
|
||||
|
||||
this.initSanitizeHtml();
|
||||
}
|
||||
|
||||
InstallScript.prototype.main = function() {
|
||||
@@ -542,15 +544,35 @@ InstallScript.prototype.getLang = function(key, type) {
|
||||
InstallScript.prototype.showMsg = function(opt) {
|
||||
this.hideMsg();
|
||||
|
||||
var msg = opt.msg || '';
|
||||
var message = opt.msg || '';
|
||||
var error = opt.error || false;
|
||||
$('#msg-box').html(msg);
|
||||
$('#msg-box').removeClass('hide');
|
||||
$('#msg-box').removeClass('alert-success');
|
||||
$('#msg-box').removeClass('alert-danger');
|
||||
|
||||
if (error) $('#msg-box').addClass('alert-danger');
|
||||
else $('#msg-box').addClass('alert-success');
|
||||
if (message) {
|
||||
message = this.sanitizeHtml(message);
|
||||
|
||||
$('#msg-box').html(message);
|
||||
$('#msg-box').removeClass('hide');
|
||||
$('#msg-box').removeClass('alert-success');
|
||||
$('#msg-box').removeClass('alert-danger');
|
||||
}
|
||||
|
||||
if (error) {
|
||||
$('#msg-box').addClass('alert-danger');
|
||||
} else {
|
||||
$('#msg-box').addClass('alert-success');
|
||||
}
|
||||
}
|
||||
|
||||
InstallScript.prototype.initSanitizeHtml = function() {
|
||||
DOMPurify.addHook('afterSanitizeAttributes', function(node) {
|
||||
if ('target' in node) {
|
||||
node.setAttribute('target','_blank');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
InstallScript.prototype.sanitizeHtml = function(html) {
|
||||
return DOMPurify.sanitize(html);
|
||||
}
|
||||
|
||||
InstallScript.prototype.hideMsg = function() {
|
||||
@@ -638,7 +660,7 @@ InstallScript.prototype.checkAction = function(dataMain) {
|
||||
// break next checking
|
||||
var ajaxData = {
|
||||
'success': false,
|
||||
'errorMsg': ['Ajax failed']
|
||||
'errorMsg': [self.getLang('Ajax failed', 'messages')]
|
||||
}
|
||||
self.callbackChecking(ajaxData);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "espocrm",
|
||||
"version": "5.6.11",
|
||||
"version": "5.6.14",
|
||||
"description": "",
|
||||
"main": "index.php",
|
||||
"repository": {
|
||||
|
||||
Executable → Regular
Executable → Regular
@@ -114,7 +114,7 @@ abstract class BaseTestCase extends \PHPUnit\Framework\TestCase
|
||||
return $this->espoTester->sendRequest($method, $action, $data);
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->beforeSetUp();
|
||||
|
||||
@@ -134,7 +134,7 @@ abstract class BaseTestCase extends \PHPUnit\Framework\TestCase
|
||||
$this->afterStartApplication();
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->espoTester->terminate();
|
||||
$this->espoTester = NULL;
|
||||
|
||||
@@ -191,6 +191,7 @@ class Tester
|
||||
}
|
||||
|
||||
//remove and copy Espo files
|
||||
Utils::checkCreateDatabase($configData['database']);
|
||||
Utils::dropTables($configData['database']);
|
||||
$fileManager->removeInDir($this->installPath);
|
||||
$tt = $fileManager->copy($latestEspo, $this->installPath, true);
|
||||
|
||||
@@ -124,6 +124,19 @@ class Utils
|
||||
} /*END: SET UNDEFINED VARIABLES*/
|
||||
}
|
||||
|
||||
public static function checkCreateDatabase(array $options)
|
||||
{
|
||||
if (!isset($options['dbname'])) {
|
||||
throw new \Espo\Core\Exceptions\Error('Option "dbname" is not found.');
|
||||
}
|
||||
|
||||
$dbname = $options['dbname'];
|
||||
unset($options['dbname']);
|
||||
|
||||
$pdo = static::createPdoConnection($options);
|
||||
$pdo->query("CREATE DATABASE IF NOT EXISTS `". $dbname ."`");
|
||||
}
|
||||
|
||||
public static function dropTables(array $options)
|
||||
{
|
||||
$pdo = static::createPdoConnection($options);
|
||||
@@ -145,4 +158,4 @@ class Utils
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,22 +73,20 @@ class GeneralTest extends \tests\integration\Core\BaseTestCase
|
||||
return $upgradeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Espo\Core\Exceptions\Error
|
||||
*/
|
||||
public function testUninstall()
|
||||
{
|
||||
$this->expectException('\\Espo\\Core\\Exceptions\\Error');
|
||||
|
||||
$upgradeId = $this->testInstall();
|
||||
|
||||
$upgradeManager = new \Espo\Core\UpgradeManager($this->getContainer());
|
||||
$upgradeManager->uninstall(array('id' => $upgradeId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Espo\Core\Exceptions\Error
|
||||
*/
|
||||
public function testDelete()
|
||||
{
|
||||
$this->expectException('\\Espo\\Core\\Exceptions\\Error');
|
||||
|
||||
$upgradeId = $this->testInstall();
|
||||
|
||||
$upgradeManager = new \Espo\Core\UpgradeManager($this->getContainer());
|
||||
|
||||
@@ -45,11 +45,10 @@ class AclTest extends \tests\integration\Core\BaseTestCase
|
||||
$metadata->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Espo\Core\Exceptions\Forbidden
|
||||
*/
|
||||
public function testUserAccess()
|
||||
{
|
||||
$this->expectException('\\Espo\\Core\\Exceptions\\Forbidden');
|
||||
|
||||
$this->createUser('tester', array(
|
||||
'assignmentPermission' => 'team',
|
||||
'userPermission' => 'team',
|
||||
@@ -86,11 +85,10 @@ class AclTest extends \tests\integration\Core\BaseTestCase
|
||||
$result = $controllerManager->process('Account', 'create', $params, $data, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Espo\Core\Exceptions\Forbidden
|
||||
*/
|
||||
public function testPortalUserAccess()
|
||||
{
|
||||
$this->expectException('\\Espo\\Core\\Exceptions\\Forbidden');
|
||||
|
||||
$newUser = $this->createUser(array(
|
||||
'userName' => 'tester',
|
||||
'lastName' => 'tester',
|
||||
|
||||
@@ -39,7 +39,7 @@ class CronManagerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
protected $filesPath= 'tests/unit/testData/EntryPoints';
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->objects['container'] = $this->getMockBuilder('\\Espo\\Core\\Container')->disableOriginalConstructor()->getMock();
|
||||
|
||||
@@ -67,7 +67,7 @@ class CronManagerTest extends \PHPUnit\Framework\TestCase
|
||||
$this->reflection = new ReflectionHelper($this->object);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->object = NULL;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ class EntryPointManagerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
protected $filesPath= 'tests/unit/testData/EntryPoints';
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->objects['container'] = $this->getMockBuilder('\\Espo\\Core\\Container')->disableOriginalConstructor()->getMock();
|
||||
|
||||
@@ -58,7 +58,7 @@ class EntryPointManagerTest extends \PHPUnit\Framework\TestCase
|
||||
));
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->object = NULL;
|
||||
}
|
||||
|
||||
@@ -33,12 +33,12 @@ use \Espo\ORM\Entity;
|
||||
|
||||
class EvaluatorTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->evaluator = new \Espo\Core\Formula\Evaluator();
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->evaluator = null;
|
||||
}
|
||||
@@ -102,4 +102,4 @@ class EvaluatorTest extends \PHPUnit\Framework\TestCase
|
||||
$actual = $this->evaluator->process($expression);
|
||||
$this->assertEquals(2.5, $actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ use \Espo\ORM\Entity;
|
||||
class FormulaTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$container = $this->container = $this->getMockBuilder('\\Espo\\Core\\Container')->disableOriginalConstructor()->getMock();
|
||||
|
||||
@@ -77,7 +77,7 @@ class FormulaTest extends \PHPUnit\Framework\TestCase
|
||||
]));
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->container = null;
|
||||
$this->functionFactory = null;
|
||||
@@ -2862,4 +2862,4 @@ class FormulaTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertEquals(5, $variables->counter);
|
||||
$this->assertEquals('hello', $variables->test);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,12 +33,12 @@ use \Espo\ORM\Entity;
|
||||
|
||||
class ParserTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->parser = new \Espo\Core\Formula\Parser();
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->parser = null;
|
||||
}
|
||||
@@ -784,4 +784,4 @@ class ParserTest extends \PHPUnit\Framework\TestCase
|
||||
];
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class HookManagerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
protected $filesPath = 'tests/unit/testData/Hooks';
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->objects['container'] = $this->getMockBuilder('\\Espo\\Core\\Container')->disableOriginalConstructor()->getMock();
|
||||
|
||||
@@ -62,7 +62,7 @@ class HookManagerTest extends \PHPUnit\Framework\TestCase
|
||||
$this->reflection = new ReflectionHelper($this->object);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->object = NULL;
|
||||
$this->reflection = NULL;
|
||||
@@ -437,4 +437,4 @@ class HookManagerTest extends \PHPUnit\Framework\TestCase
|
||||
'\\Espo\\Hooks\\Note\\Notifications',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class HtmlizerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
protected $number;
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
@@ -59,7 +59,9 @@ class HtmlizerTest extends \PHPUnit\Framework\TestCase
|
||||
->expects($this->any())
|
||||
->method('getPhpContents')
|
||||
->will($this->returnCallback(function($fileName) use ($obj) {
|
||||
$data = eval('?>' . $obj->contents . '<?php');
|
||||
$obj->contents = str_replace('<?php ', '', $obj->contents);
|
||||
$obj->contents = str_replace('?>', '', $obj->contents);
|
||||
$data = eval($obj->contents . ';');
|
||||
return $data;
|
||||
}));
|
||||
|
||||
@@ -75,7 +77,7 @@ class HtmlizerTest extends \PHPUnit\Framework\TestCase
|
||||
$this->htmlizer = new \Espo\Core\Htmlizer\Htmlizer($this->fileManager, $this->dateTime, $this->number);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
unset($this->htmlizer);
|
||||
unset($this->fileManager);
|
||||
@@ -168,4 +170,3 @@ class HtmlizerTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertEquals('test', $html);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class FiltersMatcherTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
protected $object;
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->object = new \Espo\Core\Mail\FiltersMatcher();
|
||||
|
||||
@@ -80,7 +80,7 @@ class FiltersMatcherTest extends \PHPUnit\Framework\TestCase
|
||||
);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->object = NULL;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ use \Espo\Entities\Email;
|
||||
|
||||
class ImporterTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
function setUp()
|
||||
function setUp() : void
|
||||
{
|
||||
$GLOBALS['log'] = $this->getMockBuilder('\\Espo\\Core\\Utils\\Log')->disableOriginalConstructor()->getMock();
|
||||
|
||||
@@ -126,13 +126,18 @@ class ImporterTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertEquals('test 3', $email->get('name'));
|
||||
|
||||
$teamIdList = $email->getLinkMultipleIdList('teams');
|
||||
$this->assertContains('teamTestId', $teamIdList);
|
||||
$this->assertTrue(in_array('teamTestId', $teamIdList));
|
||||
|
||||
$userIdList = $email->getLinkMultipleIdList('users');
|
||||
$this->assertContains('userTestId', $userIdList);
|
||||
$this->assertTrue(in_array('userTestId', $userIdList));
|
||||
|
||||
$this->assertContains('<br>Admin Test', $email->get('body'));
|
||||
$this->assertContains('Admin Test', $email->get('bodyPlain'));
|
||||
if (method_exists($this, 'assertStringContainsString')) { /* PHPUnit 7+ */
|
||||
$this->assertStringContainsString('<br>Admin Test', $email->get('body'));
|
||||
$this->assertStringContainsString('Admin Test', $email->get('bodyPlain'));
|
||||
} else { /* PHPUnit 6 */
|
||||
$this->assertContains('<br>Admin Test', $email->get('body'));
|
||||
$this->assertContains('Admin Test', $email->get('bodyPlain'));
|
||||
}
|
||||
|
||||
$this->assertEquals('<e558c4dfc2a0f0d60f5ebff474c97ffc/1466410740/1950@espo>', $email->get('messageId'));
|
||||
}
|
||||
@@ -182,14 +187,19 @@ class ImporterTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertEquals('test 3', $email->get('name'));
|
||||
|
||||
$teamIdList = $email->getLinkMultipleIdList('teams');
|
||||
$this->assertContains('teamTestId', $teamIdList);
|
||||
$this->assertTrue(in_array('teamTestId', $teamIdList));
|
||||
|
||||
$userIdList = $email->getLinkMultipleIdList('users');
|
||||
$this->assertContains('userTestId', $userIdList);
|
||||
$this->assertTrue(in_array('userTestId', $userIdList));
|
||||
|
||||
$this->assertContains('<br>Admin Test', $email->get('body'));
|
||||
$this->assertContains('Admin Test', $email->get('bodyPlain'));
|
||||
if (method_exists($this, 'assertStringContainsString')) { /* PHPUnit 7+ */
|
||||
$this->assertStringContainsString('<br>Admin Test', $email->get('body'));
|
||||
$this->assertStringContainsString('Admin Test', $email->get('bodyPlain'));
|
||||
} else { /* PHPUnit 6 */
|
||||
$this->assertContains('<br>Admin Test', $email->get('body'));
|
||||
$this->assertContains('Admin Test', $email->get('bodyPlain'));
|
||||
}
|
||||
|
||||
$this->assertEquals('<e558c4dfc2a0f0d60f5ebff474c97ffc/1466410740/1950@espo>', $email->get('messageId'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ use \tests\unit\testData\Entities\Test2;
|
||||
|
||||
class BaseTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$entity = $this->entity = new Test2();
|
||||
|
||||
@@ -74,7 +74,7 @@ class BaseTest extends \PHPUnit\Framework\TestCase
|
||||
$this->user->id = 'test_id';
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
unset($this->entity);
|
||||
unset($this->acl);
|
||||
|
||||
@@ -54,7 +54,7 @@ class ActionManagerTest extends \PHPUnit\Framework\TestCase
|
||||
),
|
||||
);
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->objects['container'] = $this->getMockBuilder('\Espo\Core\Container')->disableOriginalConstructor()->getMock();
|
||||
|
||||
@@ -63,7 +63,7 @@ class ActionManagerTest extends \PHPUnit\Framework\TestCase
|
||||
$this->reflection = new ReflectionHelper($this->object);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->object = NULL;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ class BaseTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
protected $currentVersion = '11.5.2';
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->objects['container'] = $this->getMockBuilder('\Espo\Core\Container')->disableOriginalConstructor()->getMock();
|
||||
$this->objects['actionManager'] = $this->getMockBuilder('\Espo\Core\Upgrades\ActionManager')->disableOriginalConstructor()->getMock();
|
||||
@@ -98,7 +98,7 @@ class BaseTest extends \PHPUnit\Framework\TestCase
|
||||
/* END */
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->object = NULL;
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class ConfigTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
protected $systemConfigPath = 'tests/unit/testData/Utils/Config/systemConfig.php';
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->objects['fileManager'] = new \Espo\Core\Utils\File\Manager();
|
||||
|
||||
@@ -60,7 +60,7 @@ class ConfigTest extends \PHPUnit\Framework\TestCase
|
||||
$this->reflection->setProperty('systemConfigPath', $this->systemConfigPath);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->object = NULL;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ class HelperTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
protected $reflection;
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->objects['config'] = $this->getMockBuilder('\\Espo\\Core\\Utils\\Config')->disableOriginalConstructor()->getMock();
|
||||
|
||||
@@ -58,7 +58,7 @@ class HelperTest extends \PHPUnit\Framework\TestCase
|
||||
]));
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->object = NULL;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class FieldManagerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
protected $reflection;
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->objects['container'] = $this->getMockBuilder('\\Espo\\Core\\Container')->disableOriginalConstructor()->getMock();
|
||||
|
||||
@@ -65,7 +65,7 @@ class FieldManagerTest extends \PHPUnit\Framework\TestCase
|
||||
$this->reflection->setProperty('metadataHelper', $this->objects['metadataHelper']);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->object = NULL;
|
||||
}
|
||||
@@ -403,4 +403,4 @@ class FieldManagerTest extends \PHPUnit\Framework\TestCase
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->invokeMethod('normalizeDefs', array('CustomEntity', $input1, $input2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class ClassParserTest extends \PHPUnit\Framework\TestCase
|
||||
protected $reflection;
|
||||
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->objects['fileManager'] = new \Espo\Core\Utils\File\Manager();
|
||||
$this->objects['config'] = $this->getMockBuilder('\Espo\Core\Utils\Config')->disableOriginalConstructor()->getMock();
|
||||
@@ -52,7 +52,7 @@ class ClassParserTest extends \PHPUnit\Framework\TestCase
|
||||
$this->reflection = new ReflectionHelper($this->object);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->object = NULL;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ class ManagerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
protected $reflection;
|
||||
|
||||
protected function setUp()
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->objects['config'] = $this->getMockBuilder('\Espo\Core\Utils\Config')->disableOriginalConstructor()->getMock();
|
||||
|
||||
@@ -51,7 +51,7 @@ class ManagerTest extends \PHPUnit\Framework\TestCase
|
||||
$this->reflection = new ReflectionHelper($this->object);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
protected function tearDown() : void
|
||||
{
|
||||
$this->object = NULL;
|
||||
}
|
||||
@@ -506,4 +506,4 @@ class ManagerTest extends \PHPUnit\Framework\TestCase
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user