mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-10 03:17:01 +00:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eadf7835db | ||
|
|
c30c4163a6 | ||
|
|
8d6db72516 | ||
|
|
71864056bc | ||
|
|
e375105a5f | ||
|
|
e066f4c6b0 | ||
|
|
b032aa4d8d | ||
|
|
342a18e0ac | ||
|
|
e27e9de701 | ||
|
|
b14b199d43 | ||
|
|
f77a7c32d5 | ||
|
|
9f84d3f233 | ||
|
|
be82244c6b | ||
|
|
7fed72d391 | ||
|
|
54d615b64d | ||
|
|
2dbbd1e23d | ||
|
|
cba8867389 | ||
|
|
32d47db15a | ||
|
|
2c65c9ff9f | ||
|
|
fa5d63253b | ||
|
|
b7ae252d3d | ||
|
|
f07b43abda | ||
|
|
276db37baf | ||
|
|
6adad84a29 | ||
|
|
f137298c49 | ||
|
|
f8839518d5 | ||
|
|
1ae39d1a40 | ||
|
|
94f920324e | ||
|
|
94c00e2901 | ||
|
|
7de988104b | ||
|
|
03bc90968c | ||
|
|
a5401a22b9 | ||
|
|
4c1375d8b2 | ||
|
|
bab4a3b0d6 | ||
|
|
33e135f227 | ||
|
|
56b9d8d5c1 | ||
|
|
38ec88e302 | ||
|
|
10be208d8d | ||
|
|
38d227a948 | ||
|
|
1a8e4435e2 | ||
|
|
12febbdff5 | ||
|
|
ebea168350 | ||
|
|
704519f80b | ||
|
|
5f1000ddd3 | ||
|
|
2ee7e6cf4a | ||
|
|
2989975829 | ||
|
|
a4c068427d | ||
|
|
e1a76b9924 | ||
|
|
1f2efcd716 | ||
|
|
576dfe068f |
@@ -137,7 +137,7 @@ class Entity extends \Espo\ORM\Entity
|
||||
}
|
||||
|
||||
$this->set($idsAttribute, $ids);
|
||||
if (!$this->hasFetched($idsAttribute)) {
|
||||
if (!$this->isNew() && !$this->hasFetched($idsAttribute)) {
|
||||
$this->setFetched($idsAttribute, $ids);
|
||||
}
|
||||
|
||||
@@ -170,7 +170,13 @@ class Entity extends \Espo\ORM\Entity
|
||||
$entityName = $entity->get('name');
|
||||
}
|
||||
|
||||
$this->set($field . 'Id', $entityId);
|
||||
$idAttribute = $field . 'Id';
|
||||
|
||||
if (!$this->isNew() && !$this->hasFetched($idAttribute)) {
|
||||
$this->setFetched($idAttribute, $entityId);
|
||||
}
|
||||
|
||||
$this->set($idAttribute, $entityId);
|
||||
$this->set($field . 'Name', $entityName);
|
||||
}
|
||||
|
||||
|
||||
@@ -465,17 +465,21 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
$data->$columnName = $foreignEntity->get($columnField);
|
||||
}
|
||||
$existingColumnsData->$foreignId = $data;
|
||||
$entity->setFetched($columnsFieldsName, $existingColumnsData);
|
||||
if (!$entity->isNew()) {
|
||||
$entity->setFetched($columnsFieldsName, $existingColumnsData);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->has($fieldName)) {
|
||||
$entity->setFetched($fieldName, $existingIds);
|
||||
}
|
||||
if ($entity->has($columnsFieldsName) && !empty($columns)) {
|
||||
$entity->setFetched($columnsFieldsName, $existingColumnsData);
|
||||
if (!$entity->isNew()) {
|
||||
if ($entity->has($fieldName)) {
|
||||
$entity->setFetched($fieldName, $existingIds);
|
||||
}
|
||||
if ($entity->has($columnsFieldsName) && !empty($columns)) {
|
||||
$entity->setFetched($columnsFieldsName, $existingColumnsData);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($existingIds as $id) {
|
||||
@@ -540,13 +544,17 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
$where[$foreignKey] = $entity->id;
|
||||
$previousForeignEntity = $this->getEntityManager()->getRepository($foreignEntityType)->where($where)->findOne();
|
||||
if ($previousForeignEntity) {
|
||||
$entity->setFetched($idFieldName, $previousForeignEntity->id);
|
||||
if (!$entity->isNew()) {
|
||||
$entity->setFetched($idFieldName, $previousForeignEntity->id);
|
||||
}
|
||||
if ($previousForeignEntity->id !== $entity->get($idFieldName)) {
|
||||
$previousForeignEntity->set($foreignKey, null);
|
||||
$this->getEntityManager()->saveEntity($previousForeignEntity);
|
||||
}
|
||||
} else {
|
||||
$entity->setFetched($idFieldName, null);
|
||||
if (!$entity->isNew()) {
|
||||
$entity->setFetched($idFieldName, null);
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->get($idFieldName)) {
|
||||
|
||||
@@ -1255,7 +1255,7 @@ class Base
|
||||
|
||||
$value = $item['value'];
|
||||
|
||||
if (is_null($value)) break;
|
||||
if (is_null($value) || !$value && !is_array($value)) break;
|
||||
|
||||
$relationType = $seed->getRelationType($link);
|
||||
|
||||
@@ -1565,6 +1565,12 @@ class Base
|
||||
$useFullTextSearch = false;
|
||||
}
|
||||
|
||||
if ($isAuxiliaryUse) {
|
||||
if (mb_strpos($textFilter, '@') !== false) {
|
||||
$useFullTextSearch = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($useFullTextSearch) {
|
||||
$textFilter = str_replace(['(', ')'], '', $textFilter);
|
||||
|
||||
@@ -1582,10 +1588,11 @@ class Base
|
||||
$function = 'MATCH_NATURAL_LANGUAGE';
|
||||
} else {
|
||||
$function = 'MATCH_BOOLEAN';
|
||||
|
||||
$textFilter = str_replace('@', '*', $textFilter);
|
||||
}
|
||||
|
||||
$textFilter = str_replace('"*', '"', $textFilter);
|
||||
$textFilter = str_replace('*"', '"', $textFilter);
|
||||
|
||||
while (strpos($textFilter, '**')) {
|
||||
$textFilter = str_replace('**', '*', $textFilter);
|
||||
$textFilter = trim($textFilter);
|
||||
|
||||
@@ -631,7 +631,13 @@ abstract class Base
|
||||
|
||||
protected function systemRebuild()
|
||||
{
|
||||
return $this->getContainer()->get('dataManager')->rebuild();
|
||||
try {
|
||||
return $this->getContainer()->get('dataManager')->rebuild();
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('Database rebuild failure, details: '.$e->getMessage().'.');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -452,5 +452,17 @@ class MySqlPlatform extends \Doctrine\DBAL\Platforms\MySqlPlatform
|
||||
|
||||
return 'MEDIUMTEXT';
|
||||
}
|
||||
|
||||
public function getColumnDeclarationListSQL(array $fields)
|
||||
{
|
||||
$queryFields = array();
|
||||
|
||||
foreach ($fields as $fieldName => $field) {
|
||||
$quotedFieldName = $this->espoQuote($fieldName);
|
||||
$queryFields[] = $this->getColumnDeclarationSQL($quotedFieldName, $field);
|
||||
}
|
||||
|
||||
return implode(', ', $queryFields);
|
||||
}
|
||||
//end: ESPO
|
||||
}
|
||||
@@ -33,28 +33,29 @@ class LinkMultiple extends Base
|
||||
{
|
||||
protected function load($fieldName, $entityName)
|
||||
{
|
||||
$data = array(
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$fieldName.'Ids' => array(
|
||||
$data = [
|
||||
$entityName => [
|
||||
'fields' => [
|
||||
$fieldName.'Ids' => [
|
||||
'type' => 'jsonArray',
|
||||
'notStorable' => true,
|
||||
'isLinkMultipleIdList' => true,
|
||||
'relation' => $fieldName
|
||||
),
|
||||
$fieldName.'Names' => array(
|
||||
'relation' => $fieldName,
|
||||
'isUnordered' => true
|
||||
],
|
||||
$fieldName.'Names' => [
|
||||
'type' => 'jsonObject',
|
||||
'notStorable' => true,
|
||||
'isLinkMultipleNameMap' => true
|
||||
)
|
||||
)
|
||||
),
|
||||
'unset' => array(
|
||||
$entityName => array(
|
||||
'fields.'.$fieldName
|
||||
)
|
||||
)
|
||||
);
|
||||
]
|
||||
]
|
||||
],
|
||||
'unset' => [
|
||||
$entityName => [
|
||||
'fields.' . $fieldName
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$fieldParams = $this->getFieldParams();
|
||||
|
||||
@@ -67,10 +68,10 @@ class LinkMultiple extends Base
|
||||
|
||||
$columns = $this->getMetadata()->get("entityDefs.{$entityName}.fields.{$fieldName}.columns");
|
||||
if (!empty($columns)) {
|
||||
$data[$entityName]['fields'][$fieldName . 'Columns'] = array(
|
||||
$data[$entityName]['fields'][$fieldName . 'Columns'] = [
|
||||
'type' => 'jsonObject',
|
||||
'notStorable' => true,
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
||||
@@ -662,7 +662,6 @@ class EntityManager
|
||||
$link => array(
|
||||
"type" => "linkMultiple",
|
||||
"layoutDetailDisabled" => !$linkMultipleField,
|
||||
"layoutListDisabled" => true,
|
||||
"layoutMassUpdateDisabled" => !$linkMultipleField,
|
||||
"noLoad" => !$linkMultipleField,
|
||||
"importDisabled" => !$linkMultipleField,
|
||||
@@ -727,7 +726,6 @@ class EntityManager
|
||||
$linkForeign => array(
|
||||
"type" => "linkMultiple",
|
||||
"layoutDetailDisabled" => !$linkMultipleFieldForeign,
|
||||
"layoutListDisabled" => true,
|
||||
"layoutMassUpdateDisabled" => !$linkMultipleFieldForeign,
|
||||
"noLoad" => !$linkMultipleFieldForeign,
|
||||
"importDisabled" => !$linkMultipleFieldForeign,
|
||||
@@ -751,7 +749,6 @@ class EntityManager
|
||||
$link => array(
|
||||
"type" => "linkMultiple",
|
||||
"layoutDetailDisabled" => !$linkMultipleField,
|
||||
"layoutListDisabled" => true,
|
||||
"layoutMassUpdateDisabled" => !$linkMultipleField,
|
||||
"importDisabled" => !$linkMultipleField,
|
||||
"noLoad" => !$linkMultipleField,
|
||||
@@ -774,7 +771,6 @@ class EntityManager
|
||||
$linkForeign => array(
|
||||
"type" => "linkMultiple",
|
||||
"layoutDetailDisabled" => !$linkMultipleFieldForeign,
|
||||
"layoutListDisabled" => true,
|
||||
"layoutMassUpdateDisabled" => !$linkMultipleFieldForeign,
|
||||
"importDisabled" => !$linkMultipleFieldForeign,
|
||||
"noLoad" => !$linkMultipleFieldForeign,
|
||||
@@ -848,7 +844,6 @@ class EntityManager
|
||||
$link => array(
|
||||
"type" => "linkMultiple",
|
||||
"layoutDetailDisabled" => !$linkMultipleField,
|
||||
"layoutListDisabled" => true,
|
||||
"layoutMassUpdateDisabled" => !$linkMultipleField,
|
||||
"noLoad" => !$linkMultipleField,
|
||||
"importDisabled" => !$linkMultipleField,
|
||||
@@ -873,7 +868,6 @@ class EntityManager
|
||||
$linkForeign => array(
|
||||
"type" => "linkMultiple",
|
||||
"layoutDetailDisabled" => !$linkMultipleFieldForeign,
|
||||
"layoutListDisabled" => true,
|
||||
"layoutMassUpdateDisabled" => !$linkMultipleFieldForeign,
|
||||
"noLoad" => !$linkMultipleFieldForeign,
|
||||
"importDisabled" => !$linkMultipleFieldForeign,
|
||||
|
||||
@@ -129,7 +129,7 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
}
|
||||
|
||||
if (!empty($size)) {
|
||||
$fileName = $sourceId . '_' . $size . '.jpg';
|
||||
$fileName = $size . '-' . $attachment->get('name');
|
||||
} else {
|
||||
$fileName = $attachment->get('name');
|
||||
}
|
||||
@@ -197,9 +197,10 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
break;
|
||||
}
|
||||
|
||||
$targetImage = imagerotate($targetImage, array_values([0, 0, 0, 180, 0, 0, -90, 0, 90])[@exif_read_data($filePath)['Orientation'] ?: 0], 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);
|
||||
}
|
||||
|
||||
return $targetImage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
[
|
||||
{
|
||||
"route":"/Activities/:scope/:id/:name",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"Activities",
|
||||
"action":"list",
|
||||
"scope":":scope",
|
||||
"id":":id",
|
||||
"name":":name"
|
||||
{
|
||||
"route": "/Activities/:scope/:id/:name",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": "Activities",
|
||||
"action": "list",
|
||||
"scope": ":scope",
|
||||
"id": ":id",
|
||||
"name": ":name"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route": "/Activities",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": "Activities",
|
||||
"action": "listCalendarEvents"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"route":"/Activities",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"Activities",
|
||||
"action":"listCalendarEvents"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -33,19 +33,23 @@ class CampaignLogRecord extends \Espo\Core\SelectManagers\Base
|
||||
{
|
||||
protected function accessOnlyOwn(&$result)
|
||||
{
|
||||
$this->addLeftJoin(['campaign', 'campaignAccess'], $result);
|
||||
|
||||
$result['whereClause'][] = array(
|
||||
'campaign.assignedUserId' => $this->getUser()->id
|
||||
'campaignAccess.assignedUserId' => $this->getUser()->id
|
||||
);
|
||||
}
|
||||
|
||||
protected function accessOnlyTeam(&$result)
|
||||
{
|
||||
$this->addLeftJoin(['campaign', 'campaignAccess'], $result);
|
||||
|
||||
$teamIdList = $this->user->get('teamsIds');
|
||||
if (empty($result['customWhere'])) {
|
||||
$result['customWhere'] = '';
|
||||
}
|
||||
if (empty($teamIdList)) {
|
||||
$result['customWhere'] .= " AND campaign.assigned_user_id = ".$this->getEntityManager()->getPDO()->quote($this->getUser()->id);
|
||||
$result['customWhere'] .= " AND campaignAccess.assigned_user_id = ".$this->getEntityManager()->getPDO()->quote($this->getUser()->id);
|
||||
return;
|
||||
}
|
||||
$arr = [];
|
||||
@@ -55,12 +59,12 @@ class CampaignLogRecord extends \Espo\Core\SelectManagers\Base
|
||||
}
|
||||
}
|
||||
|
||||
$result['customJoin'] .= " LEFT JOIN entity_team AS teamsMiddle ON teamsMiddle.entity_type = 'Campaign' AND teamsMiddle.entity_id = campaign.id AND teamsMiddle.deleted = 0";
|
||||
$result['customJoin'] .= " LEFT JOIN entity_team AS teamsMiddle ON teamsMiddle.entity_type = 'Campaign' AND teamsMiddle.entity_id = campaignAccess.id AND teamsMiddle.deleted = 0";
|
||||
$result['customWhere'] .= "
|
||||
AND (
|
||||
teamsMiddle.team_id IN (" . implode(', ', $arr) . ")
|
||||
OR
|
||||
campaign.assigned_user_id = ".$this->getEntityManager()->getPDO()->quote($this->getUser()->id)."
|
||||
campaignAccess.assigned_user_id = ".$this->getEntityManager()->getPDO()->quote($this->getUser()->id)."
|
||||
)
|
||||
";
|
||||
$result['whereClause'][] = array(
|
||||
|
||||
@@ -33,19 +33,23 @@ class CampaignTrackingUrl extends \Espo\Core\SelectManagers\Base
|
||||
{
|
||||
protected function accessOnlyOwn(&$result)
|
||||
{
|
||||
$this->addLeftJoin(['campaign', 'campaignAccess'], $result);
|
||||
|
||||
$result['whereClause'][] = array(
|
||||
'campaign.assignedUserId' => $this->getUser()->id
|
||||
'campaignAccess.assignedUserId' => $this->getUser()->id
|
||||
);
|
||||
}
|
||||
|
||||
protected function accessOnlyTeam(&$result)
|
||||
{
|
||||
$this->addLeftJoin(['campaign', 'campaignAccess'], $result);
|
||||
|
||||
$teamIdList = $this->user->get('teamsIds');
|
||||
if (empty($result['customWhere'])) {
|
||||
$result['customWhere'] = '';
|
||||
}
|
||||
if (empty($teamIdList)) {
|
||||
$result['customWhere'] .= " AND campaign.assigned_user_id = ".$this->getEntityManager()->getPDO()->quote($this->getUser()->id);
|
||||
$result['customWhere'] .= " AND campaignAccess.assigned_user_id = ".$this->getEntityManager()->getPDO()->quote($this->getUser()->id);
|
||||
return;
|
||||
}
|
||||
$arr = [];
|
||||
@@ -55,12 +59,12 @@ class CampaignTrackingUrl extends \Espo\Core\SelectManagers\Base
|
||||
}
|
||||
}
|
||||
|
||||
$result['customJoin'] .= " LEFT JOIN entity_team AS teamsMiddle ON teamsMiddle.entity_type = 'Campaign' AND teamsMiddle.entity_id = campaign.id AND teamsMiddle.deleted = 0";
|
||||
$result['customJoin'] .= " LEFT JOIN entity_team AS teamsMiddle ON teamsMiddle.entity_type = 'Campaign' AND teamsMiddle.entity_id = campaignAccess.id AND teamsMiddle.deleted = 0";
|
||||
$result['customWhere'] .= "
|
||||
AND (
|
||||
teamsMiddle.team_id IN (" . implode(', ', $arr) . ")
|
||||
OR
|
||||
campaign.assigned_user_id = ".$this->getEntityManager()->getPDO()->quote($this->getUser()->id)."
|
||||
campaignAccess.assigned_user_id = ".$this->getEntityManager()->getPDO()->quote($this->getUser()->id)."
|
||||
)
|
||||
";
|
||||
$result['whereClause'][] = array(
|
||||
|
||||
@@ -45,21 +45,25 @@ class MassEmail extends \Espo\Core\SelectManagers\Base
|
||||
);
|
||||
}
|
||||
|
||||
protected function acessOnlyOwn(&$result)
|
||||
protected function accessOnlyOwn(&$result)
|
||||
{
|
||||
$this->addLeftJoin(['campaign', 'campaignAccess'], $result);
|
||||
|
||||
$result['whereClause'][] = array(
|
||||
'campaign.assignedUserId' => $this->getUser()->id
|
||||
'campaignAccess.assignedUserId' => $this->getUser()->id
|
||||
);
|
||||
}
|
||||
|
||||
protected function accessOnlyTeam(&$result)
|
||||
{
|
||||
$teamIdList = $this->user->get('teamsIds');
|
||||
$this->addLeftJoin(['campaign', 'campaignAccess'], $result);
|
||||
|
||||
$teamIdList = $this->user->getLinkMultipleIdList('teams');
|
||||
if (empty($result['customWhere'])) {
|
||||
$result['customWhere'] = '';
|
||||
}
|
||||
if (empty($teamIdList)) {
|
||||
$result['customWhere'] .= " AND campaign.assigned_user_id = ".$this->getEntityManager()->getPDO()->quote($this->getUser()->id);
|
||||
$result['customWhere'] .= " AND campaignAccess.assigned_user_id = ".$this->getEntityManager()->getPDO()->quote($this->getUser()->id);
|
||||
return;
|
||||
}
|
||||
$arr = [];
|
||||
@@ -69,12 +73,12 @@ class MassEmail extends \Espo\Core\SelectManagers\Base
|
||||
}
|
||||
}
|
||||
|
||||
$result['customJoin'] .= " LEFT JOIN entity_team AS teamsMiddle ON teamsMiddle.entity_type = 'Campaign' AND teamsMiddle.entity_id = campaign.id AND teamsMiddle.deleted = 0";
|
||||
$result['customJoin'] .= " LEFT JOIN entity_team AS teamsMiddle ON teamsMiddle.entity_type = 'Campaign' AND teamsMiddle.entity_id = campaignAccess.id AND teamsMiddle.deleted = 0";
|
||||
$result['customWhere'] .= "
|
||||
AND (
|
||||
teamsMiddle.team_id IN (" . implode(', ', $arr) . ")
|
||||
OR
|
||||
campaign.assigned_user_id = ".$this->getEntityManager()->getPDO()->quote($this->getUser()->id)."
|
||||
campaignAccess.assigned_user_id = ".$this->getEntityManager()->getPDO()->quote($this->getUser()->id)."
|
||||
)
|
||||
";
|
||||
$result['whereClause'][] = array(
|
||||
|
||||
@@ -139,12 +139,14 @@ class Campaign extends \Espo\Services\Record
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
|
||||
$revenue = null;
|
||||
if ($row = $sth->fetch(\PDO::FETCH_ASSOC)) {
|
||||
$revenue = floatval($row['SUM:amountConverted']);
|
||||
if ($revenue > 0) {
|
||||
$entity->set('revenue', $revenue);
|
||||
if (!$revenue) {
|
||||
$revenue = null;
|
||||
}
|
||||
}
|
||||
$entity->set('revenue', $revenue);
|
||||
}
|
||||
|
||||
public function logSent($campaignId, $queueItemId = null, Entity $target, Entity $emailOrEmailTemplate = null, $emailAddress, $actionDate = null, $isTest = false)
|
||||
|
||||
@@ -718,7 +718,7 @@ abstract class Mapper implements IMapper
|
||||
|
||||
public function insert(IEntity $entity)
|
||||
{
|
||||
$dataArr = $this->toArray($entity);
|
||||
$dataArr = $this->toValueMap($entity);
|
||||
|
||||
$fieldArr = array();
|
||||
$valArr = array();
|
||||
@@ -745,33 +745,35 @@ abstract class Mapper implements IMapper
|
||||
|
||||
public function update(IEntity $entity)
|
||||
{
|
||||
$dataArr = $this->toArray($entity);
|
||||
$valueMap = $this->toValueMap($entity);
|
||||
|
||||
$setArr = array();
|
||||
foreach ($dataArr as $field => $value) {
|
||||
if ($field == 'id') {
|
||||
$setArr = [];
|
||||
|
||||
foreach ($valueMap as $attribute => $value) {
|
||||
if ($attribute == 'id') {
|
||||
continue;
|
||||
}
|
||||
$type = $entity->fields[$field]['type'];
|
||||
$type = $entity->getAttributeType($attribute);
|
||||
|
||||
if ($type == IEntity::FOREIGN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($entity->getFetched($field) === $value && $type != IEntity::JSON_ARRAY && $type != IEntity::JSON_OBJECT) {
|
||||
if (!$entity->isAttributeChanged($attribute) && $type !== IEntity::JSON_OBJECT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $this->prepareValueForInsert($type, $value);
|
||||
|
||||
$setArr[] = "`" . $this->toDb($field) . "` = " . $this->quote($value);
|
||||
$setArr[] = "`" . $this->toDb($attribute) . "` = " . $this->quote($value);
|
||||
}
|
||||
|
||||
if (count($setArr) == 0) {
|
||||
return $entity->id;
|
||||
}
|
||||
|
||||
$setPart = implode(', ', $setArr);
|
||||
$wherePart = $this->query->getWhere($entity, array('id' => $entity->id, 'deleted' => 0));
|
||||
$wherePart = $this->query->getWhere($entity, ['id' => $entity->id, 'deleted' => 0]);
|
||||
|
||||
$sql = $this->composeUpdateQuery($this->toDb($entity->getEntityType()), $setPart, $wherePart);
|
||||
|
||||
@@ -815,21 +817,25 @@ abstract class Mapper implements IMapper
|
||||
return $this->update($entity);
|
||||
}
|
||||
|
||||
protected function toArray(IEntity $entity, $onlyStorable = true)
|
||||
protected function toValueMap(IEntity $entity, $onlyStorable = true)
|
||||
{
|
||||
$arr = array();
|
||||
foreach ($entity->fields as $field => $fieldDefs) {
|
||||
if ($entity->has($field)) {
|
||||
$data = [];
|
||||
foreach ($entity->getAttributes() as $attribute => $defs) {
|
||||
if ($entity->has($attribute)) {
|
||||
if ($onlyStorable) {
|
||||
if (!empty($fieldDefs['notStorable']) || !empty($fieldDefs['autoincrement']) || isset($fieldDefs['source']) && $fieldDefs['source'] != 'db')
|
||||
continue;
|
||||
if ($fieldDefs['type'] == IEntity::FOREIGN)
|
||||
continue;
|
||||
if (
|
||||
!empty($defs['notStorable'])
|
||||
||
|
||||
!empty($defs['autoincrement'])
|
||||
||
|
||||
isset($defs['source']) && $defs['source'] != 'db'
|
||||
) continue;
|
||||
if ($defs['type'] == IEntity::FOREIGN) continue;
|
||||
}
|
||||
$arr[$field] = $entity->get($field);
|
||||
$data[$attribute] = $entity->get($attribute);
|
||||
}
|
||||
}
|
||||
return $arr;
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function fromRow(IEntity $entity, $data)
|
||||
|
||||
@@ -369,25 +369,92 @@ abstract class Entity implements IEntity
|
||||
return $this->isFetched;
|
||||
}
|
||||
|
||||
public function isFieldChanged($fieldName)
|
||||
public function isFieldChanged($name)
|
||||
{
|
||||
return $this->has($fieldName) && ($this->get($fieldName) != $this->getFetched($fieldName));
|
||||
return $this->has($name) && ($this->get($name) != $this->getFetched($name));
|
||||
}
|
||||
|
||||
public function isAttributeChanged($fieldName)
|
||||
public function isAttributeChanged($name)
|
||||
{
|
||||
return $this->has($fieldName) && ($this->get($fieldName) != $this->getFetched($fieldName));
|
||||
if (!$this->has($name)) return false;
|
||||
|
||||
if (!$this->hasFetched($name)) {
|
||||
return true;
|
||||
}
|
||||
return !self::areValuesEqual(
|
||||
$this->getAttributeType($name),
|
||||
$this->get($name),
|
||||
$this->getFetched($name),
|
||||
$this->getAttributeParam($name, 'isUnordered')
|
||||
);
|
||||
|
||||
return $this->get($name) != $this->getFetched($name);
|
||||
}
|
||||
|
||||
public function setFetched($fieldName, $value)
|
||||
public static function areValuesEqual($type, $v1, $v2, $isUnordered = false)
|
||||
{
|
||||
$this->fetchedValuesContainer[$fieldName] = $value;
|
||||
if ($type === self::JSON_ARRAY) {
|
||||
if (is_array($v1) && is_array($v2)) {
|
||||
if ($isUnordered) {
|
||||
sort($v1);
|
||||
sort($v2);
|
||||
}
|
||||
if ($v1 != $v2) {
|
||||
return false;
|
||||
}
|
||||
foreach ($v1 as $i => $itemValue) {
|
||||
if (is_object($v1[$i]) && is_object($v2[$i])) {
|
||||
if (!self::areValuesEqual(self::JSON_OBJECT, $v1[$i], $v2[$i])) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($v1[$i] !== $v2[$i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if ($type === self::JSON_OBJECT) {
|
||||
if (is_object($v1) && is_object($v2)) {
|
||||
if ($v1 != $v2) {
|
||||
return false;
|
||||
}
|
||||
$a1 = get_object_vars($v1);
|
||||
$a2 = get_object_vars($v2);
|
||||
foreach ($v1 as $key => $itemValue) {
|
||||
if (is_object($a1[$key]) && is_object($a2[$key])) {
|
||||
if (!self::areValuesEqual(self::JSON_OBJECT, $a1[$key], $a2[$key])) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (is_array($a1[$key]) && is_array($a2[$key])) {
|
||||
if (!self::areValuesEqual(self::JSON_ARRAY, $a1[$key], $a2[$key])) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($a1[$key] !== $a2[$key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return $v1 === $v2;
|
||||
}
|
||||
|
||||
public function getFetched($fieldName)
|
||||
public function setFetched($name, $value)
|
||||
{
|
||||
if (isset($this->fetchedValuesContainer[$fieldName])) {
|
||||
return $this->fetchedValuesContainer[$fieldName];
|
||||
$this->fetchedValuesContainer[$name] = $value;
|
||||
}
|
||||
|
||||
public function getFetched($name)
|
||||
{
|
||||
if (isset($this->fetchedValuesContainer[$name])) {
|
||||
return $this->fetchedValuesContainer[$name];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
"type": "float",
|
||||
"tooltip": true,
|
||||
"min": 0
|
||||
},
|
||||
{
|
||||
"name": "previewSize",
|
||||
"type": "enum",
|
||||
"default": "medium",
|
||||
"options": ["", "x-small", "small", "medium", "large"]
|
||||
}
|
||||
],
|
||||
"actualFields":[
|
||||
|
||||
@@ -1,319 +1,326 @@
|
||||
[
|
||||
{
|
||||
"route":"/",
|
||||
"method":"get",
|
||||
"params":"<h1>EspoCRM REST API<\/h1>"
|
||||
"route": "/",
|
||||
"method": "get",
|
||||
"params": "<h1>EspoCRM REST API<\/h1>"
|
||||
},
|
||||
{
|
||||
"route":"/App/user",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"App",
|
||||
"action":"user"
|
||||
"route": "/App/user",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": "App",
|
||||
"action": "user"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/Metadata",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"Metadata"
|
||||
"route": "/Metadata",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": "Metadata"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"I18n",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"I18n"
|
||||
"route": "I18n",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": "I18n"
|
||||
},
|
||||
"conditions":{
|
||||
"auth":false
|
||||
"conditions": {
|
||||
"auth": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/Settings",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"Settings"
|
||||
"route": "/Settings",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": "Settings"
|
||||
},
|
||||
"conditions":{
|
||||
"auth":false
|
||||
"conditions": {
|
||||
"auth": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/Settings",
|
||||
"method":"patch",
|
||||
"params":{
|
||||
"controller":"Settings"
|
||||
"route": "/Settings",
|
||||
"method": "patch",
|
||||
"params": {
|
||||
"controller": "Settings"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"User/passwordChangeRequest",
|
||||
"method":"post",
|
||||
"params":{
|
||||
"controller":"User",
|
||||
"action":"passwordChangeRequest"
|
||||
"route": "/Settings",
|
||||
"method": "put",
|
||||
"params": {
|
||||
"controller": "Settings"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route": "User/passwordChangeRequest",
|
||||
"method": "post",
|
||||
"params": {
|
||||
"controller": "User",
|
||||
"action": "passwordChangeRequest"
|
||||
},
|
||||
"conditions":{
|
||||
"auth":false
|
||||
"conditions": {
|
||||
"auth": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"User/changePasswordByRequest",
|
||||
"method":"post",
|
||||
"params":{
|
||||
"controller":"User",
|
||||
"action":"changePasswordByRequest"
|
||||
"route": "User/changePasswordByRequest",
|
||||
"method": "post",
|
||||
"params": {
|
||||
"controller": "User",
|
||||
"action": "changePasswordByRequest"
|
||||
},
|
||||
"conditions":{
|
||||
"auth":false
|
||||
"conditions": {
|
||||
"auth": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/Stream",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"Stream",
|
||||
"action":"list",
|
||||
"scope":"User"
|
||||
"route": "/Stream",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": "Stream",
|
||||
"action": "list",
|
||||
"scope": "User"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/GlobalSearch",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"GlobalSearch",
|
||||
"action":"search"
|
||||
"route": "/GlobalSearch",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": "GlobalSearch",
|
||||
"action": "search"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/action/:action",
|
||||
"method":"post",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"action":":action"
|
||||
"route": "/:controller/action/:action",
|
||||
"method": "post",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"action": ":action"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/action/:action",
|
||||
"method":"put",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"action":":action"
|
||||
"route": "/:controller/action/:action",
|
||||
"method": "put",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"action": ":action"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/action/:action",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"action":":action"
|
||||
"route": "/:controller/action/:action",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"action": ":action"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/layout/:name",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"Layout",
|
||||
"scope":":controller"
|
||||
"route": "/:controller/layout/:name",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": "Layout",
|
||||
"scope": ":controller"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/layout/:name",
|
||||
"method":"put",
|
||||
"params":{
|
||||
"controller":"Layout",
|
||||
"scope":":controller"
|
||||
"route": "/:controller/layout/:name",
|
||||
"method": "put",
|
||||
"params": {
|
||||
"controller": "Layout",
|
||||
"scope": ":controller"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/layout/:name",
|
||||
"method":"patch",
|
||||
"params":{
|
||||
"controller":"Layout",
|
||||
"scope":":controller"
|
||||
"route": "/:controller/layout/:name",
|
||||
"method": "patch",
|
||||
"params": {
|
||||
"controller": "Layout",
|
||||
"scope": ":controller"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/Admin/rebuild",
|
||||
"method":"post",
|
||||
"params":{
|
||||
"controller":"Admin",
|
||||
"action":"rebuild"
|
||||
"route": "/Admin/rebuild",
|
||||
"method": "post",
|
||||
"params": {
|
||||
"controller": "Admin",
|
||||
"action": "rebuild"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/Admin/clearCache",
|
||||
"method":"post",
|
||||
"params":{
|
||||
"controller":"Admin",
|
||||
"action":"clearCache"
|
||||
"route": "/Admin/clearCache",
|
||||
"method": "post",
|
||||
"params": {
|
||||
"controller": "Admin",
|
||||
"action": "clearCache"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/Admin/jobs",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"Admin",
|
||||
"action":"jobs"
|
||||
"route": "/Admin/jobs",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": "Admin",
|
||||
"action": "jobs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/Admin/fieldManager/:scope/:name",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"FieldManager",
|
||||
"action":"read",
|
||||
"scope":":scope",
|
||||
"name":":name"
|
||||
"route": "/Admin/fieldManager/:scope/:name",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": "FieldManager",
|
||||
"action": "read",
|
||||
"scope": ":scope",
|
||||
"name": ":name"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/Admin/fieldManager/:scope",
|
||||
"method":"post",
|
||||
"params":{
|
||||
"controller":"FieldManager",
|
||||
"action":"create",
|
||||
"scope":":scope"
|
||||
"route": "/Admin/fieldManager/:scope",
|
||||
"method": "post",
|
||||
"params": {
|
||||
"controller": "FieldManager",
|
||||
"action": "create",
|
||||
"scope": ":scope"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/Admin/fieldManager/:scope/:name",
|
||||
"method":"put",
|
||||
"params":{
|
||||
"controller":"FieldManager",
|
||||
"action":"update",
|
||||
"scope":":scope",
|
||||
"name":":name"
|
||||
"route": "/Admin/fieldManager/:scope/:name",
|
||||
"method": "put",
|
||||
"params": {
|
||||
"controller": "FieldManager",
|
||||
"action": "update",
|
||||
"scope": ":scope",
|
||||
"name": ":name"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/Admin/fieldManager/:scope/:name",
|
||||
"method":"patch",
|
||||
"params":{
|
||||
"controller":"FieldManager",
|
||||
"action":"update",
|
||||
"scope":":scope",
|
||||
"name":":name"
|
||||
"route": "/Admin/fieldManager/:scope/:name",
|
||||
"method": "patch",
|
||||
"params": {
|
||||
"controller": "FieldManager",
|
||||
"action": "update",
|
||||
"scope": ":scope",
|
||||
"name": ":name"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/Admin/fieldManager/:scope/:name",
|
||||
"method":"delete",
|
||||
"params":{
|
||||
"controller":"FieldManager",
|
||||
"action":"delete",
|
||||
"scope":":scope",
|
||||
"name":":name"
|
||||
"route": "/Admin/fieldManager/:scope/:name",
|
||||
"method": "delete",
|
||||
"params": {
|
||||
"controller": "FieldManager",
|
||||
"action": "delete",
|
||||
"scope": ":scope",
|
||||
"name": ":name"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/:id",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"action":"read",
|
||||
"id":":id"
|
||||
"route": "/:controller/:id",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"action": "read",
|
||||
"id": ":id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"action":"index"
|
||||
"route": "/:controller",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"action": "index"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller",
|
||||
"method":"post",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"action":"create"
|
||||
"route": "/:controller",
|
||||
"method": "post",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"action": "create"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/:id",
|
||||
"method":"put",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"action":"update",
|
||||
"id":":id"
|
||||
"route": "/:controller/:id",
|
||||
"method": "put",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"action": "update",
|
||||
"id": ":id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/:id",
|
||||
"method":"patch",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"action":"patch",
|
||||
"id":":id"
|
||||
"route": "/:controller/:id",
|
||||
"method": "patch",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"action": "patch",
|
||||
"id": ":id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/:id",
|
||||
"method":"delete",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"action":"delete",
|
||||
"id":":id"
|
||||
"route": "/:controller/:id",
|
||||
"method": "delete",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"action": "delete",
|
||||
"id": ":id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/:id/stream",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"Stream",
|
||||
"action":"list",
|
||||
"id":":id",
|
||||
"scope":":controller"
|
||||
"route": "/:controller/:id/stream",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": "Stream",
|
||||
"action": "list",
|
||||
"id": ":id",
|
||||
"scope": ":controller"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/:id/subscription",
|
||||
"method":"put",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"id":":id",
|
||||
"action":"follow"
|
||||
"route": "/:controller/:id/subscription",
|
||||
"method": "put",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"id": ":id",
|
||||
"action": "follow"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/:id/subscription",
|
||||
"method":"delete",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"id":":id",
|
||||
"action":"unfollow"
|
||||
"route": "/:controller/:id/subscription",
|
||||
"method": "delete",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"id": ":id",
|
||||
"action": "unfollow"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/:id/:link",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"action":"listLinked",
|
||||
"id":":id",
|
||||
"link":":link"
|
||||
"route": "/:controller/:id/:link",
|
||||
"method": "get",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"action": "listLinked",
|
||||
"id": ":id",
|
||||
"link": ":link"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/:id/:link",
|
||||
"method":"post",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"action":"createLink",
|
||||
"id":":id",
|
||||
"link":":link"
|
||||
"route": "/:controller/:id/:link",
|
||||
"method": "post",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"action": "createLink",
|
||||
"id": ":id",
|
||||
"link": ":link"
|
||||
}
|
||||
},
|
||||
{
|
||||
"route":"/:controller/:id/:link",
|
||||
"method":"delete",
|
||||
"params":{
|
||||
"controller":":controller",
|
||||
"action":"removeLink",
|
||||
"id":":id",
|
||||
"link":":link"
|
||||
"route": "/:controller/:id/:link",
|
||||
"method": "delete",
|
||||
"params": {
|
||||
"controller": ":controller",
|
||||
"action": "removeLink",
|
||||
"id": ":id",
|
||||
"link": ":link"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -173,14 +173,26 @@ class Email extends Record
|
||||
|
||||
if (!$smtpParams && $fromAddress === strtolower($this->getConfig()->get('outboundEmailFromAddress'))) {
|
||||
if (!$this->getConfig()->get('outboundEmailIsShared')) {
|
||||
throw new Error('Can not use system smtp. System SMTP is not shared.');
|
||||
throw new Error('Can not use system SMTP. System account is not shared.');
|
||||
}
|
||||
$emailSender->setParams(array(
|
||||
$emailSender->setParams([
|
||||
'fromName' => $this->getConfig()->get('outboundEmailFromName')
|
||||
));
|
||||
]);
|
||||
}
|
||||
|
||||
$params = array();
|
||||
if (!$smtpParams && !$this->getConfig()->get('outboundEmailIsShared')) {
|
||||
throw new Error('No SMTP params found for '.$fromAddress.'.');
|
||||
}
|
||||
|
||||
if (!$smtpParams) {
|
||||
if (in_array($fromAddress, $userAddressList)) {
|
||||
$emailSender->setParams([
|
||||
'fromName' => $this->getUser()->get('name')
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$params = [];
|
||||
|
||||
$parent = null;
|
||||
if ($entity->get('parentType') && $entity->get('parentId')) {
|
||||
|
||||
@@ -209,12 +209,15 @@ class EmailAccount extends Record
|
||||
if (empty($fetchData)) {
|
||||
$fetchData = new \StdClass();
|
||||
}
|
||||
$fetchData = clone $fetchData;
|
||||
if (!property_exists($fetchData, 'lastUID')) {
|
||||
$fetchData->lastUID = new \StdClass();;
|
||||
$fetchData->lastUID = new \StdClass();
|
||||
}
|
||||
if (!property_exists($fetchData, 'lastDate')) {
|
||||
$fetchData->lastDate = new \StdClass();;
|
||||
$fetchData->lastDate = new \StdClass();
|
||||
}
|
||||
$fetchData->lastUID = clone $fetchData->lastUID;
|
||||
$fetchData->lastDate = clone $fetchData->lastDate;
|
||||
|
||||
$storage = $this->getStorage($emailAccount);
|
||||
|
||||
@@ -385,7 +388,7 @@ class EmailAccount extends Record
|
||||
$emailAccount = $this->getEntityManager()->getRepository('EmailAccount')->where([
|
||||
'emailAddress' => $address,
|
||||
'assignedUserId' => $user->id,
|
||||
'active' => true
|
||||
'status' => 'Active'
|
||||
])->findOne();
|
||||
|
||||
return $emailAccount;
|
||||
|
||||
@@ -109,9 +109,11 @@ class EmailFolder extends Record
|
||||
|
||||
public function listAll()
|
||||
{
|
||||
$limit = $this->getConfig()->get('emailFolderMaxCount', 100);
|
||||
|
||||
$folderList = $this->getRepository()->where(array(
|
||||
'assignedUserId' => $this->getUser()->id
|
||||
))->order('order')->limit(0, 20)->find();
|
||||
))->order('order')->limit(0, $limit)->find();
|
||||
|
||||
$list = new \Espo\ORM\EntityCollection();
|
||||
|
||||
|
||||
@@ -210,12 +210,15 @@ class InboundEmail extends \Espo\Services\Record
|
||||
if (empty($fetchData)) {
|
||||
$fetchData = new \StdClass();
|
||||
}
|
||||
$fetchData = clone $fetchData;
|
||||
if (!property_exists($fetchData, 'lastUID')) {
|
||||
$fetchData->lastUID = new \StdClass();;
|
||||
}
|
||||
if (!property_exists($fetchData, 'lastDate')) {
|
||||
$fetchData->lastDate = new \StdClass();;
|
||||
$fetchData->lastDate = new \StdClass();
|
||||
}
|
||||
$fetchData->lastUID = clone $fetchData->lastUID;
|
||||
$fetchData->lastDate = clone $fetchData->lastDate;
|
||||
|
||||
$imapParams = array(
|
||||
'host' => $emailAccount->get('host'),
|
||||
|
||||
@@ -218,6 +218,7 @@ class Notification extends \Espo\Services\Record
|
||||
$note->set('relatedName', $related->get('name'));
|
||||
}
|
||||
}
|
||||
$note->loadLinkMultipleField('attachments');
|
||||
$entity->set('noteData', $note->toArray());
|
||||
} else {
|
||||
unset($collection[$k]);
|
||||
|
||||
@@ -2191,7 +2191,7 @@ class Record extends \Espo\Core\Services\Base
|
||||
}
|
||||
|
||||
// TODO remove in 5.5.0
|
||||
if (in_array($this->getEntityType(), ['Report', 'Workflow'])) {
|
||||
if (in_array($this->getEntityType(), ['Report', 'Workflow', 'ReportPanel'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -972,7 +972,7 @@ class Stream extends \Espo\Core\Services\Base
|
||||
foreach ($auditedFields as $field => $item) {
|
||||
$updated = false;
|
||||
foreach ($item['actualList'] as $attribute) {
|
||||
if ($entity->get($attribute) !== $entity->getFetched($attribute)) {
|
||||
if ($entity->hasFetched($attribute) && $entity->isAttributeChanged($attribute)) {
|
||||
$updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ Espo.define('crm:views/case/record/panels/activities', 'crm:views/record/panels/
|
||||
}, function () {resolve([])});
|
||||
}, this);
|
||||
} else if (parentModel.get('leadId')) {
|
||||
this.getModelFactory().create('Lead', function (account) {
|
||||
this.getModelFactory().create('Lead', function (lead) {
|
||||
lead.id = parentModel.get('leadId');
|
||||
lead.fetch().then(function () {
|
||||
resolve([lead]);
|
||||
|
||||
@@ -1 +1 @@
|
||||
<span class="glyphicon glyphicon-envelope action text-muted" data-action="quickView" data-id="{{model.id}}" style="cursor: pointer; margin-left: -7px; top: 2px;" title="{{translate 'View'}}"></span>
|
||||
<span class="fas fa-envelope action text-muted" data-action="quickView" data-id="{{model.id}}" style="cursor: pointer; margin-left: -7px; top: 2px;" title="{{translate 'View'}}"></span>
|
||||
@@ -1 +1,3 @@
|
||||
{{#unless isEmpty}}{{{value}}}{{else}}{{translate 'None'}}{{/unless}}
|
||||
{{#unless isEmpty}}{{{value}}}{{else}}
|
||||
{{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}}
|
||||
{{/unless}}
|
||||
|
||||
1
client/res/templates/fields/array/list.tpl
Normal file
1
client/res/templates/fields/array/list.tpl
Normal file
@@ -0,0 +1 @@
|
||||
{{#unless isEmpty}}{{{value}}}{{/unless}}
|
||||
@@ -0,0 +1,3 @@
|
||||
{{#if value}}
|
||||
{{{value}}}
|
||||
{{/if}}
|
||||
@@ -1,5 +1,5 @@
|
||||
{{#if value}}
|
||||
{{#if isNotEmpty}}
|
||||
{{value}} {{currencyValue}}
|
||||
{{else}}
|
||||
{{translate 'None'}}
|
||||
{{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}}
|
||||
{{/if}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{{#if value}}
|
||||
{{#if isNotEmpty}}
|
||||
{{currencySymbol}}{{value}}
|
||||
{{else}}
|
||||
{{translate 'None'}}
|
||||
{{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}}
|
||||
{{/if}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{{#if value}}
|
||||
{{#if isNotEmpty}}
|
||||
{{value}}
|
||||
{{else}}
|
||||
{{translate 'None'}}
|
||||
{{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}}
|
||||
{{/if}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{{#if value}}
|
||||
{{#if isNotEmpty}}
|
||||
{{value}} {{currencyValue}}
|
||||
{{else}}
|
||||
{{translate 'None'}}
|
||||
{{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}}
|
||||
{{/if}}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
{{#if value}}
|
||||
{{#if isNotEmpty}}
|
||||
<span title="{{value}} {{currencyValue}}">{{value}} {{currencyValue}}</span>
|
||||
{{else}}
|
||||
{{translate 'None'}}
|
||||
{{/if}}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
{{#if value}}
|
||||
<span title="{{currencySymbol}}{{value}}">{{currencySymbol}}{{value}}</span>
|
||||
{{else}}
|
||||
{{translate 'None'}}
|
||||
{{#if isNotEmpty}}
|
||||
<span title="{{currencySymbol}}{{value}}">{{currencySymbol}}{{value}}</span>
|
||||
{{/if}}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
{{#if value}}
|
||||
{{#if isNotEmpty}}
|
||||
<span title="{{value}} {{currencyValue}}">{{value}} {{currencyValue}}</span>
|
||||
{{else}}
|
||||
{{translate 'None'}}
|
||||
{{/if}}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{{#if isNotEmpty}}{{value}}{{else}}
|
||||
{{translate 'None'}}
|
||||
{{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}}
|
||||
{{/if}}
|
||||
4
client/res/templates/fields/link-multiple/list.tpl
Normal file
4
client/res/templates/fields/link-multiple/list.tpl
Normal file
@@ -0,0 +1,4 @@
|
||||
{{#if value}}
|
||||
{{{value}}}
|
||||
{{/if}}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{{#if isNotEmpty}}{{translateOption salutationValue field='salutationName' scope=scope}} {{firstValue}} {{lastValue}}{{else}}
|
||||
{{translate 'None'}}
|
||||
{{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}}
|
||||
{{/if}}
|
||||
@@ -1,5 +1,5 @@
|
||||
{{#if value}}
|
||||
<a href="{{url}}" target="_blank">{{value}}</a>
|
||||
{{else}}
|
||||
{{translate 'None'}}
|
||||
{{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}}
|
||||
{{/if}}
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
{{#if isNotEmpty}}{{value}}{{else}}{{translate 'None'}}{{/if}}
|
||||
{{#if isNotEmpty}}{{value}}{{else}}
|
||||
{{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}}
|
||||
{{/if}}
|
||||
@@ -4,7 +4,7 @@
|
||||
{{{avatar}}}
|
||||
</div>
|
||||
<div class="stream-head-text-container">
|
||||
<span class="text-muted"><span class="glyphicon glyphicon-envelope action" style="cursor: pointer;" title="{{translate 'View'}}" data-action="quickView" data-id="{{emailId}}" data-scope="Email"></span>
|
||||
<span class="text-muted"><span class="fas fa-envelope action" style="cursor: pointer;" title="{{translate 'View'}}" data-action="quickView" data-id="{{emailId}}" data-scope="Email"></span>
|
||||
{{{message}}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -50,6 +50,11 @@ Espo.define('model', [], function () {
|
||||
Dep.prototype.initialize.call(this);
|
||||
},
|
||||
|
||||
sync: function (method, model, options) {
|
||||
if (method === 'patch') options.type = 'PUT';
|
||||
return Dep.prototype.sync.call(this, method, model, options);
|
||||
},
|
||||
|
||||
set: function (key, val, options) {
|
||||
if (typeof key === 'object') {
|
||||
var o = key;
|
||||
|
||||
@@ -267,7 +267,7 @@ Espo.define('views/email/detail', ['views/detail', 'email-helper'], function (De
|
||||
}
|
||||
attributes.emailId = this.model.id;
|
||||
|
||||
var viewName = this.getMetadata().get('clientDefs.Contact.modalViews.detail') || 'Modals.Edit';
|
||||
var viewName = this.getMetadata().get('clientDefs.Contact.modalViews.detail') || 'views/modals/edit';
|
||||
|
||||
this.notify('Loading...');
|
||||
this.createView('quickCreate', viewName, {
|
||||
|
||||
@@ -52,45 +52,41 @@ Espo.define('views/fields/address', 'views/fields/base', function (Dep) {
|
||||
var data = Dep.prototype.data.call(this);
|
||||
data.ucName = Espo.Utils.upperCaseFirst(this.name);
|
||||
|
||||
data.postalCodeValue = this.model.get(this.postalCodeField);
|
||||
data.streetValue = this.model.get(this.streetField);
|
||||
data.cityValue = this.model.get(this.cityField);
|
||||
data.stateValue = this.model.get(this.stateField);
|
||||
data.countryValue = this.model.get(this.countryField);
|
||||
this.addressPartList.forEach(function (item) {
|
||||
var value = this.model.get(this[item + 'Field']);
|
||||
data[item + 'Value'] = value;
|
||||
}, this);
|
||||
|
||||
if (this.mode == 'detail' || this.mode == 'list') {
|
||||
data.formattedAddress = this.getFormattedAddress();
|
||||
}
|
||||
|
||||
data.isEmpty = !(data.postalCodeValue ||
|
||||
data.streetValue ||
|
||||
data.cityValue ||
|
||||
data.stateValue ||
|
||||
data.countryValue);
|
||||
var isNotEmpty = false;
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
setupSearch: function () {
|
||||
this.searchData.value = this.getSearchParamsData().value || this.searchParams.additionalValue;
|
||||
this.searchData.value = this.getSearchParamsData().value || this.searchParams.additionalValue;
|
||||
},
|
||||
|
||||
getFormattedAddress: function () {
|
||||
var postalCodeValue = this.model.get(this.postalCodeField);
|
||||
var streetValue = this.model.get(this.streetField);
|
||||
var cityValue = this.model.get(this.cityField);
|
||||
var stateValue = this.model.get(this.stateField);
|
||||
var countryValue = this.model.get(this.countryField);
|
||||
var isNotEmpty = false;
|
||||
var isSet = false;
|
||||
this.addressAttributeList.forEach(function (attribute) {
|
||||
isNotEmpty = isNotEmpty || this.model.get(attribute);
|
||||
isSet = isSet || this.model.has(attribute);
|
||||
}, this);
|
||||
|
||||
var isEmpty = !(
|
||||
postalCodeValue ||
|
||||
streetValue ||
|
||||
cityValue ||
|
||||
stateValue ||
|
||||
countryValue
|
||||
);
|
||||
var isEmpty = !isNotEmpty;
|
||||
|
||||
if (isEmpty) {
|
||||
if (this.mode === 'list') {
|
||||
return '';
|
||||
}
|
||||
if (!isSet) {
|
||||
return this.translate('...');
|
||||
}
|
||||
return this.translate('None');
|
||||
}
|
||||
|
||||
@@ -320,13 +316,18 @@ Espo.define('views/fields/address', 'views/fields/base', function (Dep) {
|
||||
}
|
||||
},
|
||||
|
||||
init: function () {
|
||||
this.postalCodeField = this.options.defs.name + 'PostalCode';
|
||||
this.streetField = this.options.defs.name + 'Street';
|
||||
this.stateField = this.options.defs.name + 'State';
|
||||
this.cityField = this.options.defs.name + 'City';
|
||||
this.countryField = this.options.defs.name + 'Country';
|
||||
Dep.prototype.init.call(this);
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
var actualAttributePartList = this.getMetadata().get(['fields', this.type, 'actualFields']) || [];
|
||||
this.addressAttributeList = [];
|
||||
this.addressPartList = [];
|
||||
actualAttributePartList.forEach(function (item) {
|
||||
var attribute = this.name + Espo.Utils.upperCaseFirst(item);
|
||||
this.addressAttributeList.push(attribute);
|
||||
this.addressPartList.push(item);
|
||||
this[item + 'Field'] = attribute;
|
||||
}, this);
|
||||
},
|
||||
|
||||
validateRequired: function () {
|
||||
@@ -397,7 +398,7 @@ Espo.define('views/fields/address', 'views/fields/base', function (Dep) {
|
||||
type: 'like',
|
||||
field: this.countryField,
|
||||
value: value + '%'
|
||||
},
|
||||
}
|
||||
],
|
||||
data: {
|
||||
value: value
|
||||
|
||||
@@ -32,7 +32,7 @@ Espo.define('views/fields/array', ['views/fields/base', 'lib!Selectize'], functi
|
||||
|
||||
type: 'array',
|
||||
|
||||
listTemplate: 'fields/array/detail',
|
||||
listTemplate: 'fields/array/list',
|
||||
|
||||
detailTemplate: 'fields/array/detail',
|
||||
|
||||
@@ -51,7 +51,8 @@ Espo.define('views/fields/array', ['views/fields/base', 'lib!Selectize'], functi
|
||||
translatedOptions: this.translatedOptions,
|
||||
hasOptions: this.params.options ? true : false,
|
||||
itemHtmlList: itemHtmlList,
|
||||
isEmpty: (this.selected || []).length === 0
|
||||
isEmpty: (this.selected || []).length === 0,
|
||||
valueIsSet: this.model.has(this.name)
|
||||
}, Dep.prototype.data.call(this));
|
||||
},
|
||||
|
||||
@@ -109,7 +110,7 @@ Espo.define('views/fields/array', ['views/fields/base', 'lib!Selectize'], functi
|
||||
}
|
||||
|
||||
if (this.options.customOptionList) {
|
||||
this.setOptionList(this.options.customOptionList);
|
||||
this.setOptionList(this.options.customOptionList, true);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -146,13 +147,21 @@ Espo.define('views/fields/array', ['views/fields/base', 'lib!Selectize'], functi
|
||||
|
||||
},
|
||||
|
||||
setOptionList: function (optionList) {
|
||||
setOptionList: function (optionList, silent) {
|
||||
if (!this.originalOptionList) {
|
||||
this.originalOptionList = this.params.options;
|
||||
}
|
||||
this.params.options = Espo.Utils.clone(optionList);
|
||||
|
||||
if (this.mode == 'edit') {
|
||||
if (this.mode == 'edit' && !silent) {
|
||||
var selectedOptionList = [];
|
||||
this.selected.forEach(function (option) {
|
||||
if (~optionList.indexOf(option)) {
|
||||
selectedOptionList.push(option);
|
||||
}
|
||||
}, this);
|
||||
this.selected = selectedOptionList;
|
||||
|
||||
if (this.isRendered()) {
|
||||
this.reRender();
|
||||
this.trigger('change');
|
||||
|
||||
@@ -32,7 +32,7 @@ Espo.define('views/fields/attachment-multiple', 'views/fields/base', function (D
|
||||
|
||||
type: 'attachmentMultiple',
|
||||
|
||||
listTemplate: 'fields/attachments-multiple/detail',
|
||||
listTemplate: 'fields/attachments-multiple/list',
|
||||
|
||||
detailTemplate: 'fields/attachments-multiple/detail',
|
||||
|
||||
@@ -40,6 +40,8 @@ Espo.define('views/fields/attachment-multiple', 'views/fields/base', function (D
|
||||
|
||||
searchTemplate: 'fields/link-multiple/search',
|
||||
|
||||
previewSize: 'medium',
|
||||
|
||||
nameHashName: null,
|
||||
|
||||
idsName: null,
|
||||
@@ -155,6 +157,8 @@ Espo.define('views/fields/attachment-multiple', 'views/fields/base', function (D
|
||||
this.idsName = this.name + 'Ids';
|
||||
this.foreignScope = 'Attachment';
|
||||
|
||||
this.previewSize = this.options.previewSize || this.params.previewSize || this.previewSize;
|
||||
|
||||
var self = this;
|
||||
|
||||
this.nameHash = _.clone(this.model.get(this.nameHashName)) || {};
|
||||
@@ -182,6 +186,12 @@ Espo.define('views/fields/attachment-multiple', 'views/fields/base', function (D
|
||||
this.listenTo(this.model, 'change:' + this.nameHashName, function () {
|
||||
this.nameHash = _.clone(this.model.get(this.nameHashName)) || {};
|
||||
}.bind(this));
|
||||
|
||||
this.once('remove', function () {
|
||||
if (this.resizeIsBeingListened) {
|
||||
$(window).off('resize.' + this.cid);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
setupSearch: function () {
|
||||
@@ -198,6 +208,11 @@ Espo.define('views/fields/attachment-multiple', 'views/fields/base', function (D
|
||||
this.$attachments.empty();
|
||||
},
|
||||
|
||||
handleResize: function () {
|
||||
var width = this.$el.width();
|
||||
this.$el.find('img.image-preview').css('maxWidth', width + 'px');
|
||||
},
|
||||
|
||||
deleteAttachment: function (id) {
|
||||
this.removeId(id);
|
||||
if (this.model.isNew()) {
|
||||
@@ -462,6 +477,16 @@ Espo.define('views/fields/attachment-multiple', 'views/fields/base', function (D
|
||||
var type = this.$el.find('select.search-type').val();
|
||||
this.handleSearchType(type);
|
||||
}
|
||||
|
||||
if (this.mode === 'detail') {
|
||||
if (this.previewSize === 'large') {
|
||||
this.handleResize();
|
||||
this.resizeIsBeingListened = true;
|
||||
$(window).on('resize.' + this.cid, function () {
|
||||
this.handleResize();
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
isTypeIsImage: function (type) {
|
||||
@@ -478,9 +503,8 @@ Espo.define('views/fields/attachment-multiple', 'views/fields/base', function (D
|
||||
name = Handlebars.Utils.escapeExpression(name);
|
||||
|
||||
var preview = name;
|
||||
|
||||
if (this.isTypeIsImage(type)) {
|
||||
preview = '<a data-action="showImagePreview" data-id="' + id + '" href="' + this.getImageUrl(id) + '"><img src="'+this.getImageUrl(id, 'medium')+'"></a>';
|
||||
preview = '<a data-action="showImagePreview" data-id="' + id + '" href="' + this.getImageUrl(id) + '"><img src="'+this.getImageUrl(id, this.previewSize)+'" class="image-preview"></a>';
|
||||
}
|
||||
return preview;
|
||||
},
|
||||
@@ -495,7 +519,13 @@ Espo.define('views/fields/attachment-multiple', 'views/fields/base', function (D
|
||||
for (var id in nameHash) {
|
||||
var type = typeHash[id] || false;
|
||||
var name = nameHash[id];
|
||||
if (this.showPreviews && ~this.previewTypeList.indexOf(type)) {
|
||||
if (
|
||||
this.showPreviews
|
||||
&&
|
||||
~this.previewTypeList.indexOf(type)
|
||||
&&
|
||||
(this.mode === 'detail' || this.mode === 'list' && this.showPreviewsInListMode)
|
||||
) {
|
||||
previews.push('<div class="attachment-preview">' + this.getDetailPreview(name, type, id) + '</div>');
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -153,6 +153,8 @@ Espo.define('views/fields/file', 'views/fields/link', function (Dep) {
|
||||
this.typeName = this.name + 'Type';
|
||||
this.foreignScope = 'Attachment';
|
||||
|
||||
this.previewSize = this.options.previewSize || this.params.previewSize || this.previewSize;
|
||||
|
||||
var sourceDefs = this.getMetadata().get(['clientDefs', 'Attachment', 'sourceDefs']) || {};
|
||||
|
||||
this.sourceList = Espo.Utils.clone(this.params.sourceList || []).filter(function (item) {
|
||||
@@ -181,6 +183,11 @@ Espo.define('views/fields/file', 'views/fields/link', function (Dep) {
|
||||
this.acceptAttribue = this.accept.join('|');
|
||||
}
|
||||
|
||||
this.once('remove', function () {
|
||||
if (this.resizeIsBeingListened) {
|
||||
$(window).off('resize.' + this.cid);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
afterRender: function () {
|
||||
@@ -219,6 +226,21 @@ Espo.define('views/fields/file', 'views/fields/link', function (Dep) {
|
||||
var type = this.$el.find('select.search-type').val();
|
||||
this.handleSearchType(type);
|
||||
}
|
||||
|
||||
if (this.mode === 'detail') {
|
||||
if (this.previewSize === 'large') {
|
||||
this.handleResize();
|
||||
this.resizeIsBeingListened = true;
|
||||
$(window).on('resize.' + this.cid, function () {
|
||||
this.handleResize();
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleResize: function () {
|
||||
var width = this.$el.width();
|
||||
this.$el.find('img.image-preview').css('maxWidth', width + 'px');
|
||||
},
|
||||
|
||||
getDetailPreview: function (name, type, id) {
|
||||
@@ -229,7 +251,7 @@ Espo.define('views/fields/file', 'views/fields/link', function (Dep) {
|
||||
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 + '"></a>';
|
||||
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;
|
||||
},
|
||||
|
||||
@@ -38,16 +38,7 @@ Espo.define('views/fields/image', 'views/fields/file', function (Dep) {
|
||||
|
||||
defaultType: 'image/jpeg',
|
||||
|
||||
previewSize: 'small',
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
if ('previewSize' in this.params && this.params.previewSize) {
|
||||
this.previewSize = this.params.previewSize;
|
||||
}
|
||||
}
|
||||
previewSize: 'small'
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ Espo.define('views/fields/int', 'views/fields/base', function (Dep) {
|
||||
if (this.model.get(this.name) !== null && typeof this.model.get(this.name) !== 'undefined') {
|
||||
data.isNotEmpty = true;
|
||||
}
|
||||
data.valueIsSet = this.model.has(this.name);
|
||||
return data;
|
||||
},
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Espo.define('views/fields/link-multiple', 'views/fields/base', function (Dep) {
|
||||
|
||||
type: 'linkMultiple',
|
||||
|
||||
listTemplate: 'fields/link-multiple/detail',
|
||||
listTemplate: 'fields/link-multiple/list',
|
||||
|
||||
detailTemplate: 'fields/link-multiple/detail',
|
||||
|
||||
@@ -126,7 +126,9 @@ Espo.define('views/fields/link-multiple', 'views/fields/base', function (Dep) {
|
||||
boolFilterList: this.getSelectBoolFilterList(),
|
||||
primaryFilterName: this.getSelectPrimaryFilterName(),
|
||||
multiple: true,
|
||||
createAttributes: (this.mode === 'edit') ? this.getCreateAttributes() : null
|
||||
createAttributes: (this.mode === 'edit') ? this.getCreateAttributes() : null,
|
||||
mandatorySelectAttributeList: this.mandatorySelectAttributeList,
|
||||
forceSelectAllAttributes: this.forceSelectAllAttributes
|
||||
}, function (dialog) {
|
||||
dialog.render();
|
||||
self.notify(false);
|
||||
@@ -359,16 +361,19 @@ Espo.define('views/fields/link-multiple', 'views/fields/base', function (Dep) {
|
||||
var type = this.$el.find('select.search-type').val();
|
||||
|
||||
if (type === 'anyOf') {
|
||||
var values = this.ids || [];
|
||||
var idList = this.ids || [];
|
||||
|
||||
var data = {
|
||||
type: 'linkedWith',
|
||||
value: this.ids || [],
|
||||
value: idList,
|
||||
nameHash: this.nameHash,
|
||||
data: {
|
||||
type: type
|
||||
}
|
||||
};
|
||||
if (!idList.length) {
|
||||
data.value = null;
|
||||
}
|
||||
return data;
|
||||
} else if (type === 'noneOf') {
|
||||
var values = this.ids || [];
|
||||
|
||||
@@ -133,7 +133,9 @@ Espo.define('views/fields/link-parent', 'views/fields/base', function (Dep) {
|
||||
filters: this.getSelectFilters(),
|
||||
boolFilterList: this.getSelectBoolFilterList(),
|
||||
primaryFilterName: this.getSelectPrimaryFilterName(),
|
||||
createAttributes: (this.mode === 'edit') ? this.getCreateAttributes() : null
|
||||
createAttributes: (this.mode === 'edit') ? this.getCreateAttributes() : null,
|
||||
mandatorySelectAttributeList: this.getMandatorySelectAttributeList(),
|
||||
forceSelectAllAttributes: this.isForceSelectAllAttributes()
|
||||
}, function (dialog) {
|
||||
dialog.render();
|
||||
Espo.Ui.notify(false);
|
||||
@@ -181,6 +183,14 @@ Espo.define('views/fields/link-parent', 'views/fields/base', function (Dep) {
|
||||
this.trigger('change');
|
||||
},
|
||||
|
||||
getMandatorySelectAttributeList: function () {
|
||||
this.mandatorySelectAttributeList;
|
||||
},
|
||||
|
||||
isForceSelectAllAttributes: function () {
|
||||
this.forceSelectAllAttributes;
|
||||
},
|
||||
|
||||
getAutocompleteUrl: function () {
|
||||
var url = this.foreignScope + '?sortBy=name&maxCount=' + this.AUTOCOMPLETE_RESULT_MAX_COUNT;
|
||||
var boolList = this.getSelectBoolFilterList();
|
||||
|
||||
@@ -116,7 +116,9 @@ Espo.define('views/fields/link', 'views/fields/base', function (Dep) {
|
||||
filters: this.getSelectFilters(),
|
||||
boolFilterList: this.getSelectBoolFilterList(),
|
||||
primaryFilterName: this.getSelectPrimaryFilterName(),
|
||||
createAttributes: (this.mode === 'edit') ? this.getCreateAttributes() : null
|
||||
createAttributes: (this.mode === 'edit') ? this.getCreateAttributes() : null,
|
||||
mandatorySelectAttributeList: this.mandatorySelectAttributeList,
|
||||
forceSelectAllAttributes: this.forceSelectAllAttributes
|
||||
}, function (view) {
|
||||
view.render();
|
||||
this.notify(false);
|
||||
|
||||
@@ -32,7 +32,7 @@ Espo.define('views/fields/multi-enum', ['views/fields/array', 'lib!Selectize'],
|
||||
|
||||
type: 'multiEnum',
|
||||
|
||||
listTemplate: 'fields//array/detail',
|
||||
listTemplate: 'fields//array/list',
|
||||
|
||||
detailTemplate: 'fields/array/detail',
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ Espo.define('views/fields/person-name', 'views/fields/varchar', function (Dep) {
|
||||
data.firstMaxLength = this.model.getFieldParam(this.firstField, 'maxLength');
|
||||
data.lastMaxLength = this.model.getFieldParam(this.lastField, 'maxLength');
|
||||
|
||||
data.valueIsSet = this.model.has(this.firstField) || this.model.has(this.lastField);
|
||||
|
||||
if (this.mode === 'detail') {
|
||||
data.isNotEmpty = !!data.firstValue || !!data.lastValue || !!data.salutationValue;
|
||||
} else if (this.mode === 'list' || this.mode === 'listLink') {
|
||||
|
||||
@@ -26,15 +26,15 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('Views.Fields.Url', 'Views.Fields.Varchar', function (Dep) {
|
||||
Espo.define('views/fields/url', 'views/fields/varchar', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
type: 'url',
|
||||
|
||||
listTemplate: 'fields.url.list',
|
||||
listTemplate: 'fields/url/list',
|
||||
|
||||
detailTemplate: 'fields.url.detail',
|
||||
detailTemplate: 'fields/url/detail',
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
@@ -58,6 +58,8 @@ Espo.define('views/fields/varchar', 'views/fields/base', function (Dep) {
|
||||
) {
|
||||
data.isNotEmpty = true;
|
||||
}
|
||||
data.valueIsSet = this.model.has(this.name);
|
||||
|
||||
if (this.mode === 'search') {
|
||||
if (typeof this.searchParams.value === 'string') {
|
||||
this.searchData.value = this.searchParams.value;
|
||||
|
||||
@@ -32,8 +32,14 @@ Espo.define('views/global-search/panel', 'view', function (Dep) {
|
||||
|
||||
template: 'global-search/panel',
|
||||
|
||||
afterRender: function () {
|
||||
setup: function () {
|
||||
this.maxSize = this.getConfig().get('globalSearchMaxSize') || 10;
|
||||
|
||||
this.navbarPanelHeightSpace = this.getThemeManager().getParam('navbarPanelHeightSpace') || 100;
|
||||
this.navbarPanelBodyMaxHeight = this.getThemeManager().getParam('navbarPanelBodyMaxHeight') || 600;
|
||||
},
|
||||
|
||||
afterRender: function () {
|
||||
this.listenToOnce(this.collection, 'sync', function () {
|
||||
this.createView('list', 'views/record/list-expanded', {
|
||||
el: this.options.el + ' .list-container',
|
||||
@@ -46,7 +52,7 @@ Espo.define('views/global-search/panel', 'view', function (Dep) {
|
||||
view: 'views/global-search/name-field',
|
||||
params: {
|
||||
containerEl: this.options.el
|
||||
},
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
@@ -59,12 +65,18 @@ Espo.define('views/global-search/panel', 'view', function (Dep) {
|
||||
}, function (view) {
|
||||
view.render();
|
||||
});
|
||||
}.bind(this));
|
||||
this.collection.maxSize = this.getConfig().get('recordsPerPageSmall') || 10;
|
||||
}, this);
|
||||
|
||||
this.collection.reset();
|
||||
this.collection.maxSize = this.maxSize;
|
||||
this.collection.fetch();
|
||||
|
||||
var windowHeight = $(window).height();
|
||||
if (windowHeight - this.navbarPanelBodyMaxHeight < this.navbarPanelHeightSpace) {
|
||||
var maxHeight = windowHeight - this.navbarPanelHeightSpace;
|
||||
this.$el.find('> .panel > .panel-body').css('maxHeight', maxHeight + 'px');
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -55,6 +55,10 @@ Espo.define('views/modals/image-preview', 'views/modal', function (Dep) {
|
||||
this.navigationEnabled = (this.options.imageList && this.options.imageList.length > 1);
|
||||
|
||||
this.imageList = this.options.imageList || [];
|
||||
|
||||
this.once('remove', function () {
|
||||
$(window).off('resize.image-review');
|
||||
}, this);
|
||||
},
|
||||
|
||||
getImageUrl: function () {
|
||||
@@ -90,7 +94,8 @@ Espo.define('views/modals/image-preview', 'views/modal', function (Dep) {
|
||||
$img.css('maxWidth', width);
|
||||
}.bind(this);
|
||||
|
||||
$(window).on('resize', function () {
|
||||
$(window).off('resize.image-review');
|
||||
$(window).on('resize.image-review', function () {
|
||||
manageSize();
|
||||
});
|
||||
|
||||
|
||||
@@ -225,15 +225,33 @@ Espo.define('views/modals/select-records', ['views/modal', 'search-manager'], fu
|
||||
}, this);
|
||||
}
|
||||
|
||||
view.getSelectAttributeList(function (selectAttributeList) {
|
||||
if (selectAttributeList) {
|
||||
this.collection.data.select = selectAttributeList.join(',');
|
||||
}
|
||||
if (this.options.forceSelectAllAttributes || this.forceSelectAllAttributes) {
|
||||
this.listenToOnce(view, 'after:build-rows', function () {
|
||||
this.wait(false);
|
||||
}, this);
|
||||
this.collection.fetch();
|
||||
}.bind(this));
|
||||
} else {
|
||||
view.getSelectAttributeList(function (selectAttributeList) {
|
||||
if (!~selectAttributeList.indexOf('name')) {
|
||||
selectAttributeList.push('name');
|
||||
}
|
||||
|
||||
var mandatorySelectAttributeList = this.options.mandatorySelectAttributeList || this.mandatorySelectAttributeList || [];
|
||||
mandatorySelectAttributeList.forEach(function (attribute) {
|
||||
if (!~selectAttributeList.indexOf(attribute)) {
|
||||
selectAttributeList.push(attribute);
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (selectAttributeList) {
|
||||
this.collection.data.select = selectAttributeList.join(',');
|
||||
}
|
||||
this.listenToOnce(view, 'after:build-rows', function () {
|
||||
this.wait(false);
|
||||
}, this);
|
||||
this.collection.fetch();
|
||||
}.bind(this));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ Espo.define('views/notification/fields/container', 'views/fields/base', function
|
||||
isUserStream: true,
|
||||
el: this.params.containerEl + ' li[data-id="' + this.model.id + '"]',
|
||||
onlyContent: true,
|
||||
isNotification: true
|
||||
});
|
||||
this.wait(false);
|
||||
}, this);
|
||||
@@ -88,6 +89,7 @@ Espo.define('views/notification/fields/container', 'views/fields/base', function
|
||||
isUserStream: true,
|
||||
el: this.params.containerEl + ' li[data-id="' + this.model.id + '"]',
|
||||
onlyContent: true,
|
||||
isNotification: true
|
||||
});
|
||||
this.wait(false);
|
||||
}, this);
|
||||
|
||||
@@ -51,9 +51,12 @@ Espo.define('views/notification/panel', 'view', function (Dep) {
|
||||
this.wait(true);
|
||||
this.getCollectionFactory().create('Notification', function (collection) {
|
||||
this.collection = collection;
|
||||
collection.maxSize = 5;
|
||||
collection.maxSize = this.getConfig().get('notificationsMaxSize') || 5;
|
||||
this.wait(false);
|
||||
}, this);
|
||||
|
||||
this.navbarPanelHeightSpace = this.getThemeManager().getParam('navbarPanelHeightSpace') || 100;
|
||||
this.navbarPanelBodyMaxHeight = this.getThemeManager().getParam('navbarPanelBodyMaxHeight') || 600;
|
||||
},
|
||||
|
||||
afterRender: function () {
|
||||
@@ -71,7 +74,7 @@ Espo.define('views/notification/panel', 'view', function (Dep) {
|
||||
view: 'views/notification/fields/container',
|
||||
params: {
|
||||
containerEl: this.options.el
|
||||
},
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
@@ -86,8 +89,13 @@ Espo.define('views/notification/panel', 'view', function (Dep) {
|
||||
});
|
||||
}, this);
|
||||
this.collection.fetch();
|
||||
|
||||
var windowHeight = $(window).height();
|
||||
if (windowHeight - this.navbarPanelBodyMaxHeight < this.navbarPanelHeightSpace) {
|
||||
var maxHeight = windowHeight - this.navbarPanelHeightSpace;
|
||||
this.$el.find('> .panel > .panel-body').css('maxHeight', maxHeight + 'px');
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -42,7 +42,18 @@ Espo.define('views/portal-user/list', 'views/list', function (Dep) {
|
||||
this.createView('modal', viewName, {
|
||||
scope: 'Contact',
|
||||
primaryFilterName: 'notPortalUsers',
|
||||
createButton: false
|
||||
createButton: false,
|
||||
mandatorySelectAttributeList: [
|
||||
'salutationName',
|
||||
'firstName',
|
||||
'lastName',
|
||||
'accountName',
|
||||
'accountId',
|
||||
'emailAddress',
|
||||
'emailAddressData',
|
||||
'phoneNumber',
|
||||
'phoneNumberData'
|
||||
]
|
||||
}, function (view) {
|
||||
view.render();
|
||||
|
||||
|
||||
@@ -30,7 +30,9 @@ Espo.define('views/stream/fields/attachment-multiple', 'views/fields/attachment-
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
showPreviews: true
|
||||
showPreviews: true,
|
||||
|
||||
showPreviewsInListMode: true,
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -118,9 +118,9 @@ Espo.define('views/stream/note', 'view', function (Dep) {
|
||||
return string;
|
||||
},
|
||||
|
||||
createField: function (name, type, params, view) {
|
||||
createField: function (name, type, params, view, options) {
|
||||
type = type || this.model.getFieldType(name) || 'base';
|
||||
this.createView(name, view || this.getFieldManager().getViewName(type), {
|
||||
var o = {
|
||||
model: this.model,
|
||||
defs: {
|
||||
name: name,
|
||||
@@ -128,7 +128,13 @@ Espo.define('views/stream/note', 'view', function (Dep) {
|
||||
},
|
||||
el: this.options.el + ' .cell-' + name,
|
||||
mode: 'list'
|
||||
});
|
||||
};
|
||||
if (options) {
|
||||
for (var i in options) {
|
||||
o[i] = options[i];
|
||||
}
|
||||
}
|
||||
this.createView(name, view || this.getFieldManager().getViewName(type), o);
|
||||
},
|
||||
|
||||
isMale: function () {
|
||||
|
||||
@@ -46,7 +46,9 @@ Espo.define('views/stream/notes/mention-in-post', 'views/stream/note', function
|
||||
this.createField('post', null, null, 'views/stream/fields/post');
|
||||
}
|
||||
if ((this.model.get('attachmentsIds') || []).length) {
|
||||
this.createField('attachments', 'attachmentMultiple', {}, 'views/stream/fields/attachment-multiple');
|
||||
this.createField('attachments', 'attachmentMultiple', {}, 'views/stream/fields/attachment-multiple', {
|
||||
previewSize: this.options.isNotification ? 'small' : null
|
||||
});
|
||||
}
|
||||
|
||||
var data = this.model.get('data');
|
||||
|
||||
@@ -49,7 +49,9 @@ Espo.define('views/stream/notes/post', 'views/stream/note', function (Dep) {
|
||||
setup: function () {
|
||||
|
||||
this.createField('post', null, null, 'views/stream/fields/post');
|
||||
this.createField('attachments', 'attachmentMultiple', {}, 'views/stream/fields/attachment-multiple');
|
||||
this.createField('attachments', 'attachmentMultiple', {}, 'views/stream/fields/attachment-multiple', {
|
||||
previewSize: this.options.isNotification ? 'small' : 'medium'
|
||||
});
|
||||
|
||||
this.isInternal = this.model.get('isInternal');
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@ Espo.define('views/user/detail', 'views/detail', function (Dep) {
|
||||
name: 'preferences',
|
||||
label: 'Preferences',
|
||||
style: 'default',
|
||||
action: "preferences"
|
||||
action: "preferences",
|
||||
link: '#Preferences/edit/' + this.getUser().id
|
||||
});
|
||||
|
||||
if (!this.model.get('isPortalUser')) {
|
||||
@@ -47,7 +48,8 @@ Espo.define('views/user/detail', 'views/detail', function (Dep) {
|
||||
name: 'emailAccounts',
|
||||
label: "Email Accounts",
|
||||
style: 'default',
|
||||
action: "emailAccounts"
|
||||
action: "emailAccounts",
|
||||
link: '#EmailAccount/list/userId=' + this.model.id + '&userName=' + encodeURIComponent(this.model.get('name'))
|
||||
});
|
||||
}
|
||||
|
||||
@@ -56,7 +58,8 @@ Espo.define('views/user/detail', 'views/detail', function (Dep) {
|
||||
name: 'externalAccounts',
|
||||
label: 'External Accounts',
|
||||
style: 'default',
|
||||
action: "externalAccounts"
|
||||
action: "externalAccounts",
|
||||
link: '#ExternalAccount'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"ext-mbstring": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-exif": "*",
|
||||
"doctrine/dbal": "2.*",
|
||||
"slim/slim": "2.6.2",
|
||||
"mtdowling/cron-expression": "1.0.*",
|
||||
|
||||
@@ -356,9 +356,9 @@ body > #header .navbar-brand span.home-icon {
|
||||
}
|
||||
|
||||
@media (min-width: @screen-lg-min) {
|
||||
.container {
|
||||
max-width: 1580px;
|
||||
}
|
||||
.container {
|
||||
max-width: @container-max-width;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -557,7 +557,8 @@ ul.dropdown-menu > li.checkbox:last-child {
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.field .link-container > .list-group-item.link-with-role a {
|
||||
.field .link-container > .list-group-item.link-with-role > a,
|
||||
.field .link-container > .list-group-item.link-with-role > div > a {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ body > #header .navbar-brand span.home-icon {
|
||||
}
|
||||
|
||||
@media (min-width: @screen-lg-min) {
|
||||
.container {
|
||||
max-width: 1366px;
|
||||
}
|
||||
.container {
|
||||
max-width: @container-max-width;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,10 +137,12 @@
|
||||
|
||||
@panel-border-width: 2px;
|
||||
|
||||
@navbar-panel-body-max-height: 350px;
|
||||
@navbar-panel-body-max-height: 600px;
|
||||
|
||||
@form-group-margin-bottom: 12px;
|
||||
|
||||
@modal-title-line-height: floor(@font-size-h4 * @line-height-base);
|
||||
|
||||
@navbar-color-border-width: 4px;
|
||||
|
||||
@container-max-width: 1800px;
|
||||
|
||||
@@ -27,43 +27,33 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
return array(
|
||||
|
||||
return [
|
||||
'apiPath' => '/api/v1',
|
||||
|
||||
'requirements' => array(
|
||||
'requirements' => [
|
||||
'phpVersion' => '5.6',
|
||||
|
||||
'phpRequires' => array(
|
||||
'JSON',
|
||||
'phpRequires' => [
|
||||
'json',
|
||||
'openssl',
|
||||
'pdo_mysql'
|
||||
),
|
||||
|
||||
'phpRecommendations' => array(
|
||||
'pdo_mysql',
|
||||
'mbstring',
|
||||
'zip',
|
||||
'gd',
|
||||
'mbstring',
|
||||
],
|
||||
'phpRecommendations' => [
|
||||
'curl',
|
||||
'xml',
|
||||
'exif',
|
||||
'max_execution_time' => 180,
|
||||
'max_input_time' => 180,
|
||||
'memory_limit' => '256M',
|
||||
'post_max_size' => '20M',
|
||||
'upload_max_filesize' => '20M',
|
||||
),
|
||||
|
||||
],
|
||||
'mysqlVersion' => '5.5.3',
|
||||
'mysqlRequires' => array(
|
||||
|
||||
),
|
||||
|
||||
'mysqlRecommendations' => array(
|
||||
|
||||
),
|
||||
),
|
||||
|
||||
'rewriteRules' => array(
|
||||
'mysqlRequires' => [],
|
||||
'mysqlRecommendations' => [],
|
||||
],
|
||||
'rewriteRules' => [
|
||||
'APACHE1' => 'a2enmod rewrite
|
||||
service apache2 restart',
|
||||
'APACHE2' => '<Directory /PATH_TO_ESPO/>
|
||||
@@ -131,10 +121,9 @@ service apache2 restart',
|
||||
deny all;
|
||||
}
|
||||
}',
|
||||
),
|
||||
],
|
||||
|
||||
'blog' => 'http://blog.espocrm.com',
|
||||
'twitter' => 'https://twitter.com/espocrm',
|
||||
'forum' => 'http://forum.espocrm.com',
|
||||
|
||||
);
|
||||
];
|
||||
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell cell-website pull-left" align="left">
|
||||
<label class="field-label-website control-label">{$langs['fields']['Choose your language']}:</label>
|
||||
<label class="field-label-website control-label">{$langs['fields']['Choose your language']}</label>
|
||||
<div class="field field-website">
|
||||
<select name="user-lang" class="form-control">
|
||||
{foreach from=$languageList item=lbl key=val}
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell cell-website col-sm-12 form-group">
|
||||
<input class="btn btn-default" type="checkbox" name="license-agree" id="license-agree" value="1" {if $fields['license-agree'].value}checked="checked"{/if}>
|
||||
<label class="point-lbl" for="license-agree"> {$langs['labels']['I accept the agreement']}</label>
|
||||
<div class="cell cell-website form-group">
|
||||
<input class="btn btn-default" type="checkbox" name="license-agree" id="license-agree" class="input-checkbox" value="1" {if $fields['license-agree'].value}checked="checked"{/if}>
|
||||
<label class="point-lbl" for="license-agree">{$langs['labels']['I accept the agreement']}</label>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -71,10 +71,6 @@ select[name="user-lang"] {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
input[type=checkbox].btn-default {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.cron-help {
|
||||
margin: 20px;
|
||||
}
|
||||
@@ -170,4 +166,9 @@ span.ok {
|
||||
@-moz-keyframes left {
|
||||
from { -moz-transform: rotate(0deg);}
|
||||
to { -moz-transform: rotate(360deg);}
|
||||
}
|
||||
|
||||
#license-agree {
|
||||
margin-right: 5px;
|
||||
margin-top: -1px;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "espocrm",
|
||||
"version": "5.3.4",
|
||||
"version": "5.3.6",
|
||||
"description": "",
|
||||
"main": "index.php",
|
||||
"repository": {
|
||||
|
||||
@@ -35,6 +35,7 @@ use Espo\Entities\Post;
|
||||
use Espo\Entities\Comment;
|
||||
use Espo\Entities\Tag;
|
||||
use Espo\Entities\Note;
|
||||
use Espo\Entities\Job;
|
||||
|
||||
require_once 'tests/unit/testData/DB/Entities.php';
|
||||
require_once 'tests/unit/testData/DB/MockPDO.php';
|
||||
@@ -348,6 +349,34 @@ class DBMapperTest extends \PHPUnit\Framework\TestCase
|
||||
$this->db->update($this->post);
|
||||
}
|
||||
|
||||
public function testUpdateArray1()
|
||||
{
|
||||
$query = "UPDATE `job` SET `array` = '[\"2\",\"1\"]' WHERE job.id = '1' AND job.deleted = '0'";
|
||||
|
||||
$this->mockQuery($query, true);
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->id = '1';
|
||||
$job->setFetched('array', ['1', '2']);
|
||||
$job->set('array', ['2', '1']);
|
||||
|
||||
$this->db->update($job);
|
||||
}
|
||||
|
||||
public function testUpdateArray2()
|
||||
{
|
||||
$query = "UPDATE `job` SET `array` = NULL WHERE job.id = '1' AND job.deleted = '0'";
|
||||
|
||||
$this->mockQuery($query, true);
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->id = '1';
|
||||
$job->setFetched('array', ['1', '2']);
|
||||
$job->set('array', null);
|
||||
|
||||
$this->db->update($job);
|
||||
}
|
||||
|
||||
public function testRemoveRelationHasMany()
|
||||
{
|
||||
$query = "UPDATE `comment` SET post_id = NULL WHERE comment.deleted = '0' AND comment.id = '100'";
|
||||
@@ -448,6 +477,5 @@ class DBMapperTest extends \PHPUnit\Framework\TestCase
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
201
tests/unit/Espo/ORM/EntityTest.php
Normal file
201
tests/unit/Espo/ORM/EntityTest.php
Normal file
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2018 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://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.
|
||||
************************************************************************/
|
||||
|
||||
use Espo\ORM\DB\MysqlMapper;
|
||||
use Espo\ORM\DB\Query\Mysql as Query;
|
||||
use Espo\ORM\EntityFactory;
|
||||
|
||||
|
||||
require_once 'tests/unit/testData/DB/Entities.php';
|
||||
|
||||
class EntityTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public function testIsAttributeChanged()
|
||||
{
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('string', 'test');
|
||||
$this->assertFalse($job->isAttributeChanged('string'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('string', 'test');
|
||||
$job->set('string', 'hello');
|
||||
$this->assertTrue($job->isAttributeChanged('string'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->set('string', 'hello');
|
||||
$this->assertTrue($job->isAttributeChanged('string'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->set('string', null);
|
||||
$this->assertTrue($job->isAttributeChanged('string'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('array', ['1', '2']);
|
||||
$job->set('array', ['2', '1']);
|
||||
$this->assertTrue($job->isAttributeChanged('array'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('array', ['1', '2']);
|
||||
$job->set('array', ['1', '2']);
|
||||
$this->assertFalse($job->isAttributeChanged('array'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('array', ['1', '2']);
|
||||
$job->set('array', ['1', 2]);
|
||||
$this->assertTrue($job->isAttributeChanged('array'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('array', [
|
||||
(object) ['1' => 'v1']
|
||||
]);
|
||||
$job->set('array', [
|
||||
(object) ['1' => 'v1']
|
||||
]);
|
||||
$this->assertFalse($job->isAttributeChanged('array'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('array', [
|
||||
(object) ['k1' => 'v1']
|
||||
]);
|
||||
$job->set('array', [
|
||||
(object) ['k1' => 'v2']
|
||||
]);
|
||||
$this->assertTrue($job->isAttributeChanged('array'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('array', [
|
||||
(object) ['k1' => 'v1']
|
||||
]);
|
||||
$job->set('array', [
|
||||
(object) ['k1' => 'v1', 'k2' => 'v2'],
|
||||
]);
|
||||
$this->assertTrue($job->isAttributeChanged('array'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('array', ['1', '2']);
|
||||
$job->set('array', ['1', '2', '3']);
|
||||
$this->assertTrue($job->isAttributeChanged('array'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->set('array', ['1', '2', '3']);
|
||||
$this->assertTrue($job->isAttributeChanged('array'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->set('array', null);
|
||||
$this->assertTrue($job->isAttributeChanged('array'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('array', null);
|
||||
$this->assertFalse($job->isAttributeChanged('array'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('arrayUnordered', ['1', '2']);
|
||||
$job->set('arrayUnordered', ['2', '1']);
|
||||
$this->assertFalse($job->isAttributeChanged('arrayUnordered'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('arrayUnordered', ['1', '2']);
|
||||
$job->set('arrayUnordered', ['1', '2']);
|
||||
$this->assertFalse($job->isAttributeChanged('arrayUnordered'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('arrayUnordered', ['1', '2']);
|
||||
$job->set('arrayUnordered', ['1', '2', '3']);
|
||||
$this->assertTrue($job->isAttributeChanged('arrayUnordered'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('arrayUnordered', ['1', '2']);
|
||||
$job->set('arrayUnordered', null);
|
||||
$this->assertTrue($job->isAttributeChanged('arrayUnordered'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('object', (object) ['1' => 'value-1']);
|
||||
$job->set('object', (object) ['1' => 'value-1']);
|
||||
$this->assertFalse($job->isAttributeChanged('object'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('object', (object) ['1' => 'value-1']);
|
||||
$job->set('object', ['1' => 'value-1']);
|
||||
$this->assertTrue($job->isAttributeChanged('object'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('object', (object) ['1' => '1']);
|
||||
$job->set('object', (object) ['1' => 1]);
|
||||
$this->assertTrue($job->isAttributeChanged('object'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('object', (object) [
|
||||
'k1' => (object) [
|
||||
'k11' => 'v1'
|
||||
]
|
||||
]);
|
||||
$job->set('object', (object) [
|
||||
'k1' => (object) [
|
||||
'k11' => 'v2'
|
||||
]
|
||||
]);
|
||||
$this->assertTrue($job->isAttributeChanged('object'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('object', (object) [
|
||||
'k1' => [
|
||||
'k11' => 'v1'
|
||||
]
|
||||
]);
|
||||
$job->set('object', (object) [
|
||||
'k1' => (object) [
|
||||
'k11' => 'v1'
|
||||
]
|
||||
]);
|
||||
$this->assertTrue($job->isAttributeChanged('object'));
|
||||
|
||||
$job = new \Espo\Entities\Job();
|
||||
$job->setFetched('object', [
|
||||
'k1' => [
|
||||
'k11' => 'v1'
|
||||
]
|
||||
]);
|
||||
$job->set('object', (object) [
|
||||
'k1' => (object) [
|
||||
'k11' => 'v1'
|
||||
]
|
||||
]);
|
||||
$this->assertTrue($job->isAttributeChanged('object'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -242,3 +242,32 @@ class Article extends TEntity
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
class Job extends TEntity
|
||||
{
|
||||
public $fields = array(
|
||||
'id' => array(
|
||||
'type' => Entity::ID
|
||||
),
|
||||
'string' => array(
|
||||
'type' => Entity::VARCHAR,
|
||||
'len' => 50
|
||||
),
|
||||
'array' => array(
|
||||
'type' => Entity::JSON_ARRAY
|
||||
),
|
||||
'arrayUnordered' => array(
|
||||
'type' => Entity::JSON_ARRAY,
|
||||
'isUnordered' => true
|
||||
),
|
||||
'object' => array(
|
||||
'type' => Entity::JSON_OBJECT
|
||||
),
|
||||
'deleted' => array(
|
||||
'type' => Entity::BOOL,
|
||||
'default' => 0
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user