mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-04 04:27:02 +00:00
Compare commits
278 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15497b96d1 | ||
|
|
9c3cf0b8dd | ||
|
|
eeaff7ac9d | ||
|
|
17e48c4e9f | ||
|
|
4a878c73be | ||
|
|
f05e41afb6 | ||
|
|
ba8e63c40b | ||
|
|
5d6b9b4785 | ||
|
|
06c0a59632 | ||
|
|
f6df48278c | ||
|
|
8207684193 | ||
|
|
49ac186f80 | ||
|
|
4325e1591c | ||
|
|
16eb1e0b6d | ||
|
|
68668acf57 | ||
|
|
5e5e82d6b6 | ||
|
|
8e23ef59a3 | ||
|
|
0213064217 | ||
|
|
d360cbcb4b | ||
|
|
d1dea478f7 | ||
|
|
778e7b335e | ||
|
|
5fc502c6a2 | ||
|
|
ba5bd60931 | ||
|
|
dfb72bb3e1 | ||
|
|
c4880b77e6 | ||
|
|
8aab9d17b1 | ||
|
|
205beb068c | ||
|
|
80cf2f2e10 | ||
|
|
5982b27b90 | ||
|
|
d696ca3013 | ||
|
|
9d10218487 | ||
|
|
b41ef6094a | ||
|
|
9a9a69ace4 | ||
|
|
1000139d01 | ||
|
|
129984f4c6 | ||
|
|
d665bc54e0 | ||
|
|
69b027698d | ||
|
|
6ffff16f06 | ||
|
|
79393f16d3 | ||
|
|
5821a06f9e | ||
|
|
3eb4cf27f2 | ||
|
|
94c345c386 | ||
|
|
6fe7853eb7 | ||
|
|
c45ea08ab2 | ||
|
|
04d41e9c86 | ||
|
|
2850cffc6a | ||
|
|
0cdc15ecaf | ||
|
|
ee85ee369b | ||
|
|
738e56cc63 | ||
|
|
6b38e1561b | ||
|
|
a56d8b7d1c | ||
|
|
db6e5ee778 | ||
|
|
a0bf1af3d3 | ||
|
|
5b47178162 | ||
|
|
3f0684c1ea | ||
|
|
d2bc49755d | ||
|
|
0502c1768b | ||
|
|
cf7d21db32 | ||
|
|
977fb47efb | ||
|
|
6c7a3adcdd | ||
|
|
3b22e08840 | ||
|
|
8d79524c62 | ||
|
|
3c70f28dc0 | ||
|
|
79b37e7047 | ||
|
|
3050d8b5b5 | ||
|
|
231a40e4a8 | ||
|
|
1f1c87513b | ||
|
|
910822334e | ||
|
|
af02d721c3 | ||
|
|
faf7cb9acd | ||
|
|
73869d5674 | ||
|
|
f60732170e | ||
|
|
aecf04a4f8 | ||
|
|
7a383912c8 | ||
|
|
21c288badf | ||
|
|
65492ea1dc | ||
|
|
7fd10104cc | ||
|
|
ad85c6fa3f | ||
|
|
e32bf06e4d | ||
|
|
f363d77cb7 | ||
|
|
8986b6f426 | ||
|
|
8b35c064c8 | ||
|
|
da5ea180ab | ||
|
|
3aca557420 | ||
|
|
ea723742c7 | ||
|
|
d85675f540 | ||
|
|
9b4aeb8e4c | ||
|
|
2c539b1fe6 | ||
|
|
5f31e7e148 | ||
|
|
cc9227910f | ||
|
|
85d8dfe885 | ||
|
|
563179bec7 | ||
|
|
386ada05d6 | ||
|
|
70c2992282 | ||
|
|
36d6483a51 | ||
|
|
01039b9881 | ||
|
|
bbd1297302 | ||
|
|
88c0d8810c | ||
|
|
b365bc17db | ||
|
|
3f24e64988 | ||
|
|
7a5ce2f4ee | ||
|
|
a410fb903a | ||
|
|
ba4004d720 | ||
|
|
cdc980c2b6 | ||
|
|
3578cc9523 | ||
|
|
09ff1d1e5a | ||
|
|
8e4a6ef183 | ||
|
|
0d111a6bd8 | ||
|
|
3e503852db | ||
|
|
d3fe435115 | ||
|
|
e6a0080c0e | ||
|
|
b8ddb72d3b | ||
|
|
58953ca009 | ||
|
|
d4e98155d0 | ||
|
|
86fabe3352 | ||
|
|
c5ccf8e6da | ||
|
|
b7e0a0de23 | ||
|
|
9c2a18f0aa | ||
|
|
aa95f2cf88 | ||
|
|
8dd7f262a2 | ||
|
|
b76feba080 | ||
|
|
1b5aea85ba | ||
|
|
c89c7f5e0e | ||
|
|
bcaaf539be | ||
|
|
48f0988373 | ||
|
|
a0c0d37bfd | ||
|
|
9c696fe8d6 | ||
|
|
224e3475d8 | ||
|
|
841c5f85bd | ||
|
|
6745419a4f | ||
|
|
6bf9bb875a | ||
|
|
d6e1322775 | ||
|
|
bb0e97160c | ||
|
|
8124ceea6b | ||
|
|
b5cb0c0881 | ||
|
|
8747ccc105 | ||
|
|
8b0147484c | ||
|
|
233037a1eb | ||
|
|
11446ef857 | ||
|
|
4403131235 | ||
|
|
9dde3d0645 | ||
|
|
2fcf00ef4f | ||
|
|
1139cb242b | ||
|
|
796e1894ac | ||
|
|
8d15bdab3c | ||
|
|
e94564b5e7 | ||
|
|
67b56345e6 | ||
|
|
9ac2fe1534 | ||
|
|
08cf619807 | ||
|
|
380aad2f4d | ||
|
|
d3a8e57fdf | ||
|
|
c6542c0698 | ||
|
|
f74959ab00 | ||
|
|
2bb28ac270 | ||
|
|
faf3350aab | ||
|
|
9fc4e0b06e | ||
|
|
4c3ecf0b3a | ||
|
|
b1a345963d | ||
|
|
ca64d7c8ec | ||
|
|
f62db8b943 | ||
|
|
ce2a2a03a3 | ||
|
|
d947223b9b | ||
|
|
b1aea34137 | ||
|
|
ae6d03ce2b | ||
|
|
fa4b459d58 | ||
|
|
372a8d0d69 | ||
|
|
bd413a75a0 | ||
|
|
9bb0d123d3 | ||
|
|
59240fb090 | ||
|
|
598852484b | ||
|
|
18548c515e | ||
|
|
6190017919 | ||
|
|
e49cbcad3f | ||
|
|
2a22b94b95 | ||
|
|
739374de59 | ||
|
|
03b8041acb | ||
|
|
a31df6f2af | ||
|
|
64317389a8 | ||
|
|
ab4552d064 | ||
|
|
20281f8cbb | ||
|
|
fb7db0f91d | ||
|
|
b3b0e9254f | ||
|
|
03ffc7727d | ||
|
|
59a4f88eeb | ||
|
|
d504ab8f54 | ||
|
|
627c167ef7 | ||
|
|
656c9b1eee | ||
|
|
92f319a2d9 | ||
|
|
da1f96595f | ||
|
|
21568efa2c | ||
|
|
8a75a5a71b | ||
|
|
012e4d609d | ||
|
|
5e66d2e2c1 | ||
|
|
49ae22e048 | ||
|
|
5d92d14125 | ||
|
|
b6d52d3c97 | ||
|
|
7e2d445db8 | ||
|
|
2325ad695f | ||
|
|
c499b06baa | ||
|
|
a03a512846 | ||
|
|
1e6062bd10 | ||
|
|
2c90558785 | ||
|
|
f6071bad41 | ||
|
|
a09120f39e | ||
|
|
8fb7cbdfcf | ||
|
|
3e8da12410 | ||
|
|
d60213e93f | ||
|
|
0864f7d604 | ||
|
|
6fb2112e40 | ||
|
|
65bb063c2c | ||
|
|
75b2c91baa | ||
|
|
530be71fdd | ||
|
|
c064b8fa80 | ||
|
|
b2b0ed82e5 | ||
|
|
71a5e1ab22 | ||
|
|
371b140056 | ||
|
|
5555383b1e | ||
|
|
ffe824e405 | ||
|
|
6586785415 | ||
|
|
8a2554ef28 | ||
|
|
ec2ddc429a | ||
|
|
1754b8e7b9 | ||
|
|
2e20b24d04 | ||
|
|
5da3df3cd2 | ||
|
|
61d428a4a5 | ||
|
|
a941f0c5da | ||
|
|
199d0a956a | ||
|
|
105ec0f441 | ||
|
|
062effd39a | ||
|
|
3ac5c71736 | ||
|
|
97d7796f9d | ||
|
|
8cd4fe5891 | ||
|
|
77df445c03 | ||
|
|
a510bb4ea0 | ||
|
|
48883211ee | ||
|
|
8b77f181da | ||
|
|
88dbc988ca | ||
|
|
0ecd387ef8 | ||
|
|
2c4cc20005 | ||
|
|
b25c115913 | ||
|
|
e46921ac33 | ||
|
|
dab213ea01 | ||
|
|
7f058b8591 | ||
|
|
76cf945d40 | ||
|
|
c5850d18da | ||
|
|
645cdc440c | ||
|
|
6e910e002e | ||
|
|
cc4de320fd | ||
|
|
7565492666 | ||
|
|
878d74bfa5 | ||
|
|
ee2d8b3f00 | ||
|
|
ebd35638b2 | ||
|
|
6372c7a22e | ||
|
|
a404f7f196 | ||
|
|
0013ca382a | ||
|
|
a9c904afa7 | ||
|
|
a0be338676 | ||
|
|
58d0f2bd98 | ||
|
|
4c92d54119 | ||
|
|
711b2df143 | ||
|
|
0307900942 | ||
|
|
4c60898002 | ||
|
|
4d350b256b | ||
|
|
d41704f1b1 | ||
|
|
5bbb5ee937 | ||
|
|
50e825b7a0 | ||
|
|
dc036225be | ||
|
|
c5a8df84f7 | ||
|
|
7ad6c495a6 | ||
|
|
e8c217e468 | ||
|
|
9e32298d42 | ||
|
|
e4d833e49f | ||
|
|
8505f583f4 | ||
|
|
c1de2d9bd5 | ||
|
|
d192e0aabf | ||
|
|
fb5b464bf6 | ||
|
|
eb71379562 | ||
|
|
b603543537 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -9,7 +9,10 @@
|
||||
/client
|
||||
/test.php
|
||||
/main.html
|
||||
/frontend/client/css/bootstrap.css
|
||||
/frontend/client/css/espo.css
|
||||
/frontend/client/css/espo-vertical.css
|
||||
/frontend/client/css/sakura.css
|
||||
/frontend/client/css/sakura-vertical.css
|
||||
/tests/testData/cache/*
|
||||
composer.phar
|
||||
vendor/
|
||||
|
||||
@@ -15,6 +15,7 @@ DirectoryIndex index.php index.html
|
||||
RewriteRule ^/?data/logs/ - [F]
|
||||
RewriteRule ^/?data/cache/ - [F]
|
||||
RewriteRule ^/?data/upload/ - [F]
|
||||
RewriteRule ^/?data/\.backup/ - [F]
|
||||
RewriteRule ^/?application/ - [F]
|
||||
RewriteRule ^/?custom/ - [F]
|
||||
RewriteRule ^/?vendor/ - [F]
|
||||
|
||||
65
Gruntfile.js
65
Gruntfile.js
@@ -21,7 +21,7 @@
|
||||
module.exports = function (grunt) {
|
||||
|
||||
var jsFilesToMinify = [
|
||||
'client/lib/jquery-2.0.2.min.js',
|
||||
'client/lib/jquery-2.1.4.min.js',
|
||||
'client/lib/underscore-min.js',
|
||||
'client/lib/backbone-min.js',
|
||||
'client/lib/handlebars.js',
|
||||
@@ -36,34 +36,8 @@ module.exports = function (grunt) {
|
||||
'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',
|
||||
'client/src/utils.js'
|
||||
];
|
||||
|
||||
grunt.initConfig({
|
||||
@@ -85,22 +59,44 @@ module.exports = function (grunt) {
|
||||
final: ['build/tmp'],
|
||||
},
|
||||
less: {
|
||||
bootstrap: {
|
||||
espo: {
|
||||
options: {
|
||||
yuicompress: true,
|
||||
},
|
||||
files: {
|
||||
'frontend/client/css/bootstrap.css': 'frontend/less/espo/main.less',
|
||||
'frontend/client/css/espo.css': 'frontend/less/espo/main.less',
|
||||
},
|
||||
},
|
||||
sakura: {
|
||||
options: {
|
||||
yuicompress: true,
|
||||
},
|
||||
files: {
|
||||
'frontend/client/css/sakura.css': 'frontend/less/sakura/main.less',
|
||||
},
|
||||
},
|
||||
espoVertical: {
|
||||
options: {
|
||||
yuicompress: true,
|
||||
},
|
||||
files: {
|
||||
'frontend/client/css/espo-vertical.css': 'frontend/less/espo-vertical/main.less',
|
||||
},
|
||||
},
|
||||
sakuraVertical: {
|
||||
options: {
|
||||
yuicompress: true,
|
||||
},
|
||||
files: {
|
||||
'frontend/client/css/sakura-vertical.css': 'frontend/less/sakura-vertical/main.less',
|
||||
},
|
||||
}
|
||||
},
|
||||
cssmin: {
|
||||
minify: {
|
||||
files: {
|
||||
'build/tmp/client/css/espo.min.css': [
|
||||
'frontend/client/css/bootstrap.css',
|
||||
'frontend/client/css/datepicker.css',
|
||||
'frontend/client/css/jquery.timepicker.css',
|
||||
'build/tmp/client/css/espo.css': [
|
||||
'frontend/client/css/espo.css',
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -157,6 +153,7 @@ module.exports = function (grunt) {
|
||||
'rebuild.php',
|
||||
'clear_cache.php',
|
||||
'upgrade.php',
|
||||
'extension.php',
|
||||
'index.php',
|
||||
'LICENSE.txt',
|
||||
'.htaccess',
|
||||
|
||||
@@ -22,8 +22,10 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error,
|
||||
\Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class Admin extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
@@ -34,17 +36,19 @@ class Admin extends \Espo\Core\Controllers\Base
|
||||
}
|
||||
}
|
||||
|
||||
public function actionRebuild($params, $data)
|
||||
public function postActionRebuild($params, $data, $request)
|
||||
{
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$result = $this->getContainer()->get('dataManager')->rebuild();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function actionClearCache($params, $data)
|
||||
public function postActionClearCache($params, $data)
|
||||
{
|
||||
$result = $this->getContainer()->get('dataManager')->clearCache();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -55,8 +59,13 @@ class Admin extends \Espo\Core\Controllers\Base
|
||||
return $scheduledJob->getAllNamesOnly();
|
||||
}
|
||||
|
||||
public function actionUploadUpgradePackage($params, $data)
|
||||
public function postActionUploadUpgradePackage($params, $data)
|
||||
{
|
||||
if ($this->getConfig()->get('restrictedMode')) {
|
||||
if (!$this->getUser()->get('isSuperAdmin')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
$upgradeManager = new \Espo\Core\UpgradeManager($this->getContainer());
|
||||
|
||||
$upgradeId = $upgradeManager->upload($data);
|
||||
@@ -68,10 +77,15 @@ class Admin extends \Espo\Core\Controllers\Base
|
||||
);
|
||||
}
|
||||
|
||||
public function actionRunUpgrade($params, $data)
|
||||
public function postActionRunUpgrade($params, $data)
|
||||
{
|
||||
$upgradeManager = new \Espo\Core\UpgradeManager($this->getContainer());
|
||||
if ($this->getConfig()->get('restrictedMode')) {
|
||||
if (!$this->getUser()->get('isSuperAdmin')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
$upgradeManager = new \Espo\Core\UpgradeManager($this->getContainer());
|
||||
$upgradeManager->install($data);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -44,7 +44,7 @@ class App extends \Espo\Core\Controllers\Base
|
||||
);
|
||||
}
|
||||
|
||||
public function actionDestroyAuthToken($params, $data)
|
||||
public function postActionDestroyAuthToken($params, $data)
|
||||
{
|
||||
$token = $data['token'];
|
||||
if (empty($token)) {
|
||||
|
||||
@@ -18,25 +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\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class Attachment extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
public function actionUpload($params, $data)
|
||||
{
|
||||
public function actionUpload($params, $data, $request)
|
||||
{
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
list($prefix, $contents) = explode(',', $data);
|
||||
$contents = base64_decode($contents);
|
||||
|
||||
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment');
|
||||
$this->getEntityManager()->saveEntity($attachment);
|
||||
$this->getEntityManager()->saveEntity($attachment);
|
||||
$this->getContainer()->get('fileManager')->putContents('data/upload/' . $attachment->id, $contents);
|
||||
|
||||
|
||||
return array(
|
||||
'attachmentId' => $attachment->id
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,49 +18,49 @@
|
||||
*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class EmailAccount extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
@@ -58,6 +58,11 @@ class Extension extends \Espo\Core\Controllers\Record
|
||||
if (!$request->isPost()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
if ($this->getConfig()->get('restrictedMode')) {
|
||||
if (!$this->getUser()->get('isSuperAdmin')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
$manager = new \Espo\Core\ExtensionManager($this->getContainer());
|
||||
|
||||
@@ -71,11 +76,14 @@ class Extension extends \Espo\Core\Controllers\Record
|
||||
if (!$request->isPost()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
if ($this->getConfig()->get('restrictedMode')) {
|
||||
if (!$this->getUser()->get('isSuperAdmin')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
$manager = new \Espo\Core\ExtensionManager($this->getContainer());
|
||||
|
||||
$manager->uninstall($data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -99,12 +107,18 @@ class Extension extends \Espo\Core\Controllers\Record
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionDelete($params)
|
||||
public function actionDelete($params, $data, $request)
|
||||
{
|
||||
if (!$request->isDelete()) {
|
||||
throw BadRequest();
|
||||
}
|
||||
if ($this->getConfig()->get('restrictedMode')) {
|
||||
if (!$this->getUser()->get('isSuperAdmin')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
$manager = new \Espo\Core\ExtensionManager($this->getContainer());
|
||||
|
||||
$manager->delete($params);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,13 @@
|
||||
*
|
||||
* 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\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class ExternalAccount extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
@@ -34,7 +35,7 @@ class ExternalAccount extends \Espo\Core\Controllers\Record
|
||||
$integrations = $this->getEntityManager()->getRepository('Integration')->find();
|
||||
$arr = array();
|
||||
foreach ($integrations as $entity) {
|
||||
if ($entity->get('enabled') && $this->getMetadata()->get('integrations.' . $entity->id .'.allowUserAccounts')) {
|
||||
if ($entity->get('enabled') && $this->getMetadata()->get('integrations.' . $entity->id .'.allowUserAccounts')) {
|
||||
$arr[] = array(
|
||||
'id' => $entity->id
|
||||
);
|
||||
@@ -77,15 +78,18 @@ class ExternalAccount extends \Espo\Core\Controllers\Record
|
||||
return $entity->toArray();
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
public function actionUpdate($params, $data, $request)
|
||||
{
|
||||
return $this->actionPatch($params, $data);
|
||||
return $this->actionPatch($params, $data, $request);
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data)
|
||||
public function actionPatch($params, $data, $request)
|
||||
{
|
||||
list($integration, $userId) = explode('__', $params['id']);
|
||||
if (!$request->isPost() && !$request->isPatch()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
list($integration, $userId) = explode('__', $params['id']);
|
||||
|
||||
if ($this->getUser()->id != $userId) {
|
||||
throw new Forbidden();
|
||||
|
||||
@@ -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\Controllers;
|
||||
|
||||
@@ -30,10 +30,10 @@ class GlobalSearch extends \Espo\Core\Controllers\Base
|
||||
public function actionSearch($params, $data, $request)
|
||||
{
|
||||
$query = $params['query'];
|
||||
|
||||
$offset = $request->get('offset');
|
||||
$maxSize = $request->get('maxSize');
|
||||
|
||||
|
||||
$offset = intval($request->get('offset'));
|
||||
$maxSize = intval($request->get('maxSize'));
|
||||
|
||||
return $this->getService('GlobalSearch')->find($query, $offset, $maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,10 +71,14 @@ class Import extends \Espo\Core\Controllers\Record
|
||||
return $this->getContainer()->get('entityManager');
|
||||
}
|
||||
|
||||
public function actionUploadFile($params, $data)
|
||||
public function actionUploadFile($params, $data, $request)
|
||||
{
|
||||
$contents = $data;
|
||||
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment');
|
||||
$attachment->set('type', 'text/csv');
|
||||
$attachment->set('role', 'Import File');
|
||||
@@ -88,24 +92,34 @@ class Import extends \Espo\Core\Controllers\Record
|
||||
);
|
||||
}
|
||||
|
||||
public function actionRevert($params, $data)
|
||||
public function actionRevert($params, $data, $request)
|
||||
{
|
||||
if (empty($data['id'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
return $this->getService('Import')->revert($data['id']);
|
||||
}
|
||||
|
||||
public function actionRemoveDuplicates($params, $data)
|
||||
public function actionRemoveDuplicates($params, $data, $request)
|
||||
{
|
||||
if (empty($data['id'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
return $this->getService('Import')->removeDuplicates($data['id']);
|
||||
}
|
||||
|
||||
public function actionCreate($params, $data)
|
||||
public function actionCreate($params, $data, $request)
|
||||
{
|
||||
if (!$request->isPost() && !$request->isPut()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$importParams = array(
|
||||
'headerRow' => $data['headerRow'],
|
||||
'fieldDelimiter' => $data['fieldDelimiter'],
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class InboundEmail extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
protected function checkControllerAccess()
|
||||
|
||||
@@ -18,21 +18,23 @@
|
||||
*
|
||||
* 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\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class Integration extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
{
|
||||
protected function checkControllerAccess()
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function actionIndex($params, $data, $request)
|
||||
{
|
||||
return false;
|
||||
@@ -40,22 +42,28 @@ class Integration extends \Espo\Core\Controllers\Record
|
||||
|
||||
public function actionRead($params, $data, $request)
|
||||
{
|
||||
$entity = $this->getEntityManager()->getEntity('Integration', $params['id']);
|
||||
if (!$request->isPut() && !$request->isPatch()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$entity = $this->getEntityManager()->getEntity('Integration', $params['id']);
|
||||
return $entity->toArray();
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
|
||||
public function actionUpdate($params, $data, $request)
|
||||
{
|
||||
return $this->actionPatch($params, $data);
|
||||
return $this->actionPatch($params, $data, $request);
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data)
|
||||
|
||||
public function actionPatch($params, $data, $request)
|
||||
{
|
||||
if (!$request->isPut() && !$request->isPatch()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$entity = $this->getEntityManager()->getEntity('Integration', $params['id']);
|
||||
$entity->set($data);
|
||||
$this->getEntityManager()->saveEntity($entity);
|
||||
|
||||
return $entity->toArray();
|
||||
|
||||
return $entity->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
72
application/Espo/Controllers/Job.php
Normal file
72
application/Espo/Controllers/Job.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 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\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class Job extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
protected function checkControllerAccess()
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
public function actionCreate($params, $data)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionListLinked($params, $data, $request)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionMassUpdate($params, $data, $request)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function actionRemoveLink($params, $data)
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ use Espo\Core\Utils as Utils;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class Layout extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
@@ -38,12 +39,16 @@ class Layout extends \Espo\Core\Controllers\Base
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
public function actionUpdate($params, $data, $request)
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
if (!$request->isPut() && !$request->isPatch()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$layoutManager = $this->getContainer()->get('layout');
|
||||
$layoutManager->set($data, $params['scope'], $params['name']);
|
||||
$result = $layoutManager->save();
|
||||
@@ -57,8 +62,20 @@ class Layout extends \Espo\Core\Controllers\Base
|
||||
return $layoutManager->get($params['scope'], $params['name']);
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data)
|
||||
public function actionPatch($params, $data, $request)
|
||||
{
|
||||
return $this->actionUpdate($params, $data);
|
||||
return $this->actionUpdate($params, $data, $request);
|
||||
}
|
||||
|
||||
public function actionResetToDefault($params, $data, $request)
|
||||
{
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
if (empty($data['scope']) || empty($data['name'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
return $this->getContainer()->get('layout')->resetToDefault($data['scope'], $data['name']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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\Controllers;
|
||||
|
||||
@@ -32,32 +32,32 @@ class Notification extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
$scope = $params['scope'];
|
||||
$id = $params['id'];
|
||||
|
||||
|
||||
$userId = $this->getUser()->id;
|
||||
|
||||
|
||||
$offset = intval($request->get('offset'));
|
||||
$maxSize = intval($request->get('maxSize'));
|
||||
|
||||
$maxSize = intval($request->get('maxSize'));
|
||||
|
||||
$params = array(
|
||||
'offset' => $offset,
|
||||
'maxSize' => $maxSize,
|
||||
);
|
||||
|
||||
$result = $this->getService('Notification')->getList($userId, $params);
|
||||
|
||||
|
||||
$result = $this->getService('Notification')->getList($userId, $params);
|
||||
|
||||
return array(
|
||||
'total' => $result['total'],
|
||||
'list' => $result['collection']->toArray()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function actionNotReadCount()
|
||||
{
|
||||
$userId = $this->getUser()->id;
|
||||
return $this->getService('Notification')->getNotReadCount($userId);
|
||||
}
|
||||
|
||||
public function actionMarkAllRead($params, $data, $request)
|
||||
|
||||
public function postActionMarkAllRead($params, $data, $request)
|
||||
{
|
||||
$userId = $this->getUser()->id;
|
||||
return $this->getService('Notification')->markAllRead($userId);
|
||||
|
||||
@@ -53,27 +53,34 @@ class Preferences extends \Espo\Core\Controllers\Base
|
||||
}
|
||||
}
|
||||
|
||||
public function actionDelete($params, $data)
|
||||
public function actionDelete($params, $data, $request)
|
||||
{
|
||||
$userId = $params['id'];
|
||||
if (empty($userId)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
if (!$request->isDelete()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$this->handleUserAccess($userId);
|
||||
|
||||
return $this->getEntityManager()->getRepository('Preferences')->resetToDefaults($userId);
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data)
|
||||
public function actionPatch($params, $data, $request)
|
||||
{
|
||||
return $this->actionUpdate($params, $data);
|
||||
return $this->actionUpdate($params, $data, $request);
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
public function actionUpdate($params, $data, $request)
|
||||
{
|
||||
$userId = $params['id'];
|
||||
$this->handleUserAccess($userId);
|
||||
|
||||
if (!$request->isPost() && !$request->isPatch()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
if (array_key_exists('smtpPassword', $data)) {
|
||||
$data['smtpPassword'] = $this->getCrypt()->encrypt($data['smtpPassword']);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class Settings extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
@@ -46,17 +47,21 @@ class Settings extends \Espo\Core\Controllers\Base
|
||||
return $this->getConfigData();
|
||||
}
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
public function actionUpdate($params, $data, $request)
|
||||
{
|
||||
return $this->actionPatch($params, $data);
|
||||
return $this->actionPatch($params, $data, $request);
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data)
|
||||
public function actionPatch($params, $data, $request)
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
if (!$request->isPut() && !$request->isPatch()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
if (isset($data['useCache']) && $data['useCache'] != $this->getConfig()->get('useCache')) {
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ class Stream extends \Espo\Core\Controllers\Base
|
||||
$offset = intval($request->get('offset'));
|
||||
$maxSize = intval($request->get('maxSize'));
|
||||
$after = $request->get('after');
|
||||
$filter = $request->get('filter');
|
||||
|
||||
$service = $this->getService('Stream');
|
||||
|
||||
@@ -52,6 +53,7 @@ class Stream extends \Espo\Core\Controllers\Base
|
||||
'offset' => $offset,
|
||||
'maxSize' => $maxSize,
|
||||
'after' => $after,
|
||||
'filter' => $filter
|
||||
));
|
||||
|
||||
return array(
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
*
|
||||
* 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;
|
||||
|
||||
class Team extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
31
application/Espo/Controllers/Template.php
Normal file
31
application/Espo/Controllers/Template.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 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\Error;
|
||||
|
||||
class Template extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -53,7 +53,10 @@ class User extends \Espo\Core\Controllers\Record
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
return $this->getService('User')->changePassword($this->getUser()->id, $data['password']);
|
||||
if (!array_key_exists('password', $data) || !array_key_exists('currentPassword', $data)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
return $this->getService('User')->changePassword($this->getUser()->id, $data['password'], true, $data['currentPassword']);
|
||||
}
|
||||
|
||||
public function actionChangePasswordByRequest($params, $data, $request)
|
||||
|
||||
@@ -76,7 +76,7 @@ class Acl
|
||||
|
||||
public function checkScope($scope, $action = null, $isOwner = null, $inTeam = null, $entity = null)
|
||||
{
|
||||
return $this->getAclManager()->checkScope($this->getUser(), $subject, $action, $isOwner, $inTeam, $entity) ;
|
||||
return $this->getAclManager()->checkScope($this->getUser(), $scope, $action, $isOwner, $inTeam, $entity) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ class Base implements Injectable
|
||||
public function checkScope(User $user, $data, $scope, $action = null, $isOwner = null, $inTeam = null, Entity $entity = null)
|
||||
{
|
||||
if (is_null($data)) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if ($data === false) {
|
||||
return false;
|
||||
|
||||
@@ -86,10 +86,12 @@ class Application
|
||||
public function runClient()
|
||||
{
|
||||
$config = $this->getContainer()->get('config');
|
||||
$themeManager = $this->getContainer()->get('themeManager');
|
||||
|
||||
$html = file_get_contents('main.html');
|
||||
$html = str_replace('{{cacheTimestamp}}', $config->get('cacheTimestamp', 0), $html);
|
||||
$html = str_replace('{{useCache}}', $config->get('useCache') ? 'true' : 'false' , $html);
|
||||
$html = str_replace('{{stylesheet}}', $themeManager->getStylesheet(), $html);
|
||||
$html = str_replace('{{runScript}}', 'app.start();' , $html);
|
||||
echo $html;
|
||||
exit;
|
||||
|
||||
@@ -161,6 +161,14 @@ class Container
|
||||
);
|
||||
}
|
||||
|
||||
private function loadNumber()
|
||||
{
|
||||
return new \Espo\Core\Utils\Number(
|
||||
$this->get('config')->get('decimalMark'),
|
||||
$this->get('config')->get('thousandSeparator')
|
||||
);
|
||||
}
|
||||
|
||||
private function loadServiceFactory()
|
||||
{
|
||||
return new \Espo\Core\ServiceFactory(
|
||||
@@ -270,6 +278,14 @@ class Container
|
||||
);
|
||||
}
|
||||
|
||||
private function loadThemeManager()
|
||||
{
|
||||
return new \Espo\Core\Utils\ThemeManager(
|
||||
$this->get('config'),
|
||||
$this->get('metadata')
|
||||
);
|
||||
}
|
||||
|
||||
public function setUser($user)
|
||||
{
|
||||
$this->data['user'] = $user;
|
||||
|
||||
@@ -87,18 +87,27 @@ class ControllerManager
|
||||
$actionNameUcfirst = ucfirst($actionName);
|
||||
|
||||
$beforeMethodName = 'before' . $actionNameUcfirst;
|
||||
$actionMethodName = 'action' . $actionNameUcfirst;
|
||||
$afterMethodName = 'after' . $actionNameUcfirst;
|
||||
|
||||
$fullActionMethodName = strtolower($request->getMethod()) . ucfirst($actionMethodName);
|
||||
|
||||
if (method_exists($controller, $fullActionMethodName)) {
|
||||
$primaryActionMethodName = $fullActionMethodName;
|
||||
} else {
|
||||
$primaryActionMethodName = $actionMethodName;
|
||||
}
|
||||
|
||||
if (!method_exists($controller, $primaryActionMethodName)) {
|
||||
throw new NotFound("Action '$actionName' (".$request->getMethod().") does not exist in controller '$controller'");
|
||||
}
|
||||
|
||||
if (method_exists($controller, $beforeMethodName)) {
|
||||
$controller->$beforeMethodName($params, $data, $request);
|
||||
}
|
||||
$actionMethodName = 'action' . $actionNameUcfirst;
|
||||
|
||||
if (!method_exists($controller, $actionMethodName)) {
|
||||
throw new NotFound("Action '$actionMethodName' does not exist in controller '$controller'");
|
||||
}
|
||||
$result = $controller->$primaryActionMethodName($params, $data, $request);
|
||||
|
||||
$result = $controller->$actionMethodName($params, $data, $request);
|
||||
|
||||
$afterMethodName = 'after' . $actionNameUcfirst;
|
||||
if (method_exists($controller, $afterMethodName)) {
|
||||
$controller->$afterMethodName($params, $data, $request);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ class Record extends Base
|
||||
public function actionCreate($params, $data, $request)
|
||||
{
|
||||
if (!$request->isPost()) {
|
||||
throw BadRequest();
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
if (!$this->getAcl()->check($this->name, 'edit')) {
|
||||
@@ -96,7 +96,7 @@ class Record extends Base
|
||||
public function actionUpdate($params, $data, $request)
|
||||
{
|
||||
if (!$request->isPut() && !$request->isPatch()) {
|
||||
throw BadRequest();
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
if (!$this->getAcl()->check($this->name, 'edit')) {
|
||||
@@ -129,7 +129,7 @@ class Record extends Base
|
||||
$maxSize = self::MAX_SIZE_LIMIT;
|
||||
}
|
||||
if (!empty($maxSize) && $maxSize > self::MAX_SIZE_LIMIT) {
|
||||
throw new Forbidden();
|
||||
throw new Forbidden("Max should should not exceed " . self::MAX_SIZE_LIMIT . ". Use pagination (offset, limit).");
|
||||
}
|
||||
|
||||
$result = $this->getRecordService()->findEntities(array(
|
||||
@@ -185,7 +185,7 @@ class Record extends Base
|
||||
public function actionDelete($params, $data, $request)
|
||||
{
|
||||
if (!$request->isDelete()) {
|
||||
throw BadRequest();
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$id = $params['id'];
|
||||
@@ -198,7 +198,7 @@ class Record extends Base
|
||||
|
||||
public function actionExport($params, $data, $request)
|
||||
{
|
||||
if ($this->getConfig()->get('disableExport') && !$this->getUser()->isAdmin()) {
|
||||
if ($this->getConfig()->get('exportDisabled') && !$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,21 @@ abstract class Base
|
||||
return $this->getContainer()->get('metadata');
|
||||
}
|
||||
|
||||
protected function getDateTime()
|
||||
{
|
||||
return $this->getContainer()->get('dateTime');
|
||||
}
|
||||
|
||||
protected function getNumber()
|
||||
{
|
||||
return $this->getContainer()->get('number');
|
||||
}
|
||||
|
||||
protected function getFileManager()
|
||||
{
|
||||
return $this->getContainer()->get('fileManager');
|
||||
}
|
||||
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
@@ -104,6 +104,9 @@ class HookManager
|
||||
foreach ($this->data[$scope][$hookName] as $className) {
|
||||
if (empty($this->hooks[$className])) {
|
||||
$this->hooks[$className] = $this->createHookByClassName($className);
|
||||
if (empty($this->hooks[$className])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$hook = $this->hooks[$className];
|
||||
$hook->$hookName($injection, $options);
|
||||
@@ -122,7 +125,7 @@ class HookManager
|
||||
}
|
||||
return $hook;
|
||||
}
|
||||
throw new Error("Class '$className' does not exist");
|
||||
$GLOBALS['log']->error("Hook class '{$name}' does not exist.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
140
application/Espo/Core/Htmlizer/Htmlizer.php
Normal file
140
application/Espo/Core/Htmlizer/Htmlizer.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 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\Htmlizer;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
use Espo\Core\Utils\File\Manager as FileManager;
|
||||
use Espo\Core\Utils\DateTime;
|
||||
use Espo\Core\Utils\Number;
|
||||
|
||||
require('vendor/zordius/lightncandy/src/lightncandy.php');
|
||||
|
||||
class Htmlizer
|
||||
{
|
||||
protected $fileManager;
|
||||
|
||||
protected $dateTime;
|
||||
|
||||
protected $config;
|
||||
|
||||
public function __construct(FileManager $fileManager, DateTime $dateTime, Number $number)
|
||||
{
|
||||
$this->fileManager = $fileManager;
|
||||
$this->dateTime = $dateTime;
|
||||
$this->number = $number;
|
||||
}
|
||||
|
||||
protected function formatNumber($value)
|
||||
{
|
||||
return $this->number->format($value);
|
||||
}
|
||||
|
||||
protected function format($value)
|
||||
{
|
||||
if (is_float($value) || is_int($value)) {
|
||||
$value = $this->formatNumber($value);
|
||||
} else if (is_string($value)) {
|
||||
$value = nl2br($value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
protected function getDataFromEntity(Entity $entity)
|
||||
{
|
||||
$data = $entity->toArray();
|
||||
|
||||
|
||||
|
||||
$fieldDefs = $entity->getFields();
|
||||
$fieldList = array_keys($fieldDefs);
|
||||
|
||||
foreach ($fieldList as $field) {
|
||||
$type = null;
|
||||
if (!empty($fieldDefs[$field]['type'])) {
|
||||
$type = $fieldDefs[$field]['type'];
|
||||
}
|
||||
if ($type == Entity::DATETIME) {
|
||||
if (!empty($data[$field])) {
|
||||
$data[$field] = $this->dateTime->convertSystemDateTime($data[$field]);
|
||||
}
|
||||
} else if ($type == Entity::DATE) {
|
||||
if (!empty($data[$field])) {
|
||||
$data[$field] = $this->dateTime->convertSystemDate($data[$field]);
|
||||
}
|
||||
} else if ($type == Entity::JSON_ARRAY) {
|
||||
if (!empty($data[$field])) {
|
||||
$list = $data[$field];
|
||||
$newList = [];
|
||||
foreach ($list as $item) {
|
||||
$v = $item;
|
||||
if ($item instanceof \StdClass) {
|
||||
$v = get_object_vars($v);
|
||||
}
|
||||
foreach ($v as $k => $w) {
|
||||
$v[$k] = $this->format($v[$k]);
|
||||
}
|
||||
$newList[] = $v;
|
||||
}
|
||||
$data[$field] = $newList;
|
||||
}
|
||||
} else if ($type == Entity::JSON_OBJECT) {
|
||||
if (!empty($data[$field])) {
|
||||
$value = $data[$field];
|
||||
if ($value instanceof \StdClass) {
|
||||
$data[$field] = get_object_vars($value);
|
||||
}
|
||||
foreach ($data[$field] as $k => $w) {
|
||||
$data[$field][$k] = $this->format($data[$field][$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($field, $data)) {
|
||||
$data[$field] = $this->format($data[$field]);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function render(Entity $entity, $template)
|
||||
{
|
||||
$code = \LightnCandy::compile($template);
|
||||
$id = uniqid('', true);
|
||||
$fileName = 'data/cache/template-' . $id;
|
||||
$this->fileManager->putContents($fileName, $code);
|
||||
$renderer = include($fileName);
|
||||
$this->fileManager->removeFile($fileName);
|
||||
|
||||
$data = $this->getDataFromEntity($entity);
|
||||
|
||||
$html = $renderer($data);
|
||||
|
||||
$html = str_replace('?entryPoint=attachment&', '?entryPoint=attachment&', $html);
|
||||
$html = preg_replace('/\?entryPoint=attachment\&id=(.*)/', 'data/upload/$1', $html);
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
@@ -99,6 +99,7 @@ class Importer
|
||||
$usersIds = $duplicate->get('usersIds');
|
||||
$usersIds[] = $userId;
|
||||
$duplicate->set('usersIds', $usersIds);
|
||||
|
||||
$this->getEntityManager()->saveEntity($duplicate);
|
||||
|
||||
if (!empty($teamsIds)) {
|
||||
@@ -136,6 +137,10 @@ class Importer
|
||||
$this->importPartDataToEmail($email, $message, $inlineIds, 'text/plain');
|
||||
}
|
||||
|
||||
if (!$email->get('body') && $email->get('bodyPlain')) {
|
||||
$email->set('body', $email->get('bodyPlain'));
|
||||
}
|
||||
|
||||
$body = $email->get('body');
|
||||
if (!empty($body)) {
|
||||
foreach ($inlineIds as $cid => $attachmentId) {
|
||||
@@ -251,6 +256,15 @@ class Importer
|
||||
$type = strtok($part->contentType, ';');
|
||||
}
|
||||
|
||||
$contentDisposition = false;
|
||||
if (isset($part->ContentDisposition)) {
|
||||
if (strpos(strtolower($part->ContentDisposition), 'attachment') === 0) {
|
||||
$contentDisposition = 'attachment';
|
||||
} else if (strpos(strtolower($part->ContentDisposition), 'inline') === 0) {
|
||||
$contentDisposition = 'inline';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($type)) {
|
||||
if (!empty($defaultContentType)) {
|
||||
$type = $defaultContentType;
|
||||
@@ -260,28 +274,26 @@ class Importer
|
||||
}
|
||||
|
||||
$encoding = null;
|
||||
|
||||
$isAttachment = true;
|
||||
|
||||
if ($type == 'text/plain' || $type == 'text/html') {
|
||||
|
||||
$isAttachment = false;
|
||||
$content = $this->getContentFromPart($part);
|
||||
if ($type == 'text/plain') {
|
||||
if ($email->get('bodyPlain')) {
|
||||
$isAttachment = true;
|
||||
} else {
|
||||
$email->set('bodyPlain', $content);
|
||||
if (!$email->get('body')) {
|
||||
$email->set('body', $content);
|
||||
if ($contentDisposition !== 'inline' && $contentDisposition !== 'attachment') {
|
||||
$isAttachment = false;
|
||||
$content = $this->getContentFromPart($part);
|
||||
if ($type == 'text/plain') {
|
||||
$bodyPlain = '';
|
||||
if ($email->get('bodyPlain')) {
|
||||
$bodyPlain .= $email->get('bodyPlain') . "\n";
|
||||
}
|
||||
}
|
||||
} else if ($type == 'text/html') {
|
||||
if ($email->get('isHtml')) {
|
||||
$isAttachment = true;
|
||||
} else {
|
||||
$email->set('body', $content);
|
||||
$bodyPlain .= $content;
|
||||
$email->set('bodyPlain', $bodyPlain);
|
||||
} else if ($type == 'text/html') {
|
||||
$body = '';
|
||||
if ($email->get('body')) {
|
||||
$body .= $email->get('body') . "<br>";
|
||||
}
|
||||
$body .= $content;
|
||||
$email->set('isHtml', true);
|
||||
$email->set('body', $body);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,16 +305,26 @@ class Importer
|
||||
$fileName = null;
|
||||
$contentId = null;
|
||||
|
||||
if (isset($part->ContentDisposition)) {
|
||||
if (strpos($part->ContentDisposition, 'attachment') === 0) {
|
||||
if ($contentDisposition) {
|
||||
if ($contentDisposition === 'attachment') {
|
||||
if (preg_match('/filename="?([^"]+)"?/i', $part->ContentDisposition, $m)) {
|
||||
$fileName = $m[1];
|
||||
$disposition = 'attachment';
|
||||
}
|
||||
} else if (strpos($part->ContentDisposition, 'inline') === 0) {
|
||||
$contentId = trim($part->contentID, '<>');
|
||||
$fileName = $contentId;
|
||||
$disposition = 'inline';
|
||||
} else if ($contentDisposition === 'inline') {
|
||||
if (isset($part->contentID)) {
|
||||
$contentId = trim($part->contentID, '<>');
|
||||
$fileName = $contentId;
|
||||
$disposition = 'inline';
|
||||
} else {
|
||||
// hack for iOS not proper attachments
|
||||
if (empty($fileName)) {
|
||||
if (preg_match('/filename="?([^"]+)"?/i', $part->ContentDisposition, $m)) {
|
||||
$fileName = $m[1];
|
||||
$disposition = 'attachment';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,37 +10,5 @@ use Zend\Loader\PluginClassLocator;
|
||||
|
||||
class Headers extends \Zend\Mail\Headers
|
||||
{
|
||||
public static function fromString($string, $EOL = self::EOL)
|
||||
{
|
||||
$headers = new static();
|
||||
$currentLine = '';
|
||||
|
||||
// iterate the header lines, some might be continuations
|
||||
foreach (explode($EOL, $string) as $line) {
|
||||
// check if a header name is present
|
||||
if (preg_match('/^(?P<name>[\x21-\x39\x3B-\x7E]+):.*$/', $line, $matches)) {
|
||||
if ($currentLine) {
|
||||
// a header name was present, then store the current complete line
|
||||
$headers->addHeaderLine($currentLine);
|
||||
}
|
||||
$currentLine = trim($line);
|
||||
} elseif (preg_match('/^\s+.*$/', $line, $matches)) {
|
||||
// continuation: append to current line
|
||||
$currentLine .= $line;
|
||||
} elseif (preg_match('/^\s*$/', $line)) {
|
||||
// empty line indicates end of headers
|
||||
break;
|
||||
} else {
|
||||
// Line does not match header format!
|
||||
throw new Exception\RuntimeException(sprintf(
|
||||
'Line "%s"does not match header format!',
|
||||
$line
|
||||
));
|
||||
}
|
||||
}
|
||||
if ($currentLine) {
|
||||
$headers->addHeaderLine($currentLine);
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ class Sender
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function send(Email $email, $params = array())
|
||||
public function send(Email $email, $params = array(), &$message = null)
|
||||
{
|
||||
$message = new Message();
|
||||
$config = $this->config;
|
||||
|
||||
@@ -37,6 +37,7 @@ class Entity extends \Espo\ORM\Entity
|
||||
$collection = $this->get($field, $defs);
|
||||
$ids = array();
|
||||
$names = new \stdClass();
|
||||
$types = new \stdClass();
|
||||
if (!empty($columns)) {
|
||||
$columnsData = new \stdClass();
|
||||
}
|
||||
@@ -46,6 +47,7 @@ class Entity extends \Espo\ORM\Entity
|
||||
$id = $e->id;
|
||||
$ids[] = $id;
|
||||
$names->$id = $e->get('name');
|
||||
$types->$id = $e->get('type');
|
||||
if (!empty($columns)) {
|
||||
$columnsData->$id = new \stdClass();
|
||||
foreach ($columns as $column => $f) {
|
||||
@@ -57,6 +59,7 @@ class Entity extends \Espo\ORM\Entity
|
||||
|
||||
$this->set($field . 'Ids', $ids);
|
||||
$this->set($field . 'Names', $names);
|
||||
$this->set($field . 'Types', $types);
|
||||
if (!empty($columns)) {
|
||||
$this->set($field . 'Columns', $columnsData);
|
||||
}
|
||||
|
||||
50
application/Espo/Core/Pdf/Tcpdf.php
Normal file
50
application/Espo/Core/Pdf/Tcpdf.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 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\Pdf;
|
||||
|
||||
require "vendor/tecnick.com/tcpdf/tcpdf.php";
|
||||
|
||||
class Tcpdf extends \TCPDF
|
||||
{
|
||||
protected $footerHtml = '';
|
||||
|
||||
protected $footerPosition = 15;
|
||||
|
||||
public function setFooterHtml($html)
|
||||
{
|
||||
$this->footerHtml = $html;
|
||||
}
|
||||
|
||||
public function setFooterPosition($position)
|
||||
{
|
||||
$this->footerPosition = $position;
|
||||
}
|
||||
|
||||
public function Footer() {
|
||||
$this->SetY((-1) * $this->footerPosition);
|
||||
|
||||
$html = str_replace('{pageNumber}', '{:pnp:}', $this->footerHtml);
|
||||
$this->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, '', 0, false, 'T');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -226,6 +226,7 @@ class Base
|
||||
$result['whereClause'][] = $part;
|
||||
}
|
||||
$result['joins'] = array_merge($result['joins'], $joins);
|
||||
$result['joins'] = array_unique($result['joins']);
|
||||
$result['distinct'] = true;
|
||||
}
|
||||
|
||||
@@ -313,6 +314,46 @@ class Base
|
||||
}
|
||||
}
|
||||
|
||||
public function manageAccess(&$result)
|
||||
{
|
||||
if (empty($result)) {
|
||||
$result = array();
|
||||
}
|
||||
if (empty($result['joins'])) {
|
||||
$result['joins'] = [];
|
||||
}
|
||||
if (empty($result['leftJoins'])) {
|
||||
$result['leftJoins'] = [];
|
||||
}
|
||||
if (empty($result['whereClause'])) {
|
||||
$result['whereClause'] = array();
|
||||
}
|
||||
if (empty($result['customJoin'])) {
|
||||
$result['customJoin'] = [];
|
||||
}
|
||||
$this->access($result);
|
||||
}
|
||||
|
||||
public function manageTextFilter($textFilter, &$result)
|
||||
{
|
||||
if (empty($result)) {
|
||||
$result = array();
|
||||
}
|
||||
if (empty($result['joins'])) {
|
||||
$result['joins'] = [];
|
||||
}
|
||||
if (empty($result['leftJoins'])) {
|
||||
$result['leftJoins'] = [];
|
||||
}
|
||||
if (empty($result['whereClause'])) {
|
||||
$result['whereClause'] = array();
|
||||
}
|
||||
if (empty($result['customJoin'])) {
|
||||
$result['customJoin'] = [];
|
||||
}
|
||||
$this->q(array('q' => $textFilter), $result);
|
||||
}
|
||||
|
||||
protected function access(&$result)
|
||||
{
|
||||
if ($this->acl->checkReadOnlyOwn($this->entityType)) {
|
||||
@@ -439,6 +480,24 @@ class Base
|
||||
$where['type'] = 'after';
|
||||
$dt->setTimezone(new \DateTimeZone('UTC'));
|
||||
$where['value'] = $dt->format($format);
|
||||
break;
|
||||
case 'lastSevenDays':
|
||||
$where['type'] = 'between';
|
||||
|
||||
$dtFrom = clone $dt;
|
||||
|
||||
$dt->setTimezone(new \DateTimeZone('UTC'));
|
||||
$to = $dt->format($format);
|
||||
|
||||
|
||||
$dtFrom->modify('-7 day');
|
||||
$dtFrom->setTime(0, 0, 0);
|
||||
$dtFrom->setTimezone(new \DateTimeZone('UTC'));
|
||||
|
||||
$from = $dtFrom->format($format);
|
||||
|
||||
$where['value'] = [$from, $to];
|
||||
|
||||
break;
|
||||
case 'on':
|
||||
$where['type'] = 'between';
|
||||
@@ -568,6 +627,15 @@ class Base
|
||||
case 'future':
|
||||
$part[$item['field'] . '>='] = date('Y-m-d');
|
||||
break;
|
||||
case 'lastSevenDays':
|
||||
$dt1 = new \DateTime();
|
||||
$dt2 = clone $dt1;
|
||||
$dt2->modify('-7 days');
|
||||
$part['AND'] = array(
|
||||
$item['field'] . '>=' => $dt2->format('Y-m-d'),
|
||||
$item['field'] . '<=' => $dt1->format('Y-m-d'),
|
||||
);
|
||||
break;
|
||||
case 'currentMonth':
|
||||
$dt = new \DateTime();
|
||||
$part['AND'] = array(
|
||||
|
||||
@@ -25,19 +25,19 @@ namespace Espo\Core\Utils;
|
||||
class Crypt
|
||||
{
|
||||
private $config;
|
||||
|
||||
|
||||
private $key = null;
|
||||
|
||||
|
||||
private $cryptKey = null;
|
||||
|
||||
private $iv = null;
|
||||
|
||||
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->cryptKey = $config->get('cryptKey', '');
|
||||
}
|
||||
|
||||
|
||||
protected function getKey()
|
||||
{
|
||||
if (empty($this->key)) {
|
||||
@@ -53,13 +53,13 @@ class Crypt
|
||||
}
|
||||
return $this->iv;
|
||||
}
|
||||
|
||||
|
||||
public function encrypt($string)
|
||||
{
|
||||
$iv = $this->getIv();
|
||||
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->getKey(), $string, MCRYPT_MODE_CBC, $iv) . $iv);
|
||||
}
|
||||
|
||||
|
||||
public function decrypt($encryptedString)
|
||||
{
|
||||
$encryptedString = base64_decode($encryptedString);
|
||||
@@ -68,7 +68,7 @@ class Crypt
|
||||
$iv = substr($encryptedString, -16);
|
||||
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->getKey(), $string, MCRYPT_MODE_CBC, $iv));
|
||||
}
|
||||
|
||||
|
||||
public function generateKey()
|
||||
{
|
||||
return md5(uniqid());
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 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 AttachmentMultiple extends Base
|
||||
{
|
||||
protected function load($fieldName, $entityType)
|
||||
{
|
||||
$data = array(
|
||||
$entityType => array (
|
||||
'fields' => array(
|
||||
$fieldName.'Ids' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true
|
||||
),
|
||||
$fieldName.'Names' => array(
|
||||
'type' => 'varchar',
|
||||
'notStorable' => true
|
||||
),
|
||||
)
|
||||
),
|
||||
'unset' => array(
|
||||
$entityType => array(
|
||||
'fields.'.$fieldName,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ class Attachments extends HasChildren
|
||||
$entityName => array (
|
||||
'fields' => array(
|
||||
$linkName.'Types' => array(
|
||||
'type' => 'varchar',
|
||||
'type' => 'jsonObject',
|
||||
'notStorable' => true,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -134,6 +134,7 @@ class EntityManager
|
||||
$scopesData['stream'] = $stream;
|
||||
$scopesData['type'] = $type;
|
||||
$scopesData['module'] = 'Custom';
|
||||
$scopesData['object'] = true;
|
||||
$scopesData['isCustom'] = true;
|
||||
|
||||
$this->getMetadata()->set('scopes', $name, $scopesData);
|
||||
@@ -277,6 +278,12 @@ class EntityManager
|
||||
throw new Conflict('Link ['.$entityForeign.'::'.$linkForeign.'] already exists.');
|
||||
}
|
||||
|
||||
if ($entity === $entityForeign) {
|
||||
if ($link === ucfirst($entity) || $linkForeign === ucfirst($entity)) {
|
||||
throw new Conflict();
|
||||
}
|
||||
}
|
||||
|
||||
switch ($linkType) {
|
||||
case 'oneToMany':
|
||||
if ($this->getMetadata()->get('entityDefs.' . $entityForeign . '.field.' . $linkForeign)) {
|
||||
|
||||
@@ -66,23 +66,31 @@ class Layout
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
protected function sanitizeInput($name)
|
||||
{
|
||||
return preg_replace("([\.]{2,})", '', $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Layout context
|
||||
*
|
||||
* @param $controller
|
||||
* @param $scope
|
||||
* @param $name
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
public function get($controller, $name)
|
||||
public function get($scope, $name)
|
||||
{
|
||||
if (isset($this->changedData[$controller][$name])) {
|
||||
return Json::encode($this->changedData[$controller][$name]);
|
||||
$scope = $this->sanitizeInput($scope);
|
||||
$name = $this->sanitizeInput($name);
|
||||
|
||||
if (isset($this->changedData[$scope][$name])) {
|
||||
return Json::encode($this->changedData[$scope][$name]);
|
||||
}
|
||||
|
||||
$fileFullPath = Util::concatPath($this->getLayoutPath($controller, true), $name.'.json');
|
||||
$fileFullPath = Util::concatPath($this->getLayoutPath($scope, true), $name.'.json');
|
||||
if (!file_exists($fileFullPath)) {
|
||||
$fileFullPath = Util::concatPath($this->getLayoutPath($controller), $name.'.json');
|
||||
$fileFullPath = Util::concatPath($this->getLayoutPath($scope), $name.'.json');
|
||||
}
|
||||
|
||||
if (!file_exists($fileFullPath)) {
|
||||
@@ -101,21 +109,39 @@ class Layout
|
||||
|
||||
/**
|
||||
* Set Layout data
|
||||
* Ex. $controller = Account, $name = detail then will be created a file layoutFolder/Account/detail.json
|
||||
* Ex. $scope = Account, $name = detail then will be created a file layoutFolder/Account/detail.json
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $controller - ex. Account
|
||||
* @param string $scope - ex. Account
|
||||
* @param string $name - detail
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($data, $controller, $name)
|
||||
public function set($data, $scope, $name)
|
||||
{
|
||||
if (empty($controller) || empty($name)) {
|
||||
$scope = $this->sanitizeInput($scope);
|
||||
$name = $this->sanitizeInput($name);
|
||||
|
||||
if (empty($scope) || empty($name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->changedData[$controller][$name] = $data;
|
||||
$this->changedData[$scope][$name] = $data;
|
||||
}
|
||||
|
||||
public function resetToDefault($scope, $name)
|
||||
{
|
||||
$scope = $this->sanitizeInput($scope);
|
||||
$name = $this->sanitizeInput($name);
|
||||
|
||||
$filePath = 'custom/Espo/Custom/Resources/layouts/' . $scope . '/' . $name . '.json';
|
||||
if ($this->getFileManager()->isFile($filePath)) {
|
||||
$this->getFileManager()->removeFile($filePath);
|
||||
}
|
||||
if (!empty($this->changedData[$scope]) && !empty($this->changedData[$scope][$name])) {
|
||||
unset($this->changedData[$scope][$name]);
|
||||
}
|
||||
return $this->get($scope, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,14 +154,14 @@ class Layout
|
||||
$result = true;
|
||||
|
||||
if (!empty($this->changedData)) {
|
||||
foreach ($this->changedData as $controllerName => $rowData) {
|
||||
foreach ($this->changedData as $scope => $rowData) {
|
||||
foreach ($rowData as $layoutName => $layoutData) {
|
||||
|
||||
if (empty($controllerName) || empty($layoutName)) {
|
||||
if (empty($scope) || empty($layoutName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$layoutPath = $this->getLayoutPath($controllerName, true);
|
||||
$layoutPath = $this->getLayoutPath($scope, true);
|
||||
$data = Json::encode($layoutData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
|
||||
$result &= $this->getFileManager()->putContents(array($layoutPath, $layoutName.'.json'), $data);
|
||||
@@ -162,17 +188,20 @@ class Layout
|
||||
|
||||
/**
|
||||
* Merge layout data
|
||||
* Ex. $controller= Account, $name= detail then will be created a file layoutFolder/Account/detail.json
|
||||
* Ex. $scope= Account, $name= detail then will be created a file layoutFolder/Account/detail.json
|
||||
*
|
||||
* @param JSON string $data
|
||||
* @param string $controller - ex. Account
|
||||
* @param string $scope - ex. Account
|
||||
* @param string $name - detail
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function merge($data, $controller, $name)
|
||||
public function merge($data, $scope, $name)
|
||||
{
|
||||
$prevData = $this->get($controller, $name);
|
||||
$scope = $this->sanitizeInput($scope);
|
||||
$name = $this->sanitizeInput($name);
|
||||
|
||||
$prevData = $this->get($scope, $name);
|
||||
|
||||
$prevDataArray = Json::getArrayData($prevData);
|
||||
$dataArray = Json::getArrayData($data);
|
||||
@@ -180,7 +209,7 @@ class Layout
|
||||
$data = Util::merge($prevDataArray, $dataArray);
|
||||
$data = Json::encode($data);
|
||||
|
||||
return $this->set($data, $controller, $name);
|
||||
return $this->set($data, $scope, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,9 +237,4 @@ class Layout
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -478,8 +478,7 @@ class Metadata
|
||||
}
|
||||
}
|
||||
|
||||
krsort($modulesToSort);
|
||||
asort($modulesToSort);
|
||||
array_multisort(array_values($modulesToSort), SORT_ASC, array_keys($modulesToSort), SORT_ASC, $modulesToSort);
|
||||
|
||||
$this->moduleList = array_keys($modulesToSort);
|
||||
}
|
||||
|
||||
60
application/Espo/Core/Utils/Number.php
Normal file
60
application/Espo/Core/Utils/Number.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 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;
|
||||
|
||||
class Number
|
||||
{
|
||||
protected $decimalMark;
|
||||
|
||||
protected $thousandSeparator;
|
||||
|
||||
public function __construct($decimalMark = '.', $thousandSeparator = ',')
|
||||
{
|
||||
$this->decimalMark = $decimalMark;
|
||||
$this->thousandSeparator = $thousandSeparator;
|
||||
}
|
||||
|
||||
public function format($value, $decimals = null)
|
||||
{
|
||||
if (!is_null($decimals)) {
|
||||
return number_format($value, $decimals, $this->decimalMark, $this->thousandSeparator);
|
||||
} else {
|
||||
$s = strval($value);
|
||||
$arr = explode('.', $value);
|
||||
|
||||
$r = '0';
|
||||
if (!empty($arr[0])) {
|
||||
$r = number_format(intval($arr[0]), 0, '.', $this->thousandSeparator);
|
||||
}
|
||||
|
||||
if (!empty($arr[1])) {
|
||||
$r = $r . $this->decimalMark . $arr[1];
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
52
application/Espo/Core/Utils/ThemeManager.php
Normal file
52
application/Espo/Core/Utils/ThemeManager.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 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;
|
||||
|
||||
class ThemeManager
|
||||
{
|
||||
protected $config;
|
||||
|
||||
protected $metadata;
|
||||
|
||||
private $defaultName = 'Espo';
|
||||
|
||||
private $defaultStylesheet = 'Espo';
|
||||
|
||||
public function __construct(Config $config, Metadata $metadata)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->config->get('theme', $this->defaultName);
|
||||
}
|
||||
|
||||
public function getStylesheet()
|
||||
{
|
||||
return $this->metadata->get('themes.' . $this->getName() . '.stylesheet', 'client/css/espo.css');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ return array (
|
||||
"tabList" => array("Account", "Contact", "Lead", "Opportunity", "Calendar", "Meeting", "Call", "Task", "Case", "Email", "Document", "Campaign"),
|
||||
"quickCreateList" => array("Account", "Contact", "Lead", "Opportunity", "Meeting", "Call", "Task", "Case"),
|
||||
'calendarDefaultEntity' => 'Meeting',
|
||||
'disableExport' => false,
|
||||
'exportDisabled' => false,
|
||||
'assignmentEmailNotifications' => false,
|
||||
'assignmentEmailNotificationsEntityList' => array('Lead', 'Opportunity', 'Task', 'Case'),
|
||||
'assignmentNotificationsEntityList' => array('Meeting', 'Call', 'Task', 'Email'),
|
||||
@@ -101,6 +101,8 @@ return array (
|
||||
'maxEmailAccountCount' => 2,
|
||||
'followCreatedEntities' => false,
|
||||
'b2cMode' => false,
|
||||
'restrictedMode' => false,
|
||||
'theme' => 'Espo',
|
||||
'isInstalled' => false,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[{
|
||||
"label":"",
|
||||
"rows": [
|
||||
[{"name":"name"}]
|
||||
[{"name":"name", "fullWidth": true}, false]
|
||||
]
|
||||
}]
|
||||
|
||||
@@ -84,14 +84,14 @@ return array (
|
||||
'permissionMap',
|
||||
'permissionRules',
|
||||
'passwordSalt',
|
||||
'cryptKey'
|
||||
'cryptKey',
|
||||
'restrictedMode',
|
||||
'userLimit',
|
||||
'stylesheet'
|
||||
),
|
||||
'adminItems' =>
|
||||
array (
|
||||
'devMode',
|
||||
'outboundEmailIsShared',
|
||||
'outboundEmailFromName',
|
||||
'outboundEmailFromAddress',
|
||||
'smtpServer',
|
||||
'smtpPort',
|
||||
'smtpAuth',
|
||||
|
||||
28
application/Espo/Entities/Template.php
Normal file
28
application/Espo/Entities/Template.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 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;
|
||||
|
||||
class Template extends \Espo\Core\ORM\Entity
|
||||
{
|
||||
|
||||
}
|
||||
@@ -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\EntryPoints;
|
||||
|
||||
@@ -29,7 +29,7 @@ use \Espo\Core\Exceptions\BadRequest;
|
||||
class ChangePassword extends \Espo\Core\EntryPoints\Base
|
||||
{
|
||||
public static $authRequired = false;
|
||||
|
||||
|
||||
public function run()
|
||||
{
|
||||
$requestId = $_GET['id'];
|
||||
@@ -38,6 +38,7 @@ class ChangePassword extends \Espo\Core\EntryPoints\Base
|
||||
}
|
||||
|
||||
$config = $this->getConfig();
|
||||
$themeManager = $this->getThemeManager();
|
||||
|
||||
$p = $this->getEntityManager()->getRepository('PasswordChangeRequest')->where(array(
|
||||
'requestId' => $requestId
|
||||
@@ -56,9 +57,15 @@ class ChangePassword extends \Espo\Core\EntryPoints\Base
|
||||
$html = file_get_contents('main.html');
|
||||
$html = str_replace('{{cacheTimestamp}}', $config->get('cacheTimestamp', 0), $html);
|
||||
$html = str_replace('{{useCache}}', $config->get('useCache') ? 'true' : 'false' , $html);
|
||||
$html = str_replace('{{stylesheet}}', $themeManager->getStylesheet(), $html);
|
||||
$html = str_replace('{{runScript}}', $runScript , $html);
|
||||
echo $html;
|
||||
exit;
|
||||
}
|
||||
|
||||
protected function getThemeManager()
|
||||
{
|
||||
return $this->getContainer()->get('themeManager');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,10 +43,10 @@ class Download extends \Espo\Core\EntryPoints\Base
|
||||
|
||||
public function run()
|
||||
{
|
||||
$id = $_GET['id'];
|
||||
if (empty($id)) {
|
||||
if (empty($_GET['id'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$id = $_GET['id'];
|
||||
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment', $id);
|
||||
|
||||
|
||||
@@ -30,13 +30,13 @@ use \Espo\Core\Exceptions\Error;
|
||||
class Image extends \Espo\Core\EntryPoints\Base
|
||||
{
|
||||
public static $authRequired = true;
|
||||
|
||||
|
||||
protected $allowedFileTypes = array(
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
);
|
||||
|
||||
|
||||
protected $imageSizes = array(
|
||||
'xxx-small' => array(18, 18),
|
||||
'xx-small' => array(32, 32),
|
||||
@@ -47,59 +47,58 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
'x-large' => array(864, 864),
|
||||
'xx-large' => array(1024, 1024),
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
public function run()
|
||||
{
|
||||
if (empty($_GET['id'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$id = $_GET['id'];
|
||||
|
||||
|
||||
$size = null;
|
||||
if (!empty($_GET['size'])) {
|
||||
$size = $_GET['size'];
|
||||
}
|
||||
|
||||
|
||||
$this->show($id, $size);
|
||||
}
|
||||
|
||||
|
||||
protected function show($id, $size)
|
||||
{
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment', $id);
|
||||
|
||||
|
||||
if (!$attachment) {
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
|
||||
if ($attachment->get('parentId') && $attachment->get('parentType')) {
|
||||
$parent = $this->getEntityManager()->getEntity($attachment->get('parentType'), $attachment->get('parentId'));
|
||||
if ($parent && !$this->getAcl()->check($parent)) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$filePath = "data/upload/{$attachment->id}";
|
||||
|
||||
|
||||
$fileType = $attachment->get('type');
|
||||
|
||||
|
||||
if (!file_exists($filePath)) {
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
|
||||
if (!in_array($fileType, $this->allowedFileTypes)) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
|
||||
if (!empty($size)) {
|
||||
if (!empty($this->imageSizes[$size])) {
|
||||
$thumbFilePath = "data/upload/thumbs/{$attachment->id}_{$size}";
|
||||
|
||||
|
||||
if (!file_exists($thumbFilePath)) {
|
||||
$targetImage = $this->getThumbImage($filePath, $fileType, $size);
|
||||
ob_start();
|
||||
|
||||
|
||||
switch ($fileType) {
|
||||
case 'image/jpeg':
|
||||
imagejpeg($targetImage);
|
||||
@@ -117,12 +116,12 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
$this->getContainer()->get('fileManager')->putContents($thumbFilePath, $contents);
|
||||
}
|
||||
$filePath = $thumbFilePath;
|
||||
|
||||
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!empty($size)) {
|
||||
$fileName = $attachment->id . '_' . $size . '.jpg';
|
||||
} else {
|
||||
@@ -143,12 +142,12 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
readfile($filePath);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
protected function getThumbImage($filePath, $fileType, $size)
|
||||
{
|
||||
list($originalWidth, $originalHeight) = getimagesize($filePath);
|
||||
list($width, $height) = $this->imageSizes[$size];
|
||||
|
||||
|
||||
if ($originalWidth <= $width && $originalHeight <= $height) {
|
||||
$targetWidth = $originalWidth;
|
||||
$targetHeight = $originalHeight;
|
||||
@@ -169,7 +168,7 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
|
||||
switch ($fileType) {
|
||||
case 'image/jpeg':
|
||||
@@ -189,8 +188,8 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return $targetImage;
|
||||
}
|
||||
}
|
||||
|
||||
95
application/Espo/EntryPoints/Pdf.php
Normal file
95
application/Espo/EntryPoints/Pdf.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 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\EntryPoints;
|
||||
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use \Espo\Core\Htmlizer\Htmlizer;
|
||||
|
||||
|
||||
class Pdf extends \Espo\Core\EntryPoints\Base
|
||||
{
|
||||
public static $authRequired = true;
|
||||
|
||||
public function run()
|
||||
{
|
||||
|
||||
if (empty($_GET['entityId']) || empty($_GET['entityType']) || empty($_GET['templateId'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$entityId = $_GET['entityId'];
|
||||
$entityType = $_GET['entityType'];
|
||||
$templateId = $_GET['templateId'];
|
||||
|
||||
$entity = $this->getEntityManager()->getEntity($entityType, $entityId);
|
||||
$template = $this->getEntityManager()->getEntity('Template', $templateId);
|
||||
|
||||
$this->getContainer()->get('serviceFactory')->create($entityType)->loadAdditionalFields($entity);
|
||||
|
||||
if (!$entity || !$template) {
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
if ($template->get('entityType') !== $entityType) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
if (!$this->getAcl()->check($entity, 'read') || !$this->getAcl()->check($template, 'read')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$fileName = $entity->get('name') . '.pdf';
|
||||
|
||||
$htmlizer = new Htmlizer($this->getFileManager(), $this->getDateTime(), $this->getNumber());
|
||||
|
||||
$pdf = new \Espo\Core\Pdf\Tcpdf();
|
||||
$pdf->setFont('freesans', '', 12, '', true);
|
||||
$pdf->setPrintHeader(false);
|
||||
|
||||
$pdf->setAutoPageBreak(true, $template->get('bottomMargin'));
|
||||
$pdf->setMargins($template->get('leftMargin'), $template->get('topMargin'), $template->get('rightMargin'));
|
||||
|
||||
|
||||
if ($template->get('printFooter')) {
|
||||
$htmlFooter = $htmlizer->render($entity, $template->get('footer'));
|
||||
$pdf->setFooterPosition($template->get('footerPosition'));
|
||||
$pdf->setFooterHtml($htmlFooter);
|
||||
} else {
|
||||
$pdf->setPrintFooter(false);
|
||||
}
|
||||
|
||||
$pdf->addPage();
|
||||
|
||||
$htmlHeader = $htmlizer->render($entity, $template->get('header'));
|
||||
$pdf->writeHTML($htmlHeader, true, false, true, false, '');
|
||||
|
||||
$htmlBody = $htmlizer->render($entity, $template->get('body'));
|
||||
$pdf->writeHTML($htmlBody, true, false, true, false, '');
|
||||
|
||||
$pdf->output($fileName);
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@ class Notifications extends \Espo\Core\Hooks\Base
|
||||
{
|
||||
public static $order = 10;
|
||||
|
||||
protected $noticatorsHash = array();
|
||||
protected $notifatorsHash = array();
|
||||
|
||||
private $streamService;
|
||||
|
||||
protected function init()
|
||||
{
|
||||
@@ -44,6 +46,11 @@ class Notifications extends \Espo\Core\Hooks\Base
|
||||
return $this->getInjection('container');
|
||||
}
|
||||
|
||||
protected function getServiceFactory()
|
||||
{
|
||||
return $this->getContainer()->get('serviceFactory');
|
||||
}
|
||||
|
||||
protected function getMetadata()
|
||||
{
|
||||
return $this->getInjection('metadata');
|
||||
@@ -59,7 +66,7 @@ class Notifications extends \Espo\Core\Hooks\Base
|
||||
|
||||
protected function getNotificator($entityType)
|
||||
{
|
||||
if (empty($this->noticatorsHash[$entityType])) {
|
||||
if (empty($this->notifatorsHash[$entityType])) {
|
||||
$normalizedName = Util::normilizeClassName($entityType);
|
||||
|
||||
$className = '\\Espo\\Custom\\Notificators\\' . $normalizedName;
|
||||
@@ -81,19 +88,19 @@ class Notifications extends \Espo\Core\Hooks\Base
|
||||
$notificator->inject($name, $this->getContainer()->get($name));
|
||||
}
|
||||
|
||||
$this->noticatorsHash[$entityType] = $notificator;
|
||||
$this->notifatorsHash[$entityType] = $notificator;
|
||||
}
|
||||
return $this->noticatorsHash[$entityType];
|
||||
return $this->notifatorsHash[$entityType];
|
||||
}
|
||||
|
||||
public function afterSave(Entity $entity, array $options = array())
|
||||
{
|
||||
$entityType = $entity->getEntityType();
|
||||
|
||||
if (!empty($options['silent']) && !empty($options['noNotifications'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$entityType = $entity->getEntityType();
|
||||
|
||||
if (!$this->checkHasStream($entityType)) {
|
||||
if (in_array($entityType, $this->getConfig()->get('assignmentNotificationsEntityList', []))) {
|
||||
$notificator = $this->getNotificator($entityType);
|
||||
@@ -102,5 +109,43 @@ class Notifications extends \Espo\Core\Hooks\Base
|
||||
}
|
||||
}
|
||||
|
||||
public function beforeRemove(Entity $entity, array $options = array())
|
||||
{
|
||||
if (!empty($options['silent']) && !empty($options['noNotifications'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$entityType = $entity->getEntityType();
|
||||
if ($this->checkHasStream($entityType)) {
|
||||
$followersData = $this->getStreamService()->getEntityFollowers($entity);
|
||||
foreach ($followersData['idList'] as $userId) {
|
||||
if ($userId === $this->getUser()->id) {
|
||||
continue;
|
||||
}
|
||||
$notification = $this->getEntityManager()->getEntity('Notification');
|
||||
$notification->set(array(
|
||||
'userId' => $userId,
|
||||
'type' => 'EntityRemoved',
|
||||
'data' => array(
|
||||
'entityType' => $entity->getEntityType(),
|
||||
'entityId' => $entity->id,
|
||||
'entityName' => $entity->get('name'),
|
||||
'userId' => $this->getUser()->id,
|
||||
'userName' => $this->getUser()->get('name')
|
||||
)
|
||||
));
|
||||
$this->getEntityManager()->saveEntity($notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getStreamService()
|
||||
{
|
||||
if (empty($this->streamService)) {
|
||||
$this->streamService = $this->getServiceFactory()->create('Stream');
|
||||
}
|
||||
return $this->streamService;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ class Stream extends \Espo\Core\Hooks\Base
|
||||
|
||||
protected function getAutofollowUserIdList(Entity $entity, array $ignoreList = array())
|
||||
{
|
||||
$entityType = $entity->getEntityName();
|
||||
$entityType = $entity->getEntityType();
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
$userIdList = [];
|
||||
|
||||
@@ -160,7 +160,7 @@ class Stream extends \Espo\Core\Hooks\Base
|
||||
|
||||
public function afterSave(Entity $entity, array $options = array())
|
||||
{
|
||||
$entityName = $entity->getEntityName();
|
||||
$entityName = $entity->getEntityType();
|
||||
|
||||
if ($this->checkHasStream($entity)) {
|
||||
if ($entity->isNew()) {
|
||||
|
||||
@@ -40,7 +40,7 @@ class Cleanup extends \Espo\Core\Jobs\Base
|
||||
|
||||
protected function cleanupJobs()
|
||||
{
|
||||
$query = "DELETE FROM `job` WHERE DATE(modified_at) < '".$this->getDate()."' ";
|
||||
$query = "DELETE FROM `job` WHERE DATE(modified_at) < '".$this->getCleanupFromDate()."' AND status <> 'Pending'";
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
$sth = $pdo->prepare($query);
|
||||
@@ -64,14 +64,14 @@ class Cleanup extends \Espo\Core\Jobs\Base
|
||||
|
||||
$delSql = "DELETE FROM `scheduled_job_log_record`
|
||||
WHERE scheduled_job_id = '".$id."'
|
||||
AND DATE(created_at) < '".$this->getDate()."'
|
||||
AND DATE(created_at) < '".$this->getCleanupFromDate()."'
|
||||
AND id NOT IN ('".implode("', '", $lastRowIds)."')
|
||||
";
|
||||
$pdo->query($delSql);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getDate($format = 'Y-m-d')
|
||||
protected function getCleanupFromDate($format = 'Y-m-d')
|
||||
{
|
||||
$datetime = new \DateTime();
|
||||
$datetime->modify($this->period);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
@@ -27,16 +27,16 @@ use \Espo\ORM\Entity;
|
||||
class EmailReminder
|
||||
{
|
||||
protected $entityManager;
|
||||
|
||||
|
||||
protected $mailSender;
|
||||
|
||||
|
||||
protected $config;
|
||||
|
||||
|
||||
protected $dateTime;
|
||||
|
||||
|
||||
protected $language;
|
||||
|
||||
|
||||
|
||||
|
||||
public function __construct($entityManager, $mailSender, $config, $dateTime, $language)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
@@ -45,17 +45,17 @@ class EmailReminder
|
||||
$this->dateTime = $dateTime;
|
||||
$this->language = $language;
|
||||
}
|
||||
|
||||
|
||||
protected function getEntityManager()
|
||||
{
|
||||
return $this->entityManager;
|
||||
}
|
||||
|
||||
|
||||
protected function parseInvitationTemplate($contents, $entity, $user = null)
|
||||
{
|
||||
|
||||
|
||||
$contents = str_replace('{eventType}', strtolower($this->language->translate($entity->getEntityName(), 'scopeNames')), $contents);
|
||||
|
||||
|
||||
$preferences = $this->getEntityManager()->getEntity('Preferences', $user->id);
|
||||
$timezone = $preferences->get('timeZone');
|
||||
|
||||
@@ -103,7 +103,7 @@ class EmailReminder
|
||||
|
||||
return file_get_contents($fileName);
|
||||
}
|
||||
|
||||
|
||||
public function send(Entity $reminder)
|
||||
{
|
||||
$user = $this->getEntityManager()->getEntity('User', $reminder->get('userId'));
|
||||
@@ -123,7 +123,7 @@ class EmailReminder
|
||||
|
||||
$subject = $this->parseInvitationTemplate($subjectTpl, $entity, $user);
|
||||
$subject = str_replace(array("\n", "\r"), '', $subject);
|
||||
|
||||
|
||||
$body = $this->parseInvitationTemplate($bodyTpl, $entity, $user);
|
||||
|
||||
$email->set('subject', $subject);
|
||||
@@ -134,7 +134,7 @@ class EmailReminder
|
||||
$emailSender = $this->mailSender;
|
||||
|
||||
$emailSender->send($email);
|
||||
|
||||
|
||||
$this->getEntityManager()->removeEntity($email);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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\Modules\Crm\Controllers;
|
||||
|
||||
@@ -27,16 +27,19 @@ use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class Lead extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
public function actionConvert($params, $data)
|
||||
{
|
||||
public function actionConvert($params, $data, $request)
|
||||
{
|
||||
if (empty($data['id'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$entity = $this->getRecordService()->convert($data['id'], $data['records']);
|
||||
|
||||
|
||||
if (!empty($entity)) {
|
||||
return $entity->toArray();
|
||||
}
|
||||
throw new Error();
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class CheckEmailAccounts extends \Espo\Core\Jobs\Base
|
||||
try {
|
||||
$service->fetchFromMailServer($entity);
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('Job CheckEmailAccounts: [' . $e->getCode() . '] ' .$e->getMessage());
|
||||
$GLOBALS['log']->error('Job CheckEmailAccounts '.$entity->id.': [' . $e->getCode() . '] ' .$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class CheckInboundEmails extends \Espo\Core\Jobs\Base
|
||||
try {
|
||||
$service->fetchFromMailServer($entity);
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('Job CheckInboundEmails: [' . $e->getCode() . '] ' .$e->getMessage());
|
||||
$GLOBALS['log']->error('Job CheckInboundEmails '.$entity->id.': [' . $e->getCode() . '] ' .$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
67
application/Espo/Modules/Crm/Repositories/CaseObj.php
Normal file
67
application/Espo/Modules/Crm/Repositories/CaseObj.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 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 CaseObj extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
public function afterSave(Entity $entity, array $options)
|
||||
{
|
||||
$result = parent::afterSave($entity, $options);
|
||||
$this->handleAfterSaveContacts($entity, $options);
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function handleAfterSaveContacts(Entity $entity, array $options)
|
||||
{
|
||||
$contactIdChanged = $entity->has('contactId') && $entity->get('contactId') != $entity->getFetched('contactId');
|
||||
|
||||
if ($contactIdChanged) {
|
||||
$contactId = $entity->get('contactId');
|
||||
if (empty($contactId)) {
|
||||
$this->unrelate($entity, 'contacts', $entity->getFetched('contactId'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($contactIdChanged) {
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$sql = "
|
||||
SELECT id FROM case_contact
|
||||
WHERE
|
||||
contact_id = ".$pdo->quote($contactId)." AND
|
||||
case_id = ".$pdo->quote($entity->id)." AND
|
||||
deleted = 0
|
||||
";
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
|
||||
if (!$sth->fetch()) {
|
||||
$this->relate($entity, 'contacts', $contactId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,17 @@ class Contact extends \Espo\Core\ORM\Repositories\RDB
|
||||
public function afterSave(Entity $entity, array $options)
|
||||
{
|
||||
$result = parent::afterSave($entity, $options);
|
||||
$this->handleAfterSaveAccounts($entity, $options);
|
||||
|
||||
if ($entity->has('targetListId') && $entity->isNew()) {
|
||||
$this->relate($entity, 'targetLists', $entity->get('targetListId'));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function handleAfterSaveAccounts(Entity $entity, array $options)
|
||||
{
|
||||
$accountIdChanged = $entity->has('accountId') && $entity->get('accountId') != $entity->getFetched('accountId');
|
||||
$titleChanged = $entity->has('title') && $entity->get('title') != $entity->getFetched('title');
|
||||
|
||||
@@ -51,7 +61,7 @@ class Contact extends \Espo\Core\ORM\Repositories\RDB
|
||||
$accountId = $entity->get('accountId');
|
||||
if (empty($accountId)) {
|
||||
$this->unrelate($entity, 'accounts', $entity->getFetched('accountId'));
|
||||
return $result;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +69,7 @@ class Contact extends \Espo\Core\ORM\Repositories\RDB
|
||||
if (empty($accountId)) {
|
||||
$accountId = $entity->getFetched('accountId');
|
||||
if (empty($accountId)) {
|
||||
return $result;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,12 +101,6 @@ class Contact extends \Espo\Core\ORM\Repositories\RDB
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->has('targetListId') && $entity->isNew()) {
|
||||
$this->relate($entity, 'targetLists', $entity->get('targetListId'));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,8 +91,6 @@ class Meeting extends \Espo\Core\ORM\Repositories\RDB
|
||||
}
|
||||
|
||||
return $reminders;
|
||||
|
||||
$entity->set('reminders', $reminders);
|
||||
}
|
||||
|
||||
protected function afterSave(Entity $entity, array $options)
|
||||
|
||||
@@ -10,16 +10,21 @@
|
||||
"sicCode": "WKN Nummer",
|
||||
"industry": "Branche",
|
||||
"type": "Typ",
|
||||
"contactRole": "Rolle"
|
||||
"contactRole": "Funktion",
|
||||
"campaign": "Kampagne"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Kontakte",
|
||||
"opportunities": "Verkaufschancen",
|
||||
"cases": "Fälle",
|
||||
"documents": "Dokumente",
|
||||
"meetingsPrimary": "Meetings (intern)",
|
||||
"callsPrimary": "Anrufe (intern)",
|
||||
"tasksPrimary": "Aufgaben (intern)"
|
||||
"meetingsPrimary": "Meetings (erweitert)",
|
||||
"callsPrimary": "Anrufe (erweitert)",
|
||||
"tasksPrimary": "Aufgaben (erweitert)",
|
||||
"emailsPrimary": "E-Mails (erweitert)",
|
||||
"targetLists": "Kontaktlisten",
|
||||
"campaignLogRecords": "Kampagnen Log",
|
||||
"campaign": "Kampagne"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
@@ -49,7 +54,7 @@
|
||||
"Real Estate": "Immobilien",
|
||||
"Service": "Dienstleistung",
|
||||
"Sports": "Sport",
|
||||
"Sofware": "Software",
|
||||
"Software": "Software",
|
||||
"Technology": "Technologie",
|
||||
"Telecommunications": "Telekommunikation",
|
||||
"Television": "Fernsehen",
|
||||
@@ -60,5 +65,9 @@
|
||||
"labels": {
|
||||
"Create Account": "Firma erstellen",
|
||||
"Copy Billing": "Rechnungsadresse kopieren"
|
||||
},
|
||||
"presetFilters": {
|
||||
"customers": "Kunden",
|
||||
"partners": "Partner"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"layouts": {
|
||||
"detailConvert": "Interessent umwandeln"
|
||||
"detailConvert": "Interessent umwandeln",
|
||||
"listForAccount": "Liste (für Firma)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
"reminders": "Erinnerungen",
|
||||
"account": "Firma"
|
||||
},
|
||||
"links": {},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Geplant",
|
||||
@@ -32,6 +33,10 @@
|
||||
"Tentative": "Mit Vorbehalt"
|
||||
}
|
||||
},
|
||||
"massActions": {
|
||||
"setHeld": "Auf gehalten setzen",
|
||||
"setNotHeld": "Auf nicht gehalten setzen"
|
||||
},
|
||||
"labels": {
|
||||
"Create Call": "Anruf erstellen",
|
||||
"Set Held": "Auf gehalten setzen",
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"description": "Beschreibung",
|
||||
"status": "Status",
|
||||
"type": "Typ",
|
||||
"startDate": "Startdatum",
|
||||
"endDate": "Enddatum",
|
||||
"targetLists": "Kontaktlisten",
|
||||
"sentCount": "Gesendet",
|
||||
"openedCount": "Geöffnet",
|
||||
"clickedCount": "Geklickt",
|
||||
"optedOutCount": "Keine E-Mails",
|
||||
"bouncedCount": "Nicht zustellbar",
|
||||
"hardBouncedCount": "Hard Bounced",
|
||||
"softBouncedCount": "Soft Bounced",
|
||||
"leadCreatedCount": "Erstellte Interessenten",
|
||||
"revenue": "Umsatz",
|
||||
"revenueConverted": "Umsatz (konvertiert)"
|
||||
},
|
||||
"links": {
|
||||
"targetLists": "Kontaktlisten",
|
||||
"accounts": "Firmen",
|
||||
"contacts": "Kontakte",
|
||||
"leads": "Interessenten",
|
||||
"opportunities": "Verkaufschancen",
|
||||
"campaignLogRecords": "Protokoll"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
"Email": "E-Mail",
|
||||
"Web": "Web",
|
||||
"Television": "Fernsehen",
|
||||
"Radio": "Radio Button",
|
||||
"Newsletter": "Newsletter",
|
||||
"Mail": "Mail"
|
||||
},
|
||||
"status": {
|
||||
"Planning": "Planung",
|
||||
"Active": "Aktiv",
|
||||
"Inactive": "Inaktiv",
|
||||
"Complete": "Fertig"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create Campaign": "Neue Kampagne",
|
||||
"Target Lists": "Kontaktlisten",
|
||||
"Statistics": "Statistik",
|
||||
"hard": "hart",
|
||||
"soft": "weich"
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Aktiv"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"fields": {
|
||||
"action": "Aktion",
|
||||
"actionDate": "Datum",
|
||||
"data": "Daten",
|
||||
"campaign": "Kampagne",
|
||||
"parent": "Zielkontakt",
|
||||
"object": "Objekt",
|
||||
"application": "Applikation"
|
||||
},
|
||||
"options": {
|
||||
"action": {
|
||||
"Sent": "Gesendet",
|
||||
"Opened": "Geöffnet",
|
||||
"Opted Out": "Keine E-Mails",
|
||||
"Bounced": "Nicht zustellbar",
|
||||
"Clicked": "Geklickt",
|
||||
"Lead Created": "Interessent erstellt"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"All": "Alle"
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,8 @@
|
||||
"type": "Typ",
|
||||
"description": "Beschreibung"
|
||||
},
|
||||
"links": {},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"New": "Neu",
|
||||
@@ -19,7 +20,7 @@
|
||||
"Rejected": "Abgelehnt",
|
||||
"Duplicate": "Duplizieren"
|
||||
},
|
||||
"priority": {
|
||||
"priority" : {
|
||||
"Low": "Niedrig",
|
||||
"Normal": "Normal",
|
||||
"High": "Hoch",
|
||||
|
||||
@@ -10,12 +10,18 @@
|
||||
"doNotCall": "Nicht anrufen",
|
||||
"address": "Adresse",
|
||||
"opportunityRole": "Verkaufschance Rolle",
|
||||
"accountRole": "Rolle",
|
||||
"description": "Beschreibung"
|
||||
"accountRole": "Funktion",
|
||||
"description": "Beschreibung",
|
||||
"campaign": "Kampagne",
|
||||
"targetLists": "Kontaktlisten",
|
||||
"targetList": "Kontaktliste"
|
||||
},
|
||||
"links": {
|
||||
"opportunities": "Verkaufschancen",
|
||||
"cases": "Fälle"
|
||||
"cases": "Fälle",
|
||||
"targetLists": "Kontaktlisten",
|
||||
"campaignLogRecords": "Kampagnen Log",
|
||||
"campaign": "Kampagne"
|
||||
},
|
||||
"labels": {
|
||||
"Create Contact": "Kontakt erstellen"
|
||||
|
||||
@@ -11,11 +11,14 @@
|
||||
"source": "Quelle",
|
||||
"publishDate": "Veröffentlichungsdatum",
|
||||
"expirationDate": "Ablaufdatum",
|
||||
"description": "Beschreibung"
|
||||
"description": "Beschreibung",
|
||||
"accounts": "Firmen",
|
||||
"folder": "Ordner"
|
||||
},
|
||||
"links": {
|
||||
"accounts": "Firmen",
|
||||
"opportunities": "Verkaufschancen"
|
||||
"opportunities": "Verkaufschancen",
|
||||
"folder": "Ordner"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
@@ -23,6 +26,13 @@
|
||||
"Draft": "Entwurf",
|
||||
"Expired": "Abgelaufen",
|
||||
"Canceled": "Storniert"
|
||||
},
|
||||
"type": {
|
||||
"": "Kein(e)",
|
||||
"Contract": "Vertrag",
|
||||
"NDA": "NDA",
|
||||
"EULA": "EULA",
|
||||
"License Agreement": "Lizenz Vereinbarung"
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create DocumentFolder": "Dokumente Ordner erstellen",
|
||||
"Manage Categories": "Ordner verwalten"
|
||||
},
|
||||
"links": {
|
||||
"documents": "Dokumente"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create Lead": "Interessent erstellen",
|
||||
"Create Contact": "Kontakt erstellen",
|
||||
"Create Task": "Neue Aufgabe",
|
||||
"Create Case": "Fall erstellen"
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,10 @@
|
||||
"Call": "Anruf",
|
||||
"Task": "Aufgabe",
|
||||
"Case": "Fall",
|
||||
"InboundEmail": "Eingehende E-Mails",
|
||||
"Document": "Dokument"
|
||||
"Document": "Dokument",
|
||||
"DocumentFolder": "Dokumente Ordner",
|
||||
"Campaign": "Kampagne",
|
||||
"TargetList": "Kontaktliste"
|
||||
},
|
||||
"scopeNamesPlural": {
|
||||
"Account": "Firmen",
|
||||
@@ -24,8 +26,10 @@
|
||||
"Call": "Anrufe",
|
||||
"Task": "Aufgaben",
|
||||
"Case": "Fälle",
|
||||
"InboundEmail": "Eingehende E-Mails",
|
||||
"Document": "Dokumente"
|
||||
"Document": "Dokumente",
|
||||
"DocumentFolder": "Dokumente Ordner",
|
||||
"Campaign": "Kampagnen",
|
||||
"TargetList": "Kontaktlisten"
|
||||
},
|
||||
"dashlets": {
|
||||
"Leads": "Meine Interessenten",
|
||||
@@ -38,7 +42,7 @@
|
||||
"OpportunitiesByStage": "Verkaufschancen nach Verkaufsphase",
|
||||
"OpportunitiesByLeadSource": "Verkaufschancen nach Quelle",
|
||||
"SalesByMonth": "Umsätze nach Monat",
|
||||
"SalesPipeline": "Verkaufspipeline"
|
||||
"SalesPipeline": "Verkaufspipeline"
|
||||
},
|
||||
"labels": {
|
||||
"Create InboundEmail": "Eingehende E-Mail erstellen",
|
||||
@@ -58,17 +62,17 @@
|
||||
"billingAddressCity": "Ort",
|
||||
"billingAddressCountry": "Land",
|
||||
"billingAddressPostalCode": "PLZ",
|
||||
"billingAddressState": "Bundesland\/Kanton",
|
||||
"billingAddressState": "Bundesland/Kanton",
|
||||
"billingAddressStreet": "Straße",
|
||||
"addressCity": "Ort",
|
||||
"addressStreet": "Straße",
|
||||
"addressCountry": "Land",
|
||||
"addressState": "Bundesland\/Kanton",
|
||||
"addressState": "Bundesland/Kanton",
|
||||
"addressPostalCode": "PLZ",
|
||||
"shippingAddressCity": "Ort (Lieferadresse)",
|
||||
"shippingAddressStreet": "Straße (Lieferadresse)",
|
||||
"shippingAddressCountry": "Land (Lieferadresse)",
|
||||
"shippingAddressState": "Bundesland\/Kanton (Lieferadresse)",
|
||||
"shippingAddressState": "Bundesland/Kanton (Lieferadresse)",
|
||||
"shippingAddressPostalCode": "PLZ (Lieferadresse)"
|
||||
},
|
||||
"links": {
|
||||
|
||||
@@ -20,9 +20,16 @@
|
||||
"description": "Beschreibung",
|
||||
"createdAccount": "Firma",
|
||||
"createdContact": "Kontakt",
|
||||
"createdOpportunity": "Verkaufschance"
|
||||
"createdOpportunity": "Verkaufschance",
|
||||
"campaign": "Kampagne",
|
||||
"targetLists": "Kontaktlisten",
|
||||
"targetList": "Kontaktliste"
|
||||
},
|
||||
"links": {
|
||||
"targetLists": "Kontaktlisten",
|
||||
"campaignLogRecords": "Kampagnen Log",
|
||||
"campaign": "Kampagne"
|
||||
},
|
||||
"links": {},
|
||||
"options": {
|
||||
"status": {
|
||||
"New": "Neu",
|
||||
@@ -33,6 +40,7 @@
|
||||
"Dead": "'Gestorben'"
|
||||
},
|
||||
"source": {
|
||||
"": "Kein(e)",
|
||||
"Call": "Anruf",
|
||||
"Email": "E-Mail",
|
||||
"Existing Customer": "Bestehender Kunde",
|
||||
@@ -44,6 +52,7 @@
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Aktiv"
|
||||
"active": "Aktiv",
|
||||
"converted": "Umgewandelt"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
"reminders": "Erinnerungen",
|
||||
"account": "Firma"
|
||||
},
|
||||
"links": {},
|
||||
"links": {
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
"Planned": "Geplant",
|
||||
@@ -27,13 +28,17 @@
|
||||
"Tentative": "Mit Vorbehalt"
|
||||
}
|
||||
},
|
||||
"massActions": {
|
||||
"setHeld": "Auf gehalten setzen",
|
||||
"setNotHeld": "Auf nicht gehalten setzen"
|
||||
},
|
||||
"labels": {
|
||||
"Create Meeting": "Meeting erstellen",
|
||||
"Set Held": "Auf gehalten setzen",
|
||||
"Set Not Held": "Auf nicht gehalten setzen",
|
||||
"Send Invitations": "Einladungen versenden",
|
||||
"on time": "Aktuelle Zeit",
|
||||
"before": "Bevor"
|
||||
"before": "bevor"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Geplant",
|
||||
|
||||
@@ -11,11 +11,13 @@
|
||||
"contacts": "Kontakte",
|
||||
"description": "Beschreibung",
|
||||
"amountConverted": "Betrag (konvertiert)",
|
||||
"amountWeightedConverted": "Betrag gewichtet"
|
||||
"amountWeightedConverted": "Betrag gewichtet",
|
||||
"campaign": "Kampagne"
|
||||
},
|
||||
"links": {
|
||||
"contacts": "Kontakte",
|
||||
"documents": "Dokumente"
|
||||
"documents": "Dokumente",
|
||||
"campaign": "Kampagne"
|
||||
},
|
||||
"options": {
|
||||
"stage": {
|
||||
@@ -26,9 +28,9 @@
|
||||
"Id. Decision Makers": "Entscheider ident.",
|
||||
"Perception Analysis": "Analyse Sichtweise",
|
||||
"Proposal/Price Quote": "Preisangebot",
|
||||
"Negotiation/Review": "Verhandlung\/Überarbeitung",
|
||||
"Negotiation/Review": "Verhandlung/Überarbeitung",
|
||||
"Closed Won": "Gewonnen",
|
||||
"Closed Lost": "Verloren"
|
||||
"Closed Lost": "Verloren"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
"address": "Adresse",
|
||||
"description": "Beschreibung"
|
||||
},
|
||||
"links": {},
|
||||
"links": {
|
||||
},
|
||||
"labels": {
|
||||
"Create Target": "Zielkontakt erstellen",
|
||||
"Convert to Lead": "Zu Interessent umwandeln"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": "Name",
|
||||
"description": "Beschreibung",
|
||||
"entryCount": "Eingabezähler",
|
||||
"campaigns": "Kampagnen",
|
||||
"endDate": "Enddatum",
|
||||
"targetLists": "Kontaktlisten"
|
||||
},
|
||||
"links": {
|
||||
"accounts": "Firmen",
|
||||
"contacts": "Kontakte",
|
||||
"leads": "Interessenten",
|
||||
"campaigns": "Kampagnen"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
"Email": "E-Mail",
|
||||
"Web": "Web",
|
||||
"Television": "Fernsehen",
|
||||
"Radio": "Radio Button",
|
||||
"Newsletter": "Newsletter"
|
||||
}
|
||||
},
|
||||
"labels": {
|
||||
"Create TargetList": "Kontaktliste erstellen",
|
||||
"Opted Out": "Keine E-Mails"
|
||||
}
|
||||
}
|
||||
@@ -5,19 +5,27 @@
|
||||
"status": "Status",
|
||||
"dateStart": "Startdatum",
|
||||
"dateEnd": "Fällig am",
|
||||
"dateStartDate": "Startdatum (ganztägig)",
|
||||
"dateEndDate": "Enddatum (ganztägig)",
|
||||
"priority": "Priorität",
|
||||
"description": "Beschreibung",
|
||||
"isOverdue": "Ist überfällig"
|
||||
"isOverdue": "Ist überfällig",
|
||||
"account": "Firma",
|
||||
"dateCompleted": "Datum erledigt",
|
||||
"attachments": "Anhänge"
|
||||
},
|
||||
"links": {
|
||||
"attachments": "Anhänge"
|
||||
},
|
||||
"links": {},
|
||||
"options": {
|
||||
"status": {
|
||||
"Not Started": "Nicht begonnen",
|
||||
"Started": "In Bearbeitung",
|
||||
"Completed": "Abgeschlossen",
|
||||
"Canceled": "Storniert"
|
||||
"Canceled": "Storniert",
|
||||
"Deferred": "Zurückgestellt"
|
||||
},
|
||||
"priority": {
|
||||
"priority" : {
|
||||
"Low": "Niedrig",
|
||||
"Normal": "Normal",
|
||||
"High": "Hoch",
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"links": {
|
||||
"targetLists": "Kontaktlisten"
|
||||
}
|
||||
}
|
||||
@@ -44,12 +44,15 @@
|
||||
"Computer": "Computer",
|
||||
"Education": "Education",
|
||||
"Electronics": "Electronics",
|
||||
"Energy": "Energy",
|
||||
"Entertainment & Leisure": "Entertainment & Leisure",
|
||||
"Finance": "Finance",
|
||||
"Food & Beverage": "Food & Beverage",
|
||||
"Grocery": "Grocery",
|
||||
"Healthcare": "Healthcare",
|
||||
"Insurance": "Insurance",
|
||||
"Legal": "Legal",
|
||||
"Manufacturing": "Manufacturing",
|
||||
"Publishing": "Publishing",
|
||||
"Real Estate": "Real Estate",
|
||||
"Service": "Service",
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
"softBouncedCount": "Soft Bounced",
|
||||
"leadCreatedCount": "Leads Created",
|
||||
"revenue": "Revenue",
|
||||
"revenueConverted": "revenue (converted)"
|
||||
"revenueConverted": "revenue (converted)",
|
||||
"budget": "Budget"
|
||||
},
|
||||
"links": {
|
||||
"targetLists": "Target Lists",
|
||||
|
||||
@@ -5,11 +5,21 @@
|
||||
"status": "Status",
|
||||
"account": "Account",
|
||||
"contact": "Contact",
|
||||
"contacts": "Contacts",
|
||||
"priority": "Priority",
|
||||
"type": "Type",
|
||||
"description": "Description"
|
||||
"description": "Description",
|
||||
"inboundEmail": "Inbound Email"
|
||||
},
|
||||
"links": {
|
||||
"inboundEmail": "Inbound Email",
|
||||
"account": "Account",
|
||||
"contact": "Contact (Primary)",
|
||||
"Contacts": "Contacts",
|
||||
"meetings": "Meetings",
|
||||
"calls": "Calls",
|
||||
"tasks": "Tasks",
|
||||
"emails": "Emails"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
|
||||
@@ -21,7 +21,10 @@
|
||||
"cases": "Cases",
|
||||
"targetLists": "Target Lists",
|
||||
"campaignLogRecords": "Campaign Log",
|
||||
"campaign": "Campaign"
|
||||
"campaign": "Campaign",
|
||||
"account": "Account (Primary)",
|
||||
"accounts": "Accounts",
|
||||
"casesPrimary": "Cases (Primary)"
|
||||
},
|
||||
"labels": {
|
||||
"Create Contact": "Create Contact"
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"Log Call": "Log Call",
|
||||
"Archive Email": "Archive Email",
|
||||
"Create Task": "Create Task",
|
||||
"Tasks": "Tasks"
|
||||
"Tasks": "Tasks"
|
||||
},
|
||||
"fields": {
|
||||
"billingAddressCity": "City",
|
||||
@@ -68,7 +68,7 @@
|
||||
"addressStreet": "Street",
|
||||
"addressCountry": "Country",
|
||||
"addressState": "State",
|
||||
"addressPostalCode": "Postal Code",
|
||||
"addressPostalCode": "Postal Code",
|
||||
"shippingAddressCity": "City (Shipping)",
|
||||
"shippingAddressStreet": "Street (Shipping)",
|
||||
"shippingAddressCountry": "Country (Shipping)",
|
||||
@@ -78,7 +78,7 @@
|
||||
"links": {
|
||||
"contacts": "Contacts",
|
||||
"opportunities": "Opportunities",
|
||||
"leads": "Leads",
|
||||
"leads": "Leads",
|
||||
"meetings": "Meetings",
|
||||
"calls": "Calls",
|
||||
"tasks": "Tasks",
|
||||
@@ -87,7 +87,7 @@
|
||||
"cases": "Cases",
|
||||
"documents": "Documents",
|
||||
"account": "Account",
|
||||
"opportunity": "Opportunity",
|
||||
"opportunity": "Opportunity",
|
||||
"contact": "Contact",
|
||||
"parent": "Parent"
|
||||
},
|
||||
|
||||
@@ -28,7 +28,10 @@
|
||||
"links": {
|
||||
"targetLists": "Target Lists",
|
||||
"campaignLogRecords": "Campaign Log",
|
||||
"campaign": "Campaign"
|
||||
"campaign": "Campaign",
|
||||
"createdAccount": "Account",
|
||||
"createdContact": "Contact",
|
||||
"createdOpportunity": "Opportunity"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
|
||||
@@ -11,11 +11,14 @@
|
||||
"source": "Fuente",
|
||||
"publishDate": "Publicar Fecha",
|
||||
"expirationDate": "Fecha de Expiración",
|
||||
"description": "Descripción"
|
||||
"description": "Descripción",
|
||||
"folder": "Carpeta"
|
||||
},
|
||||
"links": {
|
||||
"accounts": "Cuentas",
|
||||
"opportunities": "Oportunidades"
|
||||
"opportunities": "Oportunidades",
|
||||
"accounts": "Cuentas",
|
||||
"folder": "Carpeta"
|
||||
},
|
||||
"options": {
|
||||
"status": {
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
"Send Invitations": "Отправить приглашения"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Запланированный",
|
||||
"held": "Выполнен",
|
||||
"planned": "Запланированные",
|
||||
"held": "Завершенные",
|
||||
"todays": "На сегодня"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"Create Case": "Создать обращение"
|
||||
},
|
||||
"presetFilters": {
|
||||
"open": "Открыть",
|
||||
"closed": "Закрыто"
|
||||
"open": "Открытые",
|
||||
"closed": "Закрытые"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
"Send Invitations": "Отправить приглашения"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Запланированный",
|
||||
"held": "Выполнен",
|
||||
"planned": "Запланированные",
|
||||
"held": "Завершенные",
|
||||
"todays": "На сегодня"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,12 @@
|
||||
[{"label":"","rows":[[{"name":"name"}],[{"name":"website"}],[{"name":"emailAddress"}],[{"name":"phoneNumber"}]]}]
|
||||
[
|
||||
{
|
||||
"label":"",
|
||||
"rows":[
|
||||
[{"name":"name"}],
|
||||
[{"name":"website"}],
|
||||
[{"name":"emailAddress"}],
|
||||
[{"name":"phoneNumber"}],
|
||||
[{"name":"type"}, {"name":"industry"}]
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
"createdAt",
|
||||
"emailAddress",
|
||||
"industry",
|
||||
"type",
|
||||
"name"
|
||||
"phoneNumber",
|
||||
"type"
|
||||
]
|
||||
@@ -5,7 +5,7 @@
|
||||
[{"name":"name"},{"name":"parent"}],
|
||||
[{"name":"status"}, {"name":"direction"}],
|
||||
[{"name":"dateStart"}, {"name":"reminders"}],
|
||||
[{"name":"duration"}],
|
||||
[{"name":"duration"}, false],
|
||||
[{"name":"description", "fullWidth": true}]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
"label":"",
|
||||
"rows":[
|
||||
[{"name":"name"}],
|
||||
[{"name":"status"}],
|
||||
[{"name":"direction"}],
|
||||
[{"name":"status"}, {"name":"direction"}],
|
||||
[{"name":"dateStart"}],
|
||||
[{"name":"duration"}],
|
||||
[{"name":"parent"}],
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
[{"name":"name"}, {"name":"status"}],
|
||||
[{"name":"type"}, {"name":"startDate"}],
|
||||
[{"name":"targetLists"}, {"name":"endDate"}],
|
||||
[false, {"name":"budget"}],
|
||||
[{"name":"description", "fullWidth": true}]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
"label": "",
|
||||
"rows": [
|
||||
[{"name":"name"}],
|
||||
[{"name":"type"}],
|
||||
[{"name":"status"}],
|
||||
[{"name":"type"}, {"name":"status"}],
|
||||
[{"name":"endDate"}]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"rows":[
|
||||
[{"name":"name"},{"name":"number"}],
|
||||
[{"name":"status"},{"name":"account"}],
|
||||
[{"name":"priority"},{"name":"contact"}],
|
||||
[{"name":"priority"},{"name":"contacts"}],
|
||||
[{"name":"type"},false],
|
||||
[{"name":"description", "fullWidth": true}]
|
||||
]
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
"label":"",
|
||||
"rows":[
|
||||
[{"name":"name"}],
|
||||
[{"name":"status"}],
|
||||
[{"name":"priority"}],
|
||||
[{"name":"type"}],
|
||||
[{"name":"status"}, {"name":"priority"}],
|
||||
[{"name":"type"}, {"name":"number"}],
|
||||
[{"name":"account"}],
|
||||
[{"name":"description"}]
|
||||
]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user