Compare commits
292 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 56a04336fe | |||
| 1814529d3e | |||
| 1dbe2d9eac | |||
| 4ca099afc4 | |||
| 7ca09bc893 | |||
| 0a4a8c956a | |||
| 6f2a7ae08f | |||
| 45a9dd1226 | |||
| 9d904171c9 | |||
| 53abea7cdd | |||
| 6427604724 | |||
| 0d72dc7c2f | |||
| 9ee5a98ff4 | |||
| 3f0c92744c | |||
| 7a87749c4c | |||
| 0eaab6b7ee | |||
| b52722565a | |||
| 80fd2a2006 | |||
| 1c1fdffb7d | |||
| 53481890db | |||
| b82a3d0f31 | |||
| 1700b27501 | |||
| 635064e116 | |||
| f6e45d8a68 | |||
| ee0cf4bca5 | |||
| ae98290721 | |||
| 24bbcf0e0a | |||
| 23b1945a3e | |||
| e1fe3c03dd | |||
| 7e0034f674 | |||
| d73cfbca53 | |||
| 3eec2b2a33 | |||
| d60dc744e6 | |||
| bd66211c3c | |||
| 2f341c8967 | |||
| 5c7612c9cf | |||
| b41c0f34aa | |||
| 14eebc7392 | |||
| 5a86d0e396 | |||
| a4e0c8107d | |||
| 1652de16a7 | |||
| ad539e19a2 | |||
| 592f073bf9 | |||
| d5c1d1b86e | |||
| bd70e2424c | |||
| 06d6299d7f | |||
| d00d2bdb0f | |||
| 9f481f6887 | |||
| 47d0501828 | |||
| a4cd8dccfe | |||
| eee0f0eb13 | |||
| 67b9600341 | |||
| 4c0329e6be | |||
| ff6cd18411 | |||
| 8d4219802b | |||
| 07e7374a18 | |||
| 060f517591 | |||
| 1af5e93bd3 | |||
| 38df3162b3 | |||
| e03298b041 | |||
| 80278b7213 | |||
| a701905e9c | |||
| 59b896e594 | |||
| ba4c8e0afd | |||
| 9175d8c7ce | |||
| 052fee6ba2 | |||
| aae3afc895 | |||
| 1892ff6cae | |||
| aa3e9fd8b0 | |||
| 2863092911 | |||
| 1c36421157 | |||
| 77f7da0ba5 | |||
| a5f858dda2 | |||
| a5b7bfc00e | |||
| 4d2cb6c38e | |||
| b6bd70d47c | |||
| ef3ed38b97 | |||
| a38b86b2c6 | |||
| a87044623c | |||
| 44a96ddece | |||
| b0e911870b | |||
| 96bb421b0a | |||
| c281d7b2d9 | |||
| dc5766088f | |||
| fe69f97b1e | |||
| b7bc1e3622 | |||
| b3c4123669 | |||
| 0795f6f6f2 | |||
| c3cd909063 | |||
| 0e37c26b9f | |||
| 80937f8d09 | |||
| 380cdeba35 | |||
| 1eabce0d2e | |||
| 3cd5f801a5 | |||
| c1cfd75bd6 | |||
| dd5fabdfa4 | |||
| 3e9c7056b0 | |||
| 26188879b6 | |||
| 488717c6a1 | |||
| b8476d7335 | |||
| 1cfad615c0 | |||
| e3a3547a54 | |||
| e6948aba2e | |||
| d4943e4d1c | |||
| af5e7d99b2 | |||
| 667a46f141 | |||
| 67f65492de | |||
| b6a98e7121 | |||
| 9669ff91bb | |||
| acb6e245a2 | |||
| b5e015e9c9 | |||
| 70d2e311e5 | |||
| 6c7e5c0d02 | |||
| d4558d73b3 | |||
| e2257f6cfd | |||
| 149fa41e2b | |||
| 71e4c2fca0 | |||
| 5a4613617c | |||
| cbf9dd458e | |||
| 08553bdf9d | |||
| d0b61b42e0 | |||
| 3e3348c4a7 | |||
| c32b0f365b | |||
| 8fd0554714 | |||
| 982f0e1f62 | |||
| c87f5dfab3 | |||
| b335462aa4 | |||
| 97c951484d | |||
| 2215f15aaf | |||
| 65f38a4906 | |||
| 6429823cc3 | |||
| 2a71bb2ea1 | |||
| 1674c2221e | |||
| e3b448f520 | |||
| a04c973817 | |||
| 01c9939215 | |||
| 2d57824cb0 | |||
| 878385f14b | |||
| 8b82058d06 | |||
| 68e05f0935 | |||
| cb7492c042 | |||
| beb811755f | |||
| 7c7fc4ee0f | |||
| aeef25f7ec | |||
| 6856ff97b1 | |||
| 10f6f7600c | |||
| a0b678a3d9 | |||
| f78e558a33 | |||
| e205ef3370 | |||
| 8b6e4d469e | |||
| a63ec2710b | |||
| 6895fac58c | |||
| ea3c8f2d35 | |||
| 0f2c050537 | |||
| 2cd8866c73 | |||
| 86a5e19b55 | |||
| 61f435812d | |||
| 217d0f6540 | |||
| f0e7a8f029 | |||
| d2954483d9 | |||
| 999b88cba1 | |||
| 717df30063 | |||
| d889c78f0c | |||
| 4737c506f2 | |||
| 78cb1a8052 | |||
| dac8ca5a6d | |||
| e04ac6778a | |||
| 5f34d4f2fd | |||
| ca7c0f07e9 | |||
| af26f29bec | |||
| 0c44f78ea1 | |||
| bed62e2e71 | |||
| 6d61db86df | |||
| 4feb055256 | |||
| 10a44239ed | |||
| 8a78eda520 | |||
| 891b159b30 | |||
| 0d06770e80 | |||
| f8675bd45c | |||
| c35136b524 | |||
| a0384deb00 | |||
| e35fb15a31 | |||
| fe86807091 | |||
| e12a15ecdb | |||
| 24dcd46d6f | |||
| 15196f2062 | |||
| 1ae1b20111 | |||
| 84de477be0 | |||
| 97407de17d | |||
| 84bc5beed2 | |||
| 6974b1637d | |||
| dc89aff7b1 | |||
| 2bfea69fe3 | |||
| 0e1e481546 | |||
| 52e938888d | |||
| a2ef1656fb | |||
| c168c3ff9b | |||
| 56af0baea2 | |||
| 35ecf2e144 | |||
| d25692b15e | |||
| 59a66cb8fa | |||
| 75ce454b2a | |||
| b94134a35a | |||
| 4b09f055e4 | |||
| d743eca6a3 | |||
| 0e3c872310 | |||
| f8b56cba24 | |||
| b506cd726c | |||
| 998aaec170 | |||
| 4c30507a85 | |||
| a55f1aca58 | |||
| 868cf4e22c | |||
| 2decd9016e | |||
| 9cba465473 | |||
| b9344afb27 | |||
| 7074991771 | |||
| b43d37ac79 | |||
| 18b393b286 | |||
| 728fce75d7 | |||
| 50d441aea0 | |||
| d75f9e5acd | |||
| 3c96cf240e | |||
| 2583c77108 | |||
| a3ad210ec2 | |||
| 6bd7d2398d | |||
| 017cd3d978 | |||
| a3af86d248 | |||
| 99e9cbde84 | |||
| 85d60d2555 | |||
| 1fe4555209 | |||
| 8b80df2f91 | |||
| 3d7d4eb7db | |||
| 4215621eb7 | |||
| d138a5d0b7 | |||
| b3023192d0 | |||
| 7cc0c527e0 | |||
| f3f36e87a4 | |||
| b55b133ddf | |||
| 28eafdbc6c | |||
| 0036ab1ed2 | |||
| a60378a9bd | |||
| 30b246f67c | |||
| 3a23b28657 | |||
| 42e21d585f | |||
| a30ab9a1a0 | |||
| 4510295792 | |||
| ed5de64cd3 | |||
| 1c89187c49 | |||
| 169a3f6e6d | |||
| 7e2ead7949 | |||
| 8413067194 | |||
| 81c7dcaa63 | |||
| 3b12c7f1cf | |||
| cdab200898 | |||
| 0f9c3e1c1c | |||
| fe5a5b76ca | |||
| 0e3720c038 | |||
| 99f1ba8987 | |||
| 8ff5d79788 | |||
| 9d6485194f | |||
| 21e306774e | |||
| ffa340f255 | |||
| d6b65edfb1 | |||
| a3ed33a443 | |||
| 38ff477cef | |||
| c5c638b007 | |||
| 181fd8dc73 | |||
| e57f58bec3 | |||
| 5c2067f61a | |||
| 3ec5cf259b | |||
| e5e898222b | |||
| 18b2876853 | |||
| cec4ffcb6c | |||
| 1063aa74dd | |||
| b59dba0e6d | |||
| 0d9a182833 | |||
| 8674f66b4d | |||
| 605a720694 | |||
| aa761d5ef7 | |||
| 3d4d8aa7d3 | |||
| 556b72edb2 | |||
| be372b90f9 | |||
| 846e93741f | |||
| b82af3a0c6 | |||
| 02b429cb32 | |||
| 3332469c35 | |||
| 0a2469aaa4 | |||
| e7e15a32bf | |||
| fc3fa53dba | |||
| 4604f27176 | |||
| b7b118c122 | |||
| 371f243a6d |
@@ -15,3 +15,4 @@
|
||||
/client
|
||||
/test.php
|
||||
/main.html
|
||||
/tests/testData/Utils/Config/config.php
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
DirectoryIndex index.php index.html
|
||||
|
||||
RedirectMatch 403 \.config$
|
||||
# PROTECTED DIRECTORIES
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
RewriteRule (?i)(data|api) - [F]
|
||||
</IfModule>
|
||||
RedirectMatch 403 (?i)/data/config\.php$
|
||||
RedirectMatch 403 (?i)/data/logs
|
||||
RedirectMatch 403 (?i)/data/cache
|
||||
RedirectMatch 403 (?i)/data/upload
|
||||
RedirectMatch 403 (?i)/application
|
||||
RedirectMatch 403 (?i)/custom
|
||||
RedirectMatch 403 (?i)/vendor
|
||||
#END PROTECTED DIRECTORIES
|
||||
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteRule reset/?$ reset.html [QSA,L]
|
||||
RewriteEngine On
|
||||
RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}]
|
||||
|
||||
RewriteRule reset/?$ reset.html [QSA,L]
|
||||
</IfModule>
|
||||
+50
-52
@@ -1,4 +1,50 @@
|
||||
module.exports = function (grunt) {
|
||||
|
||||
var jsFilesToMinify = [
|
||||
'client/lib/jquery-2.0.2.min.js',
|
||||
'client/lib/underscore-min.js',
|
||||
'client/lib/backbone-min.js',
|
||||
'client/lib/handlebars.js',
|
||||
'client/lib/base64.js',
|
||||
'client/lib/jquery-ui.min.js',
|
||||
'client/lib/moment.min.js',
|
||||
'client/lib/moment-timezone-with-data.min.js',
|
||||
'client/lib/jquery.timepicker.min.js',
|
||||
'client/lib/jquery.autocomplete.js',
|
||||
'client/lib/bootstrap.min.js',
|
||||
'client/lib/bootstrap-datepicker.js',
|
||||
'client/lib/bull.min.js',
|
||||
'client/src/namespace.js',
|
||||
'client/src/exceptions.js',
|
||||
'client/src/app.js',
|
||||
'client/src/utils.js',
|
||||
'client/src/storage.js',
|
||||
'client/src/loader.js',
|
||||
'client/src/pre-loader.js',
|
||||
'client/src/ui.js',
|
||||
'client/src/acl.js',
|
||||
'client/src/model.js',
|
||||
'client/src/model-offline.js',
|
||||
'client/src/metadata.js',
|
||||
'client/src/language.js',
|
||||
'client/src/cache.js',
|
||||
'client/src/controller.js',
|
||||
'client/src/router.js',
|
||||
'client/src/date-time.js',
|
||||
'client/src/field-manager.js',
|
||||
'client/src/search-manager.js',
|
||||
'client/src/collection.js',
|
||||
'client/src/multi-collection.js',
|
||||
'client/src/view-helper.js',
|
||||
'client/src/layout-manager.js',
|
||||
'client/src/model-factory.js',
|
||||
'client/src/collection-factory.js',
|
||||
'client/src/models/settings.js',
|
||||
'client/src/models/user.js',
|
||||
'client/src/models/preferences.js',
|
||||
'client/src/controllers/base.js',
|
||||
'client/src/view.js',
|
||||
];
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
@@ -44,57 +90,9 @@ module.exports = function (grunt) {
|
||||
mangle: false,
|
||||
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
|
||||
},
|
||||
'build/tmp/client/espo.min.js': [
|
||||
'frontend/client/lib/jquery-2.0.2.min.js',
|
||||
'frontend/client/lib/underscore-min.js',
|
||||
'frontend/client/lib/backbone-min.js',
|
||||
'frontend/client/lib/handlebars.js',
|
||||
'frontend/client/lib/base64.js',
|
||||
'frontend/client/lib/jquery-ui.min.js',
|
||||
'frontend/client/lib/moment.min.js',
|
||||
'frontend/client/lib/moment-timezone.min.js',
|
||||
'frontend/client/lib/moment-timezone-data.js',
|
||||
'frontend/client/lib/jquery.timepicker.min.js',
|
||||
'frontend/client/lib/jquery.autocomplete.js',
|
||||
'frontend/client/lib/bootstrap.min.js',
|
||||
'frontend/client/lib/bootstrap-datepicker.js',
|
||||
'frontend/client/lib/bull.min.js',
|
||||
'frontend/client/src/namespace.js',
|
||||
'frontend/client/src/exceptions.js',
|
||||
'frontend/client/src/app.js',
|
||||
'frontend/client/src/utils.js',
|
||||
'frontend/client/src/storage.js',
|
||||
'frontend/client/src/loader.js',
|
||||
'frontend/client/src/pre-loader.js',
|
||||
'frontend/client/src/ui.js',
|
||||
'frontend/client/src/acl.js',
|
||||
'frontend/client/src/model.js',
|
||||
'frontend/client/src/model-offline.js',
|
||||
'frontend/client/src/metadata.js',
|
||||
'frontend/client/src/language.js',
|
||||
'frontend/client/src/cache.js',
|
||||
'frontend/client/src/controller.js',
|
||||
'frontend/client/src/router.js',
|
||||
'frontend/client/src/date-time.js',
|
||||
'frontend/client/src/field-manager.js',
|
||||
'frontend/client/src/search-manager.js',
|
||||
'frontend/client/src/collection.js',
|
||||
'frontend/client/src/multi-collection.js',
|
||||
'frontend/client/src/view-helper.js',
|
||||
'frontend/client/src/layout-manager.js',
|
||||
'frontend/client/src/model-factory.js',
|
||||
'frontend/client/src/collection-factory.js',
|
||||
'frontend/client/src/models/settings.js',
|
||||
'frontend/client/src/models/user.js',
|
||||
'frontend/client/src/models/preferences.js',
|
||||
'frontend/client/src/controllers/base.js',
|
||||
'frontend/client/src/controllers/record.js',
|
||||
'frontend/client/src/controllers/role.js',
|
||||
'frontend/client/src/controllers/admin.js',
|
||||
'frontend/client/src/view.js',
|
||||
'frontend/client/src/views/base.js',
|
||||
'frontend/client/src/views/login.js',
|
||||
]
|
||||
'build/tmp/client/espo.min.js': jsFilesToMinify.map(function (item) {
|
||||
return 'frontend/' + item;
|
||||
})
|
||||
},
|
||||
copy: {
|
||||
frontendFolders: {
|
||||
@@ -138,7 +136,7 @@ module.exports = function (grunt) {
|
||||
'index.php',
|
||||
'LICENSE.txt',
|
||||
'.htaccess',
|
||||
'Web.config',
|
||||
'web.config',
|
||||
],
|
||||
dest: 'build/tmp/',
|
||||
},
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<system.webServer>
|
||||
<rewrite>
|
||||
<rules>
|
||||
<rule name="rule 1X" stopProcessing="true">
|
||||
<match url="reset/?$" />
|
||||
<action type="Rewrite" url="reset.html" appendQueryString="true" />
|
||||
</rule>
|
||||
</rules>
|
||||
</rewrite>
|
||||
|
||||
<defaultDocument>
|
||||
<files>
|
||||
<clear />
|
||||
<add value="index.php" />
|
||||
</files>
|
||||
</defaultDocument>
|
||||
</system.webServer>
|
||||
|
||||
</configuration>
|
||||
@@ -6,5 +6,7 @@ RewriteEngine On
|
||||
#
|
||||
# RewriteBase /
|
||||
|
||||
RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}]
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [QSA,L]
|
||||
@@ -1,2 +0,0 @@
|
||||
Order Deny,Allow
|
||||
Deny from all
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class AuthToken extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
protected function checkControllerAccess()
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreate($params, $data)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionListLinked($params, $data)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionMassUpdate($params, $data)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionRemoveLink($params, $data)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace Espo\Controllers;
|
||||
use Espo\Core\Utils as Utils;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class Layout extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
@@ -39,6 +40,10 @@ class Layout extends \Espo\Core\Controllers\Base
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$result = $this->getContainer()->get('layout')->set($data, $params['scope'], $params['name']);
|
||||
|
||||
if ($result === false) {
|
||||
|
||||
@@ -54,7 +54,13 @@ class Notification extends \Espo\Core\Controllers\Base
|
||||
public function actionNotReadCount()
|
||||
{
|
||||
$userId = $this->getUser()->id;
|
||||
return $this->getService('Notification')->getNotReadCount($userId);
|
||||
return $this->getService('Notification')->getNotReadCount($userId);
|
||||
}
|
||||
|
||||
public function actionMarkAllRead($params, $data, $request)
|
||||
{
|
||||
$userId = $this->getUser()->id;
|
||||
return $this->getService('Notification')->markAllRead($userId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ class Settings extends \Espo\Core\Controllers\Base
|
||||
protected function getConfigData()
|
||||
{
|
||||
$data = $this->getConfig()->getData($this->getUser()->isAdmin());
|
||||
|
||||
|
||||
$fieldDefs = $this->getMetadata()->get('entityDefs.Settings.fields');
|
||||
|
||||
|
||||
foreach ($fieldDefs as $field => $d) {
|
||||
if ($d['type'] == 'password') {
|
||||
unset($data[$field]);
|
||||
@@ -40,7 +40,7 @@ class Settings extends \Espo\Core\Controllers\Base
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
public function actionRead($params, $data)
|
||||
{
|
||||
return $this->getConfigData();
|
||||
@@ -52,16 +52,23 @@ class Settings extends \Espo\Core\Controllers\Base
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data)
|
||||
{
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$result = $this->getConfig()->setData($data, $this->getUser()->isAdmin());
|
||||
|
||||
$this->getConfig()->setData($data, $this->getUser()->isAdmin());
|
||||
$result = $this->getConfig()->save();
|
||||
if ($result === false) {
|
||||
throw new Error('Cannot save settings');
|
||||
}
|
||||
|
||||
/** Rebuild for Currency Settings */
|
||||
if (isset($data['baseCurrency']) || isset($data['currencyRates'])) {
|
||||
$this->getContainer()->get('dataManager')->rebuildDatabase(array());
|
||||
}
|
||||
/** END Rebuild for Currency Settings */
|
||||
|
||||
return $this->getConfigData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,12 +128,9 @@ class Application
|
||||
$cronManager = new \Espo\Core\CronManager($this->container);
|
||||
$cronManager->run();
|
||||
}
|
||||
|
||||
|
||||
public function runRebuild()
|
||||
{
|
||||
$auth = $this->getAuth();
|
||||
$auth->useNoAuth(true);
|
||||
|
||||
$dataManager = $this->getContainer()->get('dataManager');
|
||||
$dataManager->rebuild();
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ class ControllerManager
|
||||
throw new NotFound("Controller '$controllerName' is not found");
|
||||
}
|
||||
|
||||
$controller = new $controllerClassName($this->container);
|
||||
$controller = new $controllerClassName($this->container, $request->getMethod());
|
||||
|
||||
if ($actionName == 'index') {
|
||||
$actionName = $controllerClassName::$defaultAction;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Controllers;
|
||||
|
||||
@@ -29,15 +29,21 @@ use \Espo\Core\Utils\Util;
|
||||
abstract class Base
|
||||
{
|
||||
protected $name;
|
||||
|
||||
|
||||
private $container;
|
||||
|
||||
|
||||
private $requestMethod;
|
||||
|
||||
public static $defaultAction = 'index';
|
||||
|
||||
public function __construct(Container $container)
|
||||
public function __construct(Container $container, $requestMethod = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
|
||||
if (isset($requestMethod)) {
|
||||
$this->setRequestMethod($requestMethod);
|
||||
}
|
||||
|
||||
if (empty($this->name)) {
|
||||
$name = get_class($this);
|
||||
if (preg_match('@\\\\([\w]+)$@', $name, $matches)) {
|
||||
@@ -45,40 +51,55 @@ abstract class Base
|
||||
}
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
|
||||
$this->checkControllerAccess();
|
||||
}
|
||||
|
||||
|
||||
protected function checkControllerAccess()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
protected function getContainer()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get request method name (Uppercase)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getRequestMethod()
|
||||
{
|
||||
return $this->requestMethod;
|
||||
}
|
||||
|
||||
protected function setRequestMethod($requestMethod)
|
||||
{
|
||||
$this->requestMethod = strtoupper($requestMethod);
|
||||
}
|
||||
|
||||
protected function getUser()
|
||||
{
|
||||
return $this->container->get('user');
|
||||
}
|
||||
|
||||
|
||||
protected function getAcl()
|
||||
{
|
||||
return $this->container->get('acl');
|
||||
}
|
||||
|
||||
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->container->get('config');
|
||||
}
|
||||
|
||||
|
||||
protected function getPreferences()
|
||||
{
|
||||
return $this->container->get('preferences');
|
||||
}
|
||||
|
||||
|
||||
protected function getMetadata()
|
||||
{
|
||||
return $this->container->get('metadata');
|
||||
@@ -88,7 +109,7 @@ abstract class Base
|
||||
{
|
||||
return $this->container->get('serviceFactory');
|
||||
}
|
||||
|
||||
|
||||
protected function getService($name)
|
||||
{
|
||||
return $this->getServiceFactory()->create($name);
|
||||
|
||||
@@ -38,13 +38,17 @@ class Record extends Base
|
||||
return $this->getContainer()->get('entityManager');
|
||||
}
|
||||
|
||||
protected function getRecordService()
|
||||
protected function getRecordService($name = null)
|
||||
{
|
||||
if ($this->getServiceFactory()->checkExists($this->name)) {
|
||||
$service = $this->getServiceFactory()->create($this->name);
|
||||
if (empty($name)) {
|
||||
$name = $this->name;
|
||||
}
|
||||
|
||||
if ($this->getServiceFactory()->checkExists($name)) {
|
||||
$service = $this->getServiceFactory()->create($name);
|
||||
} else {
|
||||
$service = $this->getServiceFactory()->create('Record');
|
||||
$service->setEntityName($this->name);
|
||||
$service->setEntityName($name);
|
||||
}
|
||||
|
||||
return $service;
|
||||
@@ -178,8 +182,10 @@ class Record extends Base
|
||||
}
|
||||
|
||||
public function actionExport($params, $data, $request)
|
||||
{
|
||||
// TODO move to service
|
||||
{
|
||||
if ($this->getConfig()->get('disableExport') && !$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
if (!$this->getAcl()->check($this->name, 'read')) {
|
||||
throw new Forbidden();
|
||||
|
||||
@@ -124,23 +124,25 @@ class Sender
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function send(Email $email)
|
||||
public function send(Email $email, $params = array())
|
||||
{
|
||||
$message = new Message();
|
||||
|
||||
$config = $this->config;
|
||||
|
||||
$params = $this->params + $params;
|
||||
|
||||
if ($email->get('from')) {
|
||||
$fromName = null;
|
||||
if (!empty($this->params['fromName'])) {
|
||||
$fromName = $this->params['fromName'];
|
||||
if (!empty($params['fromName'])) {
|
||||
$fromName = $params['fromName'];
|
||||
} else {
|
||||
$fromName = $config->get('outboundEmailFromName');
|
||||
}
|
||||
$message->addFrom(trim($email->get('from')), $fromName);
|
||||
} else {
|
||||
if (!empty($this->params['fromAddress'])) {
|
||||
$fromAddress = $this->params['fromAddress'];
|
||||
if (!empty($params['fromAddress'])) {
|
||||
$fromAddress = $params['fromAddress'];
|
||||
} else {
|
||||
if (!$config->get('outboundEmailFromAddress')) {
|
||||
throw new Error('outboundEmailFromAddress is not specified in config.');
|
||||
@@ -148,14 +150,22 @@ class Sender
|
||||
$fromAddress = $config->get('outboundEmailFromAddress');
|
||||
}
|
||||
|
||||
if (!empty($this->params['fromName'])) {
|
||||
$fromName = $this->params['fromName'];
|
||||
if (!empty($params['fromName'])) {
|
||||
$fromName = $params['fromName'];
|
||||
} else {
|
||||
$fromName = $config->get('outboundEmailFromName');
|
||||
}
|
||||
|
||||
$message->addFrom($fromAddress, $fromName);
|
||||
}
|
||||
|
||||
if (!empty($params['replyToAddress'])) {
|
||||
$replyToName = null;
|
||||
if (!empty($params['replyToName'])) {
|
||||
$replyToName = $params['replyToName'];
|
||||
}
|
||||
$message->setReplyTo($params['replyToAddress'], $replyToName);
|
||||
}
|
||||
|
||||
$value = $email->get('to');
|
||||
if ($value) {
|
||||
|
||||
@@ -24,19 +24,39 @@ namespace Espo\Core\ORM;
|
||||
|
||||
class Entity extends \Espo\ORM\Entity
|
||||
{
|
||||
public function loadLinkMultipleField($field)
|
||||
public function loadLinkMultipleField($field, $columns = null)
|
||||
{
|
||||
if ($this->hasRelation($field) && $this->hasField($field . 'Ids')) {
|
||||
$collection = $this->get($field);
|
||||
|
||||
$defs = array();
|
||||
if (!empty($columns)) {
|
||||
$defs['additionalColumns'] = $columns;
|
||||
}
|
||||
|
||||
$collection = $this->get($field, $defs);
|
||||
$ids = array();
|
||||
$names = new \stdClass();
|
||||
$names = new \stdClass();
|
||||
if (!empty($columns)) {
|
||||
$columnsData = new \stdClass();
|
||||
}
|
||||
|
||||
foreach ($collection as $e) {
|
||||
$id = $e->id;
|
||||
$ids[] = $id;
|
||||
$names->$id = $e->get('name');
|
||||
if (!empty($columns)) {
|
||||
$columnsData->$id = new \stdClass();
|
||||
foreach ($columns as $column => $f) {
|
||||
$columnsData->$id->$column = $e->get($f);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->set($field . 'Ids', $ids);
|
||||
$this->set($field . 'Names', $names);
|
||||
if (!empty($columns)) {
|
||||
$this->set($field . 'Columns', $columnsData);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,12 @@ class EntityManager extends \Espo\ORM\EntityManager
|
||||
public function getUser()
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
}
|
||||
|
||||
public function getEspoMetadata()
|
||||
{
|
||||
return $this->espoMetadata;
|
||||
}
|
||||
|
||||
public function setEspoMetadata($espoMetadata)
|
||||
{
|
||||
|
||||
@@ -59,16 +59,15 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
return $this->getInjection('metadata');
|
||||
}
|
||||
|
||||
protected function handleSelectParams(&$params, $entityName = false)
|
||||
public function handleSelectParams(&$params)
|
||||
{
|
||||
$this->handleEmailAddressParams($params, $entityName);
|
||||
$this->handleEmailAddressParams($params);
|
||||
$this->handlePhoneNumberParams($params);
|
||||
}
|
||||
|
||||
protected function handleEmailAddressParams(&$params, $entityName = false)
|
||||
protected function handleEmailAddressParams(&$params)
|
||||
{
|
||||
if (empty($entityName)) {
|
||||
$entityName = $this->entityName;
|
||||
}
|
||||
$entityName = $this->entityName;
|
||||
|
||||
$defs = $this->getEntityManager()->getMetadata()->get($entityName);
|
||||
if (!empty($defs['relations']) && array_key_exists('emailAddresses', $defs['relations'])) {
|
||||
@@ -81,11 +80,31 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
if (empty($params['joinConditions'])) {
|
||||
$params['joinConditions'] = array();
|
||||
}
|
||||
$params['leftJoins'] = array('emailAddresses');
|
||||
$params['joinConditions'] = array(
|
||||
'emailAddresses' => array(
|
||||
'primary' => 1
|
||||
)
|
||||
$params['leftJoins'][] = 'emailAddresses';
|
||||
$params['joinConditions']['emailAddresses'] = array(
|
||||
'primary' => 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function handlePhoneNumberParams(&$params)
|
||||
{
|
||||
$entityName = $this->entityName;
|
||||
|
||||
$defs = $this->getEntityManager()->getMetadata()->get($entityName);
|
||||
if (!empty($defs['relations']) && array_key_exists('phoneNumbers', $defs['relations'])) {
|
||||
if (empty($params['leftJoins'])) {
|
||||
$params['leftJoins'] = array();
|
||||
}
|
||||
if (empty($params['whereClause'])) {
|
||||
$params['whereClause'] = array();
|
||||
}
|
||||
if (empty($params['joinConditions'])) {
|
||||
$params['joinConditions'] = array();
|
||||
}
|
||||
$params['leftJoins'][] = 'phoneNumbers';
|
||||
$params['joinConditions']['phoneNumbers'] = array(
|
||||
'primary' => 1
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -172,6 +191,7 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
$entity->set($restoreData);
|
||||
|
||||
$this->handleEmailAddressSave($entity);
|
||||
$this->handlePhoneNumberSave($entity);
|
||||
$this->handleSpecifiedRelations($entity);
|
||||
|
||||
return $result;
|
||||
@@ -183,6 +203,13 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
$emailAddressRepository = $this->getEntityManager()->getRepository('EmailAddress')->storeEntityEmailAddress($entity);
|
||||
}
|
||||
}
|
||||
|
||||
protected function handlePhoneNumberSave(Entity $entity)
|
||||
{
|
||||
if ($entity->hasRelation('phoneNumbers') && $entity->hasField('phoneNumber')) {
|
||||
$emailAddressRepository = $this->getEntityManager()->getRepository('PhoneNumber')->storeEntityPhoneNumber($entity);
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleSpecifiedRelations(Entity $entity)
|
||||
{
|
||||
@@ -195,22 +222,60 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
if (is_array($specifiedIds)) {
|
||||
$toRemoveIds = array();
|
||||
$existingIds = array();
|
||||
foreach ($entity->get($name) as $foreignEntity) {
|
||||
$toUpdateIds = array();
|
||||
$existingColumnsData = new \stdClass();
|
||||
|
||||
$defs = array();
|
||||
$columns = $this->getMetadata()->get("entityDefs." . $entity->getEntityName() . ".fields.{$name}.columns");
|
||||
if (!empty($columns)) {
|
||||
$columnData = $entity->get($name . 'Columns');
|
||||
$defs['additionalColumns'] = $columns;
|
||||
|
||||
}
|
||||
|
||||
foreach ($entity->get($name, $defs) as $foreignEntity) {
|
||||
$existingIds[] = $foreignEntity->id;
|
||||
if (!empty($columns)) {
|
||||
$data = new \stdClass();
|
||||
foreach ($columns as $columnName => $columnField) {
|
||||
$foreignId = $foreignEntity->id;
|
||||
$data->$columnName = $foreignEntity->get($columnField);
|
||||
}
|
||||
$existingColumnsData->$foreignId = $data;
|
||||
}
|
||||
|
||||
}
|
||||
foreach ($existingIds as $id) {
|
||||
if (!in_array($id, $specifiedIds)) {
|
||||
$toRemoveIds[] = $id;
|
||||
} else {
|
||||
if (!empty($columns)) {
|
||||
foreach ($columns as $columnName => $columnField) {
|
||||
if ($columnData->$id->$columnName != $existingColumnsData->$id->$columnName) {
|
||||
$toUpdateIds[] = $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($specifiedIds as $id) {
|
||||
if (!in_array($id, $existingIds)) {
|
||||
$this->relate($entity, $name, $id);
|
||||
$data = null;
|
||||
if (!empty($columns)) {
|
||||
$data = $columnData->$id;
|
||||
}
|
||||
$this->relate($entity, $name, $id, $data);
|
||||
}
|
||||
}
|
||||
foreach ($toRemoveIds as $id) {
|
||||
$this->unrelate($entity, $name, $id);
|
||||
}
|
||||
if (!empty($columns)) {
|
||||
foreach ($toUpdateIds as $id) {
|
||||
$data = $columnData->$id;
|
||||
$this->updateRelation($entity, $name, $id, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,11 @@ class Base
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getTextFilterFields()
|
||||
{
|
||||
return $this->metadata->get("entityDefs.{$this->entityName}.collection.textFilterFields", array('name'));
|
||||
}
|
||||
|
||||
protected function where($params, &$result)
|
||||
{
|
||||
@@ -96,6 +101,18 @@ class Base
|
||||
$params['where'][] = $p;
|
||||
}
|
||||
}
|
||||
} else if ($item['type'] == 'textFilter' && !empty($item['value'])) {
|
||||
if (!empty($item['value'])) {
|
||||
if (empty($result['whereClause'])) {
|
||||
$result['whereClause'] = array();
|
||||
}
|
||||
$fieldList = $this->getTextFilterFields();
|
||||
$d = array();
|
||||
foreach ($fieldList as $field) {
|
||||
$d[$field . '*'] = $item['value'] . '%';
|
||||
}
|
||||
$where['OR'] = $d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +125,7 @@ class Base
|
||||
$where[] = $part;
|
||||
}
|
||||
} else {
|
||||
if ($item['type'] == 'linkedWith') {
|
||||
if ($item['type'] == 'linkedWith' && !empty($item['value'])) {
|
||||
$linkedWith[$item['field']] = $item['value'];
|
||||
}
|
||||
}
|
||||
@@ -159,18 +176,23 @@ class Base
|
||||
}
|
||||
$result['whereClause']['assignedUserId'] = $this->user->id;
|
||||
}
|
||||
if ($this->acl->checkReadOnlyTeam($this->entityName)) {
|
||||
if (!$this->user->isAdmin() && $this->acl->checkReadOnlyTeam($this->entityName)) {
|
||||
if (!array_key_exists('whereClause', $result)) {
|
||||
$result['whereClause'] = array();
|
||||
}
|
||||
$result['distinct'] = true;
|
||||
if (!array_key_exists('joins', $result)) {
|
||||
$result['joins'] = array();
|
||||
}
|
||||
if (!in_array('teams', $result['joins'])) {
|
||||
$result['joins'][] = 'teams';
|
||||
$result['leftJoins'][] = 'teams';
|
||||
}
|
||||
|
||||
$result['whereClause']['Team.id'] = $this->user->get('teamsIds');
|
||||
$result['whereClause']['OR'] = array(
|
||||
'Team.id' => $this->user->get('teamsIds'),
|
||||
'assignedUserId' => $this->user->id
|
||||
);
|
||||
//$result['whereClause']['Team.id'] = $this->user->get('teamsIds');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,6 +277,15 @@ class Base
|
||||
case 'isFalse':
|
||||
$part[$item['field'] . '='] = false;
|
||||
break;
|
||||
case 'today':
|
||||
$part[$item['field'] . '='] = date('Y-m-d');
|
||||
break;
|
||||
case 'past':
|
||||
$part[$item['field'] . '<'] = date('Y-m-d');
|
||||
break;
|
||||
case 'future':
|
||||
$part[$item['field'] . '>'] = date('Y-m-d');
|
||||
break;
|
||||
case 'between':
|
||||
if (is_array($item['value'])) {
|
||||
$part['AND'] = array(
|
||||
|
||||
@@ -26,7 +26,11 @@ use \Espo\Core\Interfaces\Injectable;
|
||||
|
||||
abstract class Base implements Injectable
|
||||
{
|
||||
protected $dependencies = array();
|
||||
protected $dependencies = array(
|
||||
'config',
|
||||
'entityManager',
|
||||
'user',
|
||||
);
|
||||
|
||||
protected $injections = array();
|
||||
|
||||
@@ -53,5 +57,20 @@ abstract class Base implements Injectable
|
||||
{
|
||||
return $this->dependencies;
|
||||
}
|
||||
|
||||
protected function getEntityManager()
|
||||
{
|
||||
return $this->getInjection('entityManager');
|
||||
}
|
||||
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->getInjection('config');
|
||||
}
|
||||
|
||||
protected function getUser()
|
||||
{
|
||||
return $this->getInjection('user');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -316,7 +316,13 @@ abstract class Base
|
||||
{
|
||||
if (!isset($this->data['manifest'])) {
|
||||
$upgradePath = $this->getUpgradePath();
|
||||
$manifestJson = $this->getFileManager()->getContents(array($upgradePath, $this->manifestName));
|
||||
|
||||
$manifestPath = Util::concatPath($upgradePath, $this->manifestName);
|
||||
if (!file_exists($manifestPath)) {
|
||||
throw new Error('It\'s not an uprgade package.');
|
||||
}
|
||||
|
||||
$manifestJson = $this->getFileManager()->getContents($manifestPath);
|
||||
$this->data['manifest'] = Json::decode($manifestJson, true);
|
||||
|
||||
if (!$this->data['manifest']) {
|
||||
@@ -375,6 +381,9 @@ abstract class Base
|
||||
$manifest = $this->getManifest();
|
||||
|
||||
$res = $this->getConfig()->set('version', $manifest['version']);
|
||||
if (method_exists($this->getConfig(), 'save')) {
|
||||
$res = $this->getConfig()->save();
|
||||
}
|
||||
$res &= $this->getContainer()->get('dataManager')->rebuild();
|
||||
|
||||
return $res;
|
||||
|
||||
@@ -51,9 +51,12 @@ class Auth extends \Slim\Middleware
|
||||
|
||||
$espoAuth = $req->headers('HTTP_ESPO_AUTHORIZATION');
|
||||
if (isset($espoAuth)) {
|
||||
$credentials = explode(':', base64_decode($espoAuth));
|
||||
$authUsername = $credentials[0];
|
||||
$authPassword = $credentials[1];
|
||||
list($authUsername, $authPassword) = explode(':', base64_decode($espoAuth));
|
||||
}
|
||||
|
||||
$espoCgiAuth = $req->headers('HTTP_ESPO_CGI_AUTH');
|
||||
if ( !isset($authUsername) && !isset($authPassword) && isset($espoCgiAuth) ) {
|
||||
list($authUsername, $authPassword) = explode(':' , base64_decode(substr($espoCgiAuth, 6)));
|
||||
}
|
||||
|
||||
if (is_null($this->authRequired)) {
|
||||
|
||||
@@ -18,91 +18,95 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
|
||||
class Auth
|
||||
class Auth
|
||||
{
|
||||
protected $container;
|
||||
|
||||
|
||||
protected $authentication;
|
||||
|
||||
protected $config;
|
||||
|
||||
protected $entityManager;
|
||||
|
||||
public function __construct(\Espo\Core\Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
$this->entityManager = $this->container->get('entityManager');
|
||||
$this->config = $this->container->get('config');
|
||||
|
||||
$authenticationMethod = $this->config->get('authenticationMethod', 'Espo');
|
||||
$authenticationClassName = "\\Espo\\Core\\Utils\\Authentication\\" . $authenticationMethod;
|
||||
$this->authentication = new $authenticationClassName($this->config, $this->entityManager, $this);
|
||||
}
|
||||
|
||||
|
||||
public function useNoAuth($isAdmin = false)
|
||||
{
|
||||
$entityManager = $this->container->get('entityManager');
|
||||
|
||||
$entityManager = $this->container->get('entityManager');
|
||||
|
||||
$user = $entityManager->getRepository('User')->get('system');
|
||||
$user->set('isAdmin', $isAdmin);
|
||||
if (!$user) {
|
||||
throw new Error('System user is not found');
|
||||
throw new Error('System user is not found');
|
||||
}
|
||||
|
||||
$user->set('isAdmin', $isAdmin);
|
||||
|
||||
$entityManager->setUser($user);
|
||||
$this->container->setUser($user);
|
||||
}
|
||||
|
||||
|
||||
public function login($username, $password)
|
||||
{
|
||||
$GLOBALS['log']->debug('AUTH: Try to authenticate');
|
||||
|
||||
$hash = md5($password);
|
||||
|
||||
$entityManager = $this->container->get('entityManager');
|
||||
|
||||
|
||||
$entityManager = $this->entityManager;
|
||||
|
||||
$authToken = $entityManager->getRepository('AuthToken')->where(array('token' => $password))->findOne();
|
||||
if ($authToken) {
|
||||
$hash = $authToken->get('hash');
|
||||
}
|
||||
|
||||
$user = $entityManager->getRepository('User')->findOne(array(
|
||||
'whereClause' => array(
|
||||
'userName' => $username,
|
||||
'password' => $hash
|
||||
),
|
||||
));
|
||||
|
||||
|
||||
$user = $this->authentication->login($username, $password, $authToken);
|
||||
|
||||
if ($user) {
|
||||
$entityManager->setUser($user);
|
||||
$this->container->setUser($user);
|
||||
$GLOBALS['log']->debug('AUTH: Result of authenticate is [true]');
|
||||
|
||||
|
||||
if (!$authToken) {
|
||||
$authToken = $entityManager->getEntity('AuthToken');
|
||||
$token = $this->createToken($user);
|
||||
$authToken->set('token', $token);
|
||||
$authToken->set('hash', $user->get('password'));
|
||||
$authToken->set('ipAddress', $_SERVER['REMOTE_ADDR']);
|
||||
$authToken->set('userId', $user->id);
|
||||
$authToken->set('userId', $user->id);
|
||||
}
|
||||
|
||||
|
||||
$authToken->set('lastAccess', date('Y-m-d H:i:s'));
|
||||
|
||||
|
||||
$entityManager->saveEntity($authToken);
|
||||
$user->set('token', $authToken->get('token'));
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function createToken($user)
|
||||
{
|
||||
return md5(uniqid($user->get('password')));
|
||||
return md5(uniqid($user->get('id')));
|
||||
}
|
||||
|
||||
|
||||
public function destroyAuthToken($token)
|
||||
{
|
||||
{
|
||||
$entityManager = $this->container->get('entityManager');
|
||||
|
||||
|
||||
$authToken = $entityManager->getRepository('AuthToken')->where(array('token' => $token))->findOne();
|
||||
if ($authToken) {
|
||||
$entityManager->removeEntity($authToken);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Authentication;
|
||||
|
||||
use \Espo\Core\Utils\Config;
|
||||
use \Espo\Core\ORM\EntityManager;
|
||||
use \Espo\Core\Utils\Auth;
|
||||
|
||||
abstract class Base
|
||||
{
|
||||
private $config;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
private $auth;
|
||||
|
||||
public function __construct(Config $config, EntityManager $entityManager, Auth $auth)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
protected function getEntityManager()
|
||||
{
|
||||
return $this->entityManager;
|
||||
}
|
||||
|
||||
protected function getAuth()
|
||||
{
|
||||
return $this->auth;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Authentication;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
|
||||
class Espo extends Base
|
||||
{
|
||||
|
||||
public function login($username, $password, \Espo\Entities\AuthToken $authToken = null)
|
||||
{
|
||||
if ($authToken) {
|
||||
$hash = $authToken->get('hash');
|
||||
} else {
|
||||
$hash = md5($password);
|
||||
}
|
||||
|
||||
$user = $this->getEntityManager()->getRepository('User')->findOne(array(
|
||||
'whereClause' => array(
|
||||
'userName' => $username,
|
||||
'password' => $hash
|
||||
),
|
||||
));
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Authentication;
|
||||
|
||||
use Espo\Core\Exceptions\Error,
|
||||
Espo\Core\Utils\Config,
|
||||
Espo\Core\ORM\EntityManager,
|
||||
Espo\Core\Utils\Auth;
|
||||
|
||||
class LDAP extends Base
|
||||
{
|
||||
private $utils;
|
||||
|
||||
private $zendLdap;
|
||||
|
||||
/**
|
||||
* Espo => LDAP name
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $fields = array(
|
||||
'userName' => 'cn',
|
||||
'firstName' => 'givenname',
|
||||
'lastName' => 'sn',
|
||||
'title' => 'title',
|
||||
'emailAddress' => 'mail',
|
||||
'phoneNumber' => 'telephonenumber',
|
||||
);
|
||||
|
||||
public function __construct(Config $config, EntityManager $entityManager, Auth $auth)
|
||||
{
|
||||
parent::__construct($config, $entityManager, $auth);
|
||||
|
||||
$this->zendLdap = new LDAP\LDAP();
|
||||
$this->utils = new LDAP\Utils($config);
|
||||
}
|
||||
|
||||
protected function getZendLdap()
|
||||
{
|
||||
return $this->zendLdap;
|
||||
}
|
||||
|
||||
protected function getUtils()
|
||||
{
|
||||
return $this->utils;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* LDAP login
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param \Espo\Entities\AuthToken $authToken
|
||||
* @return \Espo\Entities\User | null
|
||||
*/
|
||||
public function login($username, $password, \Espo\Entities\AuthToken $authToken = null)
|
||||
{
|
||||
if ($authToken) {
|
||||
return $this->loginByToken($username, $authToken);
|
||||
}
|
||||
|
||||
$options = $this->getUtils()->getZendOptions();
|
||||
|
||||
$ldap = $this->getZendLdap();
|
||||
$ldap = $ldap->setOptions($options);
|
||||
|
||||
try {
|
||||
$ldap->bind($username, $password);
|
||||
|
||||
$dn = $ldap->getDn($username);
|
||||
|
||||
$loginFilter = $this->getUtils()->getOption('userLoginFilter');
|
||||
$userData = $ldap->searchByLoginFilter($loginFilter, $dn, 3);
|
||||
|
||||
} catch (\Zend\Ldap\Exception\LdapException $zle) {
|
||||
|
||||
$admin = $this->adminLogin($username, $password);
|
||||
if (!isset($admin)) {
|
||||
$GLOBALS['log']->info('LDAP Authentication: ' . $zle->getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
$GLOBALS['log']->info('LDAP Authentication: Administrator login by username ['.$username.']');
|
||||
}
|
||||
|
||||
$user = $this->getEntityManager()->getRepository('User')->findOne(array(
|
||||
'whereClause' => array(
|
||||
'userName' => $username,
|
||||
),
|
||||
));
|
||||
|
||||
$isCreateUser = $this->getUtils()->getOption('createEspoUser');
|
||||
if (!isset($user) && $isCreateUser) {
|
||||
$this->getAuth()->useNoAuth(); /** Required to fix Acl "isFetched()" error */
|
||||
$user = $this->createUser($userData);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login by authorization token
|
||||
*
|
||||
* @param string $username
|
||||
* @param \Espo\Entities\AuthToken $authToken
|
||||
* @return \Espo\Entities\User | null
|
||||
*/
|
||||
protected function loginByToken($username, \Espo\Entities\AuthToken $authToken = null)
|
||||
{
|
||||
if (!isset($authToken)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$userId = $authToken->get('userId');
|
||||
$user = $this->getEntityManager()->getEntity('User', $userId);
|
||||
|
||||
$tokenUsername = $user->get('userName');
|
||||
if ($username != $tokenUsername) {
|
||||
$GLOBALS['log']->alert('Unauthorized access attempt for user ['.$username.'] from IP ['.$_SERVER['REMOTE_ADDR'].']');
|
||||
return null;
|
||||
}
|
||||
|
||||
$user = $this->getEntityManager()->getRepository('User')->findOne(array(
|
||||
'whereClause' => array(
|
||||
'userName' => $username,
|
||||
),
|
||||
));
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login user with administrator rights
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return \Espo\Entities\User | null
|
||||
*/
|
||||
protected function adminLogin($username, $password)
|
||||
{
|
||||
$hash = md5($password);
|
||||
|
||||
$user = $this->getEntityManager()->getRepository('User')->findOne(array(
|
||||
'whereClause' => array(
|
||||
'userName' => $username,
|
||||
'password' => $hash,
|
||||
'isAdmin' => 1
|
||||
),
|
||||
));
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Espo user with data gets from LDAP server
|
||||
*
|
||||
* @param array $userData LDAP entity data
|
||||
* @return \Espo\Entities\User
|
||||
*/
|
||||
protected function createUser(array $userData)
|
||||
{
|
||||
$data = array();
|
||||
foreach ($this->fields as $espo => $ldap) {
|
||||
if (isset($userData[$ldap][0])) {
|
||||
$data[$espo] = $userData[$ldap][0];
|
||||
}
|
||||
}
|
||||
|
||||
$user = $this->getEntityManager()->getEntity('User');
|
||||
$user->set($data);
|
||||
|
||||
$this->getEntityManager()->saveEntity($user);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Authentication\LDAP;
|
||||
|
||||
class LDAP extends \Zend\Ldap\Ldap
|
||||
{
|
||||
protected $usernameAttribute = 'cn';
|
||||
|
||||
|
||||
/**
|
||||
* Get DN depends on options, ex. "cn=test,ou=People,dc=maxcrc,dc=com"
|
||||
*
|
||||
* @return string DN format
|
||||
*/
|
||||
public function getDn($acctname)
|
||||
{
|
||||
return $this->getAccountDn($acctname, \Zend\Ldap\Ldap::ACCTNAME_FORM_DN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix a bug, ex. CN=Alice Baker,CN=Users,DC=example,DC=com
|
||||
*
|
||||
* @param string $acctname
|
||||
* @return string - Account DN
|
||||
*/
|
||||
protected function getAccountDn($acctname)
|
||||
{
|
||||
$baseDn = $this->getBaseDn();
|
||||
|
||||
if ($this->getBindRequiresDn() && isset($baseDn)) {
|
||||
try {
|
||||
return parent::getAccountDn($acctname);
|
||||
} catch (\Zend\Ldap\Exception\LdapException $zle) {
|
||||
if ($zle->getCode() != \Zend\Ldap\Exception\LdapException::LDAP_NO_SUCH_OBJECT) {
|
||||
throw $zle;
|
||||
}
|
||||
}
|
||||
|
||||
$acctname = $this->usernameAttribute . '=' . \Zend\Ldap\Filter\AbstractFilter::escapeValue($acctname) . ',' . $baseDn;
|
||||
}
|
||||
|
||||
return parent::getAccountDn($acctname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search a user using userLoginFilter
|
||||
*
|
||||
* @param string $filter
|
||||
* @param string $basedn
|
||||
* @param int $scope
|
||||
* @param array $attributes
|
||||
* @return array
|
||||
*/
|
||||
public function searchByLoginFilter($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB, array $attributes = array())
|
||||
{
|
||||
$filter = $this->getLoginFilter($filter);
|
||||
|
||||
$result = $this->search($filter, $basedn, $scope, $attributes);
|
||||
|
||||
if ($result->count() > 0) {
|
||||
return $result->getFirst();
|
||||
}
|
||||
|
||||
throw new \Zend\Ldap\Exception\LdapException($this, 'searching: ' . $filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get login filter in LDAP format
|
||||
*
|
||||
* @param string $filter
|
||||
* @return string
|
||||
*/
|
||||
protected function getLoginFilter($filter)
|
||||
{
|
||||
$baseFilter = '(objectClass=*)';
|
||||
|
||||
if (!empty($filter)) {
|
||||
$baseFilter = '(&' . $baseFilter . $this->convertToFilterFormat($filter). ')';
|
||||
}
|
||||
|
||||
return $baseFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and convert filter item in LDAP format
|
||||
*
|
||||
* @param string $filter [description]
|
||||
* @return string
|
||||
*/
|
||||
protected function convertToFilterFormat($filter)
|
||||
{
|
||||
$filter = trim($filter);
|
||||
if (substr($filter, 0, 1) != '(') {
|
||||
$filter = '(' . $filter;
|
||||
}
|
||||
|
||||
if (substr($filter, -1) != ')') {
|
||||
$filter = $filter . ')';
|
||||
}
|
||||
|
||||
return $filter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Authentication\LDAP;
|
||||
|
||||
use \Espo\Core\Utils\Config;
|
||||
|
||||
class Utils
|
||||
{
|
||||
private $config;
|
||||
|
||||
protected $options = null;
|
||||
|
||||
/**
|
||||
* Association between LDAP and Espo fields
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldMap = array(
|
||||
'host' => 'ldapHost',
|
||||
'port' => 'ldapPort',
|
||||
'useSsl' => 'ldapSecurity',
|
||||
'useStartTls' => 'ldapSecurity',
|
||||
'username' => 'ldapUsername',
|
||||
'password' => 'ldapPassword',
|
||||
'bindRequiresDn' => 'ldapBindRequiresDn',
|
||||
'baseDn' => 'ldapBaseDn',
|
||||
'accountCanonicalForm' => 'ldapAccountCanonicalForm',
|
||||
'accountDomainName' => 'ldapAccountDomainName',
|
||||
'accountDomainNameShort' => 'ldapAccountDomainNameShort',
|
||||
'accountFilterFormat' => 'ldapAccountFilterFormat',
|
||||
'optReferrals' => 'ldapOptReferrals',
|
||||
'tryUsernameSplit' => 'ldapTryUsernameSplit',
|
||||
'networkTimeout' => 'ldapNetworkTimeout',
|
||||
'createEspoUser' => 'ldapCreateEspoUser',
|
||||
'userLoginFilter' => 'ldapUserLoginFilter',
|
||||
);
|
||||
|
||||
/**
|
||||
* Permitted Espo Options
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $permittedEspoOptions = array(
|
||||
'createEspoUser' => false,
|
||||
'userLoginFilter' => null,
|
||||
);
|
||||
|
||||
/**
|
||||
* accountCanonicalForm Map between Espo and Zend value
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $accountCanonicalFormMap = array(
|
||||
'Dn' => 1,
|
||||
'Username' => 2,
|
||||
'Backslash' => 3,
|
||||
'Principal' => 4,
|
||||
);
|
||||
|
||||
|
||||
public function __construct(Config $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Options from espo config according to $this->fieldMap
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
if (isset($this->options)) {
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
$options = array();
|
||||
foreach ($this->fieldMap as $ldapName => $espoName) {
|
||||
|
||||
$option = $this->getConfig()->get($espoName);
|
||||
if (isset($option)) {
|
||||
$options[$ldapName] = $option;
|
||||
}
|
||||
}
|
||||
|
||||
/** peculiar fields */
|
||||
$options['useSsl'] = (bool) ($options['useSsl'] == 'SSL');
|
||||
$options['useStartTls'] = (bool) ($options['useStartTls'] == 'TLS');
|
||||
$options['accountCanonicalForm'] = $this->accountCanonicalFormMap[ $options['accountCanonicalForm'] ];
|
||||
|
||||
$this->options = $options;
|
||||
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an ldap option
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $returns Return value
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOption($name, $returns = null)
|
||||
{
|
||||
if (isset($this->options)) {
|
||||
$this->getOptions();
|
||||
}
|
||||
|
||||
if (isset($this->options[$name])) {
|
||||
return $this->options[$name];
|
||||
}
|
||||
|
||||
return $returns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Zend options for using Zend\Ldap
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getZendOptions()
|
||||
{
|
||||
$options = $this->getOptions();
|
||||
$espoOptions = array_keys($this->permittedEspoOptions);
|
||||
|
||||
$zendOptions = array_diff_key($options, array_flip($espoOptions));
|
||||
|
||||
return $zendOptions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -53,7 +53,10 @@ class Config
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $configData;
|
||||
private $data;
|
||||
|
||||
private $changedData = array();
|
||||
private $removeData = array();
|
||||
|
||||
private $fileManager;
|
||||
|
||||
@@ -109,28 +112,50 @@ class Config
|
||||
$name = array($name => $value);
|
||||
}
|
||||
|
||||
return $this->setArray($name);
|
||||
foreach ($name as $key => $value) {
|
||||
|
||||
if (is_object($value)) {
|
||||
$value = (array) $value;
|
||||
}
|
||||
|
||||
$this->data[$key] = $value;
|
||||
$this->changedData[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set options from array
|
||||
* Remove an option in config
|
||||
*
|
||||
* @param array $values
|
||||
* @return bool
|
||||
* @param string $name
|
||||
* @return bool | null - null if an option doesn't exist
|
||||
*/
|
||||
protected function setArray($values)
|
||||
public function remove($name)
|
||||
{
|
||||
if (!is_array($values)) {
|
||||
return false;
|
||||
if (array_key_exists($name, $this->data)) {
|
||||
unset($this->data[$name]);
|
||||
$this->removeData[] = $name;
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
$values = $this->changedData;
|
||||
|
||||
if (!isset($values[$this->cacheTimestamp])) {
|
||||
$values = array_merge($this->updateCacheTimestamp(true), $values);
|
||||
}
|
||||
|
||||
$result = $this->getFileManager()->mergeContentsPHP($this->configPath, $values, true);
|
||||
$this->loadConfig(true);
|
||||
$removeData = empty($this->removeData) ? null : $this->removeData;
|
||||
|
||||
$result = $this->getFileManager()->mergeContentsPHP($this->configPath, $values, 1, $removeData);
|
||||
if ($result) {
|
||||
$this->changedData = array();
|
||||
$this->removeData = array();
|
||||
$this->loadConfig(true);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
@@ -147,18 +172,18 @@ class Config
|
||||
*/
|
||||
protected function loadConfig($reload = false)
|
||||
{
|
||||
if (!$reload && isset($this->configData) && !empty($this->configData)) {
|
||||
return $this->configData;
|
||||
if (!$reload && isset($this->data) && !empty($this->data)) {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
$configPath = file_exists($this->configPath) ? $this->configPath : $this->defaultConfigPath;
|
||||
|
||||
$this->configData = $this->getFileManager()->getContents($configPath);
|
||||
$this->data = $this->getFileManager()->getContents($configPath);
|
||||
|
||||
$systemConfig = $this->getFileManager()->getContents($this->systemConfigPath);
|
||||
$this->configData = Util::merge($systemConfig, $this->configData);
|
||||
$this->data = Util::merge($systemConfig, $this->data);
|
||||
|
||||
return $this->configData;
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
|
||||
@@ -170,9 +195,9 @@ class Config
|
||||
*/
|
||||
public function getData($isAdmin = false)
|
||||
{
|
||||
$configData = $this->loadConfig();
|
||||
$data = $this->loadConfig();
|
||||
|
||||
$restrictedConfig = $configData;
|
||||
$restrictedConfig = $data;
|
||||
foreach($this->getRestrictItems($isAdmin) as $name) {
|
||||
if (isset($restrictedConfig[$name])) {
|
||||
unset($restrictedConfig[$name]);
|
||||
@@ -200,7 +225,7 @@ class Config
|
||||
}
|
||||
}
|
||||
|
||||
return $this->setArray($values);
|
||||
return $this->set($values);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -229,14 +254,14 @@ class Config
|
||||
*/
|
||||
protected function getRestrictItems($onlySystemItems = false)
|
||||
{
|
||||
$configData = $this->loadConfig();
|
||||
$data = $this->loadConfig();
|
||||
|
||||
if ($onlySystemItems) {
|
||||
return $configData['systemItems'];
|
||||
return $data['systemItems'];
|
||||
}
|
||||
|
||||
if (empty($this->adminItems)) {
|
||||
$this->adminItems= Util::merge($configData['systemItems'], $configData['adminItems']);
|
||||
$this->adminItems= Util::merge($data['systemItems'], $data['adminItems']);
|
||||
}
|
||||
|
||||
return $this->adminItems;
|
||||
|
||||
@@ -26,18 +26,21 @@ use Espo\Core\Utils\Util;
|
||||
|
||||
class Base
|
||||
{
|
||||
private $itemName = null;
|
||||
|
||||
private $entityName = null;
|
||||
|
||||
private $metadata;
|
||||
|
||||
private $params;
|
||||
private $ormEntityDefs;
|
||||
|
||||
private $foreignParams;
|
||||
private $entityDefs;
|
||||
|
||||
protected $allowParams = array();
|
||||
|
||||
|
||||
public function __construct(\Espo\Core\Utils\Metadata $metadata)
|
||||
public function __construct(\Espo\Core\Utils\Metadata $metadata, array $ormEntityDefs, array $entityDefs)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
$this->ormEntityDefs = $ormEntityDefs;
|
||||
$this->entityDefs = $entityDefs;
|
||||
}
|
||||
|
||||
protected function getMetadata()
|
||||
@@ -45,80 +48,197 @@ class Base
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
protected function getParams()
|
||||
protected function getOrmEntityDefs()
|
||||
{
|
||||
return $this->params;
|
||||
return $this->ormEntityDefs;
|
||||
}
|
||||
|
||||
protected function getForeignParams()
|
||||
protected function getEntityDefs()
|
||||
{
|
||||
return $this->foreignParams;
|
||||
return $this->entityDefs;
|
||||
}
|
||||
|
||||
protected function setParams(array $params)
|
||||
/**
|
||||
* Set current Field name OR Link name
|
||||
*
|
||||
* @param void
|
||||
*/
|
||||
protected function setItemName($itemName)
|
||||
{
|
||||
$this->params = $params;
|
||||
$this->itemName = $itemName;
|
||||
}
|
||||
|
||||
protected function setForeignParams(array $foreignParams)
|
||||
/**
|
||||
* Get current Field name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getFieldName()
|
||||
{
|
||||
$this->foreignParams = $foreignParams;
|
||||
return $this->itemName;
|
||||
}
|
||||
|
||||
|
||||
public function process($params, $foreignParams)
|
||||
/**
|
||||
* Get current Link name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getLinkName()
|
||||
{
|
||||
$this->setParams($params);
|
||||
$this->setForeignParams($foreignParams);
|
||||
|
||||
$loads = $this->load($params, $foreignParams);
|
||||
|
||||
$loads = $this->mergeAllowedParams($loads);
|
||||
|
||||
return $loads;
|
||||
return $this->itemName;
|
||||
}
|
||||
|
||||
private function mergeAllowedParams($loads)
|
||||
/**
|
||||
* Set current Entity Name
|
||||
*
|
||||
* @param void
|
||||
*/
|
||||
protected function setEntityName($entityName)
|
||||
{
|
||||
$params = $this->getParams();
|
||||
$this->entityName = $entityName;
|
||||
}
|
||||
|
||||
if (!empty($this->allowParams)) {
|
||||
$linkParams = &$loads[$params['entityName']] ['relations'] [$params['link']['name']];
|
||||
/**
|
||||
* Get current Entity Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getEntityName()
|
||||
{
|
||||
return $this->entityName;
|
||||
}
|
||||
|
||||
foreach ($this->allowParams as $name) {
|
||||
|
||||
$additionalParrams = $this->getAllowedAdditionalParams($name);
|
||||
|
||||
if (isset($additionalParrams) && !isset($linkParams[$name])) {
|
||||
$linkParams[$name] = $additionalParrams;
|
||||
}
|
||||
protected function setMethods(array $keyValueList)
|
||||
{
|
||||
foreach ($keyValueList as $key => $value) {
|
||||
$methodName = 'set' . ucfirst($key);
|
||||
if (method_exists($this, $methodName)) {
|
||||
$this->$methodName($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $loads;
|
||||
}
|
||||
|
||||
private function getAllowedAdditionalParams($allowedItemName)
|
||||
/**
|
||||
* Start process Orm converting for fields/relations
|
||||
*
|
||||
* @param string $itemName Field name OR Link name
|
||||
* @param string $entityName
|
||||
* @return array
|
||||
*/
|
||||
public function process($itemName, $entityName)
|
||||
{
|
||||
$params = $this->getParams();
|
||||
$foreignParams = $this->getForeignParams();
|
||||
$inputs = array(
|
||||
'itemName' => $itemName,
|
||||
'entityName' => $entityName,
|
||||
);
|
||||
$this->setMethods($inputs);
|
||||
|
||||
$linkParams = isset($params['link']['params'][$allowedItemName]) ? $params['link']['params'][$allowedItemName] : null;
|
||||
$foreignLinkParams = isset($foreignParams['link']['params'][$allowedItemName]) ? $foreignParams['link']['params'][$allowedItemName] : null;
|
||||
$convertedDefs = $this->load($itemName, $entityName);
|
||||
|
||||
$additionalParrams = null;
|
||||
$inputs = $this->setArrayValue(null, $inputs);
|
||||
$this->setMethods($inputs);
|
||||
|
||||
if (isset($linkParams) && isset($foreignLinkParams)) {
|
||||
$additionalParrams = Util::merge($linkParams, $foreignLinkParams);
|
||||
} else if (isset($linkParams)) {
|
||||
$additionalParrams = $linkParams;
|
||||
} else if (isset($foreignLinkParams)) {
|
||||
$additionalParrams = $foreignLinkParams;
|
||||
return $convertedDefs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Entity Defs by type (entity/orm)
|
||||
*
|
||||
* @param boolean $isOrmEntityDefs
|
||||
* @return array
|
||||
*/
|
||||
protected function getDefs($isOrmEntityDefs = false)
|
||||
{
|
||||
$entityDefs = $isOrmEntityDefs ? $this->getOrmEntityDefs() : $this->getEntityDefs();
|
||||
|
||||
return $entityDefs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get entity params by name
|
||||
*
|
||||
* @param string $entityName
|
||||
* @param bool $isOrmEntityDefs
|
||||
* @param mixed $returns
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getEntityParams($entityName = null, $isOrmEntityDefs = false, $returns = null)
|
||||
{
|
||||
if (!isset($entityName)) {
|
||||
$entityName = $this->getEntityName();
|
||||
}
|
||||
|
||||
return $additionalParrams;
|
||||
$entityDefs = $this->getDefs($isOrmEntityDefs);
|
||||
|
||||
if (isset($entityDefs[$entityName])) {
|
||||
return $entityDefs[$entityName];
|
||||
}
|
||||
|
||||
return $returns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field params by name for a specified entity
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @param string $entityName
|
||||
* @param bool $isOrmEntityDefs
|
||||
* @param mixed $returns
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getFieldParams($fieldName = null, $entityName = null, $isOrmEntityDefs = false, $returns = null)
|
||||
{
|
||||
if (!isset($fieldName)) {
|
||||
$fieldName = $this->getFieldName();
|
||||
}
|
||||
if (!isset($entityName)) {
|
||||
$entityName = $this->getEntityName();
|
||||
}
|
||||
|
||||
$entityDefs = $this->getDefs($isOrmEntityDefs);
|
||||
|
||||
if (isset($entityDefs[$entityName]) && isset($entityDefs[$entityName]['fields'][$fieldName])) {
|
||||
return $entityDefs[$entityName]['fields'][$fieldName];
|
||||
}
|
||||
|
||||
return $returns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get relation params by name for a specified entity
|
||||
*
|
||||
* @param string $linkName
|
||||
* @param string $entityName
|
||||
* @param bool $isOrmEntityDefs
|
||||
* @param mixed $returns
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getLinkParams($linkName = null, $entityName = null, $isOrmEntityDefs = false, $returns = null)
|
||||
{
|
||||
if (!isset($linkName)) {
|
||||
$linkName = $this->getLinkName();
|
||||
}
|
||||
if (!isset($entityName)) {
|
||||
$entityName = $this->getEntityName();
|
||||
}
|
||||
|
||||
$entityDefs = $this->getDefs($isOrmEntityDefs);
|
||||
$relationKeyName = $isOrmEntityDefs ? 'relations' : 'links';
|
||||
|
||||
if (isset($entityDefs[$entityName]) && isset($entityDefs[$entityName][$relationKeyName][$linkName])) {
|
||||
return $entityDefs[$entityName][$relationKeyName][$linkName];
|
||||
}
|
||||
|
||||
return $returns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Foreign field
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $entityName
|
||||
* @return string
|
||||
*/
|
||||
protected function getForeignField($name, $entityName)
|
||||
{
|
||||
$foreignField = $this->getMetadata()->get('entityDefs.'.$entityName.'.fields.'.$name);
|
||||
@@ -141,6 +261,19 @@ class Base
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value for all elements of array. So, in result all elements will have the same values
|
||||
*
|
||||
* @param string $value
|
||||
* @param array $array
|
||||
*/
|
||||
protected function setArrayValue($inputValue, array $array)
|
||||
{
|
||||
foreach ($array as &$value) {
|
||||
$value = $inputValue;
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ class Converter
|
||||
|
||||
private $relationManager;
|
||||
|
||||
private $entityDefs;
|
||||
|
||||
protected $defaultFieldType = 'varchar';
|
||||
protected $defaultNaming = 'postfix';
|
||||
|
||||
@@ -69,6 +71,9 @@ class Converter
|
||||
'default' => '{0}',
|
||||
),
|
||||
),
|
||||
'select' => 'select',
|
||||
'orderBy' => 'orderBy',
|
||||
'where' => 'where',
|
||||
);
|
||||
|
||||
protected $idParams = array(
|
||||
@@ -85,6 +90,8 @@ class Converter
|
||||
$this->relationManager = new RelationManager($this->metadata);
|
||||
|
||||
$this->metadataUtils = new \Espo\Core\Utils\Metadata\Utils($this->metadata);
|
||||
|
||||
$this->entityDefs = $this->getMetadata()->get('entityDefs');
|
||||
}
|
||||
|
||||
|
||||
@@ -93,6 +100,11 @@ class Converter
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
protected function getEntityDefs()
|
||||
{
|
||||
return $this->entityDefs;
|
||||
}
|
||||
|
||||
protected function getFileManager()
|
||||
{
|
||||
return $this->fileManager;
|
||||
@@ -108,11 +120,9 @@ class Converter
|
||||
return $this->metadataUtils;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function process()
|
||||
{
|
||||
$entityDefs = $this->getMetadata()->get('entityDefs');
|
||||
$entityDefs = $this->getEntityDefs();
|
||||
|
||||
$ormMeta = array();
|
||||
foreach($entityDefs as $entityName => $entityMeta) {
|
||||
@@ -122,7 +132,7 @@ class Converter
|
||||
continue;
|
||||
}
|
||||
|
||||
$ormMeta = Util::merge($ormMeta, $this->convertEntity($entityName, $entityMeta, $entityDefs));
|
||||
$ormMeta = Util::merge($ormMeta, $this->convertEntity($entityName, $entityMeta));
|
||||
}
|
||||
|
||||
$ormMeta = $this->afterProcess($ormMeta);
|
||||
@@ -130,10 +140,7 @@ class Converter
|
||||
return $ormMeta;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//convertToDatabaseFormat
|
||||
protected function convertEntity($entityName, $entityMeta, $entityDefs)
|
||||
protected function convertEntity($entityName, $entityMeta)
|
||||
{
|
||||
$ormMeta = array();
|
||||
$ormMeta[$entityName] = array(
|
||||
@@ -145,18 +152,19 @@ class Converter
|
||||
|
||||
$ormMeta[$entityName]['fields'] = $this->convertFields($entityName, $entityMeta);
|
||||
|
||||
$convertedLinks = $this->convertLinks($entityName, $entityMeta, $entityDefs);
|
||||
$convertedLinks = $this->convertLinks($entityName, $entityMeta, $ormMeta);
|
||||
|
||||
$ormMeta = Util::merge($ormMeta, $convertedLinks);
|
||||
|
||||
return $ormMeta;
|
||||
}
|
||||
|
||||
|
||||
public function afterProcess(array $meta)
|
||||
public function afterProcess(array $ormMeta)
|
||||
{
|
||||
$entityDefs = $this->getEntityDefs();
|
||||
|
||||
//load custom field definitions and customCodes
|
||||
foreach($meta as $entityName => &$entityParams) {
|
||||
foreach($ormMeta as $entityName => &$entityParams) {
|
||||
foreach($entityParams['fields'] as $fieldName => $fieldParams) {
|
||||
|
||||
//load custom field definitions
|
||||
@@ -167,17 +175,14 @@ class Converter
|
||||
}
|
||||
|
||||
if (class_exists($className) && method_exists($className, 'load')) {
|
||||
$helperClass = new $className($this->metadata);
|
||||
$fieldResult = $helperClass->load(
|
||||
array('name' => $entityName, 'params' => $entityParams),
|
||||
array('name' => $fieldName, 'params' => $fieldParams)
|
||||
);
|
||||
$helperClass = new $className($this->metadata, $ormMeta, $entityDefs);
|
||||
$fieldResult = $helperClass->process( $fieldName, $entityName );
|
||||
if (isset($fieldResult['unset'])) {
|
||||
$meta = Util::unsetInArray($meta, $fieldResult['unset']);
|
||||
$ormMeta = Util::unsetInArray($ormMeta, $fieldResult['unset']);
|
||||
unset($fieldResult['unset']);
|
||||
}
|
||||
|
||||
$meta = Util::merge($meta, $fieldResult);
|
||||
$ormMeta = Util::merge($ormMeta, $fieldResult);
|
||||
} //END: load custom field definitions
|
||||
|
||||
|
||||
@@ -196,7 +201,7 @@ class Converter
|
||||
}
|
||||
}
|
||||
|
||||
foreach($meta as $entityName => &$entityParams) {
|
||||
foreach($ormMeta as $entityName => &$entityParams) {
|
||||
foreach($entityParams['fields'] as $fieldName => &$fieldParams) {
|
||||
|
||||
switch ($fieldParams['type']) {
|
||||
@@ -224,10 +229,9 @@ class Converter
|
||||
|
||||
}
|
||||
|
||||
return $meta;
|
||||
return $ormMeta;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Metadata conversion from Espo format into Doctrine
|
||||
*
|
||||
@@ -293,8 +297,6 @@ class Converter
|
||||
return $outputMeta;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected function convertField($entityName, $fieldName, array $fieldParams, $fieldTypeMeta = null)
|
||||
{
|
||||
/** set default type if exists */
|
||||
@@ -376,34 +378,20 @@ class Converter
|
||||
return $subField;
|
||||
}
|
||||
|
||||
protected function convertLinks($entityName, $entityMeta, array $entityDefs)
|
||||
protected function convertLinks($entityName, $entityMeta, $ormMeta)
|
||||
{
|
||||
if (!isset($entityMeta['links'])) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$entityDefs = $this->getEntityDefs();
|
||||
|
||||
$relationships = array();
|
||||
foreach($entityMeta['links'] as $linkName => $linkParams) {
|
||||
|
||||
$linkEntityName = $this->getRelationManager()->getLinkEntityName($entityName, $linkParams);
|
||||
$convertedLink = $this->getRelationManager()->convert($linkName, $linkParams, $entityName, $ormMeta);
|
||||
|
||||
$currentType = $linkParams['type'];
|
||||
|
||||
$foreignLink = $this->getForeignLink($linkName, $linkParams, $entityDefs[$linkEntityName]);
|
||||
|
||||
$method = $currentType;
|
||||
if ($foreignLink !== false) {
|
||||
$method .= '-'.$foreignLink['params']['type'];
|
||||
}
|
||||
$method = Util::toCamelCase($method);
|
||||
|
||||
if ( $this->getRelationManager()->isRelationExists($method) ) { //ex. hasManyHasMany
|
||||
$convertedLink = $this->getRelationManager()->process($method, $entityName, array('name'=>$linkName, 'params'=>$linkParams), $foreignLink);
|
||||
} else { //ex. hasMany
|
||||
$convertedLink = $this->getRelationManager()->process($currentType, $entityName, array('name'=>$linkName, 'params'=>$linkParams), $foreignLink);
|
||||
}
|
||||
|
||||
if ($convertedLink !== false) {
|
||||
if (isset($convertedLink)) {
|
||||
$relationships = Util::merge($convertedLink, $relationships);
|
||||
}
|
||||
}
|
||||
@@ -411,27 +399,6 @@ class Converter
|
||||
return $relationships;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get foreign Link
|
||||
*
|
||||
* @param string $parentLinkName
|
||||
* @param array $parentLinkParams
|
||||
* @param array $currentEntityDefs
|
||||
*
|
||||
* @return array - in format array('name', 'params')
|
||||
*/
|
||||
protected function getForeignLink($parentLinkName, $parentLinkParams, $currentEntityDefs)
|
||||
{
|
||||
if (isset($parentLinkParams['foreign']) && isset($currentEntityDefs['links'][$parentLinkParams['foreign']])) {
|
||||
return array(
|
||||
'name' => $parentLinkParams['foreign'],
|
||||
'params' => $currentEntityDefs['links'][$parentLinkParams['foreign']],
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function getInitValues(array $fieldParams)
|
||||
{
|
||||
$values = array();
|
||||
@@ -460,4 +427,4 @@ class Converter
|
||||
return $values;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,34 +18,47 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Fields;
|
||||
|
||||
class Email extends \Espo\Core\Utils\Database\Orm\Base
|
||||
{
|
||||
|
||||
public function load($entity, $field)
|
||||
protected function load($fieldName, $entityName)
|
||||
{
|
||||
return array(
|
||||
$entity['name'] => array(
|
||||
'fields' => array(
|
||||
$field['name'] => array(
|
||||
return array(
|
||||
$entityName => array(
|
||||
'fields' => array(
|
||||
$fieldName => array(
|
||||
'select' => 'email_address.name',
|
||||
'where' =>
|
||||
array (
|
||||
'LIKE' => 'email_address.name LIKE \'{text}\'',
|
||||
'=' => 'email_address.name = \'{text}\'',
|
||||
),
|
||||
'orderBy' => 'email_address.name {direction}',
|
||||
'where' =>
|
||||
array (
|
||||
'LIKE' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".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
|
||||
email_address.deleted = 0 AND email_address.name LIKE {value}
|
||||
)",
|
||||
'=' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".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
|
||||
email_address.deleted = 0 AND email_address.name = {value}
|
||||
)"
|
||||
),
|
||||
'orderBy' => 'email_address.name {direction}',
|
||||
),
|
||||
$field['name'] .'Data' => array(
|
||||
$fieldName .'Data' => array(
|
||||
'type' => 'text',
|
||||
'notStorable' => true
|
||||
),
|
||||
),
|
||||
'relations' => array(
|
||||
$field['name'].'es' => array(
|
||||
$fieldName.'es' => array(
|
||||
'type' => 'manyMany',
|
||||
'entity' => 'EmailAddress',
|
||||
'relationName' => 'entityEmailAddress',
|
||||
@@ -54,16 +67,16 @@ class Email extends \Espo\Core\Utils\Database\Orm\Base
|
||||
'email_address_id',
|
||||
),
|
||||
'conditions' => array(
|
||||
'entityType' => $entity['name'],
|
||||
'entityType' => $entityName,
|
||||
),
|
||||
'additionalColumns' => array(
|
||||
'entityType' => array(
|
||||
'entityType' => array(
|
||||
'type' => 'varchar',
|
||||
'len' => 100,
|
||||
'len' => 100,
|
||||
),
|
||||
'primary' => array(
|
||||
'type' => 'bool',
|
||||
'default' => false,
|
||||
'default' => false,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -18,35 +18,44 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Fields;
|
||||
|
||||
class LinkMultiple extends \Espo\Core\Utils\Database\Orm\Base
|
||||
{
|
||||
|
||||
public function load($entity, $field)
|
||||
protected function load($fieldName, $entityName)
|
||||
{
|
||||
return array(
|
||||
$entity['name'] => array (
|
||||
'fields' => array(
|
||||
$field['name'].'Ids' => array(
|
||||
$data = array(
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$fieldName.'Ids' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
),
|
||||
$field['name'].'Names' => array(
|
||||
$fieldName.'Names' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
),
|
||||
),
|
||||
),
|
||||
'unset' => array(
|
||||
$entity['name'] => array(
|
||||
'fields.'.$field['name'],
|
||||
),
|
||||
),
|
||||
'unset' => array(
|
||||
$entityName => array(
|
||||
'fields.'.$fieldName,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$columns = $this->getMetadata()->get("entityDefs.{$entityName}.fields.{$fieldName}.columns");
|
||||
if (!empty($columns)) {
|
||||
$data[$entityName]['fields'][$fieldName . 'Columns'] = array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,28 +24,27 @@ namespace Espo\Core\Utils\Database\Orm\Fields;
|
||||
|
||||
class LinkParent extends \Espo\Core\Utils\Database\Orm\Base
|
||||
{
|
||||
|
||||
public function load($entity, $field)
|
||||
protected function load($fieldName, $entityName)
|
||||
{
|
||||
return array(
|
||||
$entity['name'] => array (
|
||||
'fields' => array(
|
||||
$field['name'].'Id' => array(
|
||||
return array(
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$fieldName.'Id' => array(
|
||||
'type' => 'foreignId',
|
||||
'index' => $field['name'],
|
||||
'index' => $fieldName,
|
||||
),
|
||||
$field['name'].'Type' => array(
|
||||
$fieldName.'Type' => array(
|
||||
'type' => 'foreignType',
|
||||
'notNull' => false,
|
||||
'index' => $field['name'],
|
||||
'index' => $fieldName,
|
||||
),
|
||||
$field['name'].'Name' => array(
|
||||
$fieldName.'Name' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,11 +26,10 @@ use Espo\Core\Utils\Util;
|
||||
|
||||
class PersonName extends \Espo\Core\Utils\Database\Orm\Base
|
||||
{
|
||||
|
||||
public function load($entity, $field)
|
||||
protected function load($fieldName, $entityName)
|
||||
{
|
||||
$foreignField = $this->getForeignField($field['name'], $entity['name']);
|
||||
$tableName = Util::toUnderScore($entity['name']);
|
||||
$foreignField = $this->getForeignField($fieldName, $entityName);
|
||||
$tableName = Util::toUnderScore($entityName);
|
||||
|
||||
$fullList = array(); //contains empty string (" ") like delimiter
|
||||
$fullListReverse = array(); //reverse of $fullList
|
||||
@@ -38,31 +37,31 @@ class PersonName extends \Espo\Core\Utils\Database\Orm\Base
|
||||
$like = array();
|
||||
$equal = array();
|
||||
|
||||
foreach($foreignField as $fieldName) {
|
||||
foreach($foreignField as $foreignFieldName) {
|
||||
|
||||
$fieldNameTrimmed = trim($fieldName);
|
||||
$fieldNameTrimmed = trim($foreignFieldName);
|
||||
if (!empty($fieldNameTrimmed)) {
|
||||
$columnName = $tableName.'.'.Util::toUnderScore($fieldNameTrimmed);
|
||||
|
||||
$fullList[] = $fieldList[] = $columnName;
|
||||
$like[] = $columnName." LIKE '{text}'";
|
||||
$equal[] = $columnName." = '{text}'";
|
||||
$like[] = $columnName." LIKE {value}";
|
||||
$equal[] = $columnName." = {value}";
|
||||
} else {
|
||||
$fullList[] = "'".$fieldName."'";
|
||||
$fullList[] = "'".$foreignFieldName."'";
|
||||
}
|
||||
}
|
||||
|
||||
$fullListReverse = array_reverse($fullList);
|
||||
|
||||
return array(
|
||||
$entity['name'] => array (
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$field['name'] => array(
|
||||
$fieldName => array(
|
||||
'type' => 'varchar',
|
||||
'select' => $this->getSelect($fullList),
|
||||
'where' => array(
|
||||
'LIKE' => "(".implode(" OR ", $like)." OR CONCAT(".implode(", ", $fullList).") LIKE '{text}' OR CONCAT(".implode(", ", $fullListReverse).") LIKE '{text}')",
|
||||
'=' => "(".implode(" OR ", $equal)." OR CONCAT(".implode(", ", $fullList).") = '{text}' OR CONCAT(".implode(", ", $fullListReverse).") = '{text}')",
|
||||
'LIKE' => "(".implode(" OR ", $like)." OR CONCAT(".implode(", ", $fullList).") LIKE {value} OR CONCAT(".implode(", ", $fullListReverse).") LIKE {value})",
|
||||
'=' => "(".implode(" OR ", $equal)." OR CONCAT(".implode(", ", $fullList).") = {value} OR CONCAT(".implode(", ", $fullListReverse).") = {value})",
|
||||
),
|
||||
'orderBy' => implode(", ", array_map(function ($item) {return $item . ' {direction}';}, $fieldList)),
|
||||
),
|
||||
@@ -87,4 +86,4 @@ class PersonName extends \Espo\Core\Utils\Database\Orm\Base
|
||||
return $select;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Fields;
|
||||
|
||||
class Phone extends \Espo\Core\Utils\Database\Orm\Base
|
||||
{
|
||||
protected function load($fieldName, $entityName)
|
||||
{
|
||||
return array(
|
||||
$entityName => array(
|
||||
'fields' => array(
|
||||
$fieldName => array(
|
||||
'select' => 'phone_number.name',
|
||||
'where' =>
|
||||
array (
|
||||
'LIKE' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".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
|
||||
phone_number.deleted = 0 AND phone_number.name LIKE {value}
|
||||
)",
|
||||
'=' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".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
|
||||
phone_number.deleted = 0 AND phone_number.name = {value}
|
||||
)"
|
||||
),
|
||||
'orderBy' => 'phone_number.name {direction}',
|
||||
),
|
||||
$fieldName .'Data' => array(
|
||||
'type' => 'text',
|
||||
'notStorable' => true
|
||||
),
|
||||
),
|
||||
'relations' => array(
|
||||
$fieldName.'s' => array(
|
||||
'type' => 'manyMany',
|
||||
'entity' => 'PhoneNumber',
|
||||
'relationName' => 'entityPhoneNumber',
|
||||
'midKeys' => array(
|
||||
'entity_id',
|
||||
'phone_number_id',
|
||||
),
|
||||
'conditions' => array(
|
||||
'entityType' => $entityName,
|
||||
),
|
||||
'additionalColumns' => array(
|
||||
'entityType' => array(
|
||||
'type' => 'varchar',
|
||||
'len' => 100,
|
||||
),
|
||||
'primary' => array(
|
||||
'type' => 'bool',
|
||||
'default' => false,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,10 +28,14 @@ class RelationManager
|
||||
{
|
||||
private $metadata;
|
||||
|
||||
private $entityDefs;
|
||||
|
||||
|
||||
public function __construct(\Espo\Core\Utils\Metadata $metadata)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
|
||||
$this->entityDefs = $this->getMetadata()->get('entityDefs');
|
||||
}
|
||||
|
||||
protected function getMetadata()
|
||||
@@ -39,14 +43,15 @@ class RelationManager
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
|
||||
public function getLinkEntityName($entityName, $link)
|
||||
protected function getEntityDefs()
|
||||
{
|
||||
if (isset($link['params'])) {
|
||||
return isset($link['params']['entity']) ? $link['params']['entity'] : $entityName;
|
||||
}
|
||||
return $this->entityDefs;
|
||||
}
|
||||
|
||||
return isset($link['entity']) ? $link['entity'] : $entityName;
|
||||
|
||||
public function getLinkEntityName($entityName, $linkParams)
|
||||
{
|
||||
return isset($linkParams['entity']) ? $linkParams['entity'] : $entityName;
|
||||
}
|
||||
|
||||
public function isRelationExists($relationName)
|
||||
@@ -81,33 +86,58 @@ class RelationManager
|
||||
return method_exists($className, 'load');
|
||||
}
|
||||
|
||||
public function process($method, $entityName, $link, $foreignLink = array())
|
||||
/**
|
||||
* Get foreign Link
|
||||
*
|
||||
* @param string $parentLinkName
|
||||
* @param array $parentLinkParams
|
||||
* @param array $currentEntityDefs
|
||||
*
|
||||
* @return array - in format array('name', 'params')
|
||||
*/
|
||||
private function getForeignLink($parentLinkName, $parentLinkParams, $currentEntityDefs)
|
||||
{
|
||||
$params = array();
|
||||
$params['entityName'] = $entityName;
|
||||
$params['link'] = $link;
|
||||
|
||||
$foreignParams = array();
|
||||
$foreignParams['entityName'] = $this->getLinkEntityName($entityName, $link);
|
||||
$foreignParams['link'] = $foreignLink;
|
||||
|
||||
$params['targetEntity'] = $foreignParams['entityName'];
|
||||
$foreignParams['targetEntity'] = $params['entityName'];
|
||||
|
||||
//relationDefs defined in separate file
|
||||
if (isset($link['params']['relationName']) && $this->isMethodExists($link['params']['relationName'])) {
|
||||
$className = $this->getRelationClass($link['params']['relationName']);
|
||||
} else if ($this->isMethodExists($method)) {
|
||||
$className = $this->getRelationClass($method);
|
||||
if (isset($parentLinkParams['foreign']) && isset($currentEntityDefs['links'][$parentLinkParams['foreign']])) {
|
||||
return array(
|
||||
'name' => $parentLinkParams['foreign'],
|
||||
'params' => $currentEntityDefs['links'][$parentLinkParams['foreign']],
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($className) && $className !== false) {
|
||||
$helperClass = new $className($this->metadata);
|
||||
return $helperClass->process($params, $foreignParams);
|
||||
}
|
||||
//END: relationDefs defined in separate file
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function convert($linkName, $linkParams, $entityName, $ormMeta)
|
||||
{
|
||||
$entityDefs = $this->getEntityDefs();
|
||||
|
||||
$foreignEntityName = $this->getLinkEntityName($entityName, $linkParams);
|
||||
$foreignLink = $this->getForeignLink($linkName, $linkParams, $entityDefs[$foreignEntityName]);
|
||||
|
||||
$currentType = $linkParams['type'];
|
||||
|
||||
$method = $currentType;
|
||||
if ($foreignLink !== false) {
|
||||
$method .= '-'.$foreignLink['params']['type'];
|
||||
}
|
||||
$method = Util::toCamelCase($method);
|
||||
|
||||
$relationName = $this->isRelationExists($method) ? $method /*hasManyHasMany*/ : $currentType /*hasMany*/;
|
||||
|
||||
//relationDefs defined in separate file
|
||||
if (isset($linkParams['relationName']) && $this->isMethodExists($linkParams['relationName'])) {
|
||||
$className = $this->getRelationClass($linkParams['relationName']);
|
||||
} else if ($this->isMethodExists($relationName)) {
|
||||
$className = $this->getRelationClass($relationName);
|
||||
}
|
||||
|
||||
if (isset($className) && $className !== false) {
|
||||
$helperClass = new $className($this->metadata, $ormMeta, $entityDefs);
|
||||
return $helperClass->process($linkName, $entityName, $foreignLink['name'], $foreignEntityName);
|
||||
}
|
||||
//END: relationDefs defined in separate file
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Relations;
|
||||
|
||||
class Base extends \Espo\Core\Utils\Database\Orm\Base
|
||||
{
|
||||
private $params;
|
||||
|
||||
private $foreignParams;
|
||||
|
||||
protected $foreignLinkName = null;
|
||||
protected $foreignEntityName = null;
|
||||
|
||||
protected $allowParams = array();
|
||||
|
||||
protected function getParams()
|
||||
{
|
||||
return $this->params;
|
||||
}
|
||||
|
||||
protected function getForeignParams()
|
||||
{
|
||||
return $this->foreignParams;
|
||||
}
|
||||
|
||||
protected function setParams(array $params)
|
||||
{
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
protected function setForeignParams(array $foreignParams)
|
||||
{
|
||||
$this->foreignParams = $foreignParams;
|
||||
}
|
||||
|
||||
protected function setForeignLinkName($foreignLinkName)
|
||||
{
|
||||
$this->foreignLinkName = $foreignLinkName;
|
||||
}
|
||||
|
||||
protected function getForeignLinkName()
|
||||
{
|
||||
return $this->foreignLinkName;
|
||||
}
|
||||
|
||||
protected function setForeignEntityName($foreignEntityName)
|
||||
{
|
||||
$this->foreignEntityName = $foreignEntityName;
|
||||
}
|
||||
|
||||
protected function getForeignEntityName()
|
||||
{
|
||||
return $this->foreignEntityName;
|
||||
}
|
||||
|
||||
protected function getForeignLinkParams()
|
||||
{
|
||||
$foreignLinkName = $this->getForeignLinkName();
|
||||
$foreignEntityName = $this->getForeignEntityName();
|
||||
$foreignLinkParams = $this->getLinkParams($foreignLinkName, $foreignEntityName);
|
||||
|
||||
return $foreignLinkParams;
|
||||
}
|
||||
|
||||
public function process($linkName, $entityName, $foreignLinkName, $foreignEntityName)
|
||||
{
|
||||
$inputs = array(
|
||||
'itemName' => $linkName,
|
||||
'entityName' => $entityName,
|
||||
'foreignLinkName' => $foreignLinkName,
|
||||
'foreignEntityName' => $foreignEntityName,
|
||||
);
|
||||
$this->setMethods($inputs);
|
||||
|
||||
$convertedDefs = $this->load($linkName, $entityName);
|
||||
$convertedDefs = $this->mergeAllowedParams($convertedDefs);
|
||||
|
||||
$inputs = $this->setArrayValue(null, $inputs);
|
||||
$this->setMethods($inputs);
|
||||
|
||||
return $convertedDefs;
|
||||
}
|
||||
|
||||
private function mergeAllowedParams($loads)
|
||||
{
|
||||
$linkName = $this->getLinkName();
|
||||
$entityName = $this->getEntityName();
|
||||
|
||||
if (!empty($this->allowParams)) {
|
||||
$linkParams = &$loads[$entityName]['relations'][$linkName];
|
||||
|
||||
foreach ($this->allowParams as $name) {
|
||||
|
||||
$additionalParrams = $this->getAllowedAdditionalParams($name);
|
||||
|
||||
if (isset($additionalParrams) && !isset($linkParams[$name])) {
|
||||
$linkParams[$name] = $additionalParrams;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $loads;
|
||||
}
|
||||
|
||||
private function getAllowedAdditionalParams($allowedItemName)
|
||||
{
|
||||
$linkParams = $this->getLinkParams();
|
||||
$foreignLinkParams = $this->getForeignLinkParams();
|
||||
|
||||
$itemLinkParams = isset($linkParams[$allowedItemName]) ? $linkParams[$allowedItemName] : null;
|
||||
$itemForeignLinkParams = isset($foreignLinkParams[$allowedItemName]) ? $foreignLinkParams[$allowedItemName] : null;
|
||||
|
||||
$additionalParrams = null;
|
||||
|
||||
if (isset($itemLinkParams) && isset($itemForeignLinkParams)) {
|
||||
$additionalParrams = Util::merge($itemLinkParams, $itemForeignLinkParams);
|
||||
} else if (isset($itemLinkParams)) {
|
||||
$additionalParrams = $itemLinkParams;
|
||||
} else if (isset($itemForeignLinkParams)) {
|
||||
$additionalParrams = $itemForeignLinkParams;
|
||||
}
|
||||
|
||||
return $additionalParrams;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,33 +18,34 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Relations;
|
||||
|
||||
class BelongsTo extends \Espo\Core\Utils\Database\Orm\Base
|
||||
class BelongsTo extends Base
|
||||
{
|
||||
|
||||
public function load($params, $foreignParams)
|
||||
protected function load($linkName, $entityName)
|
||||
{
|
||||
$foreignEntityName = $this->getForeignEntityName();
|
||||
|
||||
return array (
|
||||
$params['entityName'] => array (
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$params['link']['name'].'Name' => array(
|
||||
$linkName.'Name' => array(
|
||||
'type' => 'foreign',
|
||||
'relation' => $params['link']['name'],
|
||||
'foreign' => $this->getForeignField('name', $foreignParams['entityName']),
|
||||
'relation' => $linkName,
|
||||
'foreign' => $this->getForeignField('name', $foreignEntityName),
|
||||
),
|
||||
$params['link']['name'].'Id' => array(
|
||||
$linkName.'Id' => array(
|
||||
'type' => 'foreignId',
|
||||
'index' => true,
|
||||
),
|
||||
),
|
||||
'relations' => array(
|
||||
$params['link']['name'] => array(
|
||||
$linkName => array(
|
||||
'type' => 'belongsTo',
|
||||
'entity' => $params['targetEntity'],
|
||||
'key' => $params['link']['name'].'Id',
|
||||
'entity' => $foreignEntityName,
|
||||
'key' => $linkName.'Id',
|
||||
'foreignKey' => 'id', //????
|
||||
),
|
||||
),
|
||||
@@ -52,5 +53,4 @@ class BelongsTo extends \Espo\Core\Utils\Database\Orm\Base
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -18,32 +18,31 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Relations;
|
||||
|
||||
class EmailEmailAddress extends \Espo\Core\Utils\Database\Orm\Relations\HasMany
|
||||
class EmailEmailAddress extends HasMany
|
||||
{
|
||||
|
||||
public function load($params, $foreignParams)
|
||||
protected function load($linkName, $entityName)
|
||||
{
|
||||
$parentRelation = parent::load($linkName, $entityName);
|
||||
|
||||
$parentRelation = parent::load($params, $foreignParams);
|
||||
$foreignEntityName = $this->getForeignEntityName();
|
||||
|
||||
$relation = array(
|
||||
$params['entityName'] => array (
|
||||
$entityName => array (
|
||||
'relations' => array(
|
||||
$params['link']['name'] => array(
|
||||
$linkName => array(
|
||||
'midKeys' => array(
|
||||
lcfirst($params['entityName']).'Id',
|
||||
lcfirst($foreignParams['entityName']).'Id',
|
||||
lcfirst($entityName).'Id',
|
||||
lcfirst($foreignEntityName).'Id',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
$relation = \Espo\Core\Utils\Util::merge($parentRelation, $relation);
|
||||
|
||||
return $relation;
|
||||
|
||||
@@ -18,28 +18,30 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Relations;
|
||||
|
||||
class EntityTeam extends \Espo\Core\Utils\Database\Orm\Base
|
||||
class EntityTeam extends Base
|
||||
{
|
||||
|
||||
public function load($params, $foreignParams)
|
||||
protected function load($linkName, $entityName)
|
||||
{
|
||||
$linkParams = $this->getLinkParams();
|
||||
$foreignEntityName = $this->getForeignEntityName();
|
||||
|
||||
return array(
|
||||
$params['entityName'] => array(
|
||||
$entityName => array(
|
||||
'relations' => array(
|
||||
$params['link']['name'] => array(
|
||||
$linkName => array(
|
||||
'type' => 'manyMany',
|
||||
'entity' => $params['targetEntity'],
|
||||
'relationName' => lcfirst($params['link']['params']['relationName']),
|
||||
'entity' => $foreignEntityName,
|
||||
'relationName' => lcfirst($linkParams['relationName']),
|
||||
'midKeys' => array(
|
||||
'entity_id',
|
||||
'team_id',
|
||||
),
|
||||
'conditions' => array(
|
||||
'entityType' => $params['entityName'],
|
||||
'entityType' => $entityName,
|
||||
),
|
||||
'additionalColumns' => array(
|
||||
'entityType' => array(
|
||||
|
||||
@@ -18,33 +18,35 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Relations;
|
||||
|
||||
class HasChildren extends \Espo\Core\Utils\Database\Orm\Base
|
||||
class HasChildren extends Base
|
||||
{
|
||||
|
||||
public function load($params, $foreignParams)
|
||||
protected function load($linkName, $entityName)
|
||||
{
|
||||
$foreignLinkName = $this->getForeignLinkName();
|
||||
$foreignEntityName = $this->getForeignEntityName();
|
||||
|
||||
return array(
|
||||
$params['entityName'] => array (
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$params['link']['name'].'Ids' => array(
|
||||
$linkName.'Ids' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
),
|
||||
$params['link']['name'].'Names' => array(
|
||||
$linkName.'Names' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
),
|
||||
),
|
||||
'relations' => array(
|
||||
$params['link']['name'] => array(
|
||||
$linkName => array(
|
||||
'type' => 'hasChildren',
|
||||
'entity' => $params['targetEntity'],
|
||||
'foreignKey' => $foreignParams['link']['name'].'Id', //???: 'foreignKey' => $params['link']['name'].'Id',
|
||||
'foreignType' => $foreignParams['link']['name'].'Type', //???: 'foreignKey' => $params['link']['name'].'Id',
|
||||
'entity' => $foreignEntityName,
|
||||
'foreignKey' => $foreignLinkName.'Id',
|
||||
'foreignType' => $foreignLinkName.'Type',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Relations;
|
||||
|
||||
class HasMany extends \Espo\Core\Utils\Database\Orm\Base
|
||||
class HasMany extends Base
|
||||
{
|
||||
protected $allowParams = array(
|
||||
'relationName',
|
||||
@@ -30,32 +30,35 @@ class HasMany extends \Espo\Core\Utils\Database\Orm\Base
|
||||
'additionalColumns',
|
||||
);
|
||||
|
||||
public function load($params, $foreignParams)
|
||||
protected function load($linkName, $entityName)
|
||||
{
|
||||
$relationType = isset($params['link']['params']['relationName']) ? 'manyMany' : 'hasMany';
|
||||
$linkParams = $this->getLinkParams();
|
||||
$foreignLinkName = $this->getForeignLinkName();
|
||||
$foreignEntityName = $this->getForeignEntityName();
|
||||
|
||||
$relationType = isset($linkParams['relationName']) ? 'manyMany' : 'hasMany';
|
||||
|
||||
$relation = array(
|
||||
$params['entityName'] => array (
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$params['link']['name'].'Ids' => array(
|
||||
$linkName.'Ids' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
),
|
||||
$params['link']['name'].'Names' => array(
|
||||
$linkName.'Names' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
),
|
||||
),
|
||||
'relations' => array(
|
||||
$params['link']['name'] => array(
|
||||
//'type' => 'hasMany',
|
||||
$linkName => array(
|
||||
'type' => $relationType,
|
||||
'entity' => $params['targetEntity'],
|
||||
'foreignKey' => lcfirst($foreignParams['link']['name'].'Id'), //???: 'foreignKey' => $params['link']['name'].'Id',
|
||||
'entity' => $foreignEntityName,
|
||||
'foreignKey' => lcfirst($foreignLinkName.'Id'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
|
||||
return $relation;
|
||||
}
|
||||
|
||||
@@ -18,45 +18,46 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Relations;
|
||||
|
||||
use Espo\Core\Utils\Util;
|
||||
|
||||
class ManyMany extends \Espo\Core\Utils\Database\Orm\Base
|
||||
class ManyMany extends Base
|
||||
{
|
||||
|
||||
protected $allowParams = array(
|
||||
'relationName',
|
||||
'conditions',
|
||||
'additionalColumns',
|
||||
);
|
||||
|
||||
public function load($params, $foreignParams)
|
||||
protected function load($linkName, $entityName)
|
||||
{
|
||||
$foreignEntityName = $this->getForeignEntityName();
|
||||
|
||||
return array(
|
||||
$params['entityName'] => array(
|
||||
$entityName => array(
|
||||
'fields' => array(
|
||||
$params['link']['name'].'Ids' => array(
|
||||
$linkName.'Ids' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
),
|
||||
$params['link']['name'].'Names' => array(
|
||||
$linkName.'Names' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
),
|
||||
),
|
||||
'relations' => array(
|
||||
$params['link']['name'] => array(
|
||||
$linkName => array(
|
||||
'type' => 'manyMany',
|
||||
'entity' => $params['targetEntity'],
|
||||
'relationName' => $this->getJoinTable($params['entityName'], $foreignParams['entityName']),
|
||||
'entity' => $foreignEntityName,
|
||||
'relationName' => $this->getJoinTable($entityName, $foreignEntityName),
|
||||
'key' => 'id', //todo specify 'key'
|
||||
'foreignKey' => 'id', //todo specify 'foreignKey'
|
||||
'midKeys' => array(
|
||||
lcfirst($params['entityName']).'Id',
|
||||
lcfirst($foreignParams['entityName']).'Id',
|
||||
lcfirst($entityName).'Id',
|
||||
lcfirst($foreignEntityName).'Id',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -18,26 +18,29 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Relations;
|
||||
|
||||
class NoteAttachments extends \Espo\Core\Utils\Database\Orm\Relations\HasChildren
|
||||
class NoteAttachments extends HasChildren
|
||||
{
|
||||
public function load($params, $foreignParams)
|
||||
protected function load($linkName, $entityName)
|
||||
{
|
||||
$parentRelation = parent::load($params, $foreignParams);
|
||||
$parentRelation = parent::load($linkName, $entityName);
|
||||
|
||||
$relation = array(
|
||||
$params['entityName'] => array (
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$params['link']['name'].'Types' => array(
|
||||
$linkName.'Types' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
|
||||
$relation = \Espo\Core\Utils\Util::merge($parentRelation, $relation);
|
||||
|
||||
return $relation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +275,9 @@ class Converter
|
||||
switch ($fieldParams['type']) {
|
||||
case 'array':
|
||||
case 'jsonArray':
|
||||
$dbFieldParams['default'] = ''; //for db type TEXT can't be defined a default value
|
||||
case 'text':
|
||||
case 'longtext':
|
||||
unset($dbFieldParams['default']); //for db type TEXT can't be defined a default value
|
||||
break;
|
||||
|
||||
case 'bool':
|
||||
@@ -360,4 +362,4 @@ class Converter
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,24 +18,32 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Schema\rebuildActions;
|
||||
|
||||
class Currency extends \Espo\Core\Utils\Database\Schema\BaseRebuildActions
|
||||
{
|
||||
|
||||
public function afterRebuild()
|
||||
{
|
||||
$currencyConfig = $this->getConfig()->get('currency');
|
||||
$currencyConfig['rate'][ $currencyConfig['base'] ] = '1.00';
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
public function afterRebuild()
|
||||
{
|
||||
$defaultCurrency = $this->getConfig()->get('defaultCurrency');
|
||||
|
||||
$baseCurrency = $this->getConfig()->get('baseCurrency');
|
||||
$currencyRates = $this->getConfig()->get('currencyRates');
|
||||
|
||||
if ($defaultCurrency != $baseCurrency) {
|
||||
$currencyRates = $this->exchangeRates($baseCurrency, $defaultCurrency, $currencyRates);
|
||||
}
|
||||
|
||||
$currencyRates[$defaultCurrency] = '1.00';
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$sql = "TRUNCATE `currency`";
|
||||
$pdo->prepare($sql)->execute();
|
||||
|
||||
foreach ($currencyConfig['rate'] as $currencyName => $rate) {
|
||||
foreach ($currencyRates as $currencyName => $rate) {
|
||||
|
||||
$sql = "
|
||||
INSERT INTO `currency`
|
||||
@@ -43,9 +51,34 @@ class Currency extends \Espo\Core\Utils\Database\Schema\BaseRebuildActions
|
||||
VALUES
|
||||
(".$pdo->quote($currencyName) . ", " . $pdo->quote($rate) . ")
|
||||
";
|
||||
$pdo->prepare($sql)->execute();
|
||||
}
|
||||
}
|
||||
|
||||
$pdo->prepare($sql)->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate exchange rates if defaultCurrency doesn't equals baseCurrency
|
||||
*
|
||||
* @param string $baseCurrency
|
||||
* @param string $defaultCurrency
|
||||
* @param array $currencyRates [description]
|
||||
* @return array - List of new currency rates
|
||||
*/
|
||||
protected function exchangeRates($baseCurrency, $defaultCurrency, array $currencyRates)
|
||||
{
|
||||
$precision = 5;
|
||||
$defaultCurrencyRate = round(1 / $currencyRates[$defaultCurrency], $precision);
|
||||
|
||||
$exchangedRates = array();
|
||||
$exchangedRates[$baseCurrency] = $defaultCurrencyRate;
|
||||
|
||||
unset($currencyRates[$baseCurrency], $currencyRates[$defaultCurrency]);
|
||||
|
||||
foreach ($currencyRates as $currencyName => $rate) {
|
||||
$exchangedRates[$currencyName] = round($rate * $defaultCurrencyRate, $precision);
|
||||
}
|
||||
|
||||
return $exchangedRates;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ class FieldManager
|
||||
}
|
||||
|
||||
foreach ($fieldDef as $defName => $defValue) {
|
||||
if (!isset($defValue)) {
|
||||
if (!isset($defValue) || (is_string($defValue) && $defValue == '') ) {
|
||||
unset($fieldDef[$defName]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ class Manager
|
||||
$fullPath = $this->concatPaths($path); //todo remove after changing the params
|
||||
|
||||
if ($this->checkCreateFile($fullPath) === false) {
|
||||
throw new Error('Permission denied in '. $path);
|
||||
throw new Error('Permission denied in '. $fullPath);
|
||||
}
|
||||
|
||||
$res = (file_put_contents($fullPath, $data, $flags, $context) !== FALSE);
|
||||
@@ -225,22 +225,33 @@ class Manager
|
||||
* @param string | array $path
|
||||
* @param string $content JSON string
|
||||
* @param bool $isJSON
|
||||
* @param array $mergeOptions
|
||||
* @param string | array $mergeOptions
|
||||
* @param string | array $removeOptions - List of unset keys from content
|
||||
* @param bool $isReturn - Is result to be returned or stored
|
||||
*
|
||||
* @return bool
|
||||
* @return bool | array
|
||||
*/
|
||||
public function mergeContents($path, $content, $isJSON = false, $mergeOptions = null)
|
||||
public function mergeContents($path, $content, $isJSON = false, $mergeOptions = null, $removeOptions = null, $isReturn = false)
|
||||
{
|
||||
$fileContent = $this->getContents($path);
|
||||
|
||||
$savedDataArray = Utils\Json::getArrayData($fileContent);
|
||||
$newDataArray = Utils\Json::getArrayData($content);
|
||||
|
||||
if (isset($removeOptions)) {
|
||||
$savedDataArray = Utils\Util::unsetInArray($savedDataArray, $removeOptions);
|
||||
$newDataArray = Utils\Util::unsetInArray($newDataArray, $removeOptions);
|
||||
}
|
||||
|
||||
$data = Utils\Util::merge($savedDataArray, $newDataArray, $mergeOptions);
|
||||
if ($isJSON) {
|
||||
$data = Utils\Json::encode($data, JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
if ($isReturn) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
return $this->putContents($path, $data);
|
||||
}
|
||||
|
||||
@@ -248,26 +259,14 @@ class Manager
|
||||
* Merge PHP content and save it to a file
|
||||
*
|
||||
* @param string | array $path
|
||||
* @param string $content
|
||||
* @param bool $onlyFirstLevel - Merge only first level. Ex. current: array('test'=>array('item1', 'item2')). $content= array('test'=>array('item1'),). Result will be array('test'=>array('item1')).
|
||||
*
|
||||
* @param string $content JSON string
|
||||
* @param string | array $mergeOptions
|
||||
* @param string | array $removeOptions - List of unset keys from content
|
||||
* @return bool
|
||||
*/
|
||||
public function mergeContentsPHP($path, $content, $onlyFirstLevel = false, $mergeOptions = null)
|
||||
public function mergeContentsPHP($path, $content, $mergeOptions = null, $removeOptions = null)
|
||||
{
|
||||
$fileContent = $this->getContents($path);
|
||||
|
||||
$savedDataArray = Utils\Json::getArrayData($fileContent);
|
||||
$newDataArray = Utils\Json::getArrayData($content);
|
||||
|
||||
if ($onlyFirstLevel) {
|
||||
foreach($newDataArray as $key => $val) {
|
||||
$setVal = is_array($val) ? array() : '';
|
||||
$savedDataArray[$key] = $setVal;
|
||||
}
|
||||
}
|
||||
|
||||
$data = Utils\Util::merge($savedDataArray, $newDataArray, $mergeOptions);
|
||||
$data = $this->mergeContents($path, $content, false, $mergeOptions, $removeOptions, true);
|
||||
|
||||
return $this->putContentsPHP($path, $data);
|
||||
}
|
||||
|
||||
@@ -480,11 +480,12 @@ class Permission
|
||||
if (file_exists($item)) {
|
||||
|
||||
try {
|
||||
$res = $this->chmod($item, $permission, true);
|
||||
$this->chmod($item, $permission, true);
|
||||
} catch (\Exception $e) {
|
||||
$res = false;
|
||||
}
|
||||
|
||||
$res = is_readable($item);
|
||||
|
||||
/** check is wtitable */
|
||||
if ($type == 'writable') {
|
||||
|
||||
|
||||
@@ -154,10 +154,10 @@ class Language
|
||||
|
||||
return $translated;
|
||||
}
|
||||
|
||||
|
||||
public function translateOption($value, $field, $scope)
|
||||
{
|
||||
$options = $this->get($scope. '.options.' . $field);
|
||||
$options = $this->get($scope. '.options.' . $field);
|
||||
if (array_key_exists($value, $options)) {
|
||||
return $options[$value];
|
||||
}
|
||||
@@ -241,7 +241,7 @@ class Language
|
||||
$i18nCacheFile = str_replace('{*}', $i18nName, $this->cacheFile);
|
||||
|
||||
if ($i18nName != $this->defaultLanguage) {
|
||||
$i18nData = Util::merge($this->fullData[$this->defaultLanguage], $i18nData);
|
||||
$i18nData = Util::merge($this->fullData[$this->defaultLanguage], $i18nData, null, null, true);
|
||||
}
|
||||
$result &= $this->getFileManager()->putContentsPHP($i18nCacheFile, $i18nData);
|
||||
}
|
||||
|
||||
@@ -125,10 +125,13 @@ class Util
|
||||
* ),
|
||||
* )
|
||||
* @param $rewriteKeyName string - Rewrite key name. It is ignored if $rewriteLevel is NULL.
|
||||
* @param $rewriteArrays bool - Rewrite single arrays. Examples:
|
||||
* TRUE: array is [0, 1, 2], main array is [3, 4, 5], Result is [3, 4, 5].
|
||||
* FALSE: array is [0, 1, 2], main array is [3, 4, 5], Result is [0, 1, 2, 3, 4, 5].
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function merge($array, $mainArray, $rewriteLevel = null, $rewriteKeyName = null)
|
||||
public static function merge($array, $mainArray, $rewriteLevel = null, $rewriteKeyName = null, $rewriteArrays = false)
|
||||
{
|
||||
if (is_array($array) && !is_array($mainArray)) {
|
||||
return $array;
|
||||
@@ -169,7 +172,7 @@ class Util
|
||||
} /** END: check the $rewriteKeyName */
|
||||
|
||||
if (!isset($rowRewriteLevel) || $rowRewriteLevel != 1) {
|
||||
$array[$mainKey] = static::merge((array) $value, (array) $mainValue, --$rowRewriteLevel, $rewriteKeyName);
|
||||
$array[$mainKey] = static::merge((array) $value, (array) $mainValue, --$rowRewriteLevel, $rewriteKeyName, $rewriteArrays);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -185,7 +188,11 @@ class Util
|
||||
$array[$mainKey] = $mainValue;
|
||||
}
|
||||
elseif (!in_array($mainValue, $array)) {
|
||||
$array[] = $mainValue;
|
||||
if ($rewriteArrays) {
|
||||
$array[$mainKey] = $mainValue;
|
||||
} else {
|
||||
$array[] = $mainValue;
|
||||
}
|
||||
} /** END: merge logic */
|
||||
|
||||
break;
|
||||
@@ -359,11 +366,17 @@ class Util
|
||||
if (!empty($unsetSett)){
|
||||
$keyItems = explode('.', $unsetSett);
|
||||
$currVal = isset($content[$rootKey]) ? "\$content['{$rootKey}']" : "\$content";
|
||||
|
||||
$lastKey = array_pop($keyItems);
|
||||
foreach($keyItems as $keyItem){
|
||||
$currVal .= "['{$keyItem}']";
|
||||
}
|
||||
|
||||
$currVal = "if (isset({$currVal})) unset({$currVal});";
|
||||
$unsetElem = $currVal . "['{$lastKey}']";
|
||||
$currVal = "
|
||||
if (isset({$unsetElem}) || array_key_exists({$lastKey}, {$currVal})) {
|
||||
unset({$unsetElem});
|
||||
} ";
|
||||
eval($currVal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,11 +46,8 @@ return array (
|
||||
array (
|
||||
),
|
||||
'defaultCurrency' => 'USD',
|
||||
'currency' =>
|
||||
array(
|
||||
'base' => 'USD',
|
||||
'rate' => array(
|
||||
),
|
||||
'baseCurrency' => 'USD',
|
||||
'currencyRates' => array(
|
||||
),
|
||||
'outboundEmailIsShared' => true,
|
||||
'outboundEmailFromName' => 'EspoCRM',
|
||||
@@ -65,6 +62,12 @@ return array (
|
||||
'en_US',
|
||||
'de_DE',
|
||||
'es_ES',
|
||||
'fr_FR',
|
||||
'nl_NL',
|
||||
'tr_TR',
|
||||
'ro_RO',
|
||||
'pt_BR',
|
||||
'vi_VN'
|
||||
),
|
||||
'language' => 'en_US',
|
||||
'logger' =>
|
||||
@@ -74,16 +77,20 @@ return array (
|
||||
'isRotate' => true, /** rotate log files every day */
|
||||
'maxRotateFiles' => 30, /** max number of rotate files */
|
||||
),
|
||||
'authenticationMethod' => 'Espo',
|
||||
'globalSearchEntityList' =>
|
||||
array (
|
||||
0 => 'Account',
|
||||
1 => 'Contact',
|
||||
2 => 'Lead',
|
||||
3 => 'Prospect',
|
||||
4 => 'Opportunity',
|
||||
3 => 'Opportunity',
|
||||
),
|
||||
"tabList" => array("Account", "Contact", "Lead", "Opportunity", "Calendar", "Meeting", "Call", "Task", "Case", "Prospect", "Email"),
|
||||
"quickCreateList" => array("Account", "Contact", "Lead", "Opportunity", "Meeting", "Call", "Task", "Case", "Prospect"),
|
||||
"tabList" => array("Account", "Contact", "Lead", "Opportunity", "Calendar", "Meeting", "Call", "Task", "Case", "Email"),
|
||||
"quickCreateList" => array("Account", "Contact", "Lead", "Opportunity", "Meeting", "Call", "Task", "Case"),
|
||||
'calendarDefaultEntity' => 'Meeting',
|
||||
'disableExport' => false,
|
||||
'assignmentEmailNotifications' => false,
|
||||
'assignmentEmailNotificationsEntityList' => array('Lead', 'Opportunity', 'Task', 'Case'),
|
||||
'isInstalled' => false,
|
||||
);
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"name":"name"},{"name":"email","type":"base","sortable":false,"params":{}},{"name":"city"}]
|
||||
[{"name":"name"}]
|
||||
|
||||
@@ -96,6 +96,23 @@ return array (
|
||||
'smtpUsername',
|
||||
'smtpPassword',
|
||||
'cron',
|
||||
'authenticationMethod',
|
||||
'ldapHost',
|
||||
'ldapPort',
|
||||
'ldapSecurity',
|
||||
'ldapAuth',
|
||||
'ldapUsername',
|
||||
'ldapPassword',
|
||||
'ldapBindRequiresDn',
|
||||
'ldapBaseDn',
|
||||
'ldapUserLoginFilter',
|
||||
'ldapAccountCanonicalForm',
|
||||
'ldapAccountDomainName',
|
||||
'ldapAccountDomainNameShort',
|
||||
'ldapAccountFilterFormat',
|
||||
'ldapTryUsernameSplit',
|
||||
'ldapOptReferrals',
|
||||
'ldapCreateEspoUser',
|
||||
),
|
||||
'isInstalled' => false,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Entities;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
class PhoneNumber extends \Espo\Core\ORM\Entity
|
||||
{
|
||||
protected function setName($value)
|
||||
{
|
||||
if (empty($value)) {
|
||||
throw new Error("Phone number can't be empty");
|
||||
}
|
||||
$this->valuesContainer['name'] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,10 @@ class Download extends \Espo\Core\EntryPoints\Base
|
||||
{
|
||||
public static $authRequired = true;
|
||||
|
||||
protected $fileTypesToShowInline = array(
|
||||
'application/pdf',
|
||||
);
|
||||
|
||||
public function run()
|
||||
{
|
||||
$id = $_GET['id'];
|
||||
@@ -54,13 +58,21 @@ class Download extends \Espo\Core\EntryPoints\Base
|
||||
|
||||
if (!file_exists($fileName)) {
|
||||
throw new NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
$type = $attachment->get('type');
|
||||
|
||||
$disposition = 'attachment';
|
||||
if (in_array($type, $this->fileTypesToShowInline)) {
|
||||
$disposition = 'inline';
|
||||
}
|
||||
|
||||
|
||||
header('Content-Description: File Transfer');
|
||||
if ($attachment->get('type')) {
|
||||
header('Content-Type: ' . $attachment->get('type'));
|
||||
if ($type) {
|
||||
header('Content-Type: ' . $type);
|
||||
}
|
||||
header('Content-Disposition: attachment; filename=' . $attachment->get('name'));
|
||||
header('Content-Disposition: ' . $disposition . '; filename=' . $attachment->get('name'));
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate');
|
||||
header('Pragma: public');
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Hooks\Common;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class AssignmentEmailNotification extends \Espo\Core\Hooks\Base
|
||||
{
|
||||
|
||||
public function afterSave(Entity $entity)
|
||||
{
|
||||
if (
|
||||
$this->getConfig()->get('assignmentEmailNotifications')
|
||||
&&
|
||||
in_array($entity->getEntityName(), $this->getConfig()->get('assignmentEmailNotificationsEntityList', array()))
|
||||
) {
|
||||
|
||||
$userId = $entity->get('assignedUserId');
|
||||
if (!empty($userId) && $userId != $this->getUser()->id && $entity->isFieldChanged('assignedUserId')) {
|
||||
$job = $this->getEntityManager()->getEntity('Job');
|
||||
$job->set(array(
|
||||
'serviceName' => 'EmailNotification',
|
||||
'method' => 'notifyAboutAssignmentJob',
|
||||
'data' => json_encode(array(
|
||||
'userId' => $userId,
|
||||
'assignerUserId' => $this->getUser()->id,
|
||||
'entityId' => $entity->id,
|
||||
'entityType' => $entity->getEntityName()
|
||||
)),
|
||||
'executeTime' => date('Y-m-d H:i:s'),
|
||||
));
|
||||
$this->getEntityManager()->saveEntity($job);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,11 +53,25 @@ class Notifications extends \Espo\Core\Hooks\Base
|
||||
WHERE entity_id = " . $pdo->quote($parentId) . " AND entity_type = " . $pdo->quote($parentType);
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
$userIdList = array();
|
||||
while ($row = $sth->fetch(\PDO::FETCH_ASSOC)) {
|
||||
if ($this->getUser()->id != $row['userId']) {
|
||||
$this->getNotificationService()->notifyAboutNote($row['userId'], $entity->id);
|
||||
$userIdList[] = $row['userId'];
|
||||
}
|
||||
}
|
||||
if (!empty($userIdList)) {
|
||||
$job = $this->getEntityManager()->getEntity('Job');
|
||||
$job->set(array(
|
||||
'serviceName' => 'Notification',
|
||||
'method' => 'notifyAboutNoteFromJob',
|
||||
'data' => json_encode(array(
|
||||
'userIdList' => $userIdList,
|
||||
'noteId' => $entity->id
|
||||
)),
|
||||
'executeTime' => date('Y-m-d H:i:s'),
|
||||
));
|
||||
$this->getEntityManager()->saveEntity($job);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class Opportunity extends \Espo\Core\Controllers\Record
|
||||
opportunity.close_date < ".$pdo->quote($dateTo)." AND
|
||||
opportunity.stage <> 'Closed Lost' AND
|
||||
opportunity.lead_source <> ''
|
||||
GROUP BY opportunity.lead_source
|
||||
GROUP BY opportunity.lead_source
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
@@ -72,8 +72,8 @@ class Opportunity extends \Espo\Core\Controllers\Record
|
||||
opportunity.close_date >= ".$pdo->quote($dateFrom)." AND
|
||||
opportunity.close_date < ".$pdo->quote($dateTo)." AND
|
||||
opportunity.stage <> 'Closed Lost'
|
||||
GROUP BY opportunity.lead_source
|
||||
ORDER BY `amount` DESC
|
||||
GROUP BY opportunity.stage
|
||||
ORDER BY FIELD(opportunity.stage, 'Prospecting', 'Qualification', 'Needs Analysis', 'Value Proposition', 'Id. Decision Makers', 'Perception Analysis', 'Proposal/Price Quote', 'Negotiation/Review', 'Closed Won')
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ namespace Espo\Modules\Crm\Controllers;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class Prospect extends \Espo\Core\Controllers\Record
|
||||
class Target extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
public function actionConvert($params, $data)
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
|
||||
namespace Espo\Modules\Crm\Entities;
|
||||
|
||||
class Prospect extends \Espo\Core\Entities\Person
|
||||
class Target extends \Espo\Core\Entities\Person
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Call extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
protected function beforeSave(Entity $entity)
|
||||
{
|
||||
parent::beforeSave($entity);
|
||||
|
||||
$parentId = $entity->get('parentId');
|
||||
$parentType = $entity->get('parentType');
|
||||
if (!empty($parentId) || !empty($parentType)) {
|
||||
$parent = $this->getEntityManager()->getEntity($parentType, $parentId);
|
||||
if (!empty($parent)) {
|
||||
if ($parent->getEntityName() == 'Account') {
|
||||
$accountId = $parent->id;
|
||||
} else if ($parent->has('accountId')) {
|
||||
$accountId = $parent->get('accountId');
|
||||
}
|
||||
if (!empty($accountId)) {
|
||||
$entity->set('accountId', $accountId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Contact extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
public function handleSelectParams(&$params)
|
||||
{
|
||||
parent::handleSelectParams($params);
|
||||
|
||||
if (empty($params['customJoin'])) {
|
||||
$params['customJoin'] = '';
|
||||
}
|
||||
|
||||
$params['customJoin'] .= "
|
||||
LEFT JOIN `account_contact` AS accountContact
|
||||
ON accountContact.contact_id = contact.id AND accountContact.account_id = contact.account_id AND accountContact.deleted = 0
|
||||
";
|
||||
}
|
||||
|
||||
public function save(Entity $entity)
|
||||
{
|
||||
$result = parent::save($entity);
|
||||
|
||||
$accountIdChanged = $entity->has('accountId') && $entity->get('accountId') != $entity->getFetched('accountId');
|
||||
$titleChanged = $entity->has('title') && $entity->get('title') != $entity->getFetched('title');
|
||||
|
||||
if ($accountIdChanged) {
|
||||
$accountId = $entity->get('accountId');
|
||||
if (empty($accountId)) {
|
||||
$this->unrelate($entity, 'accounts', $entity->getFetched('accountId'));
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if ($titleChanged) {
|
||||
if (empty($accountId)) {
|
||||
$accountId = $entity->getFetched('accountId');
|
||||
if (empty($accountId)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($accountIdChanged || $titleChanged) {
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$sql = "
|
||||
SELECT id, role FROM account_contact
|
||||
WHERE
|
||||
account_id = ".$pdo->quote($accountId)." AND
|
||||
contact_id = ".$pdo->quote($entity->id)." AND
|
||||
deleted = 0
|
||||
";
|
||||
$sth = $pdo->prepare($sql);
|
||||
if ($row = $sth->fetch()) {
|
||||
if ($titleChanged && $entity->get('title') != $row['role']) {
|
||||
$this->updateRelation($entity, 'accounts', $accountId, array(
|
||||
'role' => $entity->get('title')
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$this->relate($entity, 'accounts', $accountId, array(
|
||||
'role' => $entity->get('title')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Lead extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
public function handleSelectParams(&$params)
|
||||
{
|
||||
parent::handleSelectParams($params);
|
||||
|
||||
if (empty($params['customJoin'])) {
|
||||
$params['customJoin'] = '';
|
||||
}
|
||||
|
||||
$params['customJoin'] .= "
|
||||
LEFT JOIN currency ON currency.id = lead.opportunity_amount_currency
|
||||
";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Meeting extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
protected function beforeSave(Entity $entity)
|
||||
{
|
||||
parent::beforeSave($entity);
|
||||
|
||||
$parentId = $entity->get('parentId');
|
||||
$parentType = $entity->get('parentType');
|
||||
if (!empty($parentId) || !empty($parentType)) {
|
||||
$parent = $this->getEntityManager()->getEntity($parentType, $parentId);
|
||||
if (!empty($parent)) {
|
||||
if ($parent->getEntityName() == 'Account') {
|
||||
$accountId = $parent->id;
|
||||
} else if ($parent->has('accountId')) {
|
||||
$accountId = $parent->get('accountId');
|
||||
}
|
||||
if (!empty($accountId)) {
|
||||
$entity->set('accountId', $accountId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Opportunity extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
public function handleSelectParams(&$params)
|
||||
{
|
||||
parent::handleSelectParams($params);
|
||||
|
||||
if (empty($params['customJoin'])) {
|
||||
$params['customJoin'] = '';
|
||||
}
|
||||
|
||||
$params['customJoin'] .= "
|
||||
LEFT JOIN currency ON currency.id = opportunity.amount_currency
|
||||
";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
"name": "Name",
|
||||
"emailAddress": "E-Mail",
|
||||
"website": "Webseite",
|
||||
"phone": "Telefon",
|
||||
"fax": "Fax",
|
||||
"phoneNumber": "Telefon",
|
||||
"billingAddress": "Rechnungsadresse",
|
||||
"shippingAddress": "Lieferadresse",
|
||||
"description": "Beschreibung",
|
||||
"sicCode": "WKN Nummer",
|
||||
"industry": "Branche",
|
||||
"type": "Typ"
|
||||
"type": "Typ",
|
||||
"contactRole": "Rolle"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Kontakte",
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
"emailAddress": "E-Mail",
|
||||
"title": "Funktion",
|
||||
"account": "Firma",
|
||||
"phone": "Telefon",
|
||||
"phoneOffice": "Phone (Office)",
|
||||
"fax": "Fax",
|
||||
"accounts": "Firmen",
|
||||
"phoneNumber": "Telefon",
|
||||
"accountType": "Firmentyp",
|
||||
"doNotCall": "Nicht anrufen",
|
||||
"address": "Adresse",
|
||||
"description": "Beschreibung"
|
||||
"opportunityRole": "Opportunity Role",
|
||||
"accountRole": "Rolle",
|
||||
"description": "Beschreibung"
|
||||
},
|
||||
"links": {
|
||||
"opportunities": "Verkaufschancen",
|
||||
@@ -18,5 +19,13 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create Contact": "Neuer Kontakt"
|
||||
},
|
||||
"options": {
|
||||
"opportunityRole": {
|
||||
"": "--None--",
|
||||
"Decision Maker": "Decision Maker",
|
||||
"Evaluator": "Evaluator",
|
||||
"Influencer": "Influencer"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"Account": "Firma",
|
||||
"Contact": "Kontakt",
|
||||
"Lead": "Interessent",
|
||||
"Prospect": "Zielkontakt",
|
||||
"Target": "Zielkontakt",
|
||||
"Opportunity": "Verkaufschance",
|
||||
"Meeting": "Meeting",
|
||||
"Calendar": "Kalender",
|
||||
@@ -16,7 +16,7 @@
|
||||
"Account": "Firmen",
|
||||
"Contact": "Kontakte",
|
||||
"Lead": "Interessenten",
|
||||
"Prospect": "Zielkontakte",
|
||||
"Target": "Targets",
|
||||
"Opportunity": "Verkaufschancen",
|
||||
"Meeting": "Meetings",
|
||||
"Calendar": "Kalender",
|
||||
|
||||
@@ -36,5 +36,8 @@
|
||||
"IMAP": "IMAP",
|
||||
"Actions": "Aktionen",
|
||||
"Main": "Wichtig"
|
||||
},
|
||||
"messages": {
|
||||
"couldNotConnectToImap": "Kann keine Verbindung zum IMAP Server herstellen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
"emailAddress": "E-Mail",
|
||||
"title": "Funktion",
|
||||
"website": "Webseite",
|
||||
"phone": "Telefon",
|
||||
"phoneOffice": "Phone (Office)",
|
||||
"fax": "Fax",
|
||||
"phoneNumber": "Telefon",
|
||||
"accountName": "Firmenname",
|
||||
"doNotCall": "Nicht anrufen",
|
||||
"address": "Adresse",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"leadSource": "Quelle",
|
||||
"doNotCall": "Nicht anrufen",
|
||||
"closeDate": "Abschlussdatum",
|
||||
"contacts": "Kontakte",
|
||||
"description": "Beschreibung"
|
||||
},
|
||||
"links": {
|
||||
@@ -19,22 +20,12 @@
|
||||
"Qualification": "Qualifikation",
|
||||
"Needs Analysis": "Bedarfserhebung",
|
||||
"Value Proposition": "Richtangebot",
|
||||
"Id. Decision Makers": "id. Entscheider",
|
||||
"Id. Decision Makers": "Entscheider ident.",
|
||||
"Perception Analysis": "Analyse Sichtweise",
|
||||
"Proposal/Price Quote": "Preisangebot",
|
||||
"Negotiation/Review": "Verhandlung/Überarbeitung",
|
||||
"Closed Won": "Gewonnen",
|
||||
"Closed Lost": "Verloren"
|
||||
},
|
||||
"leadSource": {
|
||||
"Call": "Anruf",
|
||||
"Email": "E-Mail",
|
||||
"Existing Customer": "Bestehender Kunde",
|
||||
"Partner": "Partner",
|
||||
"Public Relations": "Public Relations",
|
||||
"Web Site": "Web Seite",
|
||||
"Campaign": "Kampagne",
|
||||
"Other": "Andere"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
|
||||
+2
-4
@@ -5,9 +5,7 @@
|
||||
"title": "Funktion",
|
||||
"website": "Webseite",
|
||||
"accountName": "Firmenname",
|
||||
"phone": "Telefon",
|
||||
"phoneOffice": "Phone (Office)",
|
||||
"fax": "Fax",
|
||||
"phoneNumber": "Telefon",
|
||||
"doNotCall": "Nicht anrufen",
|
||||
"address": "Adresse",
|
||||
"description": "Beschreibung"
|
||||
@@ -15,7 +13,7 @@
|
||||
"links": {
|
||||
},
|
||||
"labels": {
|
||||
"Create Prospect": "Neuer Zielkontakt",
|
||||
"Create Target": "Create Target",
|
||||
"Convert to Lead": "Zu Interessent umwandeln"
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,14 @@
|
||||
"name": "Name",
|
||||
"emailAddress": "Email",
|
||||
"website": "Website",
|
||||
"phone": "Phone",
|
||||
"fax": "Fax",
|
||||
"phoneNumber": "Phone",
|
||||
"billingAddress": "Billing Address",
|
||||
"shippingAddress": "Shipping Address",
|
||||
"description": "Description",
|
||||
"sicCode": "Sic Code",
|
||||
"industry": "Industry",
|
||||
"type": "Type"
|
||||
"type": "Type",
|
||||
"contactRole": "Role"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contacts",
|
||||
|
||||
@@ -30,5 +30,10 @@
|
||||
"Set Held": "Set Held",
|
||||
"Set Not Held": "Set Not Held",
|
||||
"Send Invitations": "Send Invitations"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planned",
|
||||
"held": "Held",
|
||||
"todays": "Today's"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,5 +34,9 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create Case": "Create Case"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Open",
|
||||
"closed": "Closed"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
"emailAddress": "Email",
|
||||
"title": "Title",
|
||||
"account": "Account",
|
||||
"phone": "Phone",
|
||||
"phoneOffice": "Phone (Office)",
|
||||
"fax": "Fax",
|
||||
"accounts": "Accounts",
|
||||
"phoneNumber": "Phone",
|
||||
"accountType": "Account Type",
|
||||
"doNotCall": "Do Not Call",
|
||||
"address": "Address",
|
||||
"description": "Description"
|
||||
"opportunityRole": "Opportunity Role",
|
||||
"accountRole": "Role",
|
||||
"description": "Description"
|
||||
},
|
||||
"links": {
|
||||
"opportunities": "Opportunities",
|
||||
@@ -18,5 +19,13 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create Contact": "Create Contact"
|
||||
},
|
||||
"options": {
|
||||
"opportunityRole": {
|
||||
"": "--None--",
|
||||
"Decision Maker": "Decision Maker",
|
||||
"Evaluator": "Evaluator",
|
||||
"Influencer": "Influencer"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"Account": "Account",
|
||||
"Contact": "Contact",
|
||||
"Lead": "Lead",
|
||||
"Prospect": "Prospect",
|
||||
"Target": "Target",
|
||||
"Opportunity": "Opportunity",
|
||||
"Meeting": "Meeting",
|
||||
"Calendar": "Calendar",
|
||||
@@ -16,7 +16,7 @@
|
||||
"Account": "Accounts",
|
||||
"Contact": "Contacts",
|
||||
"Lead": "Leads",
|
||||
"Prospect": "Prospects",
|
||||
"Target": "Targets",
|
||||
"Opportunity": "Opportunities",
|
||||
"Meeting": "Meetings",
|
||||
"Calendar": "Calendar",
|
||||
@@ -31,6 +31,8 @@
|
||||
"Tasks": "My Tasks",
|
||||
"Cases": "My Cases",
|
||||
"Calendar": "Calendar",
|
||||
"Calls": "My Calls",
|
||||
"Meetings": "My Meetings",
|
||||
"OpportunitiesByStage": "Opportunities by Stage",
|
||||
"OpportunitiesByLeadSource": "Opportunities by Lead Source",
|
||||
"SalesByMonth": "Sales by Month",
|
||||
|
||||
@@ -16,8 +16,17 @@
|
||||
"caseDistribution": "Case Distribution",
|
||||
"replyEmailTemplate": "Reply Email Template",
|
||||
"replyFromAddress": "Reply From Address",
|
||||
"replyToAddress": "Reply To Address",
|
||||
"replyFromName": "Reply From Name"
|
||||
},
|
||||
"tooltips": {
|
||||
"reply": "Notify email senders that their emails has been received.",
|
||||
"createCase": "Automatically create case from incoming emails.",
|
||||
"replyToAddress": "Specify email address of this mailbox to make response come here.",
|
||||
"caseDistribution": "How cases will be assigned to. Assigned directly to the user or among the team.",
|
||||
"assignToUser": "User emails/cases will be assigned to.",
|
||||
"team": "Team emails/cases will be related to."
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
|
||||
@@ -9,15 +9,14 @@
|
||||
"emailAddress": "Email",
|
||||
"title": "Title",
|
||||
"website": "Website",
|
||||
"phone": "Phone",
|
||||
"phoneOffice": "Phone (Office)",
|
||||
"fax": "Fax",
|
||||
"phoneNumber": "Phone",
|
||||
"accountName": "Account Name",
|
||||
"doNotCall": "Do Not Call",
|
||||
"address": "Address",
|
||||
"status": "Status",
|
||||
"source": "Source",
|
||||
"opportunityAmount": "Opportunity Amount",
|
||||
"opportunityAmountConverted": "Opportunity Amount (converted)",
|
||||
"description": "Description",
|
||||
"createdAccount": "Account",
|
||||
"createdContact": "Contact",
|
||||
@@ -44,5 +43,8 @@
|
||||
"Campaign": "Campaign",
|
||||
"Other": "Other"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Active"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
"Create Meeting": "Create Meeting",
|
||||
"Set Held": "Set Held",
|
||||
"Set Not Held": "Set Not Held",
|
||||
"Send Invitations": "Send Invitations"
|
||||
"Send Invitations": "Send Invitations",
|
||||
"Saved as Held": "Saved as Held",
|
||||
"Saved as Not Held": "Saved as Not Held"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planned",
|
||||
"held": "Held",
|
||||
"todays": "Today's"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
"leadSource": "Lead Source",
|
||||
"doNotCall": "Do Not Call",
|
||||
"closeDate": "Close Date",
|
||||
"description": "Description"
|
||||
"contacts": "Contacts",
|
||||
"description": "Description",
|
||||
"amountConverted": "Amount (converted)"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contacts"
|
||||
@@ -25,19 +27,13 @@
|
||||
"Negotiation/Review": "Negotiation/Review",
|
||||
"Closed Won": "Closed Won",
|
||||
"Closed Lost": "Closed Lost"
|
||||
},
|
||||
"leadSource": {
|
||||
"Call": "Call",
|
||||
"Email": "Email",
|
||||
"Existing Customer": "Existing Customer",
|
||||
"Partner": "Partner",
|
||||
"Public Relations": "Public Relations",
|
||||
"Web Site": "Web Site",
|
||||
"Campaign": "Campaign",
|
||||
"Other": "Other"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Opportunity": "Create Opportunity"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Open",
|
||||
"won": "Won"
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -5,9 +5,7 @@
|
||||
"title": "Title",
|
||||
"website": "Website",
|
||||
"accountName": "Account Name",
|
||||
"phone": "Phone",
|
||||
"phoneOffice": "Phone (Office)",
|
||||
"fax": "Fax",
|
||||
"phoneNumber": "Phone",
|
||||
"doNotCall": "Do Not Call",
|
||||
"address": "Address",
|
||||
"description": "Description"
|
||||
@@ -15,7 +13,7 @@
|
||||
"links": {
|
||||
},
|
||||
"labels": {
|
||||
"Create Prospect": "Create Prospect",
|
||||
"Create Target": "Create Target",
|
||||
"Convert to Lead": "Convert to Lead"
|
||||
}
|
||||
}
|
||||
@@ -27,5 +27,11 @@
|
||||
},
|
||||
"labels": {
|
||||
"Create Task": "Create Task"
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Active",
|
||||
"completed": "Completed",
|
||||
"todays": "Today's",
|
||||
"overdue": "Overdue"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"Account": "Cuenta",
|
||||
"Contact": "Contacto",
|
||||
"Lead": "Potenciales",
|
||||
"Prospect": "Prospecto",
|
||||
"Target": "Prospecto",
|
||||
"Opportunity": "Opportunidad",
|
||||
"Meeting": "Reunión",
|
||||
"Calendar": "Calendario",
|
||||
@@ -16,7 +16,7 @@
|
||||
"Account": "Cuentas",
|
||||
"Contact": "Contactos",
|
||||
"Lead": "Potenciales",
|
||||
"Prospect": "Prospectos",
|
||||
"Targets": "Prospectos",
|
||||
"Opportunity": "Oportunidades",
|
||||
"Meeting": "Reuniones",
|
||||
"Calendar": "Calendario",
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
"links": {
|
||||
},
|
||||
"labels": {
|
||||
"Create Prospect": "Crear Prospecto",
|
||||
"Create Target": "Crear Prospecto",
|
||||
"Convert to Lead": "Convertir en Lider"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Nom",
|
||||
"emailAddress": "Email",
|
||||
"website": "Site Web",
|
||||
"phoneNumber": "Téléphone",
|
||||
"billingAddress": "Adresse de Facturation",
|
||||
"shippingAddress": "Adresse de Livraison",
|
||||
"description": "Description",
|
||||
"sicCode": "Code SIC",
|
||||
"industry": "Industrie",
|
||||
"type": "Type",
|
||||
"contactRole": "Rôle"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contacts",
|
||||
"opportunities": "Opportunités",
|
||||
"cases": "Tickets"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
"Customer": "Clients",
|
||||
"Investor": "Investisseur",
|
||||
"Partner": "Partenaire",
|
||||
"Reseller": "Revendeur"
|
||||
},
|
||||
"industry": {
|
||||
"Apparel": "Vêtements",
|
||||
"Banking": "Banque",
|
||||
"Computer Software": "Logiciel Informatique",
|
||||
"Education": "Education",
|
||||
"Electronics": "Electronique",
|
||||
"Finance": "Finance",
|
||||
"Insurance": "Assurance"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Account": "Nouveau Compte"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"modes": {
|
||||
"month": "Mois",
|
||||
"week": "Semaine",
|
||||
"day": "Jour",
|
||||
"agendaWeek": "Semaine",
|
||||
"agendaDay": "Jour"
|
||||
},
|
||||
"labels": {
|
||||
"Today": "Aujourd'hui",
|
||||
"Create": "Créer"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Nom",
|
||||
"parent": "Parent",
|
||||
"status": "Statut",
|
||||
"dateStart": "Date de Début",
|
||||
"dateEnd": "Date de Fin",
|
||||
"direction": "Direction",
|
||||
"duration": "Durée",
|
||||
"description": "Description",
|
||||
"users": "Utilisateurs",
|
||||
"contacts": "Contacts",
|
||||
"leads": "Leads"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Plannifié",
|
||||
"Held": "Fait",
|
||||
"Not Held": "Pas Fait"
|
||||
},
|
||||
"direction": {
|
||||
"Outbound": "Sortie",
|
||||
"Inbound": "Entrée"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Call": "Générer l'appel",
|
||||
"Set Held": "Marquer Fait",
|
||||
"Set Not Held": "Marquer Pas Fait",
|
||||
"Send Invitations": "Envoi d'Invitations"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Nom",
|
||||
"number": "Numéro",
|
||||
"status": "Statut",
|
||||
"account": "Compte",
|
||||
"contact": "Contact",
|
||||
"priority": "Priorité",
|
||||
"type": "Type",
|
||||
"description": "Description"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"New": "Nouveau",
|
||||
"Assigned": "Assigné",
|
||||
"Pending": "En attente",
|
||||
"Closed": "Fermé",
|
||||
"Rejected": "Rejeté",
|
||||
"Duplicate": "Doublon"
|
||||
},
|
||||
"priority" : {
|
||||
"Low": "Bas",
|
||||
"Normal": "Normal",
|
||||
"High": "Haut",
|
||||
"Urgent": "Urgent"
|
||||
},
|
||||
"type": {
|
||||
"Question": "Question",
|
||||
"Incident": "Incident",
|
||||
"Problem": "Problème"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Case": "Créer un Ticket"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Nom",
|
||||
"emailAddress": "Email",
|
||||
"title": "Titre",
|
||||
"account": "Compte",
|
||||
"accounts": "Comptes",
|
||||
"phoneNumber": "Téléphone",
|
||||
"accountType": "Type de Compte",
|
||||
"doNotCall": "Ne Pas Appeler",
|
||||
"address": "Adresse",
|
||||
"opportunityRole": "Rôle de Challenge",
|
||||
"accountRole": "Rôle",
|
||||
"description": "Description"
|
||||
},
|
||||
"links": {
|
||||
"opportunities": "Opportunités",
|
||||
"cases": "Tickets"
|
||||
},
|
||||
"labels": {
|
||||
"Create Contact": "Créer un contact"
|
||||
},
|
||||
"options": {
|
||||
"opportunityRole": {
|
||||
"": "--Aucun--",
|
||||
"Decision Maker": "Décisionnaire",
|
||||
"Evaluator": "*Evaluator",
|
||||
"Influencer": "Prescripteur"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"scopeNames": {
|
||||
"Account": "Compte",
|
||||
"Contact": "Contact",
|
||||
"Lead": "Lead",
|
||||
"Target": "Cible",
|
||||
"Opportunity": "Challenge",
|
||||
"Meeting": "Rendez-vous",
|
||||
"Calendar": "Calendrier",
|
||||
"Call": "Appel",
|
||||
"Task": "Tâche",
|
||||
"Case": "Ticket",
|
||||
"InboundEmail": "Email Entrant"
|
||||
},
|
||||
"scopeNamesPlural": {
|
||||
"Account": "Comptes",
|
||||
"Contact": "Contacts",
|
||||
"Lead": "Leads",
|
||||
"Target": "Cibles",
|
||||
"Opportunity": "Opportunités",
|
||||
"Meeting": "Rendez-vous",
|
||||
"Calendar": "Calendrier",
|
||||
"Call": "Appels",
|
||||
"Task": "Tâches",
|
||||
"Case": "Tickets",
|
||||
"InboundEmail": "Emails Entrants"
|
||||
},
|
||||
"dashlets": {
|
||||
"Leads": "My Leads",
|
||||
"Opportunities": "Mes Challenges",
|
||||
"Tasks": "Mes Tâches",
|
||||
"Cases": "Mes Tickets",
|
||||
"Calendar": "Calendrier",
|
||||
"OpportunitiesByStage": "*Challenges par étages",
|
||||
"OpportunitiesByLeadSource": "Challenges par Lead Source",
|
||||
"SalesByMonth": "Ventes par Mois",
|
||||
"SalesPipeline": "Tuyaux des ventes"
|
||||
},
|
||||
"labels": {
|
||||
"Create InboundEmail": "Créer une boîte email",
|
||||
"Activities": "Activités",
|
||||
"History": "Historique",
|
||||
"Attendees": "Participants",
|
||||
"Schedule Meeting": "Rendez-vous Planifiés",
|
||||
"Schedule Call": "Appels Planifiés",
|
||||
"Compose Email": "Créer un Email",
|
||||
"Log Meeting": "Journal des Rendez-vous",
|
||||
"Log Call": "Journal d'appels",
|
||||
"Archive Email": "Archiver les Emails",
|
||||
"Create Task": "Créer une tâche",
|
||||
"Tasks": "Tâches"
|
||||
},
|
||||
"fields": {
|
||||
"billingAddressCity": "Ville",
|
||||
"billingAddressCountry": "Pays",
|
||||
"billingAddressPostalCode": "Code Postal",
|
||||
"billingAddressState": "Département",
|
||||
"billingAddressStreet": "Rue",
|
||||
"addressCity": "Ville",
|
||||
"addressStreet": "Rue",
|
||||
"addressCountry": "Pays",
|
||||
"addressState": "Département",
|
||||
"addressPostalCode": "Code Postal",
|
||||
"shippingAddressCity": "City (Shipping)",
|
||||
"shippingAddressStreet": "Street (Shipping)",
|
||||
"shippingAddressCountry": "Country (Shipping)",
|
||||
"shippingAddressState": "State (Shipping)",
|
||||
"shippingAddressPostalCode": "Postal Code (Shipping)"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contacts",
|
||||
"opportunities": "Opportunités",
|
||||
"leads": "Leads",
|
||||
"meetings": "Rendez-vous",
|
||||
"calls": "Appels",
|
||||
"tasks": "Tâches",
|
||||
"emails": "Courriers"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Nom",
|
||||
"team": "Equipe",
|
||||
"status": "Statut",
|
||||
"assignToUser": "Assigné à l'Utilisateur",
|
||||
"host": "Hôte",
|
||||
"username": "Nom d'utilisateur",
|
||||
"password": "Mot de Passe",
|
||||
"port": "Porte",
|
||||
"monitoredFolders": "Dossiers Surveillés",
|
||||
"trashFolder": "Corbeille",
|
||||
"ssl": "SSL",
|
||||
"createCase": "Créer un Ticket",
|
||||
"reply": "Répondre",
|
||||
"caseDistribution": "Distribution de tickets",
|
||||
"replyEmailTemplate": "Modèle de Réponse par Email",
|
||||
"replyFromAddress": "Répondre Depuis l'Adresse",
|
||||
"replyFromName": "Répondre Depuis le Nom"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Active": "Activer",
|
||||
"Inactive": "Désactiver"
|
||||
},
|
||||
"caseDistribution": {
|
||||
"Direct-Assignment": "Assignation Directe",
|
||||
"Round-Robin": "Round-Robin",
|
||||
"Least-Busy": "Least-Busy"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create InboundEmail": "Créer une boîte email",
|
||||
"IMAP": "IMAP",
|
||||
"Actions": "Actions",
|
||||
"Main": "Principal"
|
||||
},
|
||||
"messages": {
|
||||
"couldNotConnectToImap": "Impossible de se connecter au serveur IMAP"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"labels": {
|
||||
"Converted To": "Convertir Vers",
|
||||
"Create Lead": "Créer Lead",
|
||||
"Convert": "Convertir"
|
||||
},
|
||||
"fields": {
|
||||
"name": "Nom",
|
||||
"emailAddress": "Email",
|
||||
"title": "Titre",
|
||||
"website": "Site Web",
|
||||
"phoneNumber": "Téléphone",
|
||||
"accountName": "Nom du Compte",
|
||||
"doNotCall": "Ne Pas Appeler",
|
||||
"address": "Adresse",
|
||||
"status": "Statut",
|
||||
"source": "Source",
|
||||
"opportunityAmount": "Montant du Challenge",
|
||||
"description": "Description",
|
||||
"createdAccount": "Compte",
|
||||
"createdContact": "Contact",
|
||||
"createdOpportunity": "Challenge"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"New": "Nouveau",
|
||||
"Assigned": "Assigné",
|
||||
"In Process": "En Cours de Traitement",
|
||||
"Converted": "Converti",
|
||||
"Recycled": "Supprimé",
|
||||
"Dead": "Mort"
|
||||
},
|
||||
"source": {
|
||||
"Call": "Appel",
|
||||
"Email": "Email",
|
||||
"Existing Customer": "Client Existant",
|
||||
"Partner": "Partenaire",
|
||||
"Public Relations": "Relations publiques",
|
||||
"Web Site": "Site Web",
|
||||
"Campaign": "Campagne",
|
||||
"Other": "Autre"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Nom",
|
||||
"parent": "Parent",
|
||||
"status": "Statut",
|
||||
"dateStart": "Date de Début",
|
||||
"dateEnd": "Date de Fin",
|
||||
"duration": "Durée",
|
||||
"description": "Description",
|
||||
"users": "Utilisateurs",
|
||||
"contacts": "Contacts",
|
||||
"leads": "Leads"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Plannifié",
|
||||
"Held": "Fait",
|
||||
"Not Held": "Pas Fait"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Meeting": "Créer un Rendez-vous",
|
||||
"Set Held": "Marquer Fait",
|
||||
"Set Not Held": "Marquer Pas Fait",
|
||||
"Send Invitations": "Envoi d'Invitations"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Nom",
|
||||
"account": "Compte",
|
||||
"stage": "Etage",
|
||||
"amount": "Montant",
|
||||
"probability": "Probabilité, %",
|
||||
"leadSource": "Lead Source",
|
||||
"doNotCall": "Ne Pas Appeler",
|
||||
"closeDate": "Date de fermeture",
|
||||
"contacts": "Contacts",
|
||||
"description": "Description"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Contacts"
|
||||
},
|
||||
"options": {
|
||||
"stage": {
|
||||
"Prospecting": "En Prospection",
|
||||
"Qualification": "Qualification",
|
||||
"Needs Analysis": "Analyse des besoins",
|
||||
"Value Proposition": "Montant de la Proposition",
|
||||
"Id. Decision Makers": "Id. Décisionnaire",
|
||||
"Perception Analysis": "Analyse de la perception",
|
||||
"Proposal/Price Quote": "Proposition/Devis",
|
||||
"Negotiation/Review": "Négociation/avis",
|
||||
"Closed Won": "Closed Won",
|
||||
"Closed Lost": "Closed Lost"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Opportunity": "Créer un Challenge"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Nom",
|
||||
"emailAddress": "Email",
|
||||
"title": "Titre",
|
||||
"website": "Site Web",
|
||||
"accountName": "Nom du Compte",
|
||||
"phoneNumber": "Téléphone",
|
||||
"doNotCall": "Ne Pas Appeler",
|
||||
"address": "Adresse",
|
||||
"description": "Description"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
"labels": {
|
||||
"Create Target": "Créer une Cible",
|
||||
"Convert to Lead": "Convertir en Lead"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user