mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-05 14:47:01 +00:00
Compare commits
136 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25b81357c7 | ||
|
|
f7f380ff04 | ||
|
|
a09d99fe53 | ||
|
|
bdd6538984 | ||
|
|
2787d3bc72 | ||
|
|
72e53d096f | ||
|
|
acd48513f7 | ||
|
|
6ffa5654ea | ||
|
|
b2dfdb3446 | ||
|
|
dc5934a0ad | ||
|
|
ec586874a6 | ||
|
|
eb99d643b1 | ||
|
|
f6b37f346f | ||
|
|
180b31f6fa | ||
|
|
b16de8591e | ||
|
|
f87f418c1b | ||
|
|
f79fd38478 | ||
|
|
2e13f73b34 | ||
|
|
300f442b22 | ||
|
|
0f1c31e55a | ||
|
|
86633b31d3 | ||
|
|
f60aa78dde | ||
|
|
ae77cb1d77 | ||
|
|
74d99d8cda | ||
|
|
a90e0874bd | ||
|
|
141d20b472 | ||
|
|
6f08ecc1a7 | ||
|
|
3e4d6edac8 | ||
|
|
19784fc09c | ||
|
|
554f8cc37c | ||
|
|
c6153f6af3 | ||
|
|
048f5318fc | ||
|
|
62985c9776 | ||
|
|
9b30c02c22 | ||
|
|
122f18e8bf | ||
|
|
9d316da4e0 | ||
|
|
46439ff394 | ||
|
|
f73a60ad9f | ||
|
|
c05a153719 | ||
|
|
094f39e987 | ||
|
|
c247def1bc | ||
|
|
c7cd372554 | ||
|
|
ea951a8738 | ||
|
|
d9973bf353 | ||
|
|
0baaf82909 | ||
|
|
e62cb881c9 | ||
|
|
a965f6037f | ||
|
|
d6251f995c | ||
|
|
483c971e3e | ||
|
|
3186dcc65f | ||
|
|
e7aeebee8d | ||
|
|
14c3287131 | ||
|
|
4754b2db2f | ||
|
|
8fa0fae265 | ||
|
|
dc4c4bd084 | ||
|
|
6a5239cedc | ||
|
|
9ea9429757 | ||
|
|
20f89cf75a | ||
|
|
e8acf8aaaf | ||
|
|
0fac47e227 | ||
|
|
fe3cc09623 | ||
|
|
91445f2f9c | ||
|
|
053d516bc9 | ||
|
|
63a9f67bd9 | ||
|
|
344f0227e9 | ||
|
|
16384b9f72 | ||
|
|
db9d8e1006 | ||
|
|
c7dd503d80 | ||
|
|
c96265e2a9 | ||
|
|
ff35f7b1ff | ||
|
|
ac1748067b | ||
|
|
a4de09ea36 | ||
|
|
0816831fe1 | ||
|
|
0e83325e92 | ||
|
|
261e52e64d | ||
|
|
f1a990e80a | ||
|
|
a3a8110ae6 | ||
|
|
82a213555b | ||
|
|
3590ff2e33 | ||
|
|
775cfec744 | ||
|
|
9ca1d6608c | ||
|
|
59140b0814 | ||
|
|
90cf300334 | ||
|
|
7bd3c7cb0d | ||
|
|
ce75cc90f5 | ||
|
|
00a911434b | ||
|
|
69840086c9 | ||
|
|
b72f6fa2cc | ||
|
|
9f9d0cb2dc | ||
|
|
6a036595d6 | ||
|
|
f4c57046dd | ||
|
|
7b507f1bab | ||
|
|
c0b8c5e7d2 | ||
|
|
6e49afddf0 | ||
|
|
4908f281a3 | ||
|
|
796b51d620 | ||
|
|
9cc44cf917 | ||
|
|
9f7eecac73 | ||
|
|
cba59fe847 | ||
|
|
07df97ab9e | ||
|
|
0a1322843f | ||
|
|
6c6a3621e8 | ||
|
|
4a075819d1 | ||
|
|
3aa3914f3a | ||
|
|
eef9c3e35c | ||
|
|
fe61fadc09 | ||
|
|
4c931514a2 | ||
|
|
8ad886d871 | ||
|
|
93b8745599 | ||
|
|
fa25dc715f | ||
|
|
c010cf43bf | ||
|
|
51bdd15c9e | ||
|
|
b48f10b45f | ||
|
|
027e928bd3 | ||
|
|
3cfcfb02de | ||
|
|
322df7ff68 | ||
|
|
d58b9cac40 | ||
|
|
cca6567bbd | ||
|
|
26eb194ccb | ||
|
|
9b42ae41e7 | ||
|
|
83916cacd9 | ||
|
|
85b484c04e | ||
|
|
0d302e99af | ||
|
|
ae4a6fa3d2 | ||
|
|
8f64fdd025 | ||
|
|
5ee83505af | ||
|
|
4527358a53 | ||
|
|
51cca50828 | ||
|
|
8f1752575a | ||
|
|
29c39fb4fd | ||
|
|
63663ccf6c | ||
|
|
1ba81c3350 | ||
|
|
f7879f425f | ||
|
|
93ed5dce6b | ||
|
|
a08adcf6d5 | ||
|
|
a7bad6aa58 |
10
.gitignore
vendored
10
.gitignore
vendored
@@ -4,7 +4,6 @@
|
||||
/data/preferences/*
|
||||
/data/.backup/*
|
||||
/data/config.php
|
||||
/custom
|
||||
/build
|
||||
/node_modules
|
||||
/client
|
||||
@@ -14,3 +13,12 @@
|
||||
/tests/testData/cache/*
|
||||
composer.phar
|
||||
vendor/
|
||||
|
||||
/custom/*
|
||||
!/custom/Espo/
|
||||
/custom/Espo/*
|
||||
!/custom/Espo/Custom/
|
||||
/custom/Espo/Custom/*
|
||||
!/custom/Espo/Custom/Core/
|
||||
/custom/Espo/Custom/Core/*
|
||||
!/custom/Espo/Custom/Core/Loaders/
|
||||
97
Gruntfile.js
97
Gruntfile.js
@@ -1,49 +1,49 @@
|
||||
module.exports = function (grunt) {
|
||||
|
||||
var jsFilesToMinify = [
|
||||
'client/lib/jquery-2.0.2.min.js',
|
||||
'client/lib/underscore-min.js',
|
||||
'client/lib/backbone-min.js',
|
||||
'client/lib/handlebars.js',
|
||||
'client/lib/base64.js',
|
||||
'client/lib/jquery-ui.min.js',
|
||||
'client/lib/moment.min.js',
|
||||
'client/lib/moment-timezone-with-data.min.js',
|
||||
'client/lib/jquery.timepicker.min.js',
|
||||
'client/lib/jquery.autocomplete.js',
|
||||
'client/lib/bootstrap.min.js',
|
||||
'client/lib/bootstrap-datepicker.js',
|
||||
'client/lib/bull.min.js',
|
||||
'client/src/namespace.js',
|
||||
'client/src/exceptions.js',
|
||||
'client/src/app.js',
|
||||
'client/src/utils.js',
|
||||
'client/src/storage.js',
|
||||
'client/src/loader.js',
|
||||
'client/src/pre-loader.js',
|
||||
'client/src/ui.js',
|
||||
'client/src/acl.js',
|
||||
'client/src/model.js',
|
||||
'client/src/model-offline.js',
|
||||
'client/src/metadata.js',
|
||||
'client/src/language.js',
|
||||
'client/src/cache.js',
|
||||
'client/src/controller.js',
|
||||
'client/src/router.js',
|
||||
'client/src/date-time.js',
|
||||
'client/src/field-manager.js',
|
||||
'client/src/search-manager.js',
|
||||
'client/src/collection.js',
|
||||
'client/src/multi-collection.js',
|
||||
'client/src/view-helper.js',
|
||||
'client/src/layout-manager.js',
|
||||
'client/src/model-factory.js',
|
||||
'client/src/collection-factory.js',
|
||||
'client/src/models/settings.js',
|
||||
'client/src/models/user.js',
|
||||
'client/src/models/preferences.js',
|
||||
'client/src/controllers/base.js',
|
||||
'client/src/view.js',
|
||||
'client/lib/jquery-2.0.2.min.js',
|
||||
'client/lib/underscore-min.js',
|
||||
'client/lib/backbone-min.js',
|
||||
'client/lib/handlebars.js',
|
||||
'client/lib/base64.js',
|
||||
'client/lib/jquery-ui.min.js',
|
||||
'client/lib/moment.min.js',
|
||||
'client/lib/moment-timezone-with-data.min.js',
|
||||
'client/lib/jquery.timepicker.min.js',
|
||||
'client/lib/jquery.autocomplete.js',
|
||||
'client/lib/bootstrap.min.js',
|
||||
'client/lib/bootstrap-datepicker.js',
|
||||
'client/lib/bull.min.js',
|
||||
'client/src/namespace.js',
|
||||
'client/src/exceptions.js',
|
||||
'client/src/app.js',
|
||||
'client/src/utils.js',
|
||||
'client/src/storage.js',
|
||||
'client/src/loader.js',
|
||||
'client/src/pre-loader.js',
|
||||
'client/src/ui.js',
|
||||
'client/src/acl.js',
|
||||
'client/src/model.js',
|
||||
'client/src/model-offline.js',
|
||||
'client/src/metadata.js',
|
||||
'client/src/language.js',
|
||||
'client/src/cache.js',
|
||||
'client/src/controller.js',
|
||||
'client/src/router.js',
|
||||
'client/src/date-time.js',
|
||||
'client/src/field-manager.js',
|
||||
'client/src/search-manager.js',
|
||||
'client/src/collection.js',
|
||||
'client/src/multi-collection.js',
|
||||
'client/src/view-helper.js',
|
||||
'client/src/layout-manager.js',
|
||||
'client/src/model-factory.js',
|
||||
'client/src/collection-factory.js',
|
||||
'client/src/models/settings.js',
|
||||
'client/src/models/user.js',
|
||||
'client/src/models/preferences.js',
|
||||
'client/src/controllers/base.js',
|
||||
'client/src/view.js',
|
||||
];
|
||||
|
||||
grunt.initConfig({
|
||||
@@ -106,6 +106,7 @@ module.exports = function (grunt) {
|
||||
'modules/**',
|
||||
'img/**',
|
||||
'css/**',
|
||||
'sounds/**'
|
||||
],
|
||||
dest: 'build/tmp/client',
|
||||
},
|
||||
@@ -119,7 +120,7 @@ module.exports = function (grunt) {
|
||||
cwd: 'frontend/client/lib',
|
||||
src: '**',
|
||||
dest: 'build/tmp/client/lib/',
|
||||
},
|
||||
},
|
||||
backend: {
|
||||
expand: true,
|
||||
dot: true,
|
||||
@@ -152,7 +153,7 @@ module.exports = function (grunt) {
|
||||
options: {
|
||||
mode: '755'
|
||||
},
|
||||
php: {
|
||||
php: {
|
||||
options: {
|
||||
mode: '644'
|
||||
},
|
||||
@@ -160,7 +161,7 @@ module.exports = function (grunt) {
|
||||
'build/EspoCRM-<%= pkg.version %>/**/*.php',
|
||||
'build/EspoCRM-<%= pkg.version %>/**/*.json',
|
||||
'build/EspoCRM-<%= pkg.version %>/**/*.config',
|
||||
'build/EspoCRM-<%= pkg.version %>/**/.htaccess',
|
||||
'build/EspoCRM-<%= pkg.version %>/**/.htaccess',
|
||||
'build/EspoCRM-<%= pkg.version %>/client/**/*.js',
|
||||
'build/EspoCRM-<%= pkg.version %>/client/**/*.css',
|
||||
'build/EspoCRM-<%= pkg.version %>/client/**/*.tpl',
|
||||
@@ -230,7 +231,7 @@ module.exports = function (grunt) {
|
||||
'clean:start',
|
||||
'mkdir:tmp',
|
||||
'less',
|
||||
'cssmin',
|
||||
'cssmin',
|
||||
'uglify',
|
||||
'copy:frontendFolders',
|
||||
'copy:frontendHtml',
|
||||
@@ -240,6 +241,6 @@ module.exports = function (grunt) {
|
||||
'copy:final',
|
||||
'chmod',
|
||||
'clean:final',
|
||||
]);
|
||||
]);
|
||||
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@ If your repository is accessible via a web server then you can run EspoCRM by ur
|
||||
|
||||
### How to build
|
||||
|
||||
You need to have nodejs installed.
|
||||
You need to have nodejs and Grunt CLI installed.
|
||||
|
||||
1. Change to the project's root directory.
|
||||
2. Install project dependencies with `npm install`.
|
||||
|
||||
@@ -25,11 +25,12 @@ namespace Espo\Controllers;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class User extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
{
|
||||
public function actionAcl($params, $data, $request)
|
||||
{
|
||||
{
|
||||
$userId = $request->get('id');
|
||||
if (empty($userId)) {
|
||||
throw new Error();
|
||||
@@ -46,12 +47,54 @@ class User extends \Espo\Core\Controllers\Record
|
||||
|
||||
$acl = new \Espo\Core\Acl($user, $this->getConfig(), $this->getContainer()->get('fileManager'), $this->getMetadata());
|
||||
|
||||
return $acl->toArray();
|
||||
return $acl->toArray();
|
||||
}
|
||||
|
||||
public function actionChangeOwnPassword($params, $data)
|
||||
{
|
||||
return $this->getService('User')->changePassword($this->getUser()->id, $data['password']);
|
||||
}
|
||||
|
||||
public function actionChangePasswordByRequest($params, $data, $request)
|
||||
{
|
||||
if (!$request->isPost()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
if (empty($data['requestId']) || empty($data['password'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$p = $this->getEntityManager()->getRepository('PasswordChangeRequest')->where(array(
|
||||
'requestId' => $data['requestId']
|
||||
))->findOne();
|
||||
|
||||
if (!$p) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
$userId = $p->get('userId');
|
||||
if (!$userId) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
$this->getEntityManager()->removeEntity($p);
|
||||
|
||||
return $this->getService('User')->changePassword($userId, $data['password']);
|
||||
}
|
||||
|
||||
public function actionPasswordChangeRequest($params, $data, $request)
|
||||
{
|
||||
if (!$request->isPost()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
if (empty($data['userName']) || empty($data['emailAddress'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$userName = $data['userName'];
|
||||
$emailAddress = $data['emailAddress'];
|
||||
|
||||
return $this->getService('User')->passwordChangeRequest($userName, $emailAddress);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -218,14 +218,14 @@ class Acl
|
||||
$userRoles = $this->user->get('roles');
|
||||
|
||||
foreach ($userRoles as $role) {
|
||||
$aclTables[] = json_decode($role->get('data'));
|
||||
$aclTables[] = $role->get('data');
|
||||
}
|
||||
|
||||
$teams = $this->user->get('teams');
|
||||
foreach ($teams as $team) {
|
||||
$teamRoles = $team->get('roles');
|
||||
foreach ($teamRoles as $role) {
|
||||
$aclTables[] = json_decode($role->get('data'));
|
||||
$aclTables[] = $role->get('data');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ class Application
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
$GLOBALS['log'] = $this->container->get('log');
|
||||
|
||||
$this->initAutoloads();
|
||||
}
|
||||
|
||||
public function getSlim()
|
||||
@@ -88,6 +90,7 @@ class Application
|
||||
$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('{{runScript}}', 'app.start();' , $html);
|
||||
echo $html;
|
||||
exit;
|
||||
}
|
||||
@@ -215,7 +218,6 @@ class Application
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
protected function initRoutes()
|
||||
{
|
||||
$routes = new \Espo\Core\Utils\Route($this->getContainer()->get('config'), $this->getMetadata(), $this->getContainer()->get('fileManager'));
|
||||
@@ -238,5 +240,31 @@ class Application
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function initAutoloads()
|
||||
{
|
||||
$autoload = new \Espo\Core\Utils\Autoload($this->getContainer()->get('config'), $this->getMetadata(), $this->getContainer()->get('fileManager'));
|
||||
$autoloadList = $autoload->getAll();
|
||||
|
||||
if (empty($autoloadList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$namespacesPath = 'vendor/composer/autoload_namespaces.php';
|
||||
$existingNamespaces = file_exists($namespacesPath) ? include($namespacesPath) : array();
|
||||
if (!empty($existingNamespaces) && is_array($existingNamespaces)) {
|
||||
$existingNamespaces = array_keys($existingNamespaces);
|
||||
}
|
||||
|
||||
$classLoader = new \Composer\Autoload\ClassLoader();
|
||||
|
||||
foreach ($autoloadList as $prefix => $path) {
|
||||
if (!in_array($prefix, $existingNamespaces)) {
|
||||
$classLoader->add($prefix, $path);
|
||||
}
|
||||
}
|
||||
|
||||
$classLoader->register(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ class EntityManager extends Base
|
||||
'password' => $config->get('database.password'),
|
||||
'metadata' => $this->getContainer()->get('metadata')->getOrmMetadata(),
|
||||
'repositoryFactoryClassName' => '\\Espo\\Core\\ORM\\RepositoryFactory',
|
||||
'driver' => $config->get('database.driver'),
|
||||
'platform' => $config->get('database.platform')
|
||||
);
|
||||
|
||||
$entityManager = new \Espo\Core\ORM\EntityManager($params);
|
||||
|
||||
@@ -5,21 +5,28 @@ namespace Espo\Core\Mail;
|
||||
use \Zend\Mime\Mime as Mime;
|
||||
|
||||
class Importer
|
||||
{
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
private $fileManager;
|
||||
|
||||
private $config;
|
||||
|
||||
public function __construct($entityManager, $fileManager)
|
||||
public function __construct($entityManager, $fileManager, $config)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->fileManager = $fileManager;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
protected function getEntityManager()
|
||||
{
|
||||
return $this->entityManager;
|
||||
}
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
protected function getFileManager()
|
||||
{
|
||||
@@ -36,22 +43,22 @@ class Importer
|
||||
$subject = '--empty--';
|
||||
}
|
||||
|
||||
$email->set('isHtml', false);
|
||||
$email->set('isHtml', false);
|
||||
$email->set('name', $subject);
|
||||
$email->set('status', 'Archived');
|
||||
$email->set('attachmentsIds', array());
|
||||
$email->set('attachmentsIds', array());
|
||||
$email->set('assignedUserId', $userId);
|
||||
$email->set('teamsIds', $teamsIds);
|
||||
|
||||
$fromArr = $this->getAddressListFromMessage($message, 'from');
|
||||
$fromArr = $this->getAddressListFromMessage($message, 'from');
|
||||
if (isset($message->from)) {
|
||||
$email->set('fromName', $message->from);
|
||||
}
|
||||
}
|
||||
$email->set('from', $fromArr[0]);
|
||||
$email->set('to', implode(';', $this->getAddressListFromMessage($message, 'to')));
|
||||
$email->set('to', implode(';', $this->getAddressListFromMessage($message, 'to')));
|
||||
$email->set('cc', implode(';', $this->getAddressListFromMessage($message, 'cc')));
|
||||
|
||||
if (isset($message->messageId) && !empty($message->messageId)) {
|
||||
if (isset($message->messageId) && !empty($message->messageId)) {
|
||||
$email->set('messageId', $message->messageId);
|
||||
if (isset($message->deliveredTo)) {
|
||||
$email->set('messageIdInternal', $message->messageId . '-' . $message->deliveredTo);
|
||||
@@ -60,29 +67,29 @@ class Importer
|
||||
|
||||
if ($this->checkIsDuplicate($email)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($message->date)) {
|
||||
$dt = new \DateTime($message->date);
|
||||
if ($dt) {
|
||||
$dateSent = $dt->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
|
||||
$dateSent = $dt->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
|
||||
$email->set('dateSent', $dateSent);
|
||||
}
|
||||
}
|
||||
if (isset($message->deliveryDate)) {
|
||||
$dt = new \DateTime($message->deliveryDate);
|
||||
if ($dt) {
|
||||
$deliveryDate = $dt->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
|
||||
$deliveryDate = $dt->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
|
||||
$email->set('deliveryDate', $deliveryDate);
|
||||
}
|
||||
}
|
||||
|
||||
$inlineIds = array();
|
||||
|
||||
if ($message->isMultipart()) {
|
||||
if ($message->isMultipart()) {
|
||||
foreach (new \RecursiveIteratorIterator($message) as $part) {
|
||||
$this->importPartDataToEmail($email, $part, $inlineIds);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->importPartDataToEmail($email, $message, $inlineIds);
|
||||
}
|
||||
@@ -95,6 +102,39 @@ class Importer
|
||||
$email->set('body', $body);
|
||||
}
|
||||
|
||||
if (isset($message->references) && !empty($message->references)) {
|
||||
$reference = str_replace(array('/', '@'), " ", trim($message->references, '<>'));
|
||||
$parentType = $parentId = null;
|
||||
$emailSent = PHP_INT_MAX;
|
||||
$n = sscanf($reference, '%s %s %d %d espo', $parentType, $parentId, $emailSent, $number);
|
||||
if ($n == 4 && $emailSent < time()) {
|
||||
if (!empty($parentType) && !empty($parentId)) {
|
||||
$email->set('parentType', $parentType);
|
||||
$email->set('parentId', $parentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$email->has('parentId')) {
|
||||
$from = $email->get('from');
|
||||
if ($from) {
|
||||
$contact = $this->getEntityManager()->getRepository('Contact')->where(array(
|
||||
'emailAddress' => $from
|
||||
))->findOne();
|
||||
if ($contact) {
|
||||
if (!$this->getConfig()->get('b2cMode')) {
|
||||
if ($contact->get('accountId')) {
|
||||
$email->set('parentType', 'Account');
|
||||
$email->set('parentId', $contact->get('accountId'));
|
||||
}
|
||||
} else {
|
||||
$email->set('parentType', 'Contact');
|
||||
$email->set('parentId', $contact->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->getEntityManager()->saveEntity($email);
|
||||
|
||||
return $email;
|
||||
@@ -128,15 +168,15 @@ class Importer
|
||||
}
|
||||
|
||||
protected function importPartDataToEmail(\Espo\Entities\Email $email, $part, &$inlineIds = array())
|
||||
{
|
||||
{
|
||||
try {
|
||||
$type = strtok($part->contentType, ';');
|
||||
$encoding = null;
|
||||
|
||||
switch ($type) {
|
||||
case 'text/plain':
|
||||
$content = $this->getContentFromPart($part);
|
||||
if (!$email->get('body')) {
|
||||
case 'text/plain':
|
||||
$content = $this->getContentFromPart($part);
|
||||
if (!$email->get('body')) {
|
||||
$email->set('body', $content);
|
||||
}
|
||||
$email->set('bodyPlain', $content);
|
||||
@@ -147,23 +187,23 @@ class Importer
|
||||
$email->set('isHtml', true);
|
||||
break;
|
||||
default:
|
||||
$content = $part->getContent();
|
||||
$content = $part->getContent();
|
||||
$disposition = null;
|
||||
|
||||
$fileName = null;
|
||||
$contentId = null;
|
||||
|
||||
if (isset($part->ContentDisposition)) {
|
||||
if (isset($part->ContentDisposition)) {
|
||||
if (strpos($part->ContentDisposition, 'attachment') === 0) {
|
||||
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';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($part->contentTransferEncoding)) {
|
||||
@@ -171,7 +211,7 @@ class Importer
|
||||
}
|
||||
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment');
|
||||
$attachment->set('name', $fileName);
|
||||
$attachment->set('name', $fileName);
|
||||
$attachment->set('type', $type);
|
||||
|
||||
if ($disposition == 'inline') {
|
||||
@@ -188,18 +228,18 @@ class Importer
|
||||
|
||||
$this->getEntityManager()->saveEntity($attachment);
|
||||
|
||||
$path = 'data/upload/' . $attachment->id;
|
||||
$this->getFileManager()->putContents($path, $content);
|
||||
$path = 'data/upload/' . $attachment->id;
|
||||
$this->getFileManager()->putContents($path, $content);
|
||||
|
||||
if ($disposition == 'attachment') {
|
||||
$attachmentsIds = $email->get('attachmentsIds');
|
||||
$attachmentsIds[] = $attachment->id;
|
||||
$email->set('attachmentsIds', $attachmentsIds);
|
||||
$email->set('attachmentsIds', $attachmentsIds);
|
||||
} else if ($disposition == 'inline') {
|
||||
$inlineIds[$contentId] = $attachment->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
protected function getContentFromPart($part)
|
||||
@@ -223,7 +263,7 @@ class Importer
|
||||
$content = base64_decode($content);
|
||||
}
|
||||
|
||||
$charset = 'UTF-8';
|
||||
$charset = 'UTF-8';
|
||||
|
||||
if (isset($part->contentType)) {
|
||||
$ctHeader = $part->getHeader('Content-Type');
|
||||
@@ -235,14 +275,14 @@ class Importer
|
||||
|
||||
if ($charset !== 'UTF-8') {
|
||||
$content = mb_convert_encoding($content, 'UTF-8', $charset);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($part->contentTransferEncoding)) {
|
||||
$cteHeader = $part->getHeader('Content-Transfer-Encoding');
|
||||
if ($cteHeader->getTransferEncoding() == 'quoted-printable') {
|
||||
$cteHeader = $part->getHeader('Content-Transfer-Encoding');
|
||||
if ($cteHeader->getTransferEncoding() == 'quoted-printable') {
|
||||
$content = quoted_printable_decode($content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ use \Espo\Core\Interfaces\Injectable;
|
||||
|
||||
class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
{
|
||||
public static $mapperClassName = '\\Espo\\Core\\ORM\\DB\\MysqlMapper';
|
||||
|
||||
protected $dependencies = array(
|
||||
'metadata'
|
||||
);
|
||||
@@ -247,8 +245,18 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
foreach ($entity->getRelations() as $name => $defs) {
|
||||
if (in_array($defs['type'], $relationTypes)) {
|
||||
$fieldName = $name . 'Ids';
|
||||
if ($entity->has($fieldName)) {
|
||||
$specifiedIds = $entity->get($fieldName);
|
||||
$columnsFieldsName = $name . 'Columns';
|
||||
|
||||
if ($entity->has($fieldName) || $entity->has($columnsFieldsName)) {
|
||||
|
||||
if ($entity->has($fieldName)) {
|
||||
$specifiedIds = $entity->get($fieldName);
|
||||
} else {
|
||||
$specifiedIds = array();
|
||||
foreach ($entity->get($columnsFieldsName) as $id => $d) {
|
||||
$specifiedIds[] = $id;
|
||||
}
|
||||
}
|
||||
if (is_array($specifiedIds)) {
|
||||
$toRemoveIds = array();
|
||||
$existingIds = array();
|
||||
@@ -258,9 +266,8 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
|
||||
$defs = array();
|
||||
$columns = $this->getMetadata()->get("entityDefs." . $entity->getEntityName() . ".fields.{$name}.columns");
|
||||
if (!empty($columns)) {
|
||||
$columnData = $entity->get($name . 'Columns');
|
||||
$columnData = $entity->get($columnsFieldsName);
|
||||
$defs['additionalColumns'] = $columns;
|
||||
|
||||
}
|
||||
|
||||
foreach ($entity->get($name, $defs) as $foreignEntity) {
|
||||
|
||||
@@ -40,6 +40,8 @@ class Base
|
||||
|
||||
protected $metadata;
|
||||
|
||||
private $seed = null;
|
||||
|
||||
const MIN_LENGTH_FOR_CONTENT_SEARCH = 4;
|
||||
|
||||
public function __construct($entityManager, \Espo\Entities\User $user, Acl $acl, $metadata)
|
||||
@@ -90,6 +92,14 @@ class Base
|
||||
return $this->metadata->get("entityDefs.{$this->entityName}.collection.textFilterFields", array('name'));
|
||||
}
|
||||
|
||||
protected function getSeed()
|
||||
{
|
||||
if (empty($this->seed)) {
|
||||
$this->seed = $this->entityManager->getEntity($this->entityName);
|
||||
}
|
||||
return $this->seed;
|
||||
}
|
||||
|
||||
protected function where($params, &$result)
|
||||
{
|
||||
if (!empty($params['where']) && is_array($params['where'])) {
|
||||
@@ -108,7 +118,7 @@ class Base
|
||||
if (empty($result['whereClause'])) {
|
||||
$result['whereClause'] = array();
|
||||
}
|
||||
$fieldDefs = $this->entityManager->getEntity($this->entityName)->getFields();
|
||||
$fieldDefs = $this->getSeed()->getFields();
|
||||
$fieldList = $this->getTextFilterFields();
|
||||
$d = array();
|
||||
foreach ($fieldList as $field) {
|
||||
@@ -146,14 +156,32 @@ class Base
|
||||
$joins = array();
|
||||
|
||||
$part = array();
|
||||
foreach ($linkedWith as $link => $ids) {
|
||||
$joins[] = $link;
|
||||
$defs = $this->entityManager->getMetadata()->get($this->entityName);
|
||||
|
||||
$entityName = $defs['relations'][$link]['entity'];
|
||||
if ($entityName) {
|
||||
$part[$entityName . '.id'] = $ids;
|
||||
foreach ($linkedWith as $link => $idsValue) {
|
||||
if (is_array($idsValue) && count($idsValue) == 1) {
|
||||
$idsValue = $idsValue[0];
|
||||
}
|
||||
|
||||
|
||||
$relDefs = $this->getSeed()->getRelations();
|
||||
|
||||
if (!empty($relDefs[$link])) {
|
||||
$defs = $relDefs[$link];
|
||||
if ($defs['type'] == 'manyMany') {
|
||||
$joins[] = $link;
|
||||
if (!empty($defs['relationName']) && !empty($defs['midKeys'])) {
|
||||
$key = $defs['midKeys'][1];
|
||||
$relationName = $defs['relationName'];
|
||||
$part[$relationName . '.' . $key] = $idsValue;
|
||||
}
|
||||
} else if ($defs['type'] == 'belongsTo') {
|
||||
if (!empty($defs['type']['key'])) {
|
||||
$key = $defs['type']['key'];
|
||||
$part[$key] = $idsValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (!empty($part)) {
|
||||
@@ -175,7 +203,7 @@ class Base
|
||||
$result['whereClause'] = array();
|
||||
}
|
||||
|
||||
$fieldDefs = $this->entityManager->getEntity($this->entityName)->getFields();
|
||||
$fieldDefs = $this->getSeed()->getFields();
|
||||
|
||||
$value = $params['q'];
|
||||
|
||||
@@ -222,7 +250,6 @@ class Base
|
||||
'Team.id' => $this->user->get('teamsIds'),
|
||||
'assignedUserId' => $this->user->id
|
||||
);
|
||||
//$result['whereClause']['Team.id'] = $this->user->get('teamsIds');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
127
application/Espo/Core/Utils/Autoload.php
Normal file
127
application/Espo/Core/Utils/Autoload.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils;
|
||||
|
||||
class Autoload
|
||||
{
|
||||
protected $data = null;
|
||||
|
||||
private $fileManager;
|
||||
private $config;
|
||||
private $metadata;
|
||||
|
||||
protected $cacheFile = 'data/cache/application/autoload.php';
|
||||
|
||||
protected $paths = array(
|
||||
'corePath' => 'application/Espo/Resources/autoload.json',
|
||||
'modulePath' => 'application/Espo/Modules/{*}/Resources/autoload.json',
|
||||
'customPath' => 'custom/Espo/Custom/Resources/autoload.json',
|
||||
);
|
||||
|
||||
public function __construct(Config $config, Metadata $metadata, File\Manager $fileManager)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->metadata = $metadata;
|
||||
$this->fileManager = $fileManager;
|
||||
}
|
||||
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
protected function getFileManager()
|
||||
{
|
||||
return $this->fileManager;
|
||||
}
|
||||
|
||||
protected function getMetadata()
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
public function get($key = null, $returns = null)
|
||||
{
|
||||
if (!isset($this->data)) {
|
||||
$this->init();
|
||||
}
|
||||
|
||||
if (!isset($key)) {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
return Utill::getValueByKey($this->data, $key, $returns);
|
||||
}
|
||||
|
||||
|
||||
public function getAll()
|
||||
{
|
||||
return $this->get();
|
||||
}
|
||||
|
||||
protected function init()
|
||||
{
|
||||
if (file_exists($this->cacheFile) && $this->getConfig()->get('useCache')) {
|
||||
$this->data = $this->getFileManager()->getContents($this->cacheFile);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->data = $this->unify();
|
||||
|
||||
if ($this->getConfig()->get('useCache')) {
|
||||
$result = $this->getFileManager()->putContentsPHP($this->cacheFile, $this->data);
|
||||
if ($result == false) {
|
||||
throw new \Espo\Core\Exceptions\Error('Autoload: Cannot save unified autoload.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function unify()
|
||||
{
|
||||
$data = $this->loadData($this->paths['corePath']);
|
||||
|
||||
foreach ($this->getMetadata()->getModuleList() as $moduleName) {
|
||||
$modulePath = str_replace('{*}', $moduleName, $this->paths['modulePath']);
|
||||
$data = array_merge($data, $this->loadData($modulePath));
|
||||
}
|
||||
|
||||
$data = array_merge($data, $this->loadData($this->paths['customPath']));
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function loadData($autoloadFile, $returns = array())
|
||||
{
|
||||
if (file_exists($autoloadFile)) {
|
||||
$content= $this->getFileManager()->getContents($autoloadFile);
|
||||
$arrayContent = Json::getArrayData($content);
|
||||
if (!empty($arrayContent)) {
|
||||
return $arrayContent;
|
||||
}
|
||||
|
||||
$GLOBALS['log']->error('Autoload::unify() - Empty file or syntax error - ['.$autoloadFile.']');
|
||||
}
|
||||
|
||||
return $returns;
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,11 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils;
|
||||
|
||||
class Crypt
|
||||
class Crypt
|
||||
{
|
||||
private $config;
|
||||
|
||||
@@ -34,9 +34,9 @@ class Crypt
|
||||
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->config = $config;
|
||||
$this->cryptKey = $config->get('cryptKey', '');
|
||||
}
|
||||
}
|
||||
|
||||
protected function getKey()
|
||||
{
|
||||
|
||||
@@ -31,7 +31,6 @@ use Doctrine\DBAL\Schema\TableDiff,
|
||||
|
||||
class MySqlPlatform extends \Doctrine\DBAL\Platforms\MySqlPlatform
|
||||
{
|
||||
|
||||
public function getAlterTableSQL(TableDiff $diff)
|
||||
{
|
||||
$columnSql = array();
|
||||
@@ -104,7 +103,6 @@ class MySqlPlatform extends \Doctrine\DBAL\Platforms\MySqlPlatform
|
||||
return array_merge($sql, $tableSql, $columnSql);
|
||||
}
|
||||
|
||||
|
||||
protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff)
|
||||
{
|
||||
$sql = array();
|
||||
@@ -139,7 +137,6 @@ class MySqlPlatform extends \Doctrine\DBAL\Platforms\MySqlPlatform
|
||||
return $sql;
|
||||
}
|
||||
|
||||
|
||||
public function getDropIndexSQL($index, $table=null)
|
||||
{
|
||||
if ($index instanceof Index) {
|
||||
@@ -270,5 +267,14 @@ class MySqlPlatform extends \Doctrine\DBAL\Platforms\MySqlPlatform
|
||||
|
||||
return 'ALTER TABLE ' . $this->espoQuote($table) . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getQuotedColumns($this)) . ')';
|
||||
}
|
||||
|
||||
protected function _getCreateTableSQL($tableName, array $columns, array $options = array())
|
||||
{
|
||||
if (!isset($options['engine'])) {
|
||||
$options['engine'] = 'MyISAM';
|
||||
}
|
||||
|
||||
return parent::_getCreateTableSQL($tableName, $columns, $options);
|
||||
}
|
||||
//end: ESPO
|
||||
}
|
||||
@@ -151,6 +151,10 @@ class Converter
|
||||
),
|
||||
);
|
||||
|
||||
if (isset($entityMeta['indexes'])) {
|
||||
$ormMeta[$entityName]['indexes'] = $entityMeta['indexes'];
|
||||
}
|
||||
|
||||
$ormMeta[$entityName]['fields'] = $this->convertFields($entityName, $entityMeta);
|
||||
|
||||
$convertedLinks = $this->convertLinks($entityName, $entityMeta, $ormMeta);
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
namespace Espo\Core\Utils\Database\Orm\Relations;
|
||||
|
||||
class NoteAttachments extends HasChildren
|
||||
class Attachments extends HasChildren
|
||||
{
|
||||
protected function load($linkName, $entityName)
|
||||
{
|
||||
@@ -162,9 +162,20 @@ class Converter
|
||||
}
|
||||
|
||||
$tables[$entityName]->setPrimaryKey($primaryColumns);
|
||||
|
||||
//add indexes
|
||||
if (isset($entityParams['indexes']) && is_array($entityParams['indexes'])) {
|
||||
foreach ($entityParams['indexes'] as $indexName => $indexParams) {
|
||||
if (is_array($indexParams['columns'])) {
|
||||
$tableIndexName = $this->generateIndexName($indexName, $entityName);
|
||||
$indexList[$tableIndexName] = Util::toUnderScore($indexParams['columns']);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($indexList)) {
|
||||
foreach($indexList as $indexItem) {
|
||||
$tables[$entityName]->addIndex($indexItem);
|
||||
foreach($indexList as $indexName => $indexItem) {
|
||||
$tableIndexName = is_string($indexName) ? $indexName : null;
|
||||
$tables[$entityName]->addIndex($indexItem, $tableIndexName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,5 +372,21 @@ class Converter
|
||||
return $dependentEntities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate index name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateIndexName($name, $entityName)
|
||||
{
|
||||
$names = array(
|
||||
'IDX',
|
||||
);
|
||||
|
||||
$names[] = strtoupper( Util::toUnderScore($entityName) );
|
||||
$names[] = strtoupper( Util::toUnderScore($name) );
|
||||
|
||||
return implode('_', $names);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ class Schema
|
||||
$result = true;
|
||||
$connection = $this->getConnection();
|
||||
foreach ($queries as $sql) {
|
||||
$GLOBALS['log']->debug('SCHEMA, Execute Query: '.$sql);
|
||||
$GLOBALS['log']->info('SCHEMA, Execute Query: '.$sql);
|
||||
try {
|
||||
$result &= (bool) $connection->executeQuery($sql);
|
||||
} catch (\Exception $e) {
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils;
|
||||
|
||||
class DateTime
|
||||
class DateTime
|
||||
{
|
||||
protected $dataFormat;
|
||||
|
||||
@@ -48,8 +48,8 @@ class DateTime
|
||||
$this->dateFormat = $dateFormat;
|
||||
$this->timeFormat = $timeFormat;
|
||||
|
||||
$this->timezone = new \DateTimeZone($timeZone);
|
||||
}
|
||||
$this->timezone = new \DateTimeZone($timeZone);
|
||||
}
|
||||
|
||||
protected function getPhpDateFormat()
|
||||
{
|
||||
@@ -63,7 +63,7 @@ class DateTime
|
||||
|
||||
public function convertSystemDateToGlobal($string)
|
||||
{
|
||||
$dateTime = \DateTime::createFromFormat('Y-m-d', $string);
|
||||
$dateTime = \DateTime::createFromFormat('Y-m-d', $string);
|
||||
if ($dateTime) {
|
||||
return $dateTime->format($this->getPhpDateFormat());
|
||||
}
|
||||
@@ -72,12 +72,32 @@ class DateTime
|
||||
|
||||
public function convertSystemDateTimeToGlobal($string)
|
||||
{
|
||||
$dateTime = \DateTime::createFromFormat('Y-m-d H:i:s', $string);
|
||||
$dateTime = \DateTime::createFromFormat('Y-m-d H:i:s', $string);
|
||||
if ($dateTime) {
|
||||
return $dateTime->setTimezone($this->timezone)->format($this->getPhpDateTimeFormat());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function convertSystemDate($string)
|
||||
{
|
||||
return $this->convertSystemDateToGlobal($string);
|
||||
}
|
||||
|
||||
public function convertSystemDateTime($string, $timezone = null)
|
||||
{
|
||||
$dateTime = \DateTime::createFromFormat('Y-m-d H:i:s', $string);
|
||||
if (empty($timezone)) {
|
||||
$timezone = $this->timezone;
|
||||
} else {
|
||||
$timezone = new \DateTimeZone($timezone);
|
||||
}
|
||||
if ($dateTime) {
|
||||
return $dateTime->setTimezone($timezone)->format($this->getPhpDateTimeFormat());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -723,7 +723,7 @@ class Manager
|
||||
*/
|
||||
public function getPHPFormat($content)
|
||||
{
|
||||
if (empty($content)) {
|
||||
if (!isset($content)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,8 +53,6 @@ class Metadata
|
||||
|
||||
private $ormCacheFile = 'data/cache/application/ormMetadata.php';
|
||||
|
||||
|
||||
|
||||
private $moduleList = null;
|
||||
|
||||
public function __construct(\Espo\Core\Utils\Config $config, \Espo\Core\Utils\File\Manager $fileManager)
|
||||
@@ -130,7 +128,7 @@ class Metadata
|
||||
*/
|
||||
protected function getData()
|
||||
{
|
||||
if (!isset($this->meta)) {
|
||||
if (empty($this->meta) || !is_array($this->meta)) {
|
||||
$this->init();
|
||||
}
|
||||
|
||||
@@ -282,7 +280,7 @@ class Metadata
|
||||
|
||||
public function getOrmMetadata($reload = false)
|
||||
{
|
||||
if (!empty($this->ormMeta) && !$reload) {
|
||||
if (!empty($this->ormMeta) && is_array($this->ormMeta) && !$reload) {
|
||||
return $this->ormMeta;
|
||||
}
|
||||
|
||||
@@ -329,7 +327,6 @@ class Metadata
|
||||
return implode($delim, array($path, 'Repositories', Util::normilizeClassName(ucfirst($entityName))));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Scopes
|
||||
*
|
||||
@@ -342,10 +339,15 @@ class Metadata
|
||||
}
|
||||
|
||||
$metadata = $this->getMetadataOnly(false);
|
||||
if (!is_array($metadata)) {
|
||||
$metadata = $this->getMetadataOnly(false, true);
|
||||
}
|
||||
|
||||
$scopes = array();
|
||||
foreach ($metadata['scopes'] as $name => $details) {
|
||||
$scopes[$name] = isset($details['module']) ? $details['module'] : false;
|
||||
if (is_array($metadata['scopes'])) {
|
||||
foreach ($metadata['scopes'] as $name => $details) {
|
||||
$scopes[$name] = isset($details['module']) ? $details['module'] : false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->scopes = $scopes;
|
||||
@@ -418,9 +420,9 @@ class Metadata
|
||||
*/
|
||||
public function isScopeExists($scopeName)
|
||||
{
|
||||
$scopeModuleMap= $this->getScopes();
|
||||
$scopeModuleMap = $this->getScopes();
|
||||
|
||||
$lowerEntityName= strtolower($scopeName);
|
||||
$lowerEntityName = strtolower($scopeName);
|
||||
foreach($scopeModuleMap as $rowEntityName => $rowModuleName) {
|
||||
if ($lowerEntityName == strtolower($rowEntityName)) {
|
||||
return true;
|
||||
|
||||
@@ -63,13 +63,21 @@ class Util
|
||||
* Convert name to Camel Case format, ex. camel_case to camelCase
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $symbol
|
||||
* @param string | array $symbol
|
||||
* @param boolean $capitaliseFirstChar
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function toCamelCase($name, $symbol = '_', $capitaliseFirstChar = false)
|
||||
{
|
||||
if (is_array($name)) {
|
||||
foreach ($name as &$value) {
|
||||
$value = static::toCamelCase($value, $symbol, $capitaliseFirstChar);
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
if($capitaliseFirstChar) {
|
||||
$name[0] = strtoupper($name[0]);
|
||||
}
|
||||
@@ -85,12 +93,20 @@ class Util
|
||||
* Convert name from Camel Case format.
|
||||
* ex. camelCase to camel-case
|
||||
*
|
||||
* @param string $name
|
||||
* @param string | array $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function fromCamelCase($name, $symbol = '_')
|
||||
{
|
||||
if (is_array($name)) {
|
||||
foreach ($name as &$value) {
|
||||
$value = static::fromCamelCase($value, $symbol);
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
$name[0] = strtolower($name[0]);
|
||||
return preg_replace_callback('/([A-Z])/', function ($matches) use ($symbol) {
|
||||
return $symbol . strtolower($matches[1]);
|
||||
@@ -101,7 +117,7 @@ class Util
|
||||
* Convert name from Camel Case format to underscore.
|
||||
* ex. camelCase to camel_case
|
||||
*
|
||||
* @param string $name
|
||||
* @param string | array $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
||||
@@ -18,24 +18,24 @@
|
||||
*
|
||||
* 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 Integration extends \Espo\Core\ORM\Entity
|
||||
{
|
||||
{
|
||||
public function get($name)
|
||||
{
|
||||
if ($name == 'id') {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
|
||||
if ($this->hasField($name)) {
|
||||
if (array_key_exists($name, $this->valuesContainer)) {
|
||||
return $this->valuesContainer[$name];
|
||||
}
|
||||
} else {
|
||||
if ($this->get('data')) {
|
||||
if ($this->get('data')) {
|
||||
$data = $this->get('data');
|
||||
} else {
|
||||
$data = new \stdClass();
|
||||
@@ -46,20 +46,20 @@ class Integration extends \Espo\Core\ORM\Entity
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public function clear($name)
|
||||
{
|
||||
parent::clear($name);
|
||||
|
||||
|
||||
$data = $this->get('data');
|
||||
if (empty($data)) {
|
||||
$data = new \stdClass();
|
||||
}
|
||||
unset($data->$name);
|
||||
$this->set('data', $data);
|
||||
$this->set('data', $data);
|
||||
}
|
||||
|
||||
public function set($p1, $p2)
|
||||
|
||||
public function set($p1, $p2 = null)
|
||||
{
|
||||
if (is_array($p1)) {
|
||||
if ($p2 === null) {
|
||||
@@ -68,49 +68,46 @@ class Integration extends \Espo\Core\ORM\Entity
|
||||
$this->populateFromArray($p1, $p2);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$name = $p1;
|
||||
$value = $p2;
|
||||
|
||||
|
||||
if ($name == 'id') {
|
||||
$this->id = $value;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ($this->hasField($name)) {
|
||||
$this->valuesContainer[$name] = $value;
|
||||
} else {
|
||||
if (!$this->get('enabled')) {
|
||||
return;
|
||||
}
|
||||
$data = $this->get('data');
|
||||
if (empty($data)) {
|
||||
$data = new \stdClass();
|
||||
}
|
||||
$data->$name = $value;
|
||||
$this->set('data', $data);
|
||||
$this->set('data', $data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function populateFromArray(array $arr, $onlyAccessible = true, $reset = false)
|
||||
{
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
foreach ($arr as $field => $value) {
|
||||
|
||||
foreach ($arr as $field => $value) {
|
||||
if (is_string($field)) {
|
||||
if (is_array($value) || ($value instanceof \stdClass)) {
|
||||
$value = json_encode($value);
|
||||
}
|
||||
|
||||
|
||||
if ($this->hasField($field)) {
|
||||
$fields = $this->getFields();
|
||||
$fieldDefs = $fields[$field];
|
||||
|
||||
|
||||
if (!is_null($value)) {
|
||||
switch ($fieldDefs['type']) {
|
||||
case self::VARCHAR:
|
||||
case self::VARCHAR:
|
||||
break;
|
||||
case self::BOOL:
|
||||
$value = ($value === 'true' || $value === '1' || $value === true);
|
||||
@@ -138,20 +135,20 @@ class Integration extends \Espo\Core\ORM\Entity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
$this->set($field, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
{
|
||||
$arr = array();
|
||||
if (isset($this->id)) {
|
||||
$arr['id'] = $this->id;
|
||||
}
|
||||
foreach ($this->fields as $field => $defs) {
|
||||
foreach ($this->fields as $field => $defs) {
|
||||
if ($field == 'id') {
|
||||
continue;
|
||||
}
|
||||
@@ -159,17 +156,17 @@ class Integration extends \Espo\Core\ORM\Entity
|
||||
$arr[$field] = $this->get($field);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$data = $this->get('data');
|
||||
if (empty($data)) {
|
||||
$data = new \stdClass();
|
||||
}
|
||||
|
||||
|
||||
$dataArr = get_object_vars($data);
|
||||
|
||||
$arr = array_merge($arr, $dataArr);
|
||||
$arr = array_merge($arr, $dataArr);
|
||||
return $arr;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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\Entities;
|
||||
|
||||
@@ -26,16 +26,29 @@ class Note extends \Espo\Core\ORM\Entity
|
||||
{
|
||||
public function loadAttachments()
|
||||
{
|
||||
$collection = $this->get('attachments');
|
||||
$data = $this->get('data');
|
||||
if (!empty($data) && !empty($data->attachmentsIds)) {
|
||||
$attachmentsIds = $data->attachmentsIds;
|
||||
$collection = array();
|
||||
foreach ($attachmentsIds as $id) {
|
||||
$attachment = $this->entityManager->getEntity('Attachment', $id);
|
||||
if ($attachment) {
|
||||
$collection[] = $attachment;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$collection = $this->get('attachments');
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
$names = new \stdClass();
|
||||
$types = new \stdClass();
|
||||
$types = new \stdClass();
|
||||
foreach ($collection as $e) {
|
||||
$id = $e->id;
|
||||
$ids[] = $id;
|
||||
$names->$id = $e->get('name');
|
||||
$types->$id = $e->get('type');
|
||||
}
|
||||
}
|
||||
$this->set('attachmentsIds', $ids);
|
||||
$this->set('attachmentsNames', $names);
|
||||
$this->set('attachmentsTypes', $types);
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\ORM\DB;
|
||||
namespace Espo\Entities;
|
||||
|
||||
class MysqlMapper extends \Espo\ORM\DB\MysqlMapper
|
||||
class PasswordChangeRequest extends \Espo\Core\ORM\Entity
|
||||
{
|
||||
protected $returnCollection = false;
|
||||
|
||||
}
|
||||
|
||||
85
application/Espo/EntryPoints/Avatar.php
Normal file
85
application/Espo/EntryPoints/Avatar.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\EntryPoints;
|
||||
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
|
||||
class Avatar extends Image
|
||||
{
|
||||
public static $authRequired = true;
|
||||
|
||||
public function run()
|
||||
{
|
||||
if (empty($_GET['id'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$userId = $_GET['id'];
|
||||
|
||||
$user = $this->getEntityManager()->getEntity('User', $userId);
|
||||
if (!$user) {
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
if (isset($_GET['attachmentId'])) {
|
||||
$id = $_GET['attachmentId'];
|
||||
if ($id == 'false') {
|
||||
$id = false;
|
||||
}
|
||||
} else {
|
||||
$id = $user->get('avatarId');
|
||||
}
|
||||
|
||||
|
||||
$size = null;
|
||||
if (!empty($_GET['size'])) {
|
||||
$size = $_GET['size'];
|
||||
}
|
||||
|
||||
if (!empty($id)) {
|
||||
$this->show($id, $size);
|
||||
} else {
|
||||
$identicon = new \Identicon\Identicon();
|
||||
if (empty($size)) {
|
||||
$size = 'small';
|
||||
}
|
||||
if (!empty($this->imageSizes[$size])) {
|
||||
$width = $this->imageSizes[$size][0];
|
||||
|
||||
header('Cache-Control: max-age=360000, must-revalidate');
|
||||
header('Content-Type: image/png');
|
||||
|
||||
ob_clean();
|
||||
flush();
|
||||
$identicon->displayImage($userId, $width);
|
||||
exit;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
64
application/Espo/EntryPoints/ChangePassword.php
Normal file
64
application/Espo/EntryPoints/ChangePassword.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\EntryPoints;
|
||||
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class ChangePassword extends \Espo\Core\EntryPoints\Base
|
||||
{
|
||||
public static $authRequired = false;
|
||||
|
||||
public function run()
|
||||
{
|
||||
$requestId = $_GET['id'];
|
||||
if (empty($requestId)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$config = $this->getConfig();
|
||||
|
||||
$p = $this->getEntityManager()->getRepository('PasswordChangeRequest')->where(array(
|
||||
'requestId' => $requestId
|
||||
))->findOne();
|
||||
|
||||
if (!$p) {
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
$runScript = "
|
||||
app.getController('PasswordChangeRequest', function (controller) {
|
||||
controller.doAction('passwordChange', '{$requestId}');
|
||||
});
|
||||
";
|
||||
|
||||
$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('{{runScript}}', $runScript , $html);
|
||||
echo $html;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -37,9 +37,11 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
'image/gif',
|
||||
);
|
||||
|
||||
protected $imageSizes = array(
|
||||
'x-small' => array(64, 64),
|
||||
'small' => array(128, 128),
|
||||
protected $imageSizes = array(
|
||||
'xxx-small' => array(18, 18),
|
||||
'xx-small' => array(32, 32),
|
||||
'x-small' => array(64, 64),
|
||||
'small' => array(128, 128),
|
||||
'medium' => array(256, 256),
|
||||
'large' => array(512, 512),
|
||||
'x-large' => array(864, 864),
|
||||
@@ -48,16 +50,17 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
|
||||
|
||||
public function run()
|
||||
{
|
||||
$id = $_GET['id'];
|
||||
if (empty($id)) {
|
||||
{
|
||||
if (empty($_GET['id'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
}
|
||||
|
||||
$id = $_GET['id'];
|
||||
|
||||
$size = null;
|
||||
$size = null;
|
||||
if (!empty($_GET['size'])) {
|
||||
$size = $_GET['size'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->show($id, $size);
|
||||
}
|
||||
@@ -68,10 +71,10 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
|
||||
if (!$attachment) {
|
||||
throw new NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
if ($attachment->get('parentId') && $attachment->get('parentType')) {
|
||||
$parent = $this->getEntityManager()->getEntity($attachment->get('parentType'), $attachment->get('parentId'));
|
||||
$parent = $this->getEntityManager()->getEntity($attachment->get('parentType'), $attachment->get('parentId'));
|
||||
if ($parent && !$this->getAcl()->check($parent)) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
@@ -94,8 +97,8 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
$thumbFilePath = "data/upload/thumbs/{$attachment->id}_{$size}";
|
||||
|
||||
if (!file_exists($thumbFilePath)) {
|
||||
$targetImage = $this->getThumbImage($filePath, $fileType, $size);
|
||||
ob_start();
|
||||
$targetImage = $this->getThumbImage($filePath, $fileType, $size);
|
||||
ob_start();
|
||||
|
||||
switch ($fileType) {
|
||||
case 'image/jpeg':
|
||||
@@ -106,31 +109,32 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
break;
|
||||
case 'image/gif':
|
||||
imagegif($targetImage);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
$contents = ob_get_contents();
|
||||
ob_end_clean();
|
||||
imagedestroy($targetImage);
|
||||
$this->getContainer()->get('fileManager')->putContents($thumbFilePath, $contents);
|
||||
}
|
||||
$filePath = $thumbFilePath;
|
||||
imagedestroy($targetImage);
|
||||
$this->getContainer()->get('fileManager')->putContents($thumbFilePath, $contents);
|
||||
}
|
||||
$filePath = $thumbFilePath;
|
||||
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($size)) {
|
||||
if (!empty($size)) {
|
||||
$fileName = $attachment->id . '_' . $size . '.jpg';
|
||||
} else {
|
||||
$fileName = $attachment->get('name');
|
||||
}
|
||||
header('Content-Disposition:inline;filename="'.$fileName.'"');
|
||||
}
|
||||
header('Content-Disposition:inline;filename="'.$fileName.'"');
|
||||
if (!empty($fileType)) {
|
||||
header('Content-Type: ' . $fileType);
|
||||
}
|
||||
}
|
||||
header('Pragma: public');
|
||||
$fileSize = filesize($filePath);
|
||||
header('Cache-Control: max-age=360000, must-revalidate');
|
||||
$fileSize = filesize($filePath);
|
||||
if ($fileSize) {
|
||||
header('Content-Length: ' . $fileSize);
|
||||
}
|
||||
@@ -144,15 +148,14 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
{
|
||||
list($originalWidth, $originalHeight) = getimagesize($filePath);
|
||||
list($width, $height) = $this->imageSizes[$size];
|
||||
|
||||
|
||||
if ($originalWidth <= $width && $originalHeight <= $height) {
|
||||
$targetWidth = $originalWidth;
|
||||
$targetHeight = $originalHeight;
|
||||
$targetHeight = $originalHeight;
|
||||
} else {
|
||||
if ($originalWidth > $originalHeight) {
|
||||
$targetWidth = $width;
|
||||
$targetHeight = $originalHeight / ($originalWidth / $width);
|
||||
$targetHeight = $originalHeight / ($originalWidth / $width);
|
||||
if ($targetHeight > $height) {
|
||||
$targetHeight = $height;
|
||||
$targetWidth = $originalWidth / ($originalHeight / $height);
|
||||
@@ -165,13 +168,13 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
$targetHeight = $originalHeight / ($originalWidth / $width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
|
||||
$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
|
||||
switch ($fileType) {
|
||||
case 'image/jpeg':
|
||||
$sourceImage = imagecreatefromjpeg($filePath);
|
||||
imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight);
|
||||
imagecopyresampled ($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight);
|
||||
break;
|
||||
case 'image/png':
|
||||
$sourceImage = imagecreatefrompng($filePath);
|
||||
@@ -183,8 +186,8 @@ class Image extends \Espo\Core\EntryPoints\Base
|
||||
break;
|
||||
case 'image/gif':
|
||||
$sourceImage = imagecreatefromgif($filePath);
|
||||
imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight);
|
||||
break;
|
||||
imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -69,6 +69,9 @@ class Mentions extends \Espo\Core\Hooks\Base
|
||||
);
|
||||
$mentionData->$item = (object) $m;
|
||||
if (!in_array($item, $previousMentionList)) {
|
||||
if ($user->id == $this->getUser()->id) {
|
||||
continue;
|
||||
}
|
||||
$this->notifyAboutMention($entity, $user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,30 +40,75 @@ class Invitations
|
||||
|
||||
protected function parseInvitationTemplate($contents, $entity, $invitee = null, $uid = null)
|
||||
{
|
||||
$contents = str_replace('{name}', $entity->get('name'), $contents);
|
||||
|
||||
$contents = str_replace('{eventType}', strtolower($this->language->translate($entity->getEntityName(), 'scopeNames')), $contents);
|
||||
$contents = str_replace('{dateStart}', $this->dateTime->convertSystemDateTimeToGlobal($entity->get('dateStart')), $contents);
|
||||
|
||||
foreach ($entity->getFields() as $field => $d) {
|
||||
if (empty($d['type'])) continue;
|
||||
$key = '{'.$field.'}';
|
||||
switch ($d['type']) {
|
||||
case 'datetime':
|
||||
$contents = str_replace($key, $this->dateTime->convertSystemDateTimeToGlobal($entity->get($field)), $contents);
|
||||
break;
|
||||
case 'date':
|
||||
$contents = str_replace($key, $this->dateTime->convertSystemDateToGlobal($entity->get($field)), $contents);
|
||||
break;
|
||||
default:
|
||||
$contents = str_replace($key, $entity->get($field), $contents);
|
||||
}
|
||||
}
|
||||
|
||||
if ($invitee) {
|
||||
$contents = str_replace('{inviteeName}', $invitee->get('name'), $contents);
|
||||
}
|
||||
|
||||
$siteUrl = rtrim($this->config->get('siteUrl'), '/');
|
||||
|
||||
$url = $siteUrl . '/#' . $entity->getEntityName() . '/view/' . $entity->id;
|
||||
$contents = str_replace('{url}', $url, $contents);
|
||||
|
||||
if ($invitee && $invitee->getEntityName() != 'User') {
|
||||
$contents = preg_replace('/\{#userOnly\}(.*?)\{\/userOnly\}/s', '', $contents);
|
||||
}
|
||||
|
||||
$contents = str_replace('{#userOnly}', '', $contents);
|
||||
$contents = str_replace('{/userOnly}', '', $contents);
|
||||
|
||||
if ($uid) {
|
||||
$siteUrl = rtrim($this->config->get('siteUrl'), '/');
|
||||
$contents = str_replace('{acceptLink}', $siteUrl . '?entryPoint=eventConfirmation&action=accept&uid=' . $uid->get('name'), $contents);
|
||||
$contents = str_replace('{declineLink}', $siteUrl . '?entryPoint=eventConfirmation&action=decline&uid=' . $uid->get('name'), $contents);
|
||||
}
|
||||
return $contents;
|
||||
}
|
||||
|
||||
protected function getTemplate($name)
|
||||
{
|
||||
$systemLanguage = $this->config->get('language');
|
||||
|
||||
$fileName = 'custom/Espo/Custom/Resources/templates/'.$name.'.'.$systemLanguage.'.tpl';
|
||||
if (!file_exists($fileName)) {
|
||||
$fileName = 'application/Espo/Modules/Crm/Resources/templates/'.$name.'.'.$systemLanguage.'.tpl';
|
||||
}
|
||||
if (!file_exists($fileName)) {
|
||||
$fileName = 'custom/Espo/Custom/Resources/templates/'.$name.'.en_US.tpl';
|
||||
}
|
||||
if (!file_exists($fileName)) {
|
||||
$fileName = 'application/Espo/Modules/Crm/Resources/templates/'.$name.'.en_US.tpl';
|
||||
}
|
||||
|
||||
return file_get_contents($fileName);
|
||||
}
|
||||
|
||||
public function sendInvitation(Entity $entity, Entity $invitee, $link)
|
||||
{
|
||||
$uid = $this->getEntityManager()->getEntity('UniqueId');
|
||||
$uid->set('data', json_encode(array(
|
||||
$uid->set('data', array(
|
||||
'eventType' => $entity->getEntityName(),
|
||||
'eventId' => $entity->id,
|
||||
'inviteeId' => $invitee->id,
|
||||
'inviteeType' => $invitee->getEntityName(),
|
||||
'link' => $link
|
||||
)));
|
||||
));
|
||||
$this->getEntityManager()->saveEntity($uid);
|
||||
|
||||
$emailAddress = $invitee->get('emailAddress');
|
||||
@@ -73,32 +118,9 @@ class Invitations
|
||||
|
||||
$email = $this->getEntityManager()->getEntity('Email');
|
||||
$email->set('to', $emailAddress);
|
||||
|
||||
$systemLanguage = $this->config->get('language');
|
||||
|
||||
$subjectTplFileName = 'custom/Espo/Custom/Resources/templates/InvitationSubject.'.$systemLanguage.'.tpl';
|
||||
if (!file_exists($subjectTplFileName)) {
|
||||
$subjectTplFileName = 'application/Espo/Modules/Crm/Resources/templates/InvitationSubject.'.$systemLanguage.'.tpl';
|
||||
}
|
||||
if (!file_exists($subjectTplFileName)) {
|
||||
$subjectTplFileName = 'custom/Espo/Custom/Resources/templates/InvitationSubject.en_US.tpl';
|
||||
}
|
||||
if (!file_exists($subjectTplFileName)) {
|
||||
$subjectTplFileName = 'application/Espo/Modules/Crm/Resources/templates/InvitationSubject.en_US.tpl';
|
||||
}
|
||||
$subjectTpl = file_get_contents($subjectTplFileName);
|
||||
|
||||
$bodyTplFileName = 'custom/Espo/Custom/Resources/templates/InvitationBody.'.$systemLanguage.'.tpl';
|
||||
if (!file_exists($bodyTplFileName)) {
|
||||
$bodyTplFileName = 'application/Espo/Modules/Crm/Resources/templates/InvitationBody.'.$systemLanguage.'.tpl';
|
||||
}
|
||||
if (!file_exists($bodyTplFileName)) {
|
||||
$bodyTplFileName = 'custom/Espo/Custom/Resources/templates/InvitationBody.en_US.tpl';
|
||||
}
|
||||
if (!file_exists($bodyTplFileName)) {
|
||||
$bodyTplFileName = 'application/Espo/Modules/Crm/Resources/templates/InvitationBody.en_US.tpl';
|
||||
}
|
||||
$bodyTpl = file_get_contents($bodyTplFileName);
|
||||
$subjectTpl = $this->getTemplate('InvitationSubject');
|
||||
$bodyTpl = $this->getTemplate('InvitationBody');
|
||||
|
||||
$subject = $this->parseInvitationTemplate($subjectTpl, $entity, $invitee, $uid);
|
||||
$subject = str_replace(array("\n", "\r"), '', $subject);
|
||||
@@ -107,7 +129,7 @@ class Invitations
|
||||
|
||||
$email->set('subject', $subject);
|
||||
$email->set('body', $body);
|
||||
$email->set('isHtml', true);
|
||||
$email->set('isHtml', true);
|
||||
$this->getEntityManager()->saveEntity($email);
|
||||
|
||||
$attachmentName = ucwords($this->language->translate($entity->getEntityName(), 'scopeNames')).'.ics';
|
||||
@@ -118,21 +140,21 @@ class Invitations
|
||||
'contents' => $this->getIscContents($entity),
|
||||
));
|
||||
|
||||
$email->addAttachment($attachment);
|
||||
$email->addAttachment($attachment);
|
||||
|
||||
$emailSender = $this->mailSender;
|
||||
|
||||
if ($this->smtpParams) {
|
||||
$emailSender->useSmtp($this->smtpParams);
|
||||
}
|
||||
$emailSender->send($email);
|
||||
$emailSender->send($email);
|
||||
|
||||
$this->getEntityManager()->removeEntity($email);
|
||||
}
|
||||
|
||||
protected function getIscContents(Entity $entity)
|
||||
{
|
||||
$user = $entity->get('assignedUser');
|
||||
$user = $entity->get('assignedUser');
|
||||
|
||||
$who = '';
|
||||
$email = '';
|
||||
|
||||
121
application/Espo/Modules/Crm/Business/Reminder/EmailReminder.php
Normal file
121
application/Espo/Modules/Crm/Business/Reminder/EmailReminder.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Modules\Crm\Business\Reminder;
|
||||
|
||||
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;
|
||||
$this->mailSender = $mailSender;
|
||||
$this->config = $config;
|
||||
$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');
|
||||
|
||||
foreach ($entity->getFields() as $field => $d) {
|
||||
if (empty($d['type'])) continue;
|
||||
$key = '{'.$field.'}';
|
||||
switch ($d['type']) {
|
||||
case 'datetime':
|
||||
$contents = str_replace($key, $this->dateTime->convertSystemDateTime($entity->get($field), $timezone), $contents);
|
||||
break;
|
||||
case 'date':
|
||||
$contents = str_replace($key, $this->dateTime->convertSystemDateToGlobal($entity->get($field)), $contents);
|
||||
break;
|
||||
default:
|
||||
$contents = str_replace($key, $entity->get($field), $contents);
|
||||
}
|
||||
}
|
||||
|
||||
if ($user) {
|
||||
$contents = str_replace('{userName}', $user->get('name'), $contents);
|
||||
}
|
||||
|
||||
$siteUrl = rtrim($this->config->get('siteUrl'), '/');
|
||||
|
||||
$url = $siteUrl . '/#' . $entity->getEntityName() . '/view/' . $entity->id;
|
||||
$contents = str_replace('{url}', $url, $contents);
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
protected function getTemplate($name)
|
||||
{
|
||||
$systemLanguage = $this->config->get('language');
|
||||
|
||||
$fileName = 'custom/Espo/Custom/Resources/templates/'.$name.'.'.$systemLanguage.'.tpl';
|
||||
if (!file_exists($fileName)) {
|
||||
$fileName = 'application/Espo/Modules/Crm/Resources/templates/'.$name.'.'.$systemLanguage.'.tpl';
|
||||
}
|
||||
if (!file_exists($fileName)) {
|
||||
$fileName = 'custom/Espo/Custom/Resources/templates/'.$name.'.en_US.tpl';
|
||||
}
|
||||
if (!file_exists($fileName)) {
|
||||
$fileName = 'application/Espo/Modules/Crm/Resources/templates/'.$name.'.en_US.tpl';
|
||||
}
|
||||
|
||||
return file_get_contents($fileName);
|
||||
}
|
||||
|
||||
public function send(Entity $reminder)
|
||||
{
|
||||
$user = $this->getEntityManager()->getEntity('User', $reminder->get('userId'));
|
||||
$entity = $this->getEntityManager()->getEntity($reminder->get('entityType'), $reminder->get('entityId'));
|
||||
|
||||
$emailAddress = $user->get('emailAddress');
|
||||
|
||||
if (empty($user) || empty($emailAddress) || empty($entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$email = $this->getEntityManager()->getEntity('Email');
|
||||
$email->set('to', $emailAddress);
|
||||
|
||||
$subjectTpl = $this->getTemplate('ReminderSubject');
|
||||
$bodyTpl = $this->getTemplate('ReminderBody');
|
||||
|
||||
$subject = $this->parseInvitationTemplate($subjectTpl, $entity, $user);
|
||||
$subject = str_replace(array("\n", "\r"), '', $subject);
|
||||
|
||||
$body = $this->parseInvitationTemplate($bodyTpl, $entity, $user);
|
||||
|
||||
$email->set('subject', $subject);
|
||||
$email->set('body', $body);
|
||||
$email->set('isHtml', true);
|
||||
$this->getEntityManager()->saveEntity($email);
|
||||
|
||||
$emailSender = $this->mailSender;
|
||||
|
||||
$emailSender->send($email);
|
||||
|
||||
$this->getEntityManager()->removeEntity($email);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ use \Espo\Core\Exceptions\Error,
|
||||
|
||||
class Activities extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
public static $defaultAction = 'index';
|
||||
public static $defaultAction = 'index';
|
||||
|
||||
public function actionListCalendarEvents($params, $data, $request)
|
||||
{
|
||||
@@ -48,6 +48,27 @@ class Activities extends \Espo\Core\Controllers\Base
|
||||
return $service->getEvents($this->getUser()->id, $from, $to);
|
||||
}
|
||||
|
||||
public function actionPopupNotifications()
|
||||
{
|
||||
$userId = $this->getUser()->id;
|
||||
|
||||
return $this->getService('Activities')->getPopupNotifications($userId);
|
||||
}
|
||||
|
||||
public function actionRemovePopupNotification($params, $data, $request)
|
||||
{
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
if (empty($data['id'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$id = $data['id'];
|
||||
|
||||
return $this->getService('Activities')->removeReminder($id);
|
||||
}
|
||||
|
||||
public function actionList($params, $data, $request)
|
||||
{
|
||||
$name = $params['name'];
|
||||
@@ -68,7 +89,7 @@ class Activities extends \Espo\Core\Controllers\Base
|
||||
$scope = null;
|
||||
if (!empty($where) && !empty($where['scope']) && $where['scope'] !== 'false') {
|
||||
$scope = $where['scope'];
|
||||
}
|
||||
}
|
||||
|
||||
$service = $this->getService('Activities');
|
||||
|
||||
|
||||
28
application/Espo/Modules/Crm/Entities/Reminder.php
Normal file
28
application/Espo/Modules/Crm/Entities/Reminder.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Entities;
|
||||
|
||||
class Reminder extends \Espo\Core\ORM\Entity
|
||||
{
|
||||
|
||||
}
|
||||
@@ -34,7 +34,7 @@ class EventConfirmation extends \Espo\Core\EntryPoints\Base
|
||||
public static $authRequired = false;
|
||||
|
||||
public function run()
|
||||
{
|
||||
{
|
||||
$uid = $_GET['uid'];
|
||||
$action = $_GET['action'];
|
||||
if (empty($uid) || empty($action)) {
|
||||
@@ -52,7 +52,7 @@ class EventConfirmation extends \Espo\Core\EntryPoints\Base
|
||||
return;
|
||||
}
|
||||
|
||||
$data = json_decode($uniqueId->get('data'));
|
||||
$data = $uniqueId->get('data');
|
||||
|
||||
$eventType = $data->eventType;
|
||||
$eventId = $data->eventId;
|
||||
@@ -63,7 +63,7 @@ class EventConfirmation extends \Espo\Core\EntryPoints\Base
|
||||
if (!empty($eventType) && !empty($eventId) && !empty($inviteeType) && !empty($inviteeId) && !empty($link)) {
|
||||
$event = $this->getEntityManager()->getEntity($eventType, $eventId);
|
||||
$invitee = $this->getEntityManager()->getEntity($inviteeType, $inviteeId);
|
||||
if ($event && $invitee) {
|
||||
if ($event && $invitee) {
|
||||
$relDefs = $event->getRelations();
|
||||
$tableName = Util::toUnderscore($relDefs[$link]['relationName']);
|
||||
|
||||
@@ -88,9 +88,9 @@ class EventConfirmation extends \Espo\Core\EntryPoints\Base
|
||||
echo $status;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error();
|
||||
}
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
68
application/Espo/Modules/Crm/Jobs/SendEmailReminders.php
Normal file
68
application/Espo/Modules/Crm/Jobs/SendEmailReminders.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Jobs;
|
||||
|
||||
use \Espo\Core\Exceptions;
|
||||
|
||||
class SendEmailReminders extends \Espo\Core\Jobs\Base
|
||||
{
|
||||
const MAX_PORTION_SIZE = 10;
|
||||
|
||||
public function run()
|
||||
{
|
||||
$dt = new \DateTime();
|
||||
|
||||
$now = $dt->format('Y-m-d H:i:s');
|
||||
$nowShifted = $dt->sub(new \DateInterval('PT1H'))->format('Y-m-d H:i:s');
|
||||
|
||||
$collection = $this->getEntityManager()->getRepository('Reminder')->where(array(
|
||||
'type' => 'Email',
|
||||
'remindAt<=' => $now,
|
||||
'startAt>' => $nowShifted,
|
||||
))->find();
|
||||
|
||||
if (!empty($collection)) {
|
||||
$emailReminder = new \Espo\Modules\Crm\Business\Reminder\EmailReminder(
|
||||
$this->getEntityManager(),
|
||||
$this->getContainer()->get('mailSender'),
|
||||
$this->getConfig(),
|
||||
$this->getContainer()->get('dateTime'),
|
||||
$this->getContainer()->get('language')
|
||||
);
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
}
|
||||
|
||||
foreach ($collection as $i => $entity) {
|
||||
if ($i >= self::MAX_PORTION_SIZE) {
|
||||
break;
|
||||
}
|
||||
$emailReminder->send($entity);
|
||||
|
||||
$sql = "DELETE FROM `reminder` WHERE id = ". $pdo->quote($entity->id);
|
||||
$pdo->query($sql);
|
||||
$this->getEntityManager()->removeEntity($entity);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,27 +24,8 @@ namespace Espo\Modules\Crm\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Call extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
protected function beforeSave(Entity $entity)
|
||||
{
|
||||
parent::beforeSave($entity);
|
||||
|
||||
$parentId = $entity->get('parentId');
|
||||
$parentType = $entity->get('parentType');
|
||||
if (!empty($parentId) || !empty($parentType)) {
|
||||
$parent = $this->getEntityManager()->getEntity($parentType, $parentId);
|
||||
if (!empty($parent)) {
|
||||
if ($parent->getEntityName() == 'Account') {
|
||||
$accountId = $parent->id;
|
||||
} else if ($parent->has('accountId')) {
|
||||
$accountId = $parent->get('accountId');
|
||||
}
|
||||
if (!empty($accountId)) {
|
||||
$entity->set('accountId', $accountId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
class Call extends Meeting
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -18,31 +18,31 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Contact extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
{
|
||||
public function handleSelectParams(&$params)
|
||||
{
|
||||
parent::handleSelectParams($params);
|
||||
parent::handleSelectParams($params);
|
||||
|
||||
if (empty($params['customJoin'])) {
|
||||
$params['customJoin'] = '';
|
||||
$params['customJoin'] = '';
|
||||
}
|
||||
|
||||
$params['customJoin'] .= "
|
||||
LEFT JOIN `account_contact` AS accountContact
|
||||
$params['customJoin'] .= "
|
||||
LEFT JOIN `account_contact` AS accountContact
|
||||
ON accountContact.contact_id = contact.id AND accountContact.account_id = contact.account_id AND accountContact.deleted = 0
|
||||
";
|
||||
}
|
||||
|
||||
public function save(Entity $entity)
|
||||
public function afterSave(Entity $entity)
|
||||
{
|
||||
$result = parent::save($entity);
|
||||
$result = parent::afterSave($entity);
|
||||
|
||||
$accountIdChanged = $entity->has('accountId') && $entity->get('accountId') != $entity->getFetched('accountId');
|
||||
$titleChanged = $entity->has('title') && $entity->get('title') != $entity->getFetched('title');
|
||||
@@ -52,7 +52,7 @@ class Contact extends \Espo\Core\ORM\Repositories\RDB
|
||||
if (empty($accountId)) {
|
||||
$this->unrelate($entity, 'accounts', $entity->getFetched('accountId'));
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($titleChanged) {
|
||||
@@ -62,20 +62,22 @@ class Contact extends \Espo\Core\ORM\Repositories\RDB
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($accountIdChanged || $titleChanged) {
|
||||
if ($accountIdChanged || $titleChanged) {
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$sql = "
|
||||
SELECT id, role FROM account_contact
|
||||
WHERE
|
||||
WHERE
|
||||
account_id = ".$pdo->quote($accountId)." AND
|
||||
contact_id = ".$pdo->quote($entity->id)." AND
|
||||
deleted = 0
|
||||
deleted = 0
|
||||
";
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
|
||||
if ($row = $sth->fetch()) {
|
||||
if ($titleChanged && $entity->get('title') != $row['role']) {
|
||||
$this->updateRelation($entity, 'accounts', $accountId, array(
|
||||
@@ -83,11 +85,13 @@ class Contact extends \Espo\Core\ORM\Repositories\RDB
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$this->relate($entity, 'accounts', $accountId, array(
|
||||
'role' => $entity->get('title')
|
||||
));
|
||||
if ($accountIdChanged) {
|
||||
$this->relate($entity, 'accounts', $accountId, array(
|
||||
'role' => $entity->get('title')
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -18,16 +18,16 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Repositories;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Meeting extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
{
|
||||
protected function beforeSave(Entity $entity)
|
||||
{
|
||||
{
|
||||
parent::beforeSave($entity);
|
||||
|
||||
$parentId = $entity->get('parentId');
|
||||
@@ -44,7 +44,143 @@ class Meeting extends \Espo\Core\ORM\Repositories\RDB
|
||||
$entity->set('accountId', $accountId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$assignedUserId = $entity->get('assignedUserId');
|
||||
if ($assignedUserId && $entity->has('usersIds')) {
|
||||
$usersIds = $entity->get('usersIds');
|
||||
if (!is_array($usersIds)) {
|
||||
$usersIds = array();
|
||||
}
|
||||
if (!in_array($assignedUserId, $usersIds)) {
|
||||
$usersIds[] = $assignedUserId;
|
||||
$entity->set('usersIds', $usersIds);
|
||||
$hash = $entity->get('usersNames');
|
||||
if ($hash instanceof \stdClass) {
|
||||
$hash->$assignedUserId = $entity->get('assignedUserName');
|
||||
$entity->set('usersNames', $hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getEntityReminders(Entity $entity)
|
||||
{
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
$reminders = array();
|
||||
|
||||
$sql = "
|
||||
SELECT id, `seconds`, `type`
|
||||
FROM `reminder`
|
||||
WHERE
|
||||
`entity_type` = ".$pdo->quote($entity->getEntityName())." AND
|
||||
`entity_id` = ".$pdo->quote($entity->id)." AND
|
||||
`deleted` = 0
|
||||
ORDER BY `seconds` ASC
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
$rows = $sth->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$o = new \StdClass();
|
||||
$o->seconds = intval($row['seconds']);
|
||||
$o->type = $row['type'];
|
||||
$reminders[] = $o;
|
||||
}
|
||||
|
||||
return $reminders;
|
||||
|
||||
$entity->set('reminders', $reminders);
|
||||
}
|
||||
|
||||
protected function afterSave(Entity $entity)
|
||||
{
|
||||
parent::afterSave($entity);
|
||||
|
||||
if (
|
||||
$entity->isNew() ||
|
||||
$entity->isFieldChanged('assignedUserId') ||
|
||||
$entity->isFieldChanged('dateStart') ||
|
||||
$entity->has('reminders')
|
||||
) {
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$reminderTypeList = $this->getMetadata()->get('entityDefs.Reminder.fields.type.options');
|
||||
|
||||
if (!$entity->has('reminders')) {
|
||||
$reminders = $this->getEntityReminders($entity);
|
||||
} else {
|
||||
$reminders = $entity->get('reminders');
|
||||
}
|
||||
|
||||
if (!$entity->isNew()) {
|
||||
$sql = "
|
||||
DELETE FROM `reminder`
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
deleted = 0
|
||||
";
|
||||
$pdo->query($sql);
|
||||
}
|
||||
|
||||
if (empty($reminders) || !is_array($reminders)) return;
|
||||
|
||||
$entityType = $entity->getEntityName();
|
||||
|
||||
$dateStart = $entity->get('dateStart');
|
||||
$assignedUserId = $entity->get('assignedUserId');
|
||||
|
||||
if (!$dateStart || !$assignedUserId) {
|
||||
$e = $this->get($entity->id);
|
||||
if ($e) {
|
||||
$dateStart = $e->get('dateStart');
|
||||
$assignedUserId = $e->get('assignedUserId');
|
||||
}
|
||||
}
|
||||
|
||||
if (!$dateStart || !$assignedUserId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$dateStartObj = new \DateTime($dateStart);
|
||||
if (!$dateStartObj) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($reminders as $item) {
|
||||
$remindAt = clone $dateStartObj;
|
||||
$seconds = intval($item->seconds);
|
||||
$type = $item->type;
|
||||
|
||||
if (!in_array($type , $reminderTypeList)) continue;
|
||||
|
||||
$remindAt->sub(new \DateInterval('PT' . $seconds . 'S'));
|
||||
|
||||
$id = uniqid();
|
||||
|
||||
$sql = "
|
||||
INSERT
|
||||
INTO `reminder`
|
||||
(id, entity_id, entity_type, `type`, user_id, remind_at, start_at, `seconds`)
|
||||
VALUES (
|
||||
".$pdo->quote($id).",
|
||||
".$pdo->quote($entity->id).",
|
||||
".$pdo->quote($entityType).",
|
||||
".$pdo->quote($type).",
|
||||
".$pdo->quote($assignedUserId).",
|
||||
".$pdo->quote($remindAt->format('Y-m-d H:i:s')).",
|
||||
".$pdo->quote($dateStart).",
|
||||
".$pdo->quote($seconds)."
|
||||
)
|
||||
";
|
||||
$pdo->query($sql);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
"description": "Beschreibung",
|
||||
"users": "Benutzer",
|
||||
"contacts": "Kontakte",
|
||||
"leads": "Interessenten"
|
||||
"leads": "Interessenten",
|
||||
"reminders": "Erinnerungen"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
@@ -34,7 +35,7 @@
|
||||
"Create Call": "Anruf erstellen",
|
||||
"Set Held": "Auf gehalten setzen",
|
||||
"Set Not Held": "Auf nicht gehalten setzen",
|
||||
"Send Invitations": "Einladungen versenden"
|
||||
"Send Invitations": "Einladungen versenden"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Geplant",
|
||||
|
||||
@@ -86,5 +86,11 @@
|
||||
"opportunity": "Verkaufschance",
|
||||
"contact": "Kontakt",
|
||||
"parent": "Bezieht sich auf"
|
||||
},
|
||||
"options": {
|
||||
"reminderTypes": {
|
||||
"Popup": "Popup",
|
||||
"Email": "E-Mail"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,15 @@
|
||||
"port": "Port",
|
||||
"monitoredFolders": "Überwachte Ordner",
|
||||
"trashFolder": "Papierkorb Ordner",
|
||||
"ssl": "SSL",
|
||||
"ssl": "SSL",
|
||||
"createCase": "Fall erstellen",
|
||||
"reply": "Antworten",
|
||||
"caseDistribution": "Fall Verteilung",
|
||||
"replyEmailTemplate": "Vorlage E-Mail Antwort",
|
||||
"replyFromAddress": "Von Adresse antworten",
|
||||
"replyToAddress": "Antwort an Adresse",
|
||||
"replyFromName": "Von Name antworten"
|
||||
"replyFromName": "Von Name antworten",
|
||||
"targetUserPosition": "Position Zielbenutzer"
|
||||
},
|
||||
"tooltips": {
|
||||
"reply": "Absender informieren, dass die E-Mail empfangen wurde.",
|
||||
@@ -44,7 +45,7 @@
|
||||
"Create InboundEmail": "Eingehende E-Mail erstellen",
|
||||
"IMAP": "IMAP",
|
||||
"Actions": "Aktionen",
|
||||
"Main": "Wichtig"
|
||||
"Main": "Wichtig"
|
||||
},
|
||||
"messages": {
|
||||
"couldNotConnectToImap": "Kann keine Verbindung zum IMAP Server herstellen"
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"description": "Beschreibung",
|
||||
"users": "Benutzer",
|
||||
"contacts": "Kontakte",
|
||||
"leads": "Interessenten"
|
||||
"leads": "Interessenten",
|
||||
"reminders": "Erinnerungen"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
@@ -29,7 +30,9 @@
|
||||
"Create Meeting": "Meeting erstellen",
|
||||
"Set Held": "Auf gehalten setzen",
|
||||
"Set Not Held": "Auf nicht gehalten setzen",
|
||||
"Send Invitations": "Einladungen versenden"
|
||||
"Send Invitations": "Einladungen versenden",
|
||||
"on time": "Aktuelle Zeit",
|
||||
"before": "Bevor"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Geplant",
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"Qualification": "Qualifikation",
|
||||
"Needs Analysis": "Bedarfserhebung",
|
||||
"Value Proposition": "Richtangebot",
|
||||
"Id. Decision Makers": "Entscheider ident.",
|
||||
"Id. Decision Makers": "Id. Entscheider",
|
||||
"Perception Analysis": "Analyse Sichtweise",
|
||||
"Proposal/Price Quote": "Preisangebot",
|
||||
"Negotiation/Review": "Verhandlung/Überarbeitung",
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
|
||||
"options": {
|
||||
"job": {
|
||||
"CheckInboundEmails": "Eingehende E-Mail überprüfen",
|
||||
"SendEmailReminders": "E-Mail Erinnerungen senden"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,8 @@
|
||||
"description": "Description",
|
||||
"users": "Users",
|
||||
"contacts": "Contacts",
|
||||
"leads": "Leads"
|
||||
"leads": "Leads",
|
||||
"reminders": "Reminders"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
@@ -34,7 +35,7 @@
|
||||
"Create Call": "Create Call",
|
||||
"Set Held": "Set Held",
|
||||
"Set Not Held": "Set Not Held",
|
||||
"Send Invitations": "Send Invitations"
|
||||
"Send Invitations": "Send Invitations"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planned",
|
||||
|
||||
@@ -86,5 +86,11 @@
|
||||
"opportunity": "Opportunity",
|
||||
"contact": "Contact",
|
||||
"parent": "Parent"
|
||||
},
|
||||
"options": {
|
||||
"reminderTypes": {
|
||||
"Popup": "Popup",
|
||||
"Email": "Email"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"description": "Description",
|
||||
"users": "Users",
|
||||
"contacts": "Contacts",
|
||||
"leads": "Leads"
|
||||
"leads": "Leads",
|
||||
"reminders": "Reminders"
|
||||
},
|
||||
"links": {
|
||||
},
|
||||
@@ -29,7 +30,9 @@
|
||||
"Create Meeting": "Create Meeting",
|
||||
"Set Held": "Set Held",
|
||||
"Set Not Held": "Set Not Held",
|
||||
"Send Invitations": "Send Invitations"
|
||||
"Send Invitations": "Send Invitations",
|
||||
"on time": "on time",
|
||||
"before": "before"
|
||||
},
|
||||
"presetFilters": {
|
||||
"planned": "Planned",
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
|
||||
"options": {
|
||||
"job": {
|
||||
"CheckInboundEmails": "Check Inbound Emails",
|
||||
"SendEmailReminders": "Send Email Reminders"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1,6 @@
|
||||
[{"name":"name","width":30,"link":true},{"name":"website"},{"name":"phoneNumber"},{"name":"billingAddressCity"}]
|
||||
[
|
||||
{"name":"name","width":30,"link":true},
|
||||
{"name":"website", "notSortable": true},
|
||||
{"name":"phoneNumber", "notSortable": true},
|
||||
{"name":"billingAddressCity"}
|
||||
]
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
[{"name":"name","link":true},{"name":"website"},{"name":"phoneNumber"}]
|
||||
@@ -1 +1,4 @@
|
||||
[{"name":"name","width":35,"link":"true"},{"name":"billingAddressCity"}]
|
||||
[
|
||||
{"name":"name","width":50,"link":"true"},
|
||||
{"name":"billingAddressCity"}
|
||||
]
|
||||
@@ -2,12 +2,11 @@
|
||||
{
|
||||
"label":"Overview",
|
||||
"rows": [
|
||||
[
|
||||
{"name":"name"},{"name":"parent"}],
|
||||
[{"name":"status"}, {"name":"direction"}],
|
||||
[{"name":"dateStart"}],
|
||||
[{"name":"duration"}],
|
||||
[{"name":"description"},false]
|
||||
[{"name":"name"},{"name":"parent"}],
|
||||
[{"name":"status"}, {"name":"direction"}],
|
||||
[{"name":"dateStart"}, {"name":"reminders"}],
|
||||
[{"name":"duration"}],
|
||||
[{"name":"description", "fullWidth": true}]
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
[{"name":"name","width":30,"link":true},{"name":"parent","width":18},{"name":"status"},{"name":"dateStart"},{"name":"assignedUser"}]
|
||||
[
|
||||
{"name":"name","width":30,"link":true},
|
||||
{"name":"parent","width":18},
|
||||
{"name":"status"},
|
||||
{"name":"dateStart"},
|
||||
{"name":"assignedUser"}
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
[{"name":"name","link":true},{"name":"parent"},{"name":"dateStart"}]
|
||||
@@ -1 +1,5 @@
|
||||
[{"name":"name","width":35,"link":"true"},{"name":"status"},{"name":"dateStart"}]
|
||||
[
|
||||
{"name":"name","width":35,"link":"true"},
|
||||
{"name":"status"},
|
||||
{"name":"dateStart"}
|
||||
]
|
||||
@@ -1 +1,6 @@
|
||||
[{"name":"number","width":18},{"name":"name","width":35,"link":true},{"name":"status"},{"name":"priority"}]
|
||||
[
|
||||
{"name":"number","width":18},
|
||||
{"name":"name","width":35,"link":true},
|
||||
{"name":"status"},
|
||||
{"name":"priority"}
|
||||
]
|
||||
@@ -1 +1,6 @@
|
||||
[{"name":"name","width":30,"link":true},{"name":"account","width":20},{"name":"emailAddress"},{"name":"phoneNumber"}]
|
||||
[
|
||||
{"name":"name","width":30,"link":true},
|
||||
{"name":"account","width":20},
|
||||
{"name":"emailAddress", "notSortable": true},
|
||||
{"name":"phoneNumber", "notSortable": true}
|
||||
]
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
[{"name":"name","link":true},{"name":"account"},{"name":"phoneNumber"},{"name":"emailAddress"}]
|
||||
[
|
||||
{"name":"name","link":true, "width": "40"},
|
||||
{"name":"account"},
|
||||
{"name":"emailAddress", "notSortable": true}
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[
|
||||
{"name":"name","width":32,"link":"true"},
|
||||
{"name":"account"},
|
||||
{"name":"emailAddress"},
|
||||
{"name":"phoneNumber"}
|
||||
{"name":"emailAddress", "notSortable": true},
|
||||
{"name":"phoneNumber", "notSortable": true}
|
||||
]
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
[{"name":"name","width":30,"link":true},{"name":"host"},{"name":"status"},{"name":"createCase"}]
|
||||
[
|
||||
{"name":"name","width":30,"link":true},
|
||||
{"name":"host", "notSortable": true},
|
||||
{"name":"status"},
|
||||
{"name":"createCase", "notSortable": true}
|
||||
]
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
[{"name":"name","width":25,"link":"true"},{"name":"status"},{"name":"emailAddress"},{"name":"assignedUser"},{"name":"createdAt"}]
|
||||
[
|
||||
{"name":"name", "width":25, "link":"true"},
|
||||
{"name":"status"},
|
||||
{"name":"emailAddress", "notSortable": true},
|
||||
{"name":"assignedUser"},
|
||||
{"name":"createdAt"}
|
||||
]
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
[{"name":"name","link":true},{"name":"website"},{"name":"emailAddress"}]
|
||||
@@ -1 +1,5 @@
|
||||
[{"name":"name","width":35,"link":true},{"name":"status"},{"name":"emailAddress"}]
|
||||
[
|
||||
{"name":"name", "width":32, "link":true},
|
||||
{"name":"status"},
|
||||
{"name":"emailAddress", "notSortable": true}
|
||||
]
|
||||
|
||||
@@ -1 +1,12 @@
|
||||
[{"label":"Overview","rows":[[{"name":"name"},{"name":"parent"}],[{"name":"status"},false],[{"name":"dateStart"},{"name":"dateEnd"}],[{"name":"duration"},false],[{"name":"description"},false]]}]
|
||||
[
|
||||
{
|
||||
"label":"Overview",
|
||||
"rows": [
|
||||
[{"name":"name"},{"name":"parent"}],
|
||||
[{"name":"status"},false],
|
||||
[{"name":"dateStart"},{"name":"dateEnd"}],
|
||||
[{"name":"duration"},{"name":"reminders"}],
|
||||
[{"name":"description", "fullWidth": true}]
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1 +1,7 @@
|
||||
[{"name":"name","width":30,"link":true},{"name":"parent","width":18},{"name":"status"},{"name":"dateStart"},{"name":"assignedUser"}]
|
||||
[
|
||||
{"name":"name","width":30,"link":true},
|
||||
{"name":"parent","width":18},
|
||||
{"name":"status"},
|
||||
{"name":"dateStart"},
|
||||
{"name":"assignedUser"}
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
[{"name":"name"},{"name":"parent"},{"name":"dateStart"}]
|
||||
@@ -1 +1,5 @@
|
||||
[{"name":"name","width":35,"link":"true"},{"name":"status"},{"name":"dateStart"}]
|
||||
[
|
||||
{"name":"name","width":35,"link":"true"},
|
||||
{"name":"status"},
|
||||
{"name":"dateStart"}
|
||||
]
|
||||
@@ -1 +1,8 @@
|
||||
[{"name":"name","width":25,"link":true},{"name":"account","width":18},{"name":"stage"},{"name":"amount"},{"name":"assignedUser"},{"name":"createdAt"}]
|
||||
[
|
||||
{"name":"name","width":25,"link":true},
|
||||
{"name":"account","width":18},
|
||||
{"name":"stage"},
|
||||
{"name":"amount"},
|
||||
{"name":"assignedUser"},
|
||||
{"name":"createdAt"}
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
[{"name":"name","link":true},{"name":"account"},{"name":"status"},{"name":"closeDate"}]
|
||||
@@ -1 +1,6 @@
|
||||
[{"name":"name","width":30,"link":true},{"name":"account"},{"name":"stage"},{"name":"createdAt"}]
|
||||
[
|
||||
{"name":"name", "width": 32, "link": true},
|
||||
{"name":"account"},
|
||||
{"name":"stage"},
|
||||
{"name":"createdAt"}
|
||||
]
|
||||
@@ -1 +1,7 @@
|
||||
[{"name":"name","width":30,"link":true},{"name":"emailAddress"},{"name":"phoneNumber"},{"name":"accountName"},{"name":"createdAt"}]
|
||||
[
|
||||
{"name":"name","width":30,"link":true},
|
||||
{"name":"emailAddress", "notSortable": true},
|
||||
{"name":"phoneNumber", "notSortable": true},
|
||||
{"name":"accountName"},
|
||||
{"name":"createdAt"}
|
||||
]
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
[{"name":"name","width":30,"link":true},{"name":"emailAddress"},{"name":"phoneNumber"}]
|
||||
[
|
||||
{"name":"name","width":30,"link":true},
|
||||
{"name":"emailAddress", "notSortable": true},
|
||||
{"name":"phoneNumber", "notSortable": true}
|
||||
]
|
||||
|
||||
@@ -1 +1,13 @@
|
||||
[{"label":"Overview","rows":[[{"name":"name"},{"name":"parent"}],[{"name":"status"},{"name":"priority"}],[{"name":"dateStart"},false],[{"name":"dateEnd"},false],[{"name":"description"},false]]}]
|
||||
[
|
||||
{
|
||||
"label":"Overview",
|
||||
"rows": [
|
||||
[{"name":"name"},{"name":"parent"}],
|
||||
[{"name":"status"},
|
||||
{"name":"priority"}],
|
||||
[{"name":"dateStart"},false],
|
||||
[{"name":"dateEnd"},false],
|
||||
[{"name":"description", "fullWidth": true}]
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1 +1,8 @@
|
||||
[{"name":"name","width":30,"link":true},{"name":"status"},{"name":"priority"},{"name":"dateEnd"},{"name":"assignedUser"},{"name":"createdAt"}]
|
||||
[
|
||||
{"name":"name","width":30,"link":true},
|
||||
{"name":"status"},
|
||||
{"name":"priority"},
|
||||
{"name":"dateEnd"},
|
||||
{"name":"assignedUser"},
|
||||
{"name":"createdAt"}
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
[{"name":"name","link":true},{"name":"status"},{"name":"parent"}]
|
||||
@@ -1 +1,7 @@
|
||||
[{"name":"name","width":30,"link":"true"},{"name":"status"},{"name":"priority"},{"name":"dateEnd"},{"name":"createdAt"}]
|
||||
[
|
||||
{"name":"name","width":30,"link":"true"},
|
||||
{"name":"status"},
|
||||
{"name":"priority"},
|
||||
{"name":"dateEnd"},
|
||||
{"name":"createdAt"}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"event": {
|
||||
"url": "Activities/action/popupNotifications",
|
||||
"interval": 15,
|
||||
"view": "Crm:Meeting.PopupNotification"
|
||||
}
|
||||
}
|
||||
@@ -162,5 +162,13 @@
|
||||
"collection": {
|
||||
"sortBy": "name",
|
||||
"asc": true
|
||||
},
|
||||
"indexes": {
|
||||
"name": {
|
||||
"columns": ["name", "deleted"]
|
||||
},
|
||||
"assignedUser": {
|
||||
"columns": ["assignedUserId", "deleted"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
"options": [300, 600, 900, 1800, 2700, 3600, 7200],
|
||||
"default": 300
|
||||
},
|
||||
"reminders": {
|
||||
"type": "jsonArray",
|
||||
"notStorable": true,
|
||||
"view": "Crm:Meeting.Fields.Reminders"
|
||||
},
|
||||
"direction": {
|
||||
"type": "enum",
|
||||
"options": ["Outbound", "Inbound"],
|
||||
@@ -166,5 +171,22 @@
|
||||
"collection": {
|
||||
"sortBy": "dateStart",
|
||||
"asc": false
|
||||
},
|
||||
"indexes": {
|
||||
"dateStartStatus": {
|
||||
"columns": ["dateStart", "status"]
|
||||
},
|
||||
"dateStart": {
|
||||
"columns": ["dateStart", "deleted"]
|
||||
},
|
||||
"status": {
|
||||
"columns": ["status", "deleted"]
|
||||
},
|
||||
"assignedUser": {
|
||||
"columns": ["assignedUserId", "deleted"]
|
||||
},
|
||||
"assignedUserStatus": {
|
||||
"columns": ["assignedUserId", "status"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"required": true
|
||||
},
|
||||
"number": {
|
||||
"type": "autoincrement"
|
||||
"type": "autoincrement",
|
||||
"index": true
|
||||
},
|
||||
"status": {
|
||||
"type": "enum",
|
||||
@@ -116,5 +117,16 @@
|
||||
"sortBy": "number",
|
||||
"asc": false,
|
||||
"boolFilters": ["onlyMy"]
|
||||
},
|
||||
"indexes": {
|
||||
"status": {
|
||||
"columns": ["status", "deleted"]
|
||||
},
|
||||
"assignedUser": {
|
||||
"columns": ["assignedUserId", "deleted"]
|
||||
},
|
||||
"assignedUserStatus": {
|
||||
"columns": ["assignedUserId", "status"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,5 +190,16 @@
|
||||
"collection": {
|
||||
"sortBy": "name",
|
||||
"asc": true
|
||||
},
|
||||
"indexes": {
|
||||
"firstName": {
|
||||
"columns": ["firstName", "deleted"]
|
||||
},
|
||||
"name": {
|
||||
"columns": ["firstName", "lastName"]
|
||||
},
|
||||
"assignedUser": {
|
||||
"columns": ["assignedUserId", "deleted"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
},
|
||||
"opportunityAmountConverted": {
|
||||
"type": "currencyConverted",
|
||||
"readOnly": true
|
||||
"readOnly": true
|
||||
},
|
||||
"website": {
|
||||
"type": "url"
|
||||
@@ -199,5 +199,28 @@
|
||||
"collection": {
|
||||
"sortBy": "createdAt",
|
||||
"asc": false
|
||||
},
|
||||
"indexes": {
|
||||
"firstName": {
|
||||
"columns": ["firstName", "deleted"]
|
||||
},
|
||||
"name": {
|
||||
"columns": ["firstName", "lastName"]
|
||||
},
|
||||
"status": {
|
||||
"columns": ["status", "deleted"]
|
||||
},
|
||||
"createdAt": {
|
||||
"columns": ["createdAt", "deleted"]
|
||||
},
|
||||
"createdAtStatus": {
|
||||
"columns": ["createdAt", "status"]
|
||||
},
|
||||
"assignedUser": {
|
||||
"columns": ["assignedUserId", "deleted"]
|
||||
},
|
||||
"assignedUserStatus": {
|
||||
"columns": ["assignedUserId", "status"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
"options": [900, 1800, 3600, 7200, 10800, 86400],
|
||||
"default": 3600
|
||||
},
|
||||
"reminders": {
|
||||
"type": "jsonArray",
|
||||
"notStorable": true,
|
||||
"view": "Crm:Meeting.Fields.Reminders"
|
||||
},
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
@@ -161,5 +166,22 @@
|
||||
"collection": {
|
||||
"sortBy": "dateStart",
|
||||
"asc": false
|
||||
},
|
||||
"indexes": {
|
||||
"dateStartStatus": {
|
||||
"columns": ["dateStart", "status"]
|
||||
},
|
||||
"dateStart": {
|
||||
"columns": ["dateStart", "deleted"]
|
||||
},
|
||||
"status": {
|
||||
"columns": ["status", "deleted"]
|
||||
},
|
||||
"assignedUser": {
|
||||
"columns": ["assignedUserId", "deleted"]
|
||||
},
|
||||
"assignedUserStatus": {
|
||||
"columns": ["assignedUserId", "status"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,5 +163,22 @@
|
||||
"Negotiation/Review": 90,
|
||||
"Closed Won": 100,
|
||||
"Closed Lost": 0
|
||||
},
|
||||
"indexes": {
|
||||
"stage": {
|
||||
"columns": ["stage", "deleted"]
|
||||
},
|
||||
"assignedUser": {
|
||||
"columns": ["assignedUserId", "deleted"]
|
||||
},
|
||||
"createdAt": {
|
||||
"columns": ["createdAt", "deleted"]
|
||||
},
|
||||
"createdAtStage": {
|
||||
"columns": ["createdAt", "stage"]
|
||||
},
|
||||
"assignedUserStage": {
|
||||
"columns": ["assignedUserId", "stage"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"fields": {
|
||||
"remindAt": {
|
||||
"type": "datetime",
|
||||
"index": true
|
||||
},
|
||||
"startAt": {
|
||||
"type": "datetime",
|
||||
"index": true
|
||||
},
|
||||
"type": {
|
||||
"type": "enum",
|
||||
"options": ["Popup", "Email"],
|
||||
"maxLength": 36,
|
||||
"index": true,
|
||||
"default": "Popup"
|
||||
},
|
||||
"seconds": {
|
||||
"type": "enumInt",
|
||||
"options": [0, 60, 120, 300, 900, 1800, 3600, 7200, 10800, 18000, 86400],
|
||||
"default": 0
|
||||
},
|
||||
"entityType": {
|
||||
"type": "varchar",
|
||||
"maxLength": 100
|
||||
},
|
||||
"entityId": {
|
||||
"type": "varchar",
|
||||
"maxLength": 50
|
||||
},
|
||||
"userId": {
|
||||
"type": "varchar",
|
||||
"maxLength": 50
|
||||
}
|
||||
},
|
||||
"collection": {
|
||||
"sortBy": "remindAt",
|
||||
"asc": false
|
||||
}
|
||||
}
|
||||
@@ -109,5 +109,16 @@
|
||||
"collection": {
|
||||
"sortBy": "createdAt",
|
||||
"asc": false
|
||||
},
|
||||
"indexes": {
|
||||
"firstName": {
|
||||
"columns": ["firstName", "deleted"]
|
||||
},
|
||||
"name": {
|
||||
"columns": ["firstName", "lastName"]
|
||||
},
|
||||
"assignedUser": {
|
||||
"columns": ["assignedUserId", "deleted"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,5 +89,28 @@
|
||||
"collection": {
|
||||
"sortBy": "createdAt",
|
||||
"asc": false
|
||||
},
|
||||
"indexes": {
|
||||
"dateStartStatus": {
|
||||
"columns": ["dateStart", "status"]
|
||||
},
|
||||
"dateEndStatus": {
|
||||
"columns": ["dateEnd", "status"]
|
||||
},
|
||||
"dateStart": {
|
||||
"columns": ["dateStart", "deleted"]
|
||||
},
|
||||
"dateEnd": {
|
||||
"columns": ["dateStart", "deleted"]
|
||||
},
|
||||
"status": {
|
||||
"columns": ["status", "deleted"]
|
||||
},
|
||||
"assignedUser": {
|
||||
"columns": ["assignedUserId", "deleted"]
|
||||
},
|
||||
"assignedUserStatus": {
|
||||
"columns": ["assignedUserId", "status"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"entity": true,
|
||||
"layouts": false,
|
||||
"tab": false,
|
||||
"acl": false,
|
||||
"module": "Crm",
|
||||
"customizable": false,
|
||||
"importable": false
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
<p>Subject: {name}</p>
|
||||
<p>Date & time: {dateStart}</p>
|
||||
<p>Start at: {dateStart}</p>
|
||||
<p>
|
||||
<a href="{acceptLink}">Accept</a>, <a href="{declineLink}">Decline</a>
|
||||
</p>
|
||||
{#userOnly}
|
||||
<p><a href="{url}">Open entry</a></p>
|
||||
{/userOnly}
|
||||
|
||||
@@ -1 +1 @@
|
||||
Invitation to the {eventType} '{name}'
|
||||
Invitation to {eventType} '{name}'
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<p>Subject: {name}</p>
|
||||
<p>Start at: {dateStart}</p>
|
||||
|
||||
<p><a href="{url}">Open entry</a></p>
|
||||
@@ -0,0 +1 @@
|
||||
Reminder about {eventType} '{name}'
|
||||
@@ -430,11 +430,73 @@ class Activities extends \Espo\Core\Services\Base
|
||||
";
|
||||
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public function removeReminder($id)
|
||||
{
|
||||
|
||||
$pdo = $this->getPDO();
|
||||
$sql = "
|
||||
DELETE FROM `reminder`
|
||||
WHERE id = ".$pdo->quote($id)."
|
||||
";
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
$sql .= " AND user_id = " . $pdo->quote($this->getUser()->id);
|
||||
}
|
||||
|
||||
$pdo->query($sql);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function getPopupNotifications($userId)
|
||||
{
|
||||
$pdo = $this->getPDO();
|
||||
|
||||
$dt = new \DateTime();
|
||||
|
||||
$now = $dt->format('Y-m-d H:i:s');
|
||||
$nowShifted = $dt->sub(new \DateInterval('PT1H'))->format('Y-m-d H:i:s');
|
||||
|
||||
$sql = "
|
||||
SELECT id, entity_type AS 'entityType', entity_id AS 'entityId'
|
||||
FROM `reminder`
|
||||
WHERE
|
||||
`type` = 'Popup' AND
|
||||
`user_id` = ".$pdo->quote($userId)." AND
|
||||
`remind_at` <= '{$now}' AND
|
||||
`start_at` > '{$nowShifted}' AND
|
||||
`deleted` = 0
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute();
|
||||
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$result = array();
|
||||
foreach ($rows as $row) {
|
||||
$entity = $this->getEntityManager()->getEntity($row['entityType'], $row['entityId']);
|
||||
$data = null;
|
||||
if ($entity) {
|
||||
$data = array(
|
||||
'id' => $entity->id,
|
||||
'entityType' => $row['entityType'],
|
||||
'dateStart' => $entity->get('dateStart'),
|
||||
'name' => $entity->get('name')
|
||||
);
|
||||
}
|
||||
$result[] = array(
|
||||
'id' => $row['id'],
|
||||
'data' => $data
|
||||
);
|
||||
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ class InboundEmail extends \Espo\Services\Record
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
$importer = new \Espo\Core\Mail\Importer($this->getEntityManager(), $this->getFileManager());
|
||||
$importer = new \Espo\Core\Mail\Importer($this->getEntityManager(), $this->getFileManager(), $this->getConfig());
|
||||
|
||||
$maxSize = $this->getConfig()->get('emailMessageMaxSize');
|
||||
|
||||
|
||||
@@ -99,25 +99,17 @@ class Meeting extends \Espo\Services\Record
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function storeEntity(Entity $entity)
|
||||
protected function loadAdditionalFields(Entity $entity)
|
||||
{
|
||||
$assignedUserId = $entity->get('assignedUserId');
|
||||
if ($assignedUserId && $entity->has('usersIds')) {
|
||||
$usersIds = $entity->get('usersIds');
|
||||
if (!is_array($usersIds)) {
|
||||
$usersIds = array();
|
||||
}
|
||||
if (!in_array($assignedUserId, $usersIds)) {
|
||||
$usersIds[] = $assignedUserId;
|
||||
$entity->set('usersIds', $usersIds);
|
||||
$hash = $entity->get('usersNames');
|
||||
if ($hash instanceof \stdClass) {
|
||||
$hash->assignedUserId = $entity->get('assignedUserName');
|
||||
$entity->set('usersNames', $hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent::storeEntity($entity);
|
||||
parent::loadAdditionalFields($entity);
|
||||
$this->loadRemindersField($entity);
|
||||
}
|
||||
|
||||
protected function loadRemindersField(Entity $entity)
|
||||
{
|
||||
$reminders = $this->getRepository()->getEntityReminders($entity);
|
||||
$entity->set('reminders', $reminders);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ abstract class Mapper implements IMapper
|
||||
protected $fieldsMapCache = array();
|
||||
protected $aliasesCache = array();
|
||||
|
||||
protected $returnCollection = true;
|
||||
protected $returnCollection = false;
|
||||
|
||||
protected $collectionClass = "\\Espo\\ORM\\EntityCollection";
|
||||
|
||||
@@ -76,7 +76,7 @@ abstract class Mapper implements IMapper
|
||||
'additionalColumnsConditions'
|
||||
);
|
||||
|
||||
public function __construct(PDO $pdo, \Espo\ORM\EntityFactory $entityFactory, Query $query) {
|
||||
public function __construct(PDO $pdo, \Espo\ORM\EntityFactory $entityFactory, Query\Base $query) {
|
||||
$this->pdo = $pdo;
|
||||
$this->query = $query;
|
||||
$this->entityFactory = $entityFactory;
|
||||
@@ -340,7 +340,7 @@ abstract class Mapper implements IMapper
|
||||
|
||||
$setArr = array();
|
||||
foreach ($columnData as $column => $value) {
|
||||
$setArr[] = $this->toDb($column) . " = " . $this->pdo->quote($value);
|
||||
$setArr[] = "`".$this->toDb($column) . "` = " . $this->pdo->quote($value);
|
||||
}
|
||||
if (empty($setArr)) {
|
||||
return true;
|
||||
|
||||
@@ -20,14 +20,14 @@
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\ORM\DB;
|
||||
namespace Espo\ORM\DB\Query;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\IEntity;
|
||||
use Espo\ORM\EntityFactory;
|
||||
use PDO;
|
||||
|
||||
class Query
|
||||
class Base
|
||||
{
|
||||
protected static $selectParamList = array(
|
||||
'select',
|
||||
33
application/Espo/ORM/DB/Query/Mysql.php
Normal file
33
application/Espo/ORM/DB/Query/Mysql.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\ORM\DB\Query;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\IEntity;
|
||||
use Espo\ORM\EntityFactory;
|
||||
use PDO;
|
||||
|
||||
class Mysql extends Base
|
||||
{
|
||||
|
||||
}
|
||||
@@ -41,12 +41,28 @@ class EntityManager
|
||||
|
||||
protected $query;
|
||||
|
||||
protected $driverPlatformMap = array(
|
||||
'pdo_mysql' => 'Mysql',
|
||||
'mysqli' => 'Mysql',
|
||||
);
|
||||
|
||||
public function __construct($params)
|
||||
{
|
||||
$this->params = $params;
|
||||
|
||||
$this->metadata = new Metadata();
|
||||
|
||||
if (empty($this->params['platform'])) {
|
||||
if (empty($this->params['driver'])) {
|
||||
throw new \Exception('No database driver specified.');
|
||||
}
|
||||
$driver = $this->params['driver'];
|
||||
if (empty($this->driverPlatformMap[$driver])) {
|
||||
throw new \Exception("Database driver '{$driver}' is not supported.");
|
||||
}
|
||||
$this->params['platform'] = $this->driverPlatformMap[$this->params['driver']];
|
||||
}
|
||||
|
||||
if (!empty($params['metadata'])) {
|
||||
$this->setMetadata($params['metadata']);
|
||||
}
|
||||
@@ -69,16 +85,36 @@ class EntityManager
|
||||
public function getQuery()
|
||||
{
|
||||
if (empty($this->query)) {
|
||||
$this->query = new DB\Query($this->getPDO(), $this->entityFactory);
|
||||
$platform = $this->params['platform'];
|
||||
$className = '\\Espo\\ORM\\DB\\Query\\' . ucfirst($platform);
|
||||
$this->query = new $className($this->getPDO(), $this->entityFactory);
|
||||
}
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
public function getMapper($className)
|
||||
protected function getMapperClassName($name)
|
||||
{
|
||||
if (empty($this->mappers[$className])) {
|
||||
// TODO use factory
|
||||
$className = null;
|
||||
|
||||
switch ($name) {
|
||||
case 'RDB':
|
||||
$platform = $this->params['platform'];
|
||||
$className = '\\Espo\\ORM\\DB\\' . ucfirst($platform) . 'Mapper';
|
||||
break;
|
||||
}
|
||||
|
||||
return $className;
|
||||
}
|
||||
|
||||
public function getMapper($name)
|
||||
{
|
||||
if ($name{0} == '\\') {
|
||||
$className = $name;
|
||||
} else {
|
||||
$className = $this->getMapperClassName($name);
|
||||
}
|
||||
|
||||
if (empty($this->mappers[$className])) {
|
||||
$this->mappers[$className] = new $className($this->getPDO(), $this->entityFactory, $this->getQuery());
|
||||
}
|
||||
return $this->mappers[$className];
|
||||
@@ -90,7 +126,9 @@ class EntityManager
|
||||
|
||||
$port = empty($params['port']) ? '' : 'port=' . $params['port'] . ';';
|
||||
|
||||
$this->pdo = new \PDO('mysql:host='.$params['host'].';'.$port.'dbname=' . $params['dbname'] . ';charset=utf8', $params['user'], $params['password']);
|
||||
$platform = strtolower($params['platform']);
|
||||
|
||||
$this->pdo = new \PDO($platform . ':host='.$params['host'].';'.$port.'dbname=' . $params['dbname'] . ';charset=utf8', $params['user'], $params['password']);
|
||||
$this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,9 +31,6 @@ use \Espo\ORM\IEntity;
|
||||
|
||||
class RDB extends \Espo\ORM\Repository
|
||||
{
|
||||
|
||||
public static $mapperClassName = '\\Espo\\ORM\\DB\\MysqlMapper';
|
||||
|
||||
/**
|
||||
* @var Object Mapper.
|
||||
*/
|
||||
@@ -66,7 +63,7 @@ class RDB extends \Espo\ORM\Repository
|
||||
protected function getMapper()
|
||||
{
|
||||
if (empty($this->mapper)) {
|
||||
$this->mapper = $this->getEntityManager()->getMapper(self::$mapperClassName);
|
||||
$this->mapper = $this->getEntityManager()->getMapper('RDB');
|
||||
}
|
||||
return $this->mapper;
|
||||
}
|
||||
|
||||
@@ -25,12 +25,12 @@ namespace Espo\Repositories;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Email extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
{
|
||||
protected function prepareAddressess(Entity $entity, $type)
|
||||
{
|
||||
$eaRepositoty = $this->getEntityManager()->getRepository('EmailAddress');
|
||||
|
||||
$address = $entity->get($type);
|
||||
$address = $entity->get($type);
|
||||
$ids = array();
|
||||
if (!empty($address) || !filter_var($address, FILTER_VALIDATE_EMAIL)) {
|
||||
$arr = array_map(function ($e) {
|
||||
@@ -38,7 +38,7 @@ class Email extends \Espo\Core\ORM\Repositories\RDB
|
||||
}, explode(';', $address));
|
||||
|
||||
$ids = $eaRepositoty->getIds($arr);
|
||||
}
|
||||
}
|
||||
$entity->set($type . 'EmailAddressesIds', $ids);
|
||||
}
|
||||
|
||||
@@ -46,9 +46,9 @@ class Email extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
$eaRepositoty = $this->getEntityManager()->getRepository('EmailAddress');
|
||||
|
||||
$from = trim($entity->get('from'));
|
||||
$from = trim($entity->get('from'));
|
||||
if (!empty($from)) {
|
||||
$ids = $eaRepositoty->getIds(array($from));
|
||||
$ids = $eaRepositoty->getIds(array($from));
|
||||
if (!empty($ids)) {
|
||||
$entity->set('fromEmailAddressId', $ids[0]);
|
||||
}
|
||||
@@ -76,13 +76,13 @@ class Email extends \Espo\Core\ORM\Repositories\RDB
|
||||
$entity->set('accountId', $accountId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
// TODO find account by from address
|
||||
}
|
||||
}
|
||||
|
||||
protected function beforeRemove(Entity $entity)
|
||||
{
|
||||
{
|
||||
parent::beforeRemove($entity);
|
||||
$attachments = $entity->get('attachments');
|
||||
foreach ($attachments as $attachment) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user