mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-06 20:17:00 +00:00
Compare commits
290 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
741a6d5dab | ||
|
|
0c0a602330 | ||
|
|
7d13018eba | ||
|
|
44c65c0117 | ||
|
|
e9e758c4b3 | ||
|
|
7e7acb8d28 | ||
|
|
1ab897db28 | ||
|
|
1a990850ca | ||
|
|
36e360e167 | ||
|
|
9ffdb1a1f0 | ||
|
|
64b15f9282 | ||
|
|
e8ebe51f1c | ||
|
|
ec2a7d2f48 | ||
|
|
6782e7c15c | ||
|
|
3c73e3e8cf | ||
|
|
4ab7d19776 | ||
|
|
34e33bd13a | ||
|
|
49fa22fa3d | ||
|
|
10fcd79155 | ||
|
|
6cdc8f2823 | ||
|
|
d611ebfc86 | ||
|
|
599a7c6080 | ||
|
|
4c21f1192d | ||
|
|
63e78baf21 | ||
|
|
fa2c689a34 | ||
|
|
a53b440b8b | ||
|
|
8189832af2 | ||
|
|
135f869e1a | ||
|
|
2d56525a25 | ||
|
|
03773dd929 | ||
|
|
5b8dba68f3 | ||
|
|
f63c75e18d | ||
|
|
6dd0bd8b90 | ||
|
|
94e86f875a | ||
|
|
b582b20003 | ||
|
|
e58e82eea1 | ||
|
|
dddc4feda8 | ||
|
|
a65421a268 | ||
|
|
b6696dcc26 | ||
|
|
4e3d8fb98f | ||
|
|
e0aaff932e | ||
|
|
17ea760851 | ||
|
|
f3d11aede3 | ||
|
|
8053d65f33 | ||
|
|
01809d2cc3 | ||
|
|
ac8e3d1a69 | ||
|
|
b669ccf733 | ||
|
|
8c42c6bf0b | ||
|
|
97bdd22795 | ||
|
|
0f3cd7913c | ||
|
|
502cfc8d76 | ||
|
|
d31e826305 | ||
|
|
28a62a2581 | ||
|
|
deff6bad36 | ||
|
|
f2bc80b7d9 | ||
|
|
b5b5cac0ac | ||
|
|
308f30510b | ||
|
|
574513a9c8 | ||
|
|
f37bc7d46b | ||
|
|
9f5db434df | ||
|
|
1c8abd6e36 | ||
|
|
c95fcd6fbd | ||
|
|
e6009366e8 | ||
|
|
286502d872 | ||
|
|
0749bdc006 | ||
|
|
72ef137dbe | ||
|
|
f624bdef5c | ||
|
|
9730680e41 | ||
|
|
c59fa40615 | ||
|
|
4dc08dd37c | ||
|
|
e76c7564dc | ||
|
|
802bac82f0 | ||
|
|
c64cc13e4c | ||
|
|
30be62eabe | ||
|
|
1c1703b349 | ||
|
|
6916f3242c | ||
|
|
d2630a5c3f | ||
|
|
3e02776fcd | ||
|
|
376bfe63e0 | ||
|
|
950a3b4703 | ||
|
|
2f5ffb7421 | ||
|
|
043ef8ef3e | ||
|
|
a959a2deaf | ||
|
|
65a3f4e5f3 | ||
|
|
97355ad024 | ||
|
|
99300d2d61 | ||
|
|
e070d9d9f1 | ||
|
|
8f9bb79978 | ||
|
|
405a5c29df | ||
|
|
4f2a2b290b | ||
|
|
fd5218c10b | ||
|
|
73ab4aa42e | ||
|
|
66a60b1257 | ||
|
|
c975954944 | ||
|
|
86799ed742 | ||
|
|
1da6eca3be | ||
|
|
a462158582 | ||
|
|
152b8991d3 | ||
|
|
5adcf013d7 | ||
|
|
9d6401cbd3 | ||
|
|
9f178bb467 | ||
|
|
f3b2cc9bcb | ||
|
|
b18a8c1b2b | ||
|
|
30dd7e560b | ||
|
|
ca35a4df75 | ||
|
|
fe0a6d1a8b | ||
|
|
f9223087df | ||
|
|
f3980ef9a1 | ||
|
|
93553d18fc | ||
|
|
e35561093d | ||
|
|
b0742aa0c6 | ||
|
|
efad2b142a | ||
|
|
362f895e72 | ||
|
|
224b73eb89 | ||
|
|
c4cf45e7f8 | ||
|
|
cb45e57a99 | ||
|
|
e7f62f79ef | ||
|
|
6fb21ccd77 | ||
|
|
f55d814cbb | ||
|
|
8fa22a6c7d | ||
|
|
b86ca3a4ec | ||
|
|
ab51e70ff4 | ||
|
|
0bde83c0e7 | ||
|
|
589754851c | ||
|
|
253930ba6d | ||
|
|
09c19bbba5 | ||
|
|
ac96ebffa5 | ||
|
|
f01715452f | ||
|
|
875b01dcd6 | ||
|
|
61def7e332 | ||
|
|
86b24ff618 | ||
|
|
1d29d74204 | ||
|
|
2cf820e181 | ||
|
|
bf8ab4dec2 | ||
|
|
7b772bde3c | ||
|
|
dfbad82ba8 | ||
|
|
84938d88fc | ||
|
|
ed5f66729d | ||
|
|
ee5218c46d | ||
|
|
6758d71e2e | ||
|
|
1eec3d88cf | ||
|
|
34f1c196f1 | ||
|
|
a87e2fb5db | ||
|
|
cecafa5e28 | ||
|
|
a0e5f2d8ec | ||
|
|
47080f9b78 | ||
|
|
dd15767263 | ||
|
|
a698085196 | ||
|
|
2d4e1a94a4 | ||
|
|
dad49b9ac8 | ||
|
|
c5c1abaeff | ||
|
|
eb4f933753 | ||
|
|
931f27cb70 | ||
|
|
e6e00d4c7f | ||
|
|
3cf48129c6 | ||
|
|
b50bf02e90 | ||
|
|
431e3428b3 | ||
|
|
6d2e056b10 | ||
|
|
1cbfacc864 | ||
|
|
f2b51d321f | ||
|
|
0fe0b8906c | ||
|
|
0876f03fe4 | ||
|
|
dd239af810 | ||
|
|
5f2fae940c | ||
|
|
02f94875b1 | ||
|
|
52536f9803 | ||
|
|
7f963bd9f3 | ||
|
|
fcfbd478ca | ||
|
|
d7164dd588 | ||
|
|
d20b2768e1 | ||
|
|
68301c52c1 | ||
|
|
57aa9fa817 | ||
|
|
910291796b | ||
|
|
e4a661721f | ||
|
|
4068a20b8e | ||
|
|
c3be6db4f3 | ||
|
|
80678c97f0 | ||
|
|
711d20f874 | ||
|
|
7f299e1aa2 | ||
|
|
ab612a3f32 | ||
|
|
c0c244adc6 | ||
|
|
46a985076e | ||
|
|
7f82fab69b | ||
|
|
12ed1b3383 | ||
|
|
eab279dd12 | ||
|
|
e59a927faa | ||
|
|
1c1cb13c4d | ||
|
|
45a37eabe2 | ||
|
|
bbe6d81aa2 | ||
|
|
5d19b1bb72 | ||
|
|
866f05fea5 | ||
|
|
bd22554756 | ||
|
|
703e170773 | ||
|
|
a226242e69 | ||
|
|
1438f8aa10 | ||
|
|
79564bab81 | ||
|
|
5c7dd0b536 | ||
|
|
7e340b8b78 | ||
|
|
a026dc577c | ||
|
|
ed6c56629e | ||
|
|
97574707e5 | ||
|
|
942726eb74 | ||
|
|
e1eb3f804e | ||
|
|
2133a1390c | ||
|
|
7fab959a2f | ||
|
|
88f64ab82f | ||
|
|
1563d63051 | ||
|
|
82026658e2 | ||
|
|
26eec19a62 | ||
|
|
f548db2783 | ||
|
|
2da689e7e9 | ||
|
|
8afb4804c3 | ||
|
|
56b8902969 | ||
|
|
95cee6c845 | ||
|
|
dc58bcbd91 | ||
|
|
8d3698e6a3 | ||
|
|
c04526dc11 | ||
|
|
6a0d622344 | ||
|
|
74797e0768 | ||
|
|
6fd0851dc9 | ||
|
|
41e2773781 | ||
|
|
bf03412bf0 | ||
|
|
6b25aa1274 | ||
|
|
634acdd770 | ||
|
|
f2f01adfc9 | ||
|
|
9cd2d1d21f | ||
|
|
fa144847e5 | ||
|
|
17138f715b | ||
|
|
0babd05bff | ||
|
|
c5f14e55c5 | ||
|
|
03918c8ada | ||
|
|
80c7008a6c | ||
|
|
3d143cd3f0 | ||
|
|
365264b393 | ||
|
|
3b4aea4966 | ||
|
|
cb77bc9085 | ||
|
|
691aff990b | ||
|
|
0f6ca667d9 | ||
|
|
ba41229a83 | ||
|
|
7c9d28098b | ||
|
|
eccf9e4d85 | ||
|
|
96dffc0b74 | ||
|
|
308d0bfc0c | ||
|
|
f9dcf2db7d | ||
|
|
88798f2b86 | ||
|
|
28ecdc46b6 | ||
|
|
6a30031f49 | ||
|
|
d4f23e391f | ||
|
|
79b7463886 | ||
|
|
eddae25d7f | ||
|
|
5e9c85fc06 | ||
|
|
b44adb34ec | ||
|
|
f0f6cac84a | ||
|
|
17e87f58c3 | ||
|
|
273698e2fc | ||
|
|
66f88e0e8e | ||
|
|
de945008fb | ||
|
|
5f91505b8e | ||
|
|
6a25c283ec | ||
|
|
74fa9289a7 | ||
|
|
ab4b975912 | ||
|
|
2260089301 | ||
|
|
9dd35f1e32 | ||
|
|
6b90cee851 | ||
|
|
6da132c034 | ||
|
|
bc966a8ea8 | ||
|
|
6eab0c9b75 | ||
|
|
cf253fae8a | ||
|
|
c0eaa8fb50 | ||
|
|
a4889de80a | ||
|
|
acac599f6b | ||
|
|
1436ffa53f | ||
|
|
c68a3dd0a6 | ||
|
|
29c42022ef | ||
|
|
dd814c1b5e | ||
|
|
7fc2c71f58 | ||
|
|
e6a3d3c982 | ||
|
|
46380ee9ff | ||
|
|
1fa3908888 | ||
|
|
914e6a1789 | ||
|
|
9a1d073072 | ||
|
|
3712caf7b1 | ||
|
|
a770e18bb2 | ||
|
|
5dc0cfb666 | ||
|
|
e4ab02c77a | ||
|
|
a0f729cd8d | ||
|
|
d544b1c264 | ||
|
|
d8549cbebe | ||
|
|
4ae4734dbf | ||
|
|
cc72de7121 |
@@ -46,6 +46,21 @@ class Note extends \Espo\Core\Acl\Base
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkEntityCreate(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
if ($entity->get('parentId') && $entity->get('parentType')) {
|
||||
$parent = $this->getEntityManager()->getEntity($entity->get('parentType'), $entity->get('parentId'));
|
||||
if ($parent) {
|
||||
if ($this->getAclManager()->checkEntity($user, $parent, 'stream')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkEntityEdit(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
|
||||
@@ -41,5 +41,26 @@ class Note extends \Espo\Core\AclPortal\Base
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function checkEntityCreate(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
if ($entity->get('type') !== 'Post') return false;
|
||||
|
||||
if ($entity->get('type') === 'Post' && $entity->get('targetType')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$entity->get('parentId') || !$entity->get('parentType')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$parent = $this->getEntityManager()->getEntity($entity->get('parentType'), $entity->get('parentId'));
|
||||
if ($parent) {
|
||||
if ($this->getAclManager()->checkEntity($user, $parent, 'stream')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,39 +33,38 @@ use \Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class ActionHistoryRecord extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
public function actionUpdate($params, $data, $request)
|
||||
public function beforeUpdate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreate($params, $data, $request)
|
||||
public function beforeCreate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionListLinked($params, $data, $request)
|
||||
public function beforeListLinked()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionMassUpdate($params, $data, $request)
|
||||
public function beforeMassUpdate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data, $request)
|
||||
public function beforeCreateLink()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionRemoveLink($params, $data, $request)
|
||||
public function beforeRemoveLink()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionMassDelete($params, $data, $request)
|
||||
public function beforeMassDelete()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,27 +40,27 @@ class AuthLogRecord extends \Espo\Core\Controllers\Record
|
||||
}
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data, $request)
|
||||
public function beforeUpdate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionMassUpdate($params, $data, $request)
|
||||
public function beforeMassUpdate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreate($params, $data, $request)
|
||||
public function beforeCreate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data, $request)
|
||||
public function beforeCreateLink()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionRemoveLink($params, $data, $request)
|
||||
public function beforeRemoveLink()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
@@ -80,17 +80,17 @@ class AuthToken extends \Espo\Core\Controllers\Record
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreate($params, $data, $request)
|
||||
public function beforeCreate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data, $request)
|
||||
public function beforeCreateLink()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionRemoveLink($params, $data, $request)
|
||||
public function beforeRemoveLink()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
@@ -94,25 +94,6 @@ class Extension extends \Espo\Core\Controllers\Record
|
||||
return true;
|
||||
}
|
||||
|
||||
public function actionCreate($params, $data, $request)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data, $request)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data, $request)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionListLinked($params, $data, $request)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionDelete($params, $data, $request)
|
||||
{
|
||||
@@ -129,22 +110,42 @@ class Extension extends \Espo\Core\Controllers\Record
|
||||
return true;
|
||||
}
|
||||
|
||||
public function actionMassUpdate($params, $data, $request)
|
||||
public function beforeCreate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionMassDelete($params, $data, $request)
|
||||
public function beforeUpdate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data, $request)
|
||||
public function beforePatch()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionRemoveLink($params, $data, $request)
|
||||
public function beforeListLinked()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function beforeMassUpdate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function beforeMassDelete()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function beforeCreateLink()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function beforeRemoveLink()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
@@ -47,17 +47,27 @@ class ExternalAccount extends \Espo\Core\Controllers\Record
|
||||
public function actionList($params, $data, $request)
|
||||
{
|
||||
$integrations = $this->getEntityManager()->getRepository('Integration')->find();
|
||||
$arr = array();
|
||||
|
||||
$list = [];
|
||||
foreach ($integrations as $entity) {
|
||||
if ($entity->get('enabled') && $this->getMetadata()->get('integrations.' . $entity->id .'.allowUserAccounts')) {
|
||||
$arr[] = array(
|
||||
|
||||
$userAccountAclScope = $this->getMetadata()->get(['integrations', $entity->id, 'userAccountAclScope']);
|
||||
|
||||
if ($userAccountAclScope) {
|
||||
if (!$this->getAcl()->checkScope($userAccountAclScope)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$list[] = [
|
||||
'id' => $entity->id
|
||||
);
|
||||
];
|
||||
}
|
||||
}
|
||||
return array(
|
||||
'list' => $arr
|
||||
);
|
||||
return [
|
||||
'list' => $list
|
||||
];
|
||||
}
|
||||
|
||||
public function actionGetOAuth2Info($params, $data, $request)
|
||||
|
||||
@@ -43,27 +43,27 @@ class Import extends \Espo\Core\Controllers\Record
|
||||
}
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data, $request)
|
||||
public function beforePatch()
|
||||
{
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data, $request)
|
||||
public function beforeUpdate()
|
||||
{
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
public function actionMassUpdate($params, $data, $request)
|
||||
public function beforeMassUpdate()
|
||||
{
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data, $request)
|
||||
public function beforeCreateLink()
|
||||
{
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
public function actionRemoveLink($params, $data, $request)
|
||||
public function beforeRemoveLink()
|
||||
{
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
@@ -41,37 +41,37 @@ class Job extends \Espo\Core\Controllers\Record
|
||||
}
|
||||
}
|
||||
|
||||
public function actionCreate($params, $data, $request)
|
||||
public function beforeCreate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data, $request)
|
||||
public function beforeUpdate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data, $request)
|
||||
public function beforePatch()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionListLinked($params, $data, $request)
|
||||
public function beforeListLinked()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionMassUpdate($params, $data, $request)
|
||||
public function beforeMassUpdate()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data, $request)
|
||||
public function beforeCreateLink()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionRemoveLink($params, $data, $request)
|
||||
public function beforeRemoveLink()
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class Notification extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
public static $defaultAction = 'list';
|
||||
|
||||
public function actionList($params, $data, $request)
|
||||
public function getActionList($params, $data, $request, $response)
|
||||
{
|
||||
$userId = $this->getUser()->id;
|
||||
|
||||
@@ -73,29 +73,28 @@ class Notification extends \Espo\Core\Controllers\Record
|
||||
return $this->getService('Notification')->markAllRead($userId);
|
||||
}
|
||||
|
||||
public function actionExport($params, $data, $request)
|
||||
public function beforeExport()
|
||||
{
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
public function actionMassUpdate($params, $data, $request)
|
||||
public function beforeMassUpdate()
|
||||
{
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data, $request)
|
||||
public function beforeCreateLink()
|
||||
{
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
public function actionRemoveLink($params, $data, $request)
|
||||
public function beforeRemoveLink()
|
||||
{
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
public function actionMerge($params, $data, $request)
|
||||
public function beforeMerge()
|
||||
{
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,13 @@ class Settings extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
$data = $this->getServiceFactory()->create('Settings')->getConfigData();
|
||||
|
||||
$data->jsLibs = $this->getMetadata()->get('app.jsLibs');
|
||||
$data->jsLibs = $this->getMetadata()->get(['app', 'jsLibs']);
|
||||
|
||||
unset($data->loginView);
|
||||
$loginView = $this->getMetadata()->get(['clientDefs', 'App', 'loginView']);
|
||||
if ($loginView) {
|
||||
$data->loginView = $loginView;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -113,17 +113,13 @@ class User extends \Espo\Core\Controllers\Record
|
||||
return $this->getRecordService()->generateNewApiKeyForEntity($data->id)->getValueMap();
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data, $request)
|
||||
public function beforeCreateLink()
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) throw new Forbidden();
|
||||
|
||||
return parent::actionCreateLink($params, $data, $request);
|
||||
}
|
||||
|
||||
public function actionRemoveLink($params, $data, $request)
|
||||
public function beforeRemoveLink($params, $data, $request)
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) throw new Forbidden();
|
||||
|
||||
return parent::actionRemoveLink($params, $data, $request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,9 @@ class Application
|
||||
|
||||
$slim->run();
|
||||
} catch (\Exception $e) {
|
||||
$container->get('output')->processError($e->getMessage(), $e->getCode(), true, $e);
|
||||
try {
|
||||
$container->get('output')->processError($e->getMessage(), $e->getCode(), true, $e);
|
||||
} catch (\Slim\Exception\Stop $e) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class Upgrade extends Base
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(\STDOUT, "EspoCRM will be upgaded to version {$nextVersion} now. Type 'Y' to continue.\n");
|
||||
fwrite(\STDOUT, "EspoCRM will be upgraded to version {$nextVersion} now. Enter [Y] to continue.\n");
|
||||
|
||||
if (!$this->confirm()) {
|
||||
echo "Upgrade canceled.\n";
|
||||
|
||||
@@ -115,7 +115,7 @@ class Container
|
||||
$rotation = $config->get('logger.rotation', true);
|
||||
|
||||
$log = new \Espo\Core\Utils\Log('Espo');
|
||||
$levelCode = $log->getLevelCode($config->get('logger.level', 'WARNING'));
|
||||
$levelCode = $log::toMonologLevel($config->get('logger.level', 'WARNING'));
|
||||
|
||||
if ($rotation) {
|
||||
$maxFileNumber = $config->get('logger.maxFileNumber', 30);
|
||||
@@ -127,7 +127,7 @@ class Container
|
||||
|
||||
$errorHandler = new \Monolog\ErrorHandler($log);
|
||||
$errorHandler->registerExceptionHandler(null, false);
|
||||
$errorHandler->registerErrorHandler(array(), false);
|
||||
$errorHandler->registerErrorHandler([], false);
|
||||
|
||||
return $log;
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ class DataManager
|
||||
$metadata->init(true);
|
||||
|
||||
$ormData = $this->getContainer()->get('ormMetadata')->getData(true);
|
||||
$this->getContainer()->get('entityManager')->setMetadata($ormData);
|
||||
|
||||
$this->updateCacheTimestamp();
|
||||
|
||||
|
||||
35
application/Espo/Core/Exceptions/ForbiddenSilent.php
Normal file
35
application/Espo/Core/Exceptions/ForbiddenSilent.php
Normal file
@@ -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 ForbiddenSilent extends Forbidden
|
||||
{
|
||||
public $logLevel = 'notice';
|
||||
}
|
||||
35
application/Espo/Core/Exceptions/NotFoundSilent.php
Normal file
35
application/Espo/Core/Exceptions/NotFoundSilent.php
Normal file
@@ -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 NotFoundSilent extends NotFound
|
||||
{
|
||||
public $logLevel = 'notice';
|
||||
}
|
||||
@@ -491,7 +491,14 @@ class Xlsx extends \Espo\Core\Injectable
|
||||
|
||||
$sheet->setCellValue("$col$rowNumber", $value);
|
||||
}
|
||||
|
||||
} else if ($type == 'multiEnum' || $type == 'array') {
|
||||
if (!empty($row[$name])) {
|
||||
$array = json_decode($row[$name]);
|
||||
if (is_array($array)) {
|
||||
$value = implode(', ', $array);
|
||||
$sheet->setCellValue("$col$rowNumber", $value, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (array_key_exists($name, $row)) {
|
||||
$sheet->setCellValueExplicit("$col$rowNumber", $row[$name], \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING);
|
||||
|
||||
@@ -69,7 +69,7 @@ class ClientManager
|
||||
$externalAccountEntity = $this->clientMap[$hash]['externalAccountEntity'];
|
||||
$externalAccountEntity->set('accessToken', $data['accessToken']);
|
||||
$externalAccountEntity->set('tokenType', $data['tokenType']);
|
||||
$this->getEntityManager()->saveEntity($externalAccountEntity);
|
||||
$this->getEntityManager()->saveEntity($externalAccountEntity, ['isTokenRenewal' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,12 @@ class ClientManager
|
||||
|
||||
$className = $this->getMetadata()->get("integrations.{$integration}.clientClassName");
|
||||
|
||||
$redirectUri = $this->getConfig()->get('siteUrl') . '?entryPoint=oauthCallback'; // TODO move to client class
|
||||
$redirectUri = $this->getConfig()->get('siteUrl') . '?entryPoint=oauthCallback';
|
||||
|
||||
$redirectUriPath = $this->getMetadata()->get(['integrations', $integration, 'params', 'redirectUriPath']);
|
||||
if ($redirectUriPath) {
|
||||
$redirectUri = rtrim($this->getConfig()->get('siteUrl'), '/') . '/' . $redirectUriPath;
|
||||
}
|
||||
|
||||
if (!$externalAccountEntity) {
|
||||
throw new Error("External Account {$integration} not found for {$userId}");
|
||||
|
||||
@@ -187,7 +187,11 @@ class Client
|
||||
|
||||
$curlOptHttpHeader = array();
|
||||
foreach ($httpHeaders as $key => $value) {
|
||||
$curlOptHttpHeader[] = "{$key}: {$value}";
|
||||
if (is_int($key) && !is_string($key)) {
|
||||
$curlOptHttpHeader[] = $value;
|
||||
continue;
|
||||
}
|
||||
$curlOptHttpHeader[] = "{$key}: {$value}";
|
||||
}
|
||||
$curlOptions[CURLOPT_HTTPHEADER] = $curlOptHttpHeader;
|
||||
|
||||
|
||||
@@ -147,6 +147,7 @@ class Htmlizer
|
||||
}
|
||||
|
||||
$type = $entity->getAttributeType($attribute);
|
||||
$fieldType = $entity->getAttributeParam($attribute, 'fieldType');
|
||||
|
||||
if ($type == Entity::DATETIME) {
|
||||
if (!empty($data[$attribute])) {
|
||||
@@ -194,6 +195,14 @@ class Htmlizer
|
||||
unset($data[$attribute]);
|
||||
}
|
||||
|
||||
if ($fieldType === 'currency' && $this->metadata) {
|
||||
if ($entity->getAttributeParam($attribute, 'attributeRole') === 'currency') {
|
||||
if ($currencyValue = $data[$attribute]) {
|
||||
$data[$attribute . 'Symbol'] = $this->metadata->get(['app', 'currency', 'symbolMap', $currencyValue]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($attribute, $data)) {
|
||||
$keyRaw = $attribute . '_RAW';
|
||||
$data[$keyRaw] = $data[$attribute];
|
||||
|
||||
@@ -201,7 +201,7 @@ class Importer
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$email->set('body', '(Not fetched)');
|
||||
$email->set('body', 'Not fetched. The email size exceeds the limit.');
|
||||
$email->set('isHtml', false);
|
||||
}
|
||||
|
||||
|
||||
@@ -284,6 +284,7 @@ class Sender
|
||||
$contents = $a->get('contents');
|
||||
} else {
|
||||
$fileName = $this->getEntityManager()->getRepository('Attachment')->getFilePath($a);
|
||||
if (!is_file($fileName)) continue;
|
||||
$contents = file_get_contents($fileName);
|
||||
}
|
||||
$attachment = new MimePart($contents);
|
||||
@@ -303,6 +304,7 @@ class Sender
|
||||
$contents = $a->get('contents');
|
||||
} else {
|
||||
$fileName = $this->getEntityManager()->getRepository('Attachment')->getFilePath($a);
|
||||
if (!is_file($fileName)) continue;
|
||||
$contents = file_get_contents($fileName);
|
||||
}
|
||||
$attachment = new MimePart($contents);
|
||||
|
||||
@@ -50,9 +50,9 @@ class Application extends \Espo\Core\Application
|
||||
$portal = $this->getContainer()->get('entityManager')->getEntity('Portal', $portalId);
|
||||
|
||||
if (!$portal) {
|
||||
$portal = $this->getContainer()->get('entityManager')->getRepository('Portal')->where(array(
|
||||
$portal = $this->getContainer()->get('entityManager')->getRepository('Portal')->where([
|
||||
'customId' => $portalId
|
||||
))->findOne();
|
||||
])->findOne();
|
||||
}
|
||||
|
||||
if (!$portal) {
|
||||
|
||||
@@ -1038,7 +1038,8 @@ class Base
|
||||
$where['type'] = 'between';
|
||||
$dt = new \DateTime($value, new \DateTimeZone($timeZone));
|
||||
$dtTo = clone $dt;
|
||||
$dtTo->modify('+1 day -1 second');
|
||||
if (strlen($value) <= 10)
|
||||
$dtTo->modify('+1 day -1 second');
|
||||
$dt->setTimezone(new \DateTimeZone('UTC'));
|
||||
$dtTo->setTimezone(new \DateTimeZone('UTC'));
|
||||
$from = $dt->format($format);
|
||||
@@ -1054,7 +1055,9 @@ class Base
|
||||
case 'after':
|
||||
$where['type'] = 'after';
|
||||
$dt = new \DateTime($value, new \DateTimeZone($timeZone));
|
||||
$dt->modify('+1 day -1 second');
|
||||
if (strlen($value) <= 10)
|
||||
$dt->modify('+1 day -1 second');
|
||||
|
||||
$dt->setTimezone(new \DateTimeZone('UTC'));
|
||||
$where['value'] = $dt->format($format);
|
||||
break;
|
||||
@@ -1068,7 +1071,8 @@ class Base
|
||||
|
||||
$dt = new \DateTime($value[1], new \DateTimeZone($timeZone));
|
||||
$dt->setTimezone(new \DateTimeZone('UTC'));
|
||||
$dt->modify('-1 second');
|
||||
if (strlen($value[1]) <= 10)
|
||||
$dt->modify('+1 day -1 second');
|
||||
$to = $dt->format($format);
|
||||
|
||||
$where['value'] = [$from, $to];
|
||||
@@ -1840,6 +1844,35 @@ class Base
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasLinkJoined($join, array &$result)
|
||||
{
|
||||
if (in_array($join, $result['joins'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($result['joins'] as $item) {
|
||||
if (is_array($item) && count($item) > 1) {
|
||||
if ($item[0] == $join) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($join, $result['leftJoins'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($result['leftJoins'] as $item) {
|
||||
if (is_array($item) && count($item) > 1) {
|
||||
if ($item[0] == $join) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addJoin($join, array &$result)
|
||||
{
|
||||
if (empty($result['joins'])) {
|
||||
@@ -1965,7 +1998,7 @@ class Base
|
||||
|
||||
if ($useFullTextSearch) {
|
||||
foreach ($fieldList as $field) {
|
||||
if (strpos($item, '.') !== false) {
|
||||
if (strpos($field, '.') !== false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,4 +48,23 @@ class Event extends \Espo\Services\Record
|
||||
$reminders = $this->getRepository()->getEntityReminderList($entity);
|
||||
$entity->set('reminders', $reminders);
|
||||
}
|
||||
|
||||
public function getSelectAttributeList($params)
|
||||
{
|
||||
$attributeList = parent::getSelectAttributeList($params);
|
||||
if (is_array($attributeList)) {
|
||||
if (array_key_exists('select', $params)) {
|
||||
$passedAttributeList = $params['select'];
|
||||
if (in_array('duration', $passedAttributeList)) {
|
||||
if (!in_array('dateStart', $attributeList)) {
|
||||
$attributeList[] = 'dateStart';
|
||||
}
|
||||
if (!in_array('dateEnd', $attributeList)) {
|
||||
$attributeList[] = 'dateEnd';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $attributeList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
{
|
||||
"fields": {
|
||||
"billingAddress": "Betalingsadresse",
|
||||
"shippingAddress": "Leveringsadresse",
|
||||
"website": "Website"
|
||||
"shippingAddress": "Leveringsadresse"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Møder",
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
"dateStart": "Startdato",
|
||||
"dateEnd": "Slutdato",
|
||||
"duration": "Varighed",
|
||||
"status": "Status",
|
||||
"reminders": "Underretninger"
|
||||
"reminders": "Underretninger",
|
||||
"dateStartDate": "Start dato (hele dagen)",
|
||||
"dateEndDate": "Slut dato (hele dagen)",
|
||||
"isAllDay": "Hele dagen"
|
||||
},
|
||||
"links": {
|
||||
"parent": "Henviser til"
|
||||
@@ -20,7 +22,6 @@
|
||||
"labels": {
|
||||
"Create {entityType}": "Opret {entityTypeTranslated}",
|
||||
"Schedule {entityType}": "Planlæg {entityTypeTranslated}",
|
||||
"Log {entityType}": "Log {entityTypeTranslated}",
|
||||
"Set Held": "Marker som Gennemført",
|
||||
"Set Not Held": "Marker som Ikke Gennemført"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Klant {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"labels": {
|
||||
"Create {entityType}": "Klant {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Klant {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"links": {
|
||||
"meetings": "Vergaderingen",
|
||||
"calls": "Gesprekken",
|
||||
"tasks": "Taken"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Klant {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,14 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Klant {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"fields": {
|
||||
"billingAddress": "Facturatie adres",
|
||||
"shippingAddress": "Verzending adres"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "vergaderingen",
|
||||
"calls": "gesprekken",
|
||||
"tasks": "taken"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Klant {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,37 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Klant {entityTypeTranslated}"
|
||||
"fields": {
|
||||
"parent": "Ouder",
|
||||
"dateStart": "Datum Start",
|
||||
"dateEnd": "Datum einde",
|
||||
"duration": "Looptijd",
|
||||
"status": "staat",
|
||||
"reminders": "herinneringen",
|
||||
"dateStartDate": "Startdatum (de hele dag)",
|
||||
"dateEndDate": "Datum einde (hele dag)",
|
||||
"isAllDay": "Is de hele dag"
|
||||
},
|
||||
"links": {
|
||||
"parent": "Ouder"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Gepland",
|
||||
"Held": "Vastgehouden",
|
||||
"Not Held": "Niet vastgehouden"
|
||||
}
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Klant {entityTypeTranslated}",
|
||||
"Schedule {entityType}": "Schema {entityTypeTranslated}",
|
||||
"Set Held": "Held instellen",
|
||||
"Set Not Held": "Set not Held"
|
||||
},
|
||||
"massActions": {
|
||||
"setHeld": "Held instellen",
|
||||
"setNotHeld": "Set not Held"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Gepland",
|
||||
"todays": "Vandaag"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Klant {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"fields": {
|
||||
"address": "Adres"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Vergaderingen",
|
||||
"calls": "Gesprekken",
|
||||
"tasks": "Taken"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Klant {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Criar {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"labels": {
|
||||
"Create {entityType}": "Criar {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Criar {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"links": {
|
||||
"meetings": "Reuniões",
|
||||
"tasks": "Tarefas"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Criar {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Criar {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"fields": {
|
||||
"billingAddress": "Endereço de Cobrança",
|
||||
"shippingAddress": "Endereço de Entrega"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Reuniões",
|
||||
"tasks": "Tarefas"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Criar {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Criar {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"labels": {
|
||||
"Create {entityType}": "Criar {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create {entityType}": "Criar {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
"fields": {
|
||||
"address": "Endereço"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Reuniões",
|
||||
"tasks": "Tarefas"
|
||||
},
|
||||
"labels": {
|
||||
"Create {entityType}": "Criar {entityTypeTranslated}"
|
||||
}
|
||||
}
|
||||
1
application/Espo/Core/Templates/i18n/vi_VN/Base.json
Normal file
1
application/Espo/Core/Templates/i18n/vi_VN/Base.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
application/Espo/Core/Templates/i18n/vi_VN/BasePlus.json
Normal file
1
application/Espo/Core/Templates/i18n/vi_VN/BasePlus.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
application/Espo/Core/Templates/i18n/vi_VN/Company.json
Normal file
1
application/Espo/Core/Templates/i18n/vi_VN/Company.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
8
application/Espo/Core/Templates/i18n/vi_VN/Event.json
Normal file
8
application/Espo/Core/Templates/i18n/vi_VN/Event.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"fields": {
|
||||
"status": "Tình trạng"
|
||||
},
|
||||
"presetFilters": {
|
||||
"todays": "Hôm nay"
|
||||
}
|
||||
}
|
||||
5
application/Espo/Core/Templates/i18n/vi_VN/Person.json
Normal file
5
application/Espo/Core/Templates/i18n/vi_VN/Person.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"fields": {
|
||||
"address": "Địa chỉ"
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,8 @@ abstract class Base
|
||||
|
||||
protected $packagePostfix = 'z';
|
||||
|
||||
protected $scriptParams = [];
|
||||
|
||||
/**
|
||||
* Directory name of files in a package
|
||||
*/
|
||||
@@ -291,7 +293,7 @@ abstract class Base
|
||||
$script = new $scriptName();
|
||||
|
||||
try {
|
||||
$script->run($this->getContainer());
|
||||
$script->run($this->getContainer(), $this->scriptParams);
|
||||
} catch (\Exception $e) {
|
||||
$this->throwErrorAndRemovePackage($e->getMessage());
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ class Install extends \Espo\Core\Upgrades\Actions\Base\Install
|
||||
{
|
||||
$this->findExtension();
|
||||
if (!$this->isNew()) {
|
||||
$this->scriptParams['isUpgrade'] = true;
|
||||
|
||||
$this->compareVersion();
|
||||
$this->uninstallExtension();
|
||||
$this->deleteExtension();
|
||||
|
||||
@@ -71,22 +71,62 @@ class Output
|
||||
echo $data;
|
||||
}
|
||||
|
||||
public function processError(string $message = 'Error', int $code = 500, bool $toPrint = false, $exception = null)
|
||||
public function processError(string $message = 'Error', int $statusCode = 500, bool $toPrint = false, $exception = null)
|
||||
{
|
||||
$currentRoute = $this->getSlim()->router()->getCurrentRoute();
|
||||
|
||||
if (isset($currentRoute)) {
|
||||
$inputData = $this->getSlim()->request()->getBody();
|
||||
$inputData = $this->clearPasswords($inputData);
|
||||
$GLOBALS['log']->error('API ['.$this->getSlim()->request()->getMethod().']:'.$currentRoute->getPattern().', Params:'.print_r($currentRoute->getParams(), true).', InputData: '.$inputData.' - '.$message);
|
||||
|
||||
$routePattern = $currentRoute->getPattern();
|
||||
$routeParams = $currentRoute->getParams();
|
||||
$method = $this->getSlim()->request()->getMethod();
|
||||
|
||||
$logMessage = "API ($statusCode) ";
|
||||
$logMessageItemList = [];
|
||||
if ($message) $logMessageItemList[] = $message;
|
||||
$logMessageItemList[] .= "$method " . $_SERVER['REQUEST_URI'];
|
||||
if ($inputData) $logMessageItemList[] = "Input data: " . $inputData;
|
||||
if ($routePattern) $logMessageItemList[] = "Route pattern: ". $routePattern;
|
||||
if (!empty($routeParams)) $logMessageItemList[] = "Route params: ". print_r($routeParams, true);
|
||||
|
||||
$logMessage .= implode("; ", $logMessageItemList);
|
||||
|
||||
$GLOBALS['log']->log('debug', $logMessage);
|
||||
}
|
||||
|
||||
$this->displayError($message, $code, $toPrint, $exception);
|
||||
$this->displayError($message, $statusCode, $toPrint, $exception);
|
||||
}
|
||||
|
||||
public function displayError(string $text, int $statusCode = 500, bool $toPrint = false, $exception = null)
|
||||
{
|
||||
$GLOBALS['log']->error('Display Error: '.$text.', Code: '.$statusCode.' URL: '.$_SERVER['REQUEST_URI']);
|
||||
$logLevel = 'error';
|
||||
$messageLineFile = null;
|
||||
|
||||
if ($exception) {
|
||||
$messageLineFile = 'line: ' . $exception->getLine() . ', file: ' . $exception->getFile();
|
||||
}
|
||||
|
||||
if ($exception && !empty($exception->logLevel)) {
|
||||
$logLevel = $exception->logLevel;
|
||||
}
|
||||
|
||||
$logMessageItemList = [];
|
||||
|
||||
if ($text) $logMessageItemList[] = "{$text}";
|
||||
|
||||
if (!empty($this->slim)) {
|
||||
$logMessageItemList[] = $this->getSlim()->request()->getMethod() . ' ' .$_SERVER['REQUEST_URI'];
|
||||
}
|
||||
|
||||
if ($messageLineFile) {
|
||||
$logMessageItemList[] = $messageLineFile;
|
||||
}
|
||||
|
||||
$logMessage = "($statusCode) " . implode("; ", $logMessageItemList);
|
||||
|
||||
$GLOBALS['log']->log($logLevel, $logMessage);
|
||||
|
||||
ob_clean();
|
||||
|
||||
|
||||
@@ -195,6 +195,9 @@ class NamespaceLoader
|
||||
|
||||
if (file_exists($this->vendorNamespacesCacheFile) && $this->getConfig()->get('useCache')) {
|
||||
$this->vendorNamespaces = $this->getFileManager()->getPhpContents($this->vendorNamespacesCacheFile);
|
||||
if (!is_array($this->vendorNamespaces)) {
|
||||
$this->vendorNamespaces = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,19 +98,45 @@ class ClientManager
|
||||
|
||||
if ($isDeveloperMode) {
|
||||
$useCache = $this->getConfig()->get('useCacheInDeveloperMode');
|
||||
$jsFileList = $this->getMetadata()->get(['app', 'client', 'developerModeScriptList']);
|
||||
$jsFileList = $this->getMetadata()->get(['app', 'client', 'developerModeScriptList'], []);
|
||||
$loaderCacheTimestamp = 'null';
|
||||
} else {
|
||||
$useCache = $this->getConfig()->get('useCache');
|
||||
$jsFileList = $this->getMetadata()->get(['app', 'client', 'scriptList']);
|
||||
$jsFileList = $this->getMetadata()->get(['app', 'client', 'scriptList'], []);
|
||||
$loaderCacheTimestamp = $cacheTimestamp;
|
||||
}
|
||||
|
||||
$cssFileList = $this->getMetadata()->get(['app', 'client', 'cssList'], []);
|
||||
|
||||
$linkList = $this->getMetadata()->get(['app', 'client', 'linkList'], []);
|
||||
|
||||
$scriptsHtml = '';
|
||||
foreach ($jsFileList as $jsFile) {
|
||||
$src = $this->basePath . $jsFile . '?r=' . $cacheTimestamp;
|
||||
$scriptsHtml .= ' ' .
|
||||
'<script type="text/javascript" src="'.$src.'" data-base-path="'.$this->basePath.'"></script>' . "\n";
|
||||
$scriptsHtml .= "\n " .
|
||||
"<script type=\"text/javascript\" src=\"{$src}\" data-base-path=\"{$this->basePath}\"></script>";
|
||||
}
|
||||
|
||||
$additionalStyleSheetsHtml = '';
|
||||
foreach ($cssFileList as $cssFile) {
|
||||
$src = $this->basePath . $cssFile . '?r=' . $cacheTimestamp;
|
||||
$additionalStyleSheetsHtml .= "\n <link rel=\"stylesheet\" href=\"{$src}\">";
|
||||
}
|
||||
|
||||
$linksHtml = '';
|
||||
foreach ($linkList as $item) {
|
||||
$href = $this->basePath . $item['href'];
|
||||
if (empty($item['noTimestamp'])) {
|
||||
$href .= '?r=' . $cacheTimestamp;
|
||||
}
|
||||
$as = $item['as'] ?? '';
|
||||
$rel = $item['rel'] ?? '';
|
||||
$type = $item['type'] ?? '';
|
||||
$additinalPlaceholder = '';
|
||||
if (!empty($item['crossorigin'])) {
|
||||
$additinalPlaceholder .= ' crossorigin';
|
||||
}
|
||||
$linksHtml .= "\n <link rel=\"{$rel}\" href=\"{$href}\" as=\"{$as}\" as=\"{$type}\"{$additinalPlaceholder}>";
|
||||
}
|
||||
|
||||
$data = [
|
||||
@@ -124,7 +150,9 @@ class ClientManager
|
||||
'basePath' => $this->basePath,
|
||||
'useCache' => $useCache ? 'true' : 'false',
|
||||
'appClientClassName' => 'app',
|
||||
'scriptsHtml' => $scriptsHtml
|
||||
'scriptsHtml' => $scriptsHtml,
|
||||
'additionalStyleSheetsHtml' => $additionalStyleSheetsHtml,
|
||||
'linksHtml' => $linksHtml,
|
||||
];
|
||||
|
||||
$html = file_get_contents($htmlFilePath);
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace Espo\Core\Utils\Database\Orm;
|
||||
|
||||
use Espo\Core\Utils\Util;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Core\Utils\Database\Schema\Utils as SchemaUtils;
|
||||
|
||||
class Converter
|
||||
{
|
||||
@@ -90,7 +91,7 @@ class Converter
|
||||
'select' => 'select',
|
||||
'orderBy' => 'orderBy',
|
||||
'where' => 'where',
|
||||
'storeArrayValues' => 'storeArrayValues'
|
||||
'storeArrayValues' => 'storeArrayValues',
|
||||
);
|
||||
|
||||
protected $idParams = array(
|
||||
@@ -188,10 +189,8 @@ class Converter
|
||||
{
|
||||
$ormMetadata = array();
|
||||
$ormMetadata[$entityName] = array(
|
||||
'fields' => array(
|
||||
),
|
||||
'relations' => array(
|
||||
)
|
||||
'fields' => [],
|
||||
'relations' => []
|
||||
);
|
||||
|
||||
foreach ($this->permittedEntityOptions as $optionName) {
|
||||
@@ -208,6 +207,7 @@ class Converter
|
||||
$ormMetadata = Util::merge($ormMetadata, $convertedLinks);
|
||||
|
||||
$this->applyFullTextSearch($ormMetadata, $entityName);
|
||||
$this->applyIndexes($ormMetadata, $entityName);
|
||||
|
||||
if (!empty($entityMetadata['collection']) && is_array($entityMetadata['collection'])) {
|
||||
$collectionDefs = $entityMetadata['collection'];
|
||||
@@ -291,7 +291,7 @@ class Converter
|
||||
*/
|
||||
protected function convertFields($entityName, &$entityMetadata)
|
||||
{
|
||||
//List of unmerged fields with default field defenitions in $outputMeta
|
||||
//List of unmerged fields with default field definitions in $outputMeta
|
||||
$unmergedFields = array(
|
||||
'name',
|
||||
);
|
||||
@@ -344,7 +344,7 @@ class Converter
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct fields defenitions based on \Espo\Custom\Core\Utils\Database\Orm\Fields
|
||||
* Correct fields definitions based on \Espo\Custom\Core\Utils\Database\Orm\Fields
|
||||
*
|
||||
* @param array $ormMetadata
|
||||
*
|
||||
@@ -506,6 +506,10 @@ class Converter
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($fieldParams['type'])) {
|
||||
$values['fieldType'] = $fieldParams['type'];
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
@@ -552,4 +556,18 @@ class Converter
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyIndexes(&$ormMetadata, $entityType)
|
||||
{
|
||||
if (!isset($ormMetadata[$entityType]['indexes'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($ormMetadata[$entityType]['indexes'] as $indexName => &$indexData) {
|
||||
if (!isset($indexData['key'])) {
|
||||
$indexType = SchemaUtils::getIndexTypeByIndexDefs($indexData);
|
||||
$indexData['key'] = SchemaUtils::generateIndexName($indexName, $indexType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,8 @@ class Currency extends Base
|
||||
'sql' => $converedFieldName . " {direction}",
|
||||
'leftJoins' => $leftJoins,
|
||||
],
|
||||
'attributeRole' => 'valueConverted',
|
||||
'fieldType' => 'currency',
|
||||
];
|
||||
|
||||
$defs[$entityType]['fields'][$fieldName]['orderBy'] = [
|
||||
@@ -108,6 +110,12 @@ class Currency extends Base
|
||||
];
|
||||
}
|
||||
|
||||
$defs[$entityType]['fields'][$fieldName]['attributeRole'] = 'value';
|
||||
$defs[$entityType]['fields'][$fieldName]['fieldType'] = 'currency';
|
||||
|
||||
$defs[$entityType]['fields'][$fieldName . 'Currency']['attributeRole'] = 'currency';
|
||||
$defs[$entityType]['fields'][$fieldName . 'Currency']['fieldType'] = 'currency';
|
||||
|
||||
return $defs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,25 +31,47 @@ namespace Espo\Core\Utils\Database\Orm\Fields;
|
||||
|
||||
class Email extends Base
|
||||
{
|
||||
protected function load($fieldName, $entityName)
|
||||
protected function load($fieldName, $entityType)
|
||||
{
|
||||
return array(
|
||||
$entityName => array(
|
||||
'fields' => array(
|
||||
$fieldName => array(
|
||||
$foreignJoinAlias = "{$fieldName}{$entityType}Foreign";
|
||||
$foreignJoinMiddleAlias = "{$fieldName}{$entityType}ForeignMiddle";
|
||||
|
||||
return [
|
||||
$entityType => [
|
||||
'fields' => [
|
||||
$fieldName => [
|
||||
'select' => [
|
||||
'sql' => 'emailAddresses.name',
|
||||
'leftJoins' => [['emailAddresses', 'emailAddresses', ['primary' => 1]]],
|
||||
],
|
||||
'selectForeign' => [
|
||||
'sql' => "{$foreignJoinAlias}.name",
|
||||
'leftJoins' => [
|
||||
[
|
||||
'EntityEmailAddress',
|
||||
$foreignJoinMiddleAlias,
|
||||
[
|
||||
"{$foreignJoinMiddleAlias}.entityId:" => "{alias}.id",
|
||||
"{$foreignJoinMiddleAlias}.primary" => 1,
|
||||
]
|
||||
],
|
||||
[
|
||||
'EmailAddress',
|
||||
$foreignJoinAlias,
|
||||
[
|
||||
"{$foreignJoinAlias}.id:" => "{$foreignJoinMiddleAlias}.emailAddressId",
|
||||
]
|
||||
]
|
||||
],
|
||||
],
|
||||
'fieldType' => 'email',
|
||||
'where' =>
|
||||
array (
|
||||
'LIKE' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
|
||||
'where' => [
|
||||
'LIKE' => \Espo\Core\Utils\Util::toUnderScore($entityType) . ".id IN (
|
||||
SELECT entity_id
|
||||
FROM entity_email_address
|
||||
JOIN email_address ON email_address.id = entity_email_address.email_address_id
|
||||
WHERE
|
||||
entity_email_address.deleted = 0 AND entity_email_address.entity_type = '{$entityName}' AND
|
||||
entity_email_address.deleted = 0 AND entity_email_address.entity_type = '{$entityType}' AND
|
||||
email_address.deleted = 0 AND email_address.lower LIKE {value}
|
||||
)",
|
||||
'=' => array(
|
||||
@@ -82,31 +104,34 @@ class Email extends Base
|
||||
'sql' => 'emailAddressesMultiple.lower IS NOT NULL',
|
||||
'distinct' => true
|
||||
)
|
||||
),
|
||||
],
|
||||
'orderBy' => [
|
||||
'sql' => 'emailAddresses.lower {direction}',
|
||||
'leftJoins' => [['emailAddresses', 'emailAddresses', ['primary' => 1]]],
|
||||
],
|
||||
),
|
||||
$fieldName .'Data' => array(
|
||||
],
|
||||
$fieldName .'Data' => [
|
||||
'type' => 'text',
|
||||
'notStorable' => true
|
||||
),
|
||||
$fieldName .'IsOptedOut' => array(
|
||||
'notStorable' => true,
|
||||
'notExportable' => true,
|
||||
],
|
||||
$fieldName .'IsOptedOut' => [
|
||||
'type' => 'bool',
|
||||
'notStorable' => true,
|
||||
'select' => 'emailAddresses.opt_out',
|
||||
'where' => [
|
||||
'= TRUE' => [
|
||||
'sql' => 'emailAddresses.opt_out = true AND emailAddresses.opt_out IS NOT NULL'
|
||||
'sql' => 'emailAddresses.opt_out = true AND emailAddresses.opt_out IS NOT NULL',
|
||||
'leftJoins' => [['emailAddresses', 'emailAddresses', ['primary' => 1]]],
|
||||
],
|
||||
'= FALSE' => [
|
||||
'sql' => 'emailAddresses.opt_out = false OR emailAddresses.opt_out IS NULL'
|
||||
'sql' => 'emailAddresses.opt_out = false OR emailAddresses.opt_out IS NULL',
|
||||
'leftJoins' => [['emailAddresses', 'emailAddresses', ['primary' => 1]]],
|
||||
]
|
||||
],
|
||||
'orderBy' => 'emailAddresses.opt_out {direction}'
|
||||
)
|
||||
),
|
||||
]
|
||||
],
|
||||
'relations' => [
|
||||
'emailAddresses' => [
|
||||
'type' => 'manyMany',
|
||||
@@ -117,7 +142,7 @@ class Email extends Base
|
||||
'emailAddressId'
|
||||
],
|
||||
'conditions' => [
|
||||
'entityType' => $entityName
|
||||
'entityType' => $entityType
|
||||
],
|
||||
'additionalColumns' => [
|
||||
'entityType' => [
|
||||
@@ -131,7 +156,7 @@ class Email extends Base
|
||||
]
|
||||
]
|
||||
]
|
||||
)
|
||||
);
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,25 +35,30 @@ class Link extends Base
|
||||
{
|
||||
$fieldParams = $this->getFieldParams();
|
||||
|
||||
$data = array(
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$fieldName.'Id' => array(
|
||||
$data = [
|
||||
$entityName => [
|
||||
'fields' => [
|
||||
$fieldName.'Id' => [
|
||||
'type' => 'foreignId',
|
||||
'index' => $fieldName
|
||||
),
|
||||
$fieldName.'Name' => array(
|
||||
'index' => $fieldName,
|
||||
'attributeRole' => 'id',
|
||||
'fieldType' => 'link',
|
||||
],
|
||||
$fieldName.'Name' => [
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true
|
||||
)
|
||||
)
|
||||
),
|
||||
'unset' => array(
|
||||
$entityName => array(
|
||||
'fields.'.$fieldName
|
||||
)
|
||||
)
|
||||
);
|
||||
'notStorable' => true,
|
||||
'attributeRole' => 'name',
|
||||
'fieldType' => 'link',
|
||||
]
|
||||
]
|
||||
],
|
||||
'unset' => [
|
||||
$entityName => [
|
||||
'fields.' . $fieldName
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
if (!empty($fieldParams['notStorable'])) {
|
||||
$data[$entityName]['fields'][$fieldName.'Id']['notStorable'] = true;
|
||||
}
|
||||
@@ -64,4 +69,4 @@ class Link extends Base
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,12 +41,16 @@ class LinkMultiple extends Base
|
||||
'notStorable' => true,
|
||||
'isLinkMultipleIdList' => true,
|
||||
'relation' => $fieldName,
|
||||
'isUnordered' => true
|
||||
'isUnordered' => true,
|
||||
'attributeRole' => 'idList',
|
||||
'fieldType' => 'linkMultiple',
|
||||
],
|
||||
$fieldName.'Names' => [
|
||||
'type' => 'jsonObject',
|
||||
'notStorable' => true,
|
||||
'isLinkMultipleNameMap' => true
|
||||
'isLinkMultipleNameMap' => true,
|
||||
'attributeRole' => 'nameMap',
|
||||
'fieldType' => 'linkMultiple',
|
||||
]
|
||||
]
|
||||
],
|
||||
@@ -71,7 +75,8 @@ class LinkMultiple extends Base
|
||||
$data[$entityName]['fields'][$fieldName . 'Columns'] = [
|
||||
'type' => 'jsonObject',
|
||||
'notStorable' => true,
|
||||
'columns' => $columns
|
||||
'columns' => $columns,
|
||||
'attributeRole' => 'columnsMap',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -33,33 +33,39 @@ class LinkParent extends Base
|
||||
{
|
||||
protected function load($fieldName, $entityName)
|
||||
{
|
||||
$data = array(
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$fieldName.'Id' => array(
|
||||
$data = [
|
||||
$entityName => [
|
||||
'fields' => [
|
||||
$fieldName.'Id' => [
|
||||
'type' => 'foreignId',
|
||||
'index' => $fieldName
|
||||
),
|
||||
$fieldName.'Type' => array(
|
||||
'index' => $fieldName,
|
||||
'attributeRole' => 'id',
|
||||
'fieldType' => 'linkParent',
|
||||
],
|
||||
$fieldName.'Type' => [
|
||||
'type' => 'foreignType',
|
||||
'notNull' => false,
|
||||
'index' => $fieldName,
|
||||
'len' => 100
|
||||
),
|
||||
$fieldName.'Name' => array(
|
||||
'len' => 100,
|
||||
'attributeRole' => 'type',
|
||||
'fieldType' => 'linkParent',
|
||||
],
|
||||
$fieldName.'Name' => [
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
'relation' => $fieldName,
|
||||
'isParentName' => true
|
||||
)
|
||||
)
|
||||
),
|
||||
'unset' => array(
|
||||
$entityName => array(
|
||||
'isParentName' => true,
|
||||
'attributeRole' => 'name',
|
||||
'fieldType' => 'linkParent',
|
||||
]
|
||||
]
|
||||
],
|
||||
'unset' => [
|
||||
$entityName => [
|
||||
'fields.'.$fieldName
|
||||
)
|
||||
)
|
||||
);
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$fieldParams = $this->getFieldParams();
|
||||
|
||||
@@ -72,4 +78,4 @@ class LinkParent extends Base
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,25 +31,48 @@ namespace Espo\Core\Utils\Database\Orm\Fields;
|
||||
|
||||
class Phone extends Base
|
||||
{
|
||||
protected function load($fieldName, $entityName)
|
||||
protected function load($fieldName, $entityType)
|
||||
{
|
||||
return array(
|
||||
$entityName => array(
|
||||
'fields' => array(
|
||||
$foreignJoinAlias = "{$fieldName}{$entityType}Foreign";
|
||||
$foreignJoinMiddleAlias = "{$fieldName}{$entityType}ForeignMiddle";
|
||||
|
||||
return [
|
||||
$entityType => [
|
||||
'fields' => [
|
||||
$fieldName => array(
|
||||
'select' => [
|
||||
'sql' => 'phoneNumbers.name',
|
||||
'leftJoins' => [['phoneNumbers', 'phoneNumbers', ['primary' => 1]]],
|
||||
],
|
||||
'selectForeign' => [
|
||||
'sql' => "{$foreignJoinAlias}.name",
|
||||
'leftJoins' => [
|
||||
[
|
||||
'EntityPhoneNumber',
|
||||
$foreignJoinMiddleAlias,
|
||||
[
|
||||
"{$foreignJoinMiddleAlias}.entityId:" => "{alias}.id",
|
||||
"{$foreignJoinMiddleAlias}.primary" => 1,
|
||||
]
|
||||
],
|
||||
[
|
||||
'PhoneNumber',
|
||||
$foreignJoinAlias,
|
||||
[
|
||||
"{$foreignJoinAlias}.id:" => "{$foreignJoinMiddleAlias}.phoneNumberId",
|
||||
]
|
||||
]
|
||||
],
|
||||
],
|
||||
'fieldType' => 'phone',
|
||||
'where' =>
|
||||
array (
|
||||
'LIKE' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
|
||||
'LIKE' => \Espo\Core\Utils\Util::toUnderScore($entityType) . ".id IN (
|
||||
SELECT entity_id
|
||||
FROM entity_phone_number
|
||||
JOIN phone_number ON phone_number.id = entity_phone_number.phone_number_id
|
||||
WHERE
|
||||
entity_phone_number.deleted = 0 AND entity_phone_number.entity_type = '{$entityName}' AND
|
||||
entity_phone_number.deleted = 0 AND entity_phone_number.entity_type = '{$entityType}' AND
|
||||
phone_number.deleted = 0 AND phone_number.name LIKE {value}
|
||||
)",
|
||||
'=' => array(
|
||||
@@ -90,18 +113,36 @@ class Phone extends Base
|
||||
),
|
||||
$fieldName .'Data' => array(
|
||||
'type' => 'text',
|
||||
'notStorable' => true
|
||||
'notStorable' => true,
|
||||
'notExportable' => true,
|
||||
),
|
||||
$fieldName .'IsOptedOut' => [
|
||||
'type' => 'bool',
|
||||
'notStorable' => true,
|
||||
'select' => 'phoneNumbers.opt_out',
|
||||
'where' => [
|
||||
'= TRUE' => [
|
||||
'sql' => 'phoneNumbers.opt_out = true AND phoneNumbers.opt_out IS NOT NULL',
|
||||
'leftJoins' => [['phoneNumbers', 'phoneNumbers', ['primary' => 1]]],
|
||||
],
|
||||
'= FALSE' => [
|
||||
'sql' => 'phoneNumbers.opt_out = false OR phoneNumbers.opt_out IS NULL',
|
||||
'leftJoins' => [['phoneNumbers', 'phoneNumbers', ['primary' => 1]]],
|
||||
]
|
||||
],
|
||||
'orderBy' => 'phoneNumbers.opt_out {direction}'
|
||||
],
|
||||
$fieldName . 'Numeric' => [
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
'notExportable' => true,
|
||||
'where' => [
|
||||
'LIKE' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
|
||||
'LIKE' => \Espo\Core\Utils\Util::toUnderScore($entityType) . ".id IN (
|
||||
SELECT entity_id
|
||||
FROM entity_phone_number
|
||||
JOIN phone_number ON phone_number.id = entity_phone_number.phone_number_id
|
||||
WHERE
|
||||
entity_phone_number.deleted = 0 AND entity_phone_number.entity_type = '{$entityName}' AND
|
||||
entity_phone_number.deleted = 0 AND entity_phone_number.entity_type = '{$entityType}' AND
|
||||
phone_number.deleted = 0 AND phone_number.numeric LIKE {value}
|
||||
)",
|
||||
'=' => [
|
||||
@@ -134,9 +175,9 @@ class Phone extends Base
|
||||
'sql' => 'phoneNumbersNumericMultiple.numeric IS NOT NULL',
|
||||
'distinct' => true
|
||||
]
|
||||
]
|
||||
],
|
||||
]
|
||||
),
|
||||
],
|
||||
'relations' => [
|
||||
'phoneNumbers' => [
|
||||
'type' => 'manyMany',
|
||||
@@ -147,7 +188,7 @@ class Phone extends Base
|
||||
'phoneNumberId'
|
||||
],
|
||||
'conditions' => [
|
||||
'entityType' => $entityName
|
||||
'entityType' => $entityType
|
||||
],
|
||||
'additionalColumns' => [
|
||||
'entityType' => [
|
||||
@@ -161,7 +202,7 @@ class Phone extends Base
|
||||
]
|
||||
]
|
||||
]
|
||||
)
|
||||
);
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,20 +35,29 @@ class Attachments extends HasChildren
|
||||
{
|
||||
$parentRelation = parent::load($linkName, $entityName);
|
||||
|
||||
$relation = array(
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$linkName.'Types' => array(
|
||||
$relation = [
|
||||
$entityName => [
|
||||
'fields' => [
|
||||
$linkName.'Types' => [
|
||||
'type' => 'jsonObject',
|
||||
'notStorable' => true,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
],
|
||||
],
|
||||
'relations' => [
|
||||
$linkName => [
|
||||
'conditions' => [
|
||||
'OR' => [
|
||||
['field' => null],
|
||||
['field' => $linkName],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$relation = \Espo\Core\Utils\Util::merge($parentRelation, $relation);
|
||||
|
||||
return $relation;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ use Espo\Core\Utils\Util;
|
||||
|
||||
class ManyMany extends Base
|
||||
{
|
||||
protected function load($linkName, $entityName)
|
||||
protected function load($linkName, $entityType)
|
||||
{
|
||||
$foreignEntityName = $this->getForeignEntityName();
|
||||
$foreignLinkName = $this->getForeignLinkName();
|
||||
@@ -43,15 +43,28 @@ class ManyMany extends Base
|
||||
if (!empty($linkParams['relationName'])) {
|
||||
$relationName = $linkParams['relationName'];
|
||||
} else {
|
||||
$relationName = $this->getJoinTable($entityName, $foreignEntityName);
|
||||
$relationName = $this->getJoinTable($entityType, $foreignEntityName);
|
||||
}
|
||||
|
||||
$isStub = !$this->getMetadata()->get(['entityDefs', $entityName, 'fields', $linkName]);
|
||||
$isStub = !$this->getMetadata()->get(['entityDefs', $entityType, 'fields', $linkName]);
|
||||
|
||||
$key1 = lcfirst($entityType) . 'Id';
|
||||
$key2 = lcfirst($foreignEntityName) . 'Id';
|
||||
|
||||
if ($key1 === $key2) {
|
||||
if (strcmp($linkName, $foreignLinkName)) {
|
||||
$key1 = 'leftId';
|
||||
$key2 = 'rightId';
|
||||
} else {
|
||||
$key1 = 'rightId';
|
||||
$key2 = 'leftId';
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
$entityName => [
|
||||
$entityType => [
|
||||
'fields' => [
|
||||
$linkName.'Ids' => [
|
||||
$linkName.'Ids' => [
|
||||
'type' => 'jsonArray',
|
||||
'notStorable' => true,
|
||||
'isLinkStub' => $isStub,
|
||||
@@ -67,13 +80,13 @@ class ManyMany extends Base
|
||||
'type' => 'manyMany',
|
||||
'entity' => $foreignEntityName,
|
||||
'relationName' => $relationName,
|
||||
'key' => 'id', //todo specify 'key'
|
||||
'foreignKey' => 'id', //todo specify 'foreignKey'
|
||||
'key' => 'id',
|
||||
'foreignKey' => 'id',
|
||||
'midKeys' => [
|
||||
lcfirst($entityName).'Id',
|
||||
lcfirst($foreignEntityName).'Id',
|
||||
$key1,
|
||||
$key2,
|
||||
],
|
||||
'foreign' => $foreignLinkName
|
||||
'foreign' => $foreignLinkName,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
@@ -205,7 +205,6 @@ class Converter
|
||||
}
|
||||
|
||||
$primaryColumns = array();
|
||||
$uniqueColumns = array();
|
||||
|
||||
foreach ($entityParams['fields'] as $fieldName => $fieldParams) {
|
||||
|
||||
@@ -234,26 +233,24 @@ class Converter
|
||||
if (!$tables[$entityName]->hasColumn($columnName)) {
|
||||
$tables[$entityName]->addColumn($columnName, $fieldType, $this->getDbFieldParams($fieldParams));
|
||||
}
|
||||
|
||||
//add unique
|
||||
if ($fieldParams['type'] != 'id' && isset($fieldParams['unique'])) {
|
||||
$uniqueColumns = $this->getKeyList($columnName, $fieldParams['unique'], $uniqueColumns);
|
||||
} //END: add unique
|
||||
}
|
||||
|
||||
$tables[$entityName]->setPrimaryKey($primaryColumns);
|
||||
|
||||
if (!empty($indexList[$entityName])) {
|
||||
foreach($indexList[$entityName] as $indexName => $indexParams) {
|
||||
$indexColumnList = $indexParams['columns'];
|
||||
$indexFlagList = isset($indexParams['flags']) ? $indexParams['flags'] : array();
|
||||
$tables[$entityName]->addIndex($indexColumnList, $indexName, $indexFlagList);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($uniqueColumns)) {
|
||||
foreach($uniqueColumns as $uniqueItem) {
|
||||
$tables[$entityName]->addUniqueIndex($uniqueItem);
|
||||
switch ($indexParams['type']) {
|
||||
case 'index':
|
||||
case 'fulltext':
|
||||
$indexFlagList = isset($indexParams['flags']) ? $indexParams['flags'] : array();
|
||||
$tables[$entityName]->addIndex($indexParams['columns'], $indexName, $indexFlagList);
|
||||
break;
|
||||
|
||||
case 'unique':
|
||||
$tables[$entityName]->addUniqueIndex($indexParams['columns'], $indexName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -320,7 +317,7 @@ class Converter
|
||||
'type' => 'foreignId',
|
||||
'len' => $this->idParams['len'],
|
||||
)));
|
||||
$table->addIndex(array($columnName));
|
||||
$table->addIndex(array($columnName), SchemaUtils::generateIndexName($columnName));
|
||||
|
||||
$uniqueIndex[] = $columnName;
|
||||
}
|
||||
@@ -349,7 +346,7 @@ class Converter
|
||||
}
|
||||
|
||||
if (!empty($uniqueIndex)) {
|
||||
$table->addUniqueIndex($uniqueIndex);
|
||||
$table->addUniqueIndex($uniqueIndex, SchemaUtils::generateIndexName($columnName, 'unique'));
|
||||
}
|
||||
//END: add unique indexes
|
||||
|
||||
@@ -421,26 +418,7 @@ class Converter
|
||||
}
|
||||
|
||||
/**
|
||||
* Get key list (index, unique). Ex. index => true OR index => 'somename'
|
||||
* @param string $columnName Column name (underscore field name)
|
||||
* @param bool | string $keyValue
|
||||
* @return array
|
||||
*/
|
||||
protected function getKeyList($columnName, $keyValue, array $keyList)
|
||||
{
|
||||
if ($keyValue === true) {
|
||||
$tableIndexName = SchemaUtils::generateIndexName($columnName);
|
||||
$keyList[$tableIndexName] = array($columnName);
|
||||
} else if (is_string($keyValue)) {
|
||||
$tableIndexName = SchemaUtils::generateIndexName($keyValue);
|
||||
$keyList[$tableIndexName][] = $columnName;
|
||||
}
|
||||
|
||||
return $keyList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom table defenition in "application/Espo/Core/Utils/Database/Schema/tables/" and in metadata 'additionalTables'
|
||||
* Get custom table definition in "application/Espo/Core/Utils/Database/Schema/tables/" and in metadata 'additionalTables'
|
||||
*
|
||||
* @param array $ormMeta
|
||||
*
|
||||
|
||||
@@ -43,30 +43,35 @@ class Utils
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($fieldParams['index'])) {
|
||||
$keyValue = $fieldParams['index'];
|
||||
$columnName = Util::toUnderScore($fieldName);
|
||||
$indexType = static::getIndexTypeByFieldDefs($fieldParams);
|
||||
if (!$indexType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($indexList[$entityName])) {
|
||||
$indexList[$entityName] = [];
|
||||
}
|
||||
if (!isset($indexList[$entityName])) {
|
||||
$indexList[$entityName] = [];
|
||||
}
|
||||
|
||||
if ($keyValue === true) {
|
||||
$tableIndexName = static::generateIndexName($columnName);
|
||||
$indexList[$entityName][$tableIndexName]['columns'] = array($columnName);
|
||||
} else if (is_string($keyValue)) {
|
||||
$tableIndexName = static::generateIndexName($keyValue);
|
||||
$indexList[$entityName][$tableIndexName]['columns'][] = $columnName;
|
||||
}
|
||||
$keyValue = $fieldParams[$indexType];
|
||||
$columnName = Util::toUnderScore($fieldName);
|
||||
|
||||
if ($keyValue === true) {
|
||||
$tableIndexName = static::generateIndexName($columnName, $indexType);
|
||||
$indexList[$entityName][$tableIndexName]['type'] = $indexType;
|
||||
$indexList[$entityName][$tableIndexName]['columns'] = array($columnName);
|
||||
} else if (is_string($keyValue)) {
|
||||
$tableIndexName = static::generateIndexName($keyValue, $indexType);
|
||||
$indexList[$entityName][$tableIndexName]['type'] = $indexType;
|
||||
$indexList[$entityName][$tableIndexName]['columns'][] = $columnName;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($entityParams['indexes']) && is_array($entityParams['indexes'])) {
|
||||
foreach ($entityParams['indexes'] as $indexName => $indexParams) {
|
||||
$tableIndexName = static::generateIndexName($indexName);
|
||||
$indexType = static::getIndexTypeByIndexDefs($indexParams);
|
||||
$tableIndexName = static::generateIndexName($indexName, $indexType);
|
||||
|
||||
if (isset($indexParams['flags']) && is_array($indexParams['flags'])) {
|
||||
|
||||
$skipIndex = false;
|
||||
foreach ($ignoreFlags as $ignoreFlag) {
|
||||
if (($flagKey = array_search($ignoreFlag, $indexParams['flags'])) !== false) {
|
||||
@@ -83,6 +88,7 @@ class Utils
|
||||
}
|
||||
|
||||
if (is_array($indexParams['columns'])) {
|
||||
$indexList[$entityName][$tableIndexName]['type'] = $indexType;
|
||||
$indexList[$entityName][$tableIndexName]['columns'] = Util::toUnderScore($indexParams['columns']);
|
||||
}
|
||||
}
|
||||
@@ -92,8 +98,42 @@ class Utils
|
||||
return $indexList;
|
||||
}
|
||||
|
||||
public static function generateIndexName($name, $prefix = 'IDX', $maxLength = 30)
|
||||
public static function getIndexTypeByFieldDefs(array $fieldDefs)
|
||||
{
|
||||
if ($fieldDefs['type'] != 'id' && isset($fieldDefs['unique']) && $fieldDefs['unique']) {
|
||||
return 'unique';
|
||||
}
|
||||
|
||||
if (isset($fieldDefs['index']) && $fieldDefs['index']) {
|
||||
return 'index';
|
||||
}
|
||||
}
|
||||
|
||||
public static function getIndexTypeByIndexDefs(array $indexDefs)
|
||||
{
|
||||
if (isset($indexDefs['unique']) && $indexDefs['unique']) {
|
||||
return 'unique';
|
||||
}
|
||||
|
||||
if (isset($indexDefs['flags']) && in_array('fulltext', $indexDefs['flags'])) {
|
||||
return 'fulltext';
|
||||
}
|
||||
|
||||
return 'index';
|
||||
}
|
||||
|
||||
public static function generateIndexName($name, $type = 'index', $maxLength = 60)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'unique':
|
||||
$prefix = 'UNIQ';
|
||||
break;
|
||||
|
||||
default:
|
||||
$prefix = 'IDX';
|
||||
break;
|
||||
}
|
||||
|
||||
$nameList = [];
|
||||
$nameList[] = strtoupper($prefix);
|
||||
$nameList[] = strtoupper( Util::toUnderScore($name) );
|
||||
|
||||
@@ -251,4 +251,9 @@ class DateTime
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function getSystemNowString()
|
||||
{
|
||||
return date(self::$systemDateTimeFormat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,7 +588,7 @@ class FieldManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all needed block for a field defenition
|
||||
* Add all needed block for a field definition
|
||||
*
|
||||
* @param string $scope
|
||||
* @param string $fieldName
|
||||
|
||||
@@ -206,7 +206,7 @@ class Manager
|
||||
|
||||
$res = (file_put_contents($fullPath, $data, $flags) !== FALSE);
|
||||
if ($res && function_exists('opcache_invalidate')) {
|
||||
opcache_invalidate($fullPath);
|
||||
@opcache_invalidate($fullPath);
|
||||
}
|
||||
|
||||
return $res;
|
||||
@@ -467,7 +467,7 @@ class Manager
|
||||
if (file_exists($sourceFile) && is_file($sourceFile)) {
|
||||
$res &= copy($sourceFile, $destFile);
|
||||
if (function_exists('opcache_invalidate')) {
|
||||
opcache_invalidate($destFile);
|
||||
@opcache_invalidate($destFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -562,7 +562,7 @@ class Manager
|
||||
|
||||
if (file_exists($filePath) && is_file($filePath)) {
|
||||
if (function_exists('opcache_invalidate')) {
|
||||
opcache_invalidate($filePath, true);
|
||||
@opcache_invalidate($filePath, true);
|
||||
}
|
||||
$result &= unlink($filePath);
|
||||
}
|
||||
|
||||
@@ -28,28 +28,21 @@
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Log\Monolog;
|
||||
|
||||
class Logger extends \Monolog\Logger
|
||||
{
|
||||
protected $defaultLevelName = 'DEBUG';
|
||||
|
||||
|
||||
/**
|
||||
* Get Level Code
|
||||
* @param string $level Ex. DEBUG, ...
|
||||
* @return int
|
||||
*/
|
||||
public function getLevelCode($levelName)
|
||||
public function setLevel($levelName)
|
||||
{
|
||||
$levelName = strtoupper($levelName);
|
||||
$level = static::toMonologLevel($levelName);
|
||||
|
||||
$levels = $this->getLevels();
|
||||
|
||||
if (isset($levels[$levelName])) {
|
||||
return $levels[$levelName];
|
||||
$handlers = $this->getHandlers();
|
||||
foreach ($handlers as $handler) {
|
||||
if ($handler->getLevel() > $level) {
|
||||
$className = get_class($handler);
|
||||
$handler->setLevel($level);
|
||||
}
|
||||
}
|
||||
|
||||
return $levels[$this->defaultLevelName];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,11 +41,16 @@ class Helper
|
||||
*/
|
||||
protected $copiedDefParams = array(
|
||||
'readOnly',
|
||||
'disabled',
|
||||
'notStorable',
|
||||
'layoutListDisabled',
|
||||
'layoutDetailDisabled',
|
||||
'layoutMassUpdateDisabled',
|
||||
'layoutFiltersDisabled',
|
||||
'directAccessDisabled',
|
||||
'customizationDisabled',
|
||||
'importDisabled',
|
||||
'exportDisabled',
|
||||
);
|
||||
|
||||
public function __construct(\Espo\Core\Utils\Metadata $metadata)
|
||||
@@ -59,9 +64,9 @@ class Helper
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field defenition by type in metadata, "fields" key
|
||||
* Get field definition by type in metadata, "fields" key
|
||||
*
|
||||
* @param array | string $fieldDef - It can be a string or field defenition from entityDefs
|
||||
* @param array | string $fieldDef - It can be a string or field definition from entityDefs
|
||||
* @return array | null
|
||||
*/
|
||||
public function getFieldDefsByType($fieldDef)
|
||||
|
||||
@@ -52,8 +52,6 @@ class ThemeManager
|
||||
|
||||
public function getStylesheet()
|
||||
{
|
||||
return $this->metadata->get('themes.' . $this->getName() . '.stylesheet', 'client/css/espo.css');
|
||||
return $this->metadata->get(['themes', $this->getName(), 'stylesheet'], 'client/css/espo/espo.css');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -80,9 +80,10 @@ class Pusher implements WampServerInterface
|
||||
if ($checkCommand) {
|
||||
$checkResult = shell_exec($checkCommand);
|
||||
if ($checkResult !== 'true') {
|
||||
if ($this->isDebugMode) $this->log("check access failed for topic {$topicId} for user {$userId}");
|
||||
if ($this->isDebugMode) $this->log("{$connectionId}: check access failed for topic {$topicId} for user {$userId}");
|
||||
return;
|
||||
}
|
||||
if ($this->isDebugMode) $this->log("{$connectionId}: check access succeed for topic {$topicId} for user {$userId}");
|
||||
}
|
||||
|
||||
if (!in_array($topicId, $this->connectionIdTopicIdListMap[$connectionId])) {
|
||||
@@ -110,20 +111,37 @@ class Pusher implements WampServerInterface
|
||||
if ($index !== false) {
|
||||
if ($this->isDebugMode) $this->log("{$connectionId}: remove topic {$topicId} for user {$userId}");
|
||||
unset($this->connectionIdTopicIdListMap[$connectionId][$index]);
|
||||
$this->connectionIdTopicIdListMap[$connectionId][$index] = array_values($this->connectionIdTopicIdListMap[$connectionId][$index]);
|
||||
$this->connectionIdTopicIdListMap[$connectionId] = array_values($this->connectionIdTopicIdListMap[$connectionId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getCategoryData(string $topicId) : array
|
||||
{
|
||||
$arr = explode('.', $topicId);
|
||||
$category = $arr[0];
|
||||
|
||||
if (array_key_exists($category, $this->categoriesData)) {
|
||||
$data = $this->categoriesData[$category];
|
||||
} else if (array_key_exists($topicId, $this->categoriesData)) {
|
||||
$data = $this->categoriesData[$topicId];
|
||||
} else {
|
||||
$data = [];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getParamsFromTopicId(string $topicId) : array
|
||||
{
|
||||
$arr = explode('.', $topicId);
|
||||
$category = $arr[0];
|
||||
|
||||
$data = $this->getCategoryData($topicId);
|
||||
|
||||
$params = [];
|
||||
|
||||
if (array_key_exists('paramList', $this->categoriesData[$category])) {
|
||||
foreach ($this->categoriesData[$category]['paramList'] as $i => $item) {
|
||||
if (array_key_exists('paramList', $data)) {
|
||||
foreach ($data['paramList'] as $i => $item) {
|
||||
if (isset($arr[$i + 1])) {
|
||||
$params[$item] = $arr[$i + 1];
|
||||
} else {
|
||||
@@ -146,10 +164,12 @@ class Pusher implements WampServerInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
$category = $this->getTopicCategory($topic);
|
||||
if (!array_key_exists('accessCheckCommand', $this->categoriesData[$category])) return null;
|
||||
$data = $this->getCategoryData($topic->getId());
|
||||
|
||||
if (!array_key_exists('accessCheckCommand', $data)) return null;
|
||||
|
||||
$command = $this->phpExecutablePath . " command.php " . $data['accessCheckCommand'];
|
||||
|
||||
$command = $this->phpExecutablePath . " command.php " . $this->categoriesData[$category]['accessCheckCommand'];
|
||||
foreach ($params as $key => $value) {
|
||||
$command = str_replace(':' . $key, $value, $command);
|
||||
}
|
||||
@@ -165,8 +185,9 @@ class Pusher implements WampServerInterface
|
||||
|
||||
protected function isTopicAllowed($topicId)
|
||||
{
|
||||
list($category) = explode('.', $topicId);
|
||||
return in_array($category, $this->categoryList);
|
||||
list($category) = explode( '.', $topicId);
|
||||
|
||||
return in_array($topicId, $this->categoryList) || in_array($category, $this->categoryList);
|
||||
}
|
||||
|
||||
protected function getConnectionIdListByUserId($userId)
|
||||
|
||||
@@ -101,6 +101,7 @@ return [
|
||||
'portalUserLimit',
|
||||
'stylesheet',
|
||||
'userItems',
|
||||
'globalItems',
|
||||
'internalSmtpServer',
|
||||
'internalSmtpPort',
|
||||
'internalSmtpAuth',
|
||||
@@ -193,6 +194,11 @@ return [
|
||||
'adminNotificationsNewExtensionVersion',
|
||||
'leadCaptureAllowOrigin',
|
||||
'cronDisabled',
|
||||
'defaultPortalId',
|
||||
'cleanupDeletedRecords',
|
||||
'authTokenPreventConcurrent',
|
||||
'emailParser',
|
||||
'latestVersion',
|
||||
],
|
||||
'superAdminItems' => [
|
||||
'jobMaxPortion',
|
||||
@@ -215,10 +221,30 @@ return [
|
||||
'superAdminSystemItems' => [
|
||||
],
|
||||
'userItems' => [
|
||||
'outboundEmailFromAddress',
|
||||
'outboundEmailFromName',
|
||||
'outboundEmailBccAddress',
|
||||
'integrations',
|
||||
|
||||
],
|
||||
'globalItems' => [
|
||||
'cacheTimestamp',
|
||||
'language',
|
||||
'isDeveloperMode',
|
||||
'dateFormat',
|
||||
'timeFormat',
|
||||
'timeZone',
|
||||
'decimalMark',
|
||||
'weekStart',
|
||||
'thousandSeparator',
|
||||
'companyLogoId',
|
||||
'applicationName',
|
||||
'jsLibs',
|
||||
'maintenanceMode',
|
||||
'siteUrl',
|
||||
'useCache',
|
||||
'useCacheInDeveloperMode',
|
||||
'isDeveloperMode',
|
||||
'version',
|
||||
'useWebSocket',
|
||||
'webSocketUrl',
|
||||
'aclAllowDeleteCreated',
|
||||
],
|
||||
'isInstalled' => false,
|
||||
'ldapUserNameAttribute' => 'sAMAccountName',
|
||||
|
||||
@@ -185,7 +185,7 @@ class Email extends \Espo\Core\ORM\Entity
|
||||
if (!empty($body)) {
|
||||
$attachmentList = $this->getInlineAttachments();
|
||||
foreach ($attachmentList as $attachment) {
|
||||
$body = str_replace("?entryPoint=attachment&id={$attachment->id}", "cid:{$attachment->id}", $body);
|
||||
$body = str_replace("\"?entryPoint=attachment&id={$attachment->id}\"", "\"cid:{$attachment->id}\"", $body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,12 +196,15 @@ class Email extends \Espo\Core\ORM\Entity
|
||||
|
||||
public function getInlineAttachments()
|
||||
{
|
||||
$attachmentList = array();
|
||||
$attachmentList = [];
|
||||
$idList = [];
|
||||
$body = $this->get('body');
|
||||
if (!empty($body)) {
|
||||
if (preg_match_all("/\?entryPoint=attachment&id=([^&=\"']+)/", $body, $matches)) {
|
||||
if (!empty($matches[1]) && is_array($matches[1])) {
|
||||
foreach($matches[1] as $id) {
|
||||
foreach ($matches[1] as $id) {
|
||||
if (in_array($id, $idList)) continue;
|
||||
$idList[] = $id;
|
||||
$attachment = $this->entityManager->getEntity('Attachment', $id);
|
||||
if ($attachment) {
|
||||
$attachmentList[] = $attachment;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
namespace Espo\EntryPoints;
|
||||
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\NotFoundSilent;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
@@ -84,7 +85,7 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment', $id);
|
||||
|
||||
if (!$attachment) {
|
||||
throw new NotFound();
|
||||
throw new NotFoundSilent();
|
||||
}
|
||||
|
||||
if (!$disableAccessCheck && !$this->getAcl()->checkEntity($attachment)) {
|
||||
@@ -98,7 +99,7 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
$fileType = $attachment->get('type');
|
||||
|
||||
if (!file_exists($filePath)) {
|
||||
throw new NotFound();
|
||||
throw new NotFoundSilent();
|
||||
}
|
||||
|
||||
if (!in_array($fileType, $this->allowedFileTypes)) {
|
||||
|
||||
@@ -87,6 +87,17 @@ class Stream extends \Espo\Core\Hooks\Base
|
||||
if ($this->checkHasStream($entity)) {
|
||||
$this->getStreamService()->unfollowAllUsersFromEntity($entity);
|
||||
}
|
||||
|
||||
$query = $this->getEntityManager()->getQuery();
|
||||
$sql = "
|
||||
UPDATE `note`
|
||||
SET `deleted` = 1, `modified_at` = '".date('Y-m-d H:i:s')."'
|
||||
WHERE
|
||||
(
|
||||
(related_id = ".$query->quote($entity->id)." AND related_type = ".$query->quote($entity->getEntityType()) .")
|
||||
)
|
||||
";
|
||||
$this->getEntityManager()->getPDO()->query($sql);
|
||||
}
|
||||
|
||||
protected function handleCreateRelated(Entity $entity)
|
||||
|
||||
@@ -205,25 +205,25 @@ class Cleanup extends \Espo\Core\Jobs\Base
|
||||
}
|
||||
|
||||
if ($this->getConfig()->get('cleanupOrphanAttachments')) {
|
||||
$collection = $this->getEntityManager()->getRepository('Attachment')->where(array(
|
||||
array(
|
||||
'role' => 'Attachment'
|
||||
),
|
||||
'OR' => array(
|
||||
array(
|
||||
$collection = $this->getEntityManager()->getRepository('Attachment')->where([
|
||||
[
|
||||
'role' => 'Attachment',
|
||||
],
|
||||
'OR' => [
|
||||
[
|
||||
'parentId' => null,
|
||||
'parentType!=' => null,
|
||||
'relatedType=' => null
|
||||
),
|
||||
array(
|
||||
'relatedType=' => null,
|
||||
],
|
||||
[
|
||||
'parentType' => null,
|
||||
'relatedId' => null,
|
||||
'relatedType!=' => null
|
||||
)
|
||||
),
|
||||
'relatedType!=' => null,
|
||||
]
|
||||
],
|
||||
'createdAt<' => $datetime->format('Y-m-d H:i:s'),
|
||||
'createdAt>' => '2017-05-10 00:00:00'
|
||||
))->limit(0, 5000)->find();
|
||||
'createdAt>' => '2018-01-01 00:00:00',
|
||||
])->limit(0, 5000)->find();
|
||||
|
||||
foreach ($collection as $e) {
|
||||
$this->getEntityManager()->removeEntity($e);
|
||||
@@ -428,13 +428,14 @@ class Cleanup extends \Espo\Core\Jobs\Base
|
||||
{
|
||||
if (!$this->getConfig()->get('cleanupDeletedRecords')) return;
|
||||
$period = '-' . $this->getConfig()->get('cleanupDeletedRecordsPeriod', $this->cleanupDeletedRecordsPeriod);
|
||||
$datetime = new \DateTime('-' . $period);
|
||||
$datetime = new \DateTime($period);
|
||||
|
||||
$serviceFactory = $this->getServiceFactory();
|
||||
|
||||
$scopeList = array_keys($this->getMetadata()->get(['scopes']));
|
||||
foreach ($scopeList as $scope) {
|
||||
if (!$this->getMetadata()->get(['scopes', $scope, 'entity'])) continue;
|
||||
if ($scope === 'Attachment') continue;
|
||||
if (!$this->getMetadata()->get(['entityDefs', $scope, 'fields', 'modifiedAt'])) continue;
|
||||
|
||||
if (!$this->getEntityManager()->hasRepository($scope)) continue;
|
||||
$repository = $this->getEntityManager()->getRepository($scope);
|
||||
@@ -444,11 +445,34 @@ class Cleanup extends \Espo\Core\Jobs\Base
|
||||
if (!method_exists($repository, 'select')) continue;
|
||||
if (!method_exists($repository, 'deleteFromDb')) continue;
|
||||
|
||||
$deletedEntityList = $repository->select(['id', 'deleted'])->where([
|
||||
$hasCleanupMethod = false;
|
||||
$service = null;
|
||||
if ($serviceFactory->checkExists($scope)) {
|
||||
$service = $serviceFactory->create($scope);
|
||||
if (method_exists($service, 'cleanup')) {
|
||||
$hasCleanupMethod = true;
|
||||
}
|
||||
}
|
||||
|
||||
$whereClause = [
|
||||
'deleted' => 1,
|
||||
'modifiedAt<' => $datetime->format('Y-m-d H:i:s')
|
||||
])->find(['withDeleted' => true]);
|
||||
];
|
||||
|
||||
if ($this->getMetadata()->get(['entityDefs', $scope, 'fields', 'modifiedAt'])) {
|
||||
$whereClause['modifiedAt<'] = $datetime->format('Y-m-d H:i:s');
|
||||
} else if ($this->getMetadata()->get(['entityDefs', $scope, 'fields', 'createdAt'])) {
|
||||
$whereClause['createdAt<'] = $datetime->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
$deletedEntityList = $repository->select(['id', 'deleted'])->where($whereClause)->find(['withDeleted' => true]);
|
||||
foreach ($deletedEntityList as $e) {
|
||||
if ($hasCleanupMethod) {
|
||||
try {
|
||||
$service->cleanup($e->id);
|
||||
} catch (\Throwable $e) {
|
||||
$GLOBALS['log']->error("Cleanup job: Cleanup scope {$scope}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
$this->cleanupDeletedEntity($e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,12 +88,12 @@ class SubscribeAgain extends \Espo\Core\EntryPoints\Base
|
||||
}
|
||||
|
||||
$link = null;
|
||||
$m = array(
|
||||
$m = [
|
||||
'Account' => 'accounts',
|
||||
'Contact' => 'contacts',
|
||||
'Lead' => 'leads',
|
||||
'User' => 'users'
|
||||
);
|
||||
];
|
||||
if (!empty($m[$target->getEntityType()])) {
|
||||
$link = $m[$target->getEntityType()];
|
||||
}
|
||||
@@ -115,7 +115,11 @@ class SubscribeAgain extends \Espo\Core\EntryPoints\Base
|
||||
}
|
||||
|
||||
$data = [
|
||||
'queueItemId' => $queueItemId
|
||||
'actionData' => [
|
||||
'queueItemId' => $queueItemId,
|
||||
],
|
||||
'view' => $this->getMetadata()->get(['clientDefs', 'Campaign', 'subscribeView']),
|
||||
'template' => $this->getMetadata()->get(['clientDefs', 'Campaign', 'subscribeTemplate']),
|
||||
];
|
||||
|
||||
$runScript = "
|
||||
|
||||
@@ -88,12 +88,12 @@ class Unsubscribe extends \Espo\Core\EntryPoints\Base
|
||||
}
|
||||
|
||||
$link = null;
|
||||
$m = array(
|
||||
$m = [
|
||||
'Account' => 'accounts',
|
||||
'Contact' => 'contacts',
|
||||
'Lead' => 'leads',
|
||||
'User' => 'users'
|
||||
);
|
||||
];
|
||||
if (!empty($m[$target->getEntityType()])) {
|
||||
$link = $m[$target->getEntityType()];
|
||||
}
|
||||
@@ -115,7 +115,11 @@ class Unsubscribe extends \Espo\Core\EntryPoints\Base
|
||||
}
|
||||
|
||||
$data = [
|
||||
'queueItemId' => $queueItemId
|
||||
'actionData' => [
|
||||
'queueItemId' => $queueItemId,
|
||||
],
|
||||
'view' => $this->getMetadata()->get(['clientDefs', 'Campaign', 'unsubscribeView']),
|
||||
'template' => $this->getMetadata()->get(['clientDefs', 'Campaign', 'unsubscribeTemplate']),
|
||||
];
|
||||
|
||||
$runScript = "
|
||||
@@ -137,4 +141,3 @@ class Unsubscribe extends \Espo\Core\EntryPoints\Base
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ class Opportunity extends \Espo\Core\ORM\Repositories\RDB
|
||||
if ($entity->isNew()) {
|
||||
if (!$entity->has('probability') && $entity->get('stage')) {
|
||||
$probability = $this->getMetadata()->get('entityDefs.Opportunity.fields.stage.probabilityMap.' . $entity->get('stage'), 0);
|
||||
$entity->set('probability', $probability);
|
||||
if (!is_null($probability)) {
|
||||
$entity->set('probability', $probability);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Navn",
|
||||
"emailAddress": "Email",
|
||||
"website": "Website",
|
||||
"phoneNumber": "Telefon",
|
||||
"billingAddress": "Betalingsadresse",
|
||||
"shippingAddress": "Leveringsadresse",
|
||||
"description": "Beskrivelse",
|
||||
"sicCode": "Sic Kode",
|
||||
"industry": "Industri",
|
||||
"type": "Type",
|
||||
"contactRole": "Titel",
|
||||
"campaign": "Kampagne",
|
||||
"targetLists": "Kontaktlister",
|
||||
"targetList": "Kontaktliste",
|
||||
"originalLead": "Oprindelig Lead"
|
||||
"originalLead": "Oprindelig Lead",
|
||||
"contactIsInactive": "inaktiv"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Kontakter",
|
||||
@@ -34,8 +32,6 @@
|
||||
"options": {
|
||||
"type": {
|
||||
"Customer": "Kunde",
|
||||
"Investor": "Investor",
|
||||
"Partner": "Partner",
|
||||
"Reseller": "Forhandler"
|
||||
},
|
||||
"industry": {
|
||||
@@ -61,9 +57,7 @@
|
||||
"Manufacturing": "Produktion",
|
||||
"Publishing": "Medien",
|
||||
"Real Estate": "Ejendom",
|
||||
"Service": "Service",
|
||||
"Sports": "Sport",
|
||||
"Software": "Software",
|
||||
"Technology": "Teknologi",
|
||||
"Telecommunications": "Telekommunikation",
|
||||
"Television": "TV",
|
||||
@@ -75,25 +69,23 @@
|
||||
"Defense": "Forsvar",
|
||||
"Creative": "Kreativ",
|
||||
"Culture": "Kultur",
|
||||
"Consulting": "Consulting",
|
||||
"Electric Power": "Elektroenergi",
|
||||
"Hospitality": "Hotel og Restaurant",
|
||||
"Mass Media": "Massemedier",
|
||||
"Mining": "Mineindustri",
|
||||
"Music": "Musik",
|
||||
"Marketing": "Marketing",
|
||||
"Petroleum": "Olieindustri",
|
||||
"Retail": "Retail",
|
||||
"Shipping": "Shipping",
|
||||
"Support": "Service",
|
||||
"Testing, Inspection & Certification": "Testning, Inspektion og Certificering",
|
||||
"Wholesale": "Engros",
|
||||
"Water": "Vand"
|
||||
"Water": "Vand",
|
||||
"Travel": "Rejse"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Account": "Opret Konto",
|
||||
"Copy Billing": "Kopier Betalingsadresse"
|
||||
"Copy Billing": "Kopier Betalingsadresse",
|
||||
"Set Primary": "Sæt primær"
|
||||
},
|
||||
"presetFilters": {
|
||||
"customers": "Kunder",
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
{
|
||||
"layouts": {
|
||||
"detailConvert": "Konverter Lead",
|
||||
"listForAccount": "Liste (for Konto)"
|
||||
"listForAccount": "Liste (for Konto)",
|
||||
"listForContact": "Liste (for kontakter)"
|
||||
},
|
||||
"templates": {
|
||||
"reminder": "Påmindelse"
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
"current": "Aktuel",
|
||||
"time": "Tid",
|
||||
"User List": "Brugerliste",
|
||||
"Manage Users": "Administrer Brugere"
|
||||
"Manage Users": "Administrer Brugere",
|
||||
"View Calendar": "Se kalender",
|
||||
"Create Shared View": "Opret delt visning"
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
"fields": {
|
||||
"name": "Navn",
|
||||
"parent": "Henviser til",
|
||||
"status": "Status",
|
||||
"dateStart": "Startdato",
|
||||
"dateEnd": "Slutdato",
|
||||
"direction": "Retning",
|
||||
@@ -10,7 +9,6 @@
|
||||
"description": "Beskrivelse",
|
||||
"users": "Brugere",
|
||||
"contacts": "Kontakter",
|
||||
"leads": "Leads",
|
||||
"reminders": "Underretninger",
|
||||
"account": "Konto",
|
||||
"acceptanceStatus": "Acceptstatus"
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
"fields": {
|
||||
"name": "Navn",
|
||||
"description": "Beskrivelse",
|
||||
"status": "Status",
|
||||
"type": "Type",
|
||||
"startDate": "Startdato",
|
||||
"endDate": "Slutdato",
|
||||
"targetLists": "Kontaktliste",
|
||||
@@ -18,28 +16,31 @@
|
||||
"leadCreatedCount": "Oprettede Leads",
|
||||
"revenue": "Indtægt",
|
||||
"revenueConverted": "Indtægt (konverteret)",
|
||||
"budget": "Budget",
|
||||
"budgetConverted": "Budget (konverteret)"
|
||||
"budgetConverted": "Budget (konverteret)",
|
||||
"contactsTemplate": "Kontakt skabelon",
|
||||
"leadsTemplate": "Leads skabeloner",
|
||||
"accountsTemplate": "Konto skabelon",
|
||||
"usersTemplate": "Brugere skabelon",
|
||||
"mailMergeOnlyWithAddress": "Spring over poster uden fyldt adresse",
|
||||
"optedInCount": "Tilmeldt",
|
||||
"budgetCurrency": "Budget Valuta"
|
||||
},
|
||||
"links": {
|
||||
"targetLists": "Kontaktliste",
|
||||
"excludingTargetLists": "Udelukker Kontaktlister",
|
||||
"accounts": "Konti",
|
||||
"contacts": "Kontakter",
|
||||
"leads": "Leads",
|
||||
"opportunities": "Muligheder",
|
||||
"campaignLogRecords": "Log",
|
||||
"massEmails": "Masse-Email",
|
||||
"trackingUrls": "Tracking URLs"
|
||||
"contactsTemplate": "Kontakt skabelon",
|
||||
"leadsTemplate": "Leads skabeloner",
|
||||
"accountsTemplate": "Konto skabelon",
|
||||
"usersTemplate": "Brugere skabelon"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
"Email": "Email",
|
||||
"Web": "Web",
|
||||
"Television": "TV",
|
||||
"Radio": "Radio",
|
||||
"Newsletter": "Nyhedsbrev",
|
||||
"Mail": "Mail"
|
||||
"Newsletter": "Nyhedsbrev"
|
||||
},
|
||||
"status": {
|
||||
"Planning": "Planlægning",
|
||||
@@ -59,7 +60,9 @@
|
||||
"Email Templates": "Emailskabeloner",
|
||||
"Unsubscribe again": "Frameld igen",
|
||||
"Subscribe again": "Tilmeld igen",
|
||||
"Create Target List": "Opret Kontaktliste"
|
||||
"Create Target List": "Opret Kontaktliste",
|
||||
"Mail Merge": "Mailfletning",
|
||||
"Generate Mail Merge PDF": "Generer mailfletning i PDF"
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Aktiv"
|
||||
|
||||
@@ -2,19 +2,20 @@
|
||||
"fields": {
|
||||
"action": "Handling",
|
||||
"actionDate": "Dato",
|
||||
"data": "Data",
|
||||
"campaign": "Kampagne",
|
||||
"parent": "Mål",
|
||||
"object": "Objekt",
|
||||
"application": "Applikation",
|
||||
"queueItem": "Sæt i Kø",
|
||||
"stringData": "Streng Data",
|
||||
"stringAdditionalData": "Streng Ekstra Data"
|
||||
"stringAdditionalData": "Streng Ekstra Data",
|
||||
"isTest": "Er test"
|
||||
},
|
||||
"links": {
|
||||
"queueItem": "Sæt i Kø",
|
||||
"parent": "Henviser til",
|
||||
"object": "Objekt"
|
||||
"object": "Objekt",
|
||||
"campaign": "Kampagne"
|
||||
},
|
||||
"options": {
|
||||
"action": {
|
||||
@@ -23,7 +24,8 @@
|
||||
"Opted Out": "Sat til Opt-Out",
|
||||
"Bounced": "Kunne ikke leveres",
|
||||
"Clicked": "Klikket",
|
||||
"Lead Created": "Lead Oprettet"
|
||||
"Lead Created": "Lead Oprettet",
|
||||
"Opted In": "Tilmeldt"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
@@ -35,6 +37,7 @@
|
||||
"optedOut": "Sat til Opt-Out",
|
||||
"bounced": "Kunne ikke leveres",
|
||||
"clicked": "Klikket",
|
||||
"leadCreated": "Lead Oprettet"
|
||||
"leadCreated": "Lead Oprettet",
|
||||
"optedIn": "Tilmeldt"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"fields": {
|
||||
"url": "URL",
|
||||
"urlToUse": "Kode til indsættelse i stedet for URL",
|
||||
"campaign": "Kampagne"
|
||||
},
|
||||
|
||||
@@ -2,27 +2,24 @@
|
||||
"fields": {
|
||||
"name": "Navn",
|
||||
"number": "Nummer",
|
||||
"status": "Status",
|
||||
"account": "Konto",
|
||||
"contact": "Kontakt",
|
||||
"contacts": "Kontakter",
|
||||
"priority": "Prioritet",
|
||||
"type": "Type",
|
||||
"description": "Beskrivelse",
|
||||
"inboundEmail": "Ingående Email",
|
||||
"lead": "Lead"
|
||||
"attachments": "Vedhæftede filer",
|
||||
"inboundEmail": "Gruppe email konto"
|
||||
},
|
||||
"links": {
|
||||
"inboundEmail": "Indgående Email",
|
||||
"account": "Konto",
|
||||
"contact": "Kontakt (Primær)",
|
||||
"Contacts": "Kontakter",
|
||||
"meetings": "Møder",
|
||||
"calls": "Opkald",
|
||||
"tasks": "Opgaver",
|
||||
"emails": "Emails",
|
||||
"articles": "Vidensbase Artikler",
|
||||
"lead": "Lead"
|
||||
"attachments": "Vedhæftede filer",
|
||||
"inboundEmail": "Gruppe email konto"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
@@ -35,14 +32,12 @@
|
||||
},
|
||||
"priority": {
|
||||
"Low": "Lav",
|
||||
"Normal": "Normal",
|
||||
"High": "Høj",
|
||||
"Urgent": "Vigtig"
|
||||
},
|
||||
"type": {
|
||||
"Question": "Spørgsmål",
|
||||
"Incident": "Hændelse",
|
||||
"Problem": "Problem"
|
||||
"Incident": "Hændelse"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Navn",
|
||||
"emailAddress": "Email",
|
||||
"title": "Titel",
|
||||
"accountRole": "Titel",
|
||||
"account": "Konto",
|
||||
"accounts": "Konti",
|
||||
@@ -17,7 +15,10 @@
|
||||
"targetList": "Kontaktliste",
|
||||
"portalUser": "Portalbruger",
|
||||
"originalLead": "Oprindelig Lead",
|
||||
"acceptanceStatus": "Acceptance Status"
|
||||
"accountIsInactive": "Konto inaktiv",
|
||||
"acceptanceStatusMeetings": "Accept status (Møder)",
|
||||
"acceptanceStatusCalls": "Accpet status (Opkald)",
|
||||
"title": "Primær brugertitel"
|
||||
},
|
||||
"links": {
|
||||
"opportunities": "Muligheder",
|
||||
@@ -30,21 +31,21 @@
|
||||
"casesPrimary": "Sager (Primære)",
|
||||
"portalUser": "Portalbruger",
|
||||
"originalLead": "Oprindelig Lead",
|
||||
"documents": "Dokumenter"
|
||||
"documents": "Dokumenter",
|
||||
"tasksPrimary": "Opgaver (udvidede)"
|
||||
},
|
||||
"labels": {
|
||||
"Create Contact": "Opret Kontakt"
|
||||
},
|
||||
"options": {
|
||||
"opportunityRole": {
|
||||
"": "--Ingen--",
|
||||
"Decision Maker": "Beslutningstager",
|
||||
"Evaluator": "Evaluator",
|
||||
"Influencer": "Har Indflydelse"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"portalUsers": "Portalbrugere",
|
||||
"notPortalUsers": "Ikke Portalbrugere"
|
||||
"notPortalUsers": "Ikke Portalbrugere",
|
||||
"accountActive": "Aktiv"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"fields": {
|
||||
"futureDays": "Næste X dage",
|
||||
"useLastStage": "Gruppe med sidste opnået stadie"
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,7 @@
|
||||
},
|
||||
"fields": {
|
||||
"name": "Navn",
|
||||
"status": "Status",
|
||||
"file": "Fil",
|
||||
"type": "Type",
|
||||
"publishDate": "Offentliggørelsesdato",
|
||||
"expirationDate": "Afslutningsdato",
|
||||
"description": "Beskrivelse",
|
||||
@@ -18,7 +16,6 @@
|
||||
"accounts": "Konti",
|
||||
"opportunities": "Muligheder",
|
||||
"folder": "Mappe",
|
||||
"leads": "Leads",
|
||||
"contacts": "Kontakter"
|
||||
},
|
||||
"options": {
|
||||
@@ -31,8 +28,6 @@
|
||||
"type": {
|
||||
"": "ingen",
|
||||
"Contract": "Kontrakt",
|
||||
"NDA": "NDA",
|
||||
"EULA": "EULA",
|
||||
"License Agreement": "Licensaftale"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
"Create Lead": "Opret Lead",
|
||||
"Create Contact": "Opret Kontakt",
|
||||
"Create Task": "Opret Opgave",
|
||||
"Create Case": "Opret Sag",
|
||||
"Add to Contact": "Add to Contact",
|
||||
"Add to Lead": "Add to Lead"
|
||||
"Create Case": "Opret Sag"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Navn",
|
||||
"status": "Status",
|
||||
"target": "Mål",
|
||||
"sentAt": "Dato Sendt",
|
||||
"attemptCount": "Forsøg",
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
"parent": "Overordnet",
|
||||
"contacts": "Kontakter",
|
||||
"opportunities": "Muligheder",
|
||||
"leads": "Leads",
|
||||
"meetings": "Møder",
|
||||
"calls": "Opkald",
|
||||
"tasks": "Opgaver",
|
||||
"emails": "Emails",
|
||||
"accounts": "Konti",
|
||||
"cases": "Sager",
|
||||
"documents": "Dokumenter",
|
||||
@@ -18,7 +16,6 @@
|
||||
"scopeNames": {
|
||||
"Account": "Konto",
|
||||
"Contact": "Kontakt",
|
||||
"Lead": "Lead",
|
||||
"Target": "Mål",
|
||||
"Opportunity": "Mulighed",
|
||||
"Meeting": "Møde",
|
||||
@@ -32,7 +29,6 @@
|
||||
"TargetList": "Kontaktliste",
|
||||
"MassEmail": "Masse-Email",
|
||||
"EmailQueueItem": "Emne i Email-Kø",
|
||||
"CampaignTrackingUrl": "Tracking URL",
|
||||
"Activities": "Aktiviteter",
|
||||
"KnowledgeBaseArticle": "Vidensbase Artikel",
|
||||
"KnowledgeBaseCategory": "Vidensbase Kategori",
|
||||
@@ -41,7 +37,6 @@
|
||||
"scopeNamesPlural": {
|
||||
"Account": "Konti",
|
||||
"Contact": "Kontakter",
|
||||
"Lead": "Leads",
|
||||
"Target": "Mål",
|
||||
"Opportunity": "Muligheder",
|
||||
"Meeting": "Møder",
|
||||
@@ -108,11 +103,5 @@
|
||||
"shippingAddressState": "Stat (Levering)",
|
||||
"shippingAddressPostalCode": "Postnummer (Levering)",
|
||||
"shippingAddressMap": "Kort (Levering)"
|
||||
},
|
||||
"options": {
|
||||
"reminderTypes": {
|
||||
"Popup": "Popup",
|
||||
"Email": "Email"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,6 @@
|
||||
},
|
||||
"fields": {
|
||||
"name": "Navn",
|
||||
"status": "Status",
|
||||
"type": "Type",
|
||||
"attachments": "Vedhæftede",
|
||||
"publishDate": "Startdato",
|
||||
"expirationDate": "Slutdato",
|
||||
@@ -40,8 +38,5 @@
|
||||
},
|
||||
"presetFilters": {
|
||||
"published": "Publiseret"
|
||||
},
|
||||
"tooltips": {
|
||||
"portals": "Article will be available only in specified portals."
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,15 @@
|
||||
"labels": {
|
||||
"Converted To": "Konverteret Til",
|
||||
"Create Lead": "Opret Lead",
|
||||
"Convert": "Konverter",
|
||||
"convert": "convert"
|
||||
"Convert": "Konverter"
|
||||
},
|
||||
"fields": {
|
||||
"name": " Navn",
|
||||
"emailAddress": "Email",
|
||||
"title": "Titel",
|
||||
"website": "Website",
|
||||
"phoneNumber": "Telefon",
|
||||
"accountName": "Kontonavn",
|
||||
"doNotCall": "Ring Ikke!",
|
||||
"address": "Adresse",
|
||||
"status": "Status",
|
||||
"source": "Kilde",
|
||||
"opportunityAmount": "Beløb for Mulighed",
|
||||
"opportunityAmountConverted": "Beløb for Mulighed (Konverteret)",
|
||||
@@ -26,8 +22,8 @@
|
||||
"targetLists": "Kontaktlister",
|
||||
"targetList": "Kontaktliste",
|
||||
"industry": "Industri",
|
||||
"acceptanceStatus": "Acceptance Status",
|
||||
"opportunityAmountCurrency": "Opportunity Amount Currency"
|
||||
"acceptanceStatusMeetings": "Accept status (Møder)",
|
||||
"acceptanceStatusCalls": "Accept status (Opkald)"
|
||||
},
|
||||
"links": {
|
||||
"targetLists": "Kontaktlister",
|
||||
@@ -51,9 +47,7 @@
|
||||
"source": {
|
||||
"": "Ingen",
|
||||
"Call": "Samtale",
|
||||
"Email": "Email",
|
||||
"Existing Customer": "Eksisterende Kunde",
|
||||
"Partner": "Partner",
|
||||
"Public Relations": "PR",
|
||||
"Web Site": "Webside",
|
||||
"Campaign": "Kampagne",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Navn",
|
||||
"status": "Status",
|
||||
"storeSentEmails": "Lager Sendte Emails",
|
||||
"startAt": "Startdato",
|
||||
"fromAddress": "Fra Adresse",
|
||||
@@ -13,7 +12,8 @@
|
||||
"inboundEmail": "Emailkonto",
|
||||
"targetLists": "Kontaktlister",
|
||||
"excludingTargetLists": "Ekskluderer Kontaktlister",
|
||||
"optOutEntirely": "Fuldstændig Opt-Out"
|
||||
"optOutEntirely": "Fuldstændig Opt-Out",
|
||||
"smtpAccount": "SMTP konto"
|
||||
},
|
||||
"links": {
|
||||
"targetLists": "Kontaktlister",
|
||||
@@ -35,7 +35,7 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create MassEmail": "Opret Masse-Email",
|
||||
"Send Test": "Send Test"
|
||||
"group": "gruppe"
|
||||
},
|
||||
"messages": {
|
||||
"selectAtLeastOneTarget": "Vælg mindst et Mål",
|
||||
@@ -44,7 +44,8 @@
|
||||
"tooltips": {
|
||||
"optOutEntirely": "Emailadresser tilhørende modtagere, som er afmeldt, bliver markeret som \"afmeldt\", og de vil ikke modtage masse-emails fremover.",
|
||||
"targetLists": "Kontakter der skal modtage meddelelser",
|
||||
"excludingTargetLists": "Kontakter der ikke skal modtage meddelelser"
|
||||
"excludingTargetLists": "Kontakter der ikke skal modtage meddelelser",
|
||||
"storeSentEmails": "Emails vil blive gemt i CRM"
|
||||
},
|
||||
"presetFilters": {
|
||||
"actual": "Aktuel",
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"fields": {
|
||||
"name": "Navn",
|
||||
"parent": "Henviser til",
|
||||
"status": "Status",
|
||||
"dateStart": "Startdato",
|
||||
"dateEnd": "Slutdato",
|
||||
"duration": "Varighed",
|
||||
@@ -12,7 +11,11 @@
|
||||
"leads": "leads",
|
||||
"reminders": "Påmindelser",
|
||||
"account": "Konto",
|
||||
"acceptanceStatus": "Acceptstatus"
|
||||
"acceptanceStatus": "Acceptstatus",
|
||||
"dateStartDate": "Start dato (hele dagen)",
|
||||
"dateEndDate": "Slut dato (hele dagen)",
|
||||
"isAllDay": "Hele dagen",
|
||||
"Acceptance": "Accept"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
@@ -37,7 +40,8 @@
|
||||
"Set Not Held": "Marker som Ikke Gennemført",
|
||||
"Send Invitations": "Send Invitationer",
|
||||
"on time": "Til Tiden",
|
||||
"before": "Før"
|
||||
"before": "Før",
|
||||
"All-Day": "Hele dagen"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planlagt",
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
"amountWeightedConverted": "Beløb Vægtet",
|
||||
"campaign": "Kampagne",
|
||||
"originalLead": "Oprindelig Lead",
|
||||
"amountCurrency": "Amount Currency"
|
||||
"contactRole": "Kontakt roller",
|
||||
"lastStage": "Sidste etape"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Kontakter",
|
||||
@@ -26,8 +27,6 @@
|
||||
"stage": {
|
||||
"Prospecting": "Undersøges",
|
||||
"Qualification": "Kvalifikation",
|
||||
"Proposal": "Tilbud",
|
||||
"Negotiation": "Forhandler",
|
||||
"Needs Analysis": "Behovsanalyse",
|
||||
"Value Proposition": "Vejledende Tilbud",
|
||||
"Id. Decision Makers": "Identifikation af Beslutningstagere",
|
||||
@@ -35,7 +34,9 @@
|
||||
"Proposal/Price Quote": "Tilbud/Pristilbud",
|
||||
"Negotiation/Review": "Forhandler/Gennemgår",
|
||||
"Closed Won": "Vundet og Lukket",
|
||||
"Closed Lost": "Tabt og Lukket"
|
||||
"Closed Lost": "Tabt og Lukket",
|
||||
"Proposal": "Forslag",
|
||||
"Negotiation": "Forhandling"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
|
||||
@@ -7,22 +7,25 @@
|
||||
"endDate": "Slutdato",
|
||||
"targetLists": "Kontaktliste",
|
||||
"includingActionList": "Inkluder",
|
||||
"excludingActionList": "Ekskluder"
|
||||
"excludingActionList": "Ekskluder",
|
||||
"optedOutCount": "Antal fravalgte",
|
||||
"targetStatus": "Mål status",
|
||||
"isOptedOut": "er fravalgte"
|
||||
},
|
||||
"links": {
|
||||
"accounts": "Konti",
|
||||
"contacts": "Kontakter",
|
||||
"leads": "Leads",
|
||||
"campaigns": "Kampagner",
|
||||
"massEmails": "Masse-Emails"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
"Email": "Email",
|
||||
"Web": "Web",
|
||||
"Television": "TV",
|
||||
"Radio": "Radio",
|
||||
"Newsletter": "Nyhedsbrev"
|
||||
},
|
||||
"targetStatus": {
|
||||
"Opted Out": "Fravalgt",
|
||||
"Listed": "Listet"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"fields": {
|
||||
"name": "Navn",
|
||||
"parent": "Henviser til",
|
||||
"status": "Status",
|
||||
"dateStart": "Startdato",
|
||||
"dateEnd": "Tidsfrist",
|
||||
"dateStartDate": "Startdato (Hele dagen)",
|
||||
@@ -13,10 +12,13 @@
|
||||
"account": "Konto",
|
||||
"dateCompleted": "Afsluttet Dato",
|
||||
"attachments": "Vedhæftede",
|
||||
"reminders": "Underretninger"
|
||||
"reminders": "Underretninger",
|
||||
"contact": "Kontakt"
|
||||
},
|
||||
"links": {
|
||||
"attachments": "Vedhæftede"
|
||||
"attachments": "Vedhæftede",
|
||||
"account": "Konto",
|
||||
"contact": "Kontakt"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
@@ -28,7 +30,6 @@
|
||||
},
|
||||
"priority": {
|
||||
"Low": "Lav",
|
||||
"Normal": "Normal",
|
||||
"High": "Høj",
|
||||
"Urgent": "Vigtig"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"targetLists": "Kontaktlister"
|
||||
},
|
||||
"fields": {
|
||||
"acceptanceStatus": "Acceptance Status"
|
||||
"acceptanceStatusMeetings": "Accept satus (Møde)",
|
||||
"acceptanceStatusCalls": "Accept status (Opkald)"
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,9 @@
|
||||
"detailConvert": "Convertir Referencia",
|
||||
"listForAccount": "Listado (por Cuentas)",
|
||||
"listForContact": "Lista (para Contactos)"
|
||||
},
|
||||
"templates": {
|
||||
"invitation": "Invitación",
|
||||
"reminder": "Recordatorio"
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,8 @@
|
||||
"leadsTemplate": "Formato de Referencias",
|
||||
"accountsTemplate": "Formato de Cuentas",
|
||||
"usersTemplate": "Formato de Usuarios",
|
||||
"mailMergeOnlyWithAddress": "Saltar registros sin dirección capturada"
|
||||
"mailMergeOnlyWithAddress": "Saltar registros sin dirección capturada",
|
||||
"optedInCount": "Opt-In aceptado"
|
||||
},
|
||||
"links": {
|
||||
"targetLists": "Listas de Intereses",
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
"Opted Out": "Rechazado",
|
||||
"Bounced": "Rebotados",
|
||||
"Clicked": "Leído",
|
||||
"Lead Created": "Referencias Creadas"
|
||||
"Lead Created": "Referencias Creadas",
|
||||
"Opted In": "Opt-In aceptado"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
@@ -37,6 +38,7 @@
|
||||
"optedOut": "Rechazado",
|
||||
"bounced": "Rebotados",
|
||||
"clicked": "Leído",
|
||||
"leadCreated": "Referencia Creada"
|
||||
"leadCreated": "Referencia Creada",
|
||||
"optedIn": "Opt-In aceptado"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user