Compare commits

...

113 Commits
1.0.0 ... 1.2.1

Author SHA1 Message Date
Yuri Kuznetsov
28eafdbc6c version 2014-07-01 17:43:33 +03:00
Yuri Kuznetsov
0036ab1ed2 Merge branch 'hotfix/1.2.1' of ssh://172.20.0.1/var/git/espo/backend into hotfix/1.2.1 2014-07-01 17:42:49 +03:00
Taras Machyshyn
30b246f67c fixed issue with Basic Authorization for cgi/fastcgi 2014-07-01 17:41:26 +03:00
Yuri Kuznetsov
1063aa74dd fix create related 2014-06-26 17:12:54 +03:00
Taras Machyshyn
0a2469aaa4 fixed labels 2014-06-17 12:33:02 +03:00
Yuri Kuznetsov
e7e15a32bf fix lang 2014-06-16 18:04:03 +03:00
Yuri Kuznetsov
fc3fa53dba fix label 2014-06-16 17:59:41 +03:00
Yuri Kuznetsov
4604f27176 fix double metadata load 2014-06-16 11:12:04 +03:00
Yuri Kuznetsov
b7b118c122 update timepicker 2014-06-13 16:42:11 +03:00
Yuri Kuznetsov
ea2934129a Merge branch 'release/1.2' into stable 2014-06-13 12:34:42 +03:00
Yuri Kuznetsov
ba2d72dff9 grunt chmod 2014-06-13 11:10:41 +03:00
Yuri Kuznetsov
7312988057 Merge branch 'release/1.2' of ssh://172.20.0.1/var/git/espo/backend into release/1.2 2014-06-12 17:02:23 +03:00
Taras Machyshyn
de12418a8f fixed installation language issue 2014-06-12 17:01:21 +03:00
Yuri Kuznetsov
b4c7075331 fix image resize 2014-06-12 16:23:16 +03:00
Yuri Kuznetsov
355ec4398f Merge branch 'release/1.2' of ssh://172.20.0.1/var/git/espo/backend into release/1.2 2014-06-12 16:09:40 +03:00
Taras Machyshyn
2c681ede52 fixed upgrade 2014-06-12 15:46:01 +03:00
Yuri Kuznetsov
cb2df7b6a2 fix image resize 2014-06-12 14:28:05 +03:00
Yuri Kuznetsov
f2a5474b4a version 2014-06-12 11:20:39 +03:00
Taras Machyshyn
1fc8921a18 fixed MySQL port 2014-06-12 11:14:14 +03:00
Yuri Kuznetsov
0458544bbb fix auto logout if auth error 2014-06-11 16:57:10 +03:00
Yuri Kuznetsov
c09c4b2035 add translateOption and fix firstName lastName concat in Person Entity 2014-06-11 15:06:41 +03:00
Yuri Kuznetsov
176c77ec96 company logo 2014-06-11 12:47:28 +03:00
Yuri Kuznetsov
7b032802e9 image transparent 2014-06-11 12:22:14 +03:00
Yuri Kuznetsov
8a7a317252 remove password from user edit small 2014-06-11 11:57:18 +03:00
Yuri Kuznetsov
3ef01a4639 remove createDefaultUserPreferences method 2014-06-11 11:55:27 +03:00
Yuri Kuznetsov
e27edf5b0d fix change password 2014-06-11 11:53:10 +03:00
Yuri Kuznetsov
fe0f5b3886 change own password 2014-06-11 11:48:09 +03:00
Yuri Kuznetsov
9836517c6c options.el for modal view 2014-06-11 10:49:10 +03:00
Yuri Kuznetsov
c143ba47d2 generate password 2014-06-10 16:59:19 +03:00
Yuri Kuznetsov
64a8ccf787 spanish language 2014-06-10 15:33:48 +03:00
Yuri Kuznetsov
31eafca88f fix warning 2014-06-10 15:13:22 +03:00
Yuri Kuznetsov
80e440c875 export delimiter 2014-06-10 14:27:41 +03:00
Yuri Kuznetsov
92451934af fix pref 2014-06-10 14:12:05 +03:00
Yuri Kuznetsov
7e2ad2ae94 default preferences from config 2014-06-10 12:22:59 +03:00
Yuri Kuznetsov
c410e47d6b restrict posting in stream 2014-06-10 12:03:44 +03:00
Yuri Kuznetsov
7bb3780277 maxLength for text field 2014-06-10 11:31:22 +03:00
Yuri Kuznetsov
d734b8b3d2 improve address field 2014-06-10 11:25:47 +03:00
Yuri Kuznetsov
2acc245100 Merge branch 'stable' 2014-06-10 10:43:04 +03:00
Yuri Kuznetsov
fac477330c Merge branch 'hotfix/1.1.2' into stable 2014-06-10 10:41:44 +03:00
Yuri Kuznetsov
7993a65939 version 2014-06-10 10:35:26 +03:00
Yuri Kuznetsov
1285008af7 fix image resize 2014-06-10 10:35:07 +03:00
Yuri Kuznetsov
a67d43edbb fix select related cound with joins 2014-06-10 10:24:30 +03:00
Yuri Kuznetsov
d326925e06 fix relationship panel option.el 2014-06-09 12:29:27 +03:00
Yuri Kuznetsov
13d65c7535 Merge branch 'stable' 2014-06-09 10:42:00 +03:00
Yuri Kuznetsov
e5762b96d2 Merge branch 'hotfix/1.1.1' into stable 2014-06-09 10:40:19 +03:00
Yuri Kuznetsov
180983940e version 2014-06-09 10:21:29 +03:00
Yuri Kuznetsov
31f36caffa fix acl 2014-06-09 10:20:49 +03:00
Yuri Kuznetsov
6f76efee36 Merge branch 'stable' 2014-06-06 17:00:28 +03:00
Yuri Kuznetsov
44792d1a35 Merge branch 'release/1.1' into stable 2014-06-06 16:59:31 +03:00
Yuri Kuznetsov
3f824be525 fix image preview 2014-06-06 11:52:12 +03:00
Yuri Kuznetsov
fbed072a80 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend into release/1.1 2014-06-06 11:32:44 +03:00
Yuri Kuznetsov
f92da57b4d version 2014-06-06 11:32:28 +03:00
Taras Machyshyn
9059ce615f removed set upgrade permission 2014-06-06 11:32:05 +03:00
Yuri Kuznetsov
c13cc2a798 fix footer 2014-06-06 11:27:48 +03:00
Taras Machyshyn
17bf3b017f fixed duplicate weekStart in installation 2014-06-06 11:18:19 +03:00
Taras Machyshyn
9e04d2f2f0 improved upgrading process 2014-06-06 10:52:42 +03:00
Taras Machyshyn
98e998dc34 fixed Zend OPCache issue 2014-06-05 17:33:53 +03:00
Taras Machyshyn
3155947795 Mod to improved check permission in installation 2014-06-05 17:32:23 +03:00
Taras Machyshyn
fa6f471be9 improved check permission in installation 2014-06-05 17:28:45 +03:00
Taras Machyshyn
865f87018a fixed footer scroll 2014-06-05 16:31:02 +03:00
Yuri Kuznetsov
8da5ba8961 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-06-05 12:08:25 +03:00
Yuri Kuznetsov
9842ebcc4a gruntfile 2014-06-05 12:08:07 +03:00
Taras Machyshyn
787d47c2aa fixed test errors 2014-06-04 13:19:14 +03:00
Taras Machyshyn
ee3cbc2358 config changes. Added application/Espo/Core/defaults/systemConfig.php which merges with data/config.php 2014-06-04 12:42:30 +03:00
Yuri Kuznetsov
87caba2646 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-06-04 10:26:45 +03:00
Yuri Kuznetsov
c45b614270 dont check file type in upgrade 2014-06-04 10:26:31 +03:00
Taras Machyshyn
eccef0b92f fixed jsonArray DBAL issue 2014-06-03 16:49:15 +03:00
Yuri Kuznetsov
f9b68fcbba select modal link click issue 2014-06-03 11:40:38 +03:00
Taras Machyshyn
776acd9b64 changed default value of = null, if push array() will no rebuild 2014-06-02 18:05:08 +03:00
Taras Machyshyn
60b11cb11e fixed FieldManager bug, when rebuild exception 2014-06-02 17:19:09 +03:00
Yuri Kuznetsov
defa3b5cfc fix cli error messages 2014-06-02 16:27:44 +03:00
Yuri Kuznetsov
f89ff39dbb added missing use 2014-06-02 16:20:55 +03:00
Yuri Kuznetsov
6284b56718 cli rebuild.php 2014-06-02 16:14:58 +03:00
Yuri Kuznetsov
5d78730dde lang 2014-06-02 15:56:47 +03:00
Yuri Kuznetsov
bfba129846 fix view-helper # options 2014-06-02 15:52:19 +03:00
Yuri Kuznetsov
b48bf2685c use token instead of password 2014-06-02 15:08:52 +03:00
Yuri Kuznetsov
c5549000b4 merge release 1.0.1 2014-05-30 17:22:41 +03:00
Yuri Kuznetsov
fe88d10e35 fix inbound email 2014-05-30 16:46:05 +03:00
Taras Machyshyn
4dd85eb97d edit instllation help 2014-05-30 16:16:21 +03:00
Taras Machyshyn
245e99ef9f fixed language list problem 2014-05-30 16:09:17 +03:00
Yuri Kuznetsov
3478cf2d8c change version to 1.0.1 2014-05-30 14:39:30 +03:00
Yuri Kuznetsov
da1feee303 fix password for user 2014-05-30 14:08:23 +03:00
Yuri Kuznetsov
9fdd0b9a86 hide passwords 2014-05-30 13:50:50 +03:00
Yuri Kuznetsov
d4f2975f0d Entity:toArray now dont return not set attributes 2014-05-30 13:50:37 +03:00
Yuri Kuznetsov
47ce2f587e fix link frontend field 2014-05-30 13:21:41 +03:00
Yuri Kuznetsov
0a25c0dbc2 version 1.1-dev 2014-05-23 17:48:15 +03:00
Yuri Kuznetsov
7aeaa153ae merge with release 2014-05-23 16:10:05 +03:00
Yuri Kuznetsov
5c4afa8a23 add large preview size 2014-05-22 17:23:30 +03:00
Yuri Kuznetsov
0a7e442194 fix detail image-preview css 2014-05-22 17:22:39 +03:00
Yuri Kuznetsov
6b8a05cd4e lang admin 2014-05-22 16:54:48 +03:00
Yuri Kuznetsov
946a7a65f7 fix field manager 2014-05-22 16:52:21 +03:00
Yuri Kuznetsov
b68946375f image type field 2014-05-22 16:36:31 +03:00
Yuri Kuznetsov
463299c3ab file type accept param 2014-05-22 16:12:39 +03:00
Yuri Kuznetsov
34f81f4831 fix file input 2014-05-22 15:59:02 +03:00
Yuri Kuznetsov
72ba8892b7 File type fields 2014-05-22 15:50:18 +03:00
Yuri Kuznetsov
3ece40f9de image preview in popup and cached thumbs 2014-05-22 12:44:02 +03:00
Yuri Kuznetsov
f392c1da04 chgange version to 1.1-dev 2014-05-21 17:31:01 +03:00
Yuri Kuznetsov
589b8f3210 Stream: image preview fix 2014-05-21 17:29:09 +03:00
Yuri Kuznetsov
ff6fd2698d Stream: display attachment preview 2014-05-21 17:24:07 +03:00
Yuri Kuznetsov
6b22c8e370 Stream: preview attached images 2014-05-21 16:48:51 +03:00
Yuri Kuznetsov
340eb6d004 Merge branch 'release/1.0' 2014-05-20 17:20:04 +03:00
Yuri Kuznetsov
071e5fb85d Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-05-20 15:36:27 +03:00
Yuri Kuznetsov
a21469846b Merge branch 'feature/email-address' 2014-05-20 15:35:46 +03:00
Yuri Kuznetsov
32ce8629a1 email address develop 2014-05-20 15:15:49 +03:00
Yuri Kuznetsov
93be4a43d0 email address save 2014-05-19 17:54:47 +03:00
Yuri Kuznetsov
e21f5daa59 fix email address client 2014-05-19 16:34:37 +03:00
Yuri Kuznetsov
5cae7dff68 email address detail 2014-05-19 15:55:22 +03:00
Yuri Kuznetsov
4cd08fc8ad email address frontend 2014-05-19 15:37:33 +03:00
Yuri Kuznetsov
c065b95f48 getByAddress method 2014-05-16 17:29:02 +03:00
Yuri Kuznetsov
23d0620890 trim email address 2014-05-16 16:29:09 +03:00
Yuri Kuznetsov
620510b6cd fetch email address data 2014-05-16 16:25:44 +03:00
Taras Machyshyn
31690f2199 fixed 'cacheTimestamp' for config changes 2014-05-15 16:31:12 +03:00
Taras Machyshyn
3972269738 fixed 'jsonArray' field type issue 2014-05-15 15:47:47 +03:00
183 changed files with 4495 additions and 813 deletions

View File

@@ -4,5 +4,7 @@ RedirectMatch 403 \.config$
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}]
RewriteRule reset/?$ reset.html [QSA,L]
</IfModule>

View File

@@ -134,6 +134,7 @@ module.exports = function (grunt) {
'vendor/**',
'bootstrap.php',
'cron.php',
'rebuild.php',
'index.php',
'LICENSE.txt',
'.htaccess',
@@ -146,9 +147,30 @@ module.exports = function (grunt) {
dot: true,
src: '**',
cwd: 'build/tmp',
dest: 'build/EspoCRM-<%= pkg.espoVersion %>/',
dest: 'build/EspoCRM-<%= pkg.version %>/',
},
},
chmod: {
options: {
mode: '755'
},
php: {
options: {
mode: '644'
},
src: [
'build/EspoCRM-<%= pkg.version %>/**/*.php',
'build/EspoCRM-<%= pkg.version %>/**/*.json',
'build/EspoCRM-<%= pkg.version %>/**/*.config',
'build/EspoCRM-<%= pkg.version %>/**/.htaccess',
'build/EspoCRM-<%= pkg.version %>/client/**/*.js',
'build/EspoCRM-<%= pkg.version %>/client/**/*.css',
'build/EspoCRM-<%= pkg.version %>/client/**/*.tpl',
'build/EspoCRM-<%= pkg.version %>/**/*.html',
'build/EspoCRM-<%= pkg.version %>/**/*.txt',
]
}
},
replace: {
timestamp: {
options: {
@@ -171,7 +193,7 @@ module.exports = function (grunt) {
patterns: [
{
match: 'version',
replacement: '<%= pkg.espoVersion %>'
replacement: '<%= pkg.version %>'
}
]
},
@@ -186,12 +208,12 @@ module.exports = function (grunt) {
compress: {
final: {
options: {
archive: 'build/EspoCRM-<%= pkg.espoVersion %>.zip',
archive: 'build/EspoCRM-<%= pkg.version %>.zip',
mode: 'zip'
},
src: ['**'],
cwd: 'build/EspoCRM-<%= pkg.espoVersion %>',
dest: 'EspoCRM-<%= pkg.espoVersion %>'
cwd: 'build/EspoCRM-<%= pkg.version %>',
dest: 'EspoCRM-<%= pkg.version %>'
}
}
});
@@ -204,6 +226,7 @@ module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-replace');
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-chmod');
grunt.registerTask('default', [
'clean:start',
@@ -217,8 +240,8 @@ module.exports = function (grunt) {
'copy:backend',
'replace',
'copy:final',
'chmod',
'clean:final',
//'compress',
]);
};

View File

@@ -6,5 +6,7 @@ RewriteEngine On
#
# RewriteBase /
RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]

View File

@@ -22,6 +22,8 @@
namespace Espo\Controllers;
use \Espo\Core\Exceptions\BadRequest;
class App extends \Espo\Core\Controllers\Record
{
public function actionUser()
@@ -29,7 +31,20 @@ class App extends \Espo\Core\Controllers\Record
return array(
'user' => $this->getUser()->toArray(),
'acl' => $this->getAcl()->toArray(),
'preferences' => $this->getPreferences()->toArray()
'preferences' => $this->getPreferences()->toArray(),
'token' => $this->getUser()->get('token')
);
}
public function actionDestroyAuthToken($params, $data)
{
$token = $data['token'];
if (empty($token)) {
throw new BadRequest();
}
$auth = new \Espo\Core\Utils\Auth($this->getContainer());
return $auth->destroyAuthToken($token);
}
}

View File

@@ -55,7 +55,12 @@ class FieldManager extends \Espo\Core\Controllers\Base
$fieldManager = $this->getContainer()->get('fieldManager');
$fieldManager->create($data['name'], $data, $params['scope']);
$this->getContainer()->get('dataManager')->rebuild($params['scope']);
try {
$this->getContainer()->get('dataManager')->rebuild($params['scope']);
} catch (Error $e) {
$fieldManager->delete($data['name'], $params['scope']);
throw new Error($e->getMessage());
}
return $fieldManager->read($data['name'], $params['scope']);
}

View File

@@ -23,12 +23,27 @@
namespace Espo\Controllers;
use \Espo\Core\Exceptions\Error;
use \Espo\Core\Exceptions\Forbidden;
class Settings extends \Espo\Core\Controllers\Base
{
public function actionRead($params, $data)
protected function getConfigData()
{
return $this->getConfig()->getData($this->getUser()->isAdmin());
$data = $this->getConfig()->getData($this->getUser()->isAdmin());
$fieldDefs = $this->getMetadata()->get('entityDefs.Settings.fields');
foreach ($fieldDefs as $field => $d) {
if ($d['type'] == 'password') {
unset($data[$field]);
}
}
return $data;
}
public function actionRead($params, $data)
{
return $this->getConfigData();
}
public function actionUpdate($params, $data)
@@ -37,12 +52,16 @@ class Settings extends \Espo\Core\Controllers\Base
}
public function actionPatch($params, $data)
{
$result = $this->getConfig()->setData($data, $this->getUser()->isAdmin());
if ($result === false) {
throw new Error('Cannot save settings');
}
{
if (!$this->getUser()->isAdmin()) {
throw new Forbidden();
}
$result = $this->getConfig()->setData($data, $this->getUser()->isAdmin());
if ($result === false) {
throw new Error('Cannot save settings');
}
return $this->getConfig()->getData($this->getUser()->isAdmin());
return $this->getConfigData();
}
}

View File

@@ -48,4 +48,10 @@ class User extends \Espo\Core\Controllers\Record
return $acl->toArray();
}
public function actionChangeOwnPassword($params, $data)
{
return $this->getService('User')->changePassword($this->getUser()->id, $data['password']);
}
}

View File

@@ -54,6 +54,8 @@ class Acl
if ($config && $config->get('useCache') && file_exists($this->cacheFile)) {
$cached = include $this->cacheFile;
$this->data = $cached;
$this->initSolid();
} else {
$this->load();
$this->initSolid();
@@ -62,7 +64,6 @@ class Acl
}
}
}
public function checkScope($scope, $action = null, $isOwner = null, $inTeam = null)
@@ -217,6 +218,11 @@ class Acl
'edit' => 'no',
'delete' => 'no',
);
$this->data['Note'] = array(
'read' => 'all',
'edit' => 'own',
'delete' => 'own',
);
}
private function merge($tables)

View File

@@ -128,6 +128,15 @@ class Application
$cronManager = new \Espo\Core\CronManager($this->container);
$cronManager->run();
}
public function runRebuild()
{
$auth = $this->getAuth();
$auth->useNoAuth(true);
$dataManager = $this->getContainer()->get('dataManager');
$dataManager->rebuild();
}
public function isInstalled()
{

View File

@@ -76,9 +76,7 @@ class Container
private function loadFileManager()
{
return new \Espo\Core\Utils\File\Manager(
array(
'defaultPermissions' => $this->get('config')->get('defaultPermissions'),
)
$this->get('config')
);
}

View File

@@ -44,7 +44,7 @@ class DataManager
*
* @return bool
*/
public function rebuild($entityList = array())
public function rebuild($entityList = null)
{
$result = $this->clearCache();
@@ -78,7 +78,7 @@ class DataManager
*
* @return bool
*/
public function rebuildDatabase($entityList = array())
public function rebuildDatabase($entityList = null)
{
try {
$result = $this->getContainer()->get('schema')->rebuild($entityList);

View File

@@ -31,7 +31,9 @@ class Person extends \Espo\Core\ORM\Entity
$this->setValue('lastName', $value);
$firstName = $this->get('firstName');
if (!empty($firstName)) {
if (empty($firstName)) {
$this->setValue('name', $value);
} else {
$this->setValue('name', $firstName . ' ' . $value);
}
}
@@ -41,7 +43,9 @@ class Person extends \Espo\Core\ORM\Entity
$this->setValue('firstName', $value);
$lastName = $this->get('lastName');
if (!empty($lastName)) {
if (empty($lastName)) {
$this->setValue('name', $value);
} else {
$this->setValue('name', $value . ' ' . $lastName);
}
}

View File

@@ -45,6 +45,7 @@ class EntityManager
$params = array(
'host' => $config->get('database.host'),
'port' => $config->get('database.port'),
'dbname' => $config->get('database.dbname'),
'user' => $config->get('database.user'),
'password' => $config->get('database.password'),

View File

@@ -178,50 +178,9 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
}
protected function handleEmailAddressSave(Entity $entity)
{
if ($entity->hasRelation('emailAddresses') && $entity->hasField('emailAddress')) {
$email = $entity->get('emailAddress');
$pdo = $this->getPDO();
$emailAddressRepository = $this->getEntityManager()->getRepository('EmailAddress');
if (!empty($email)) {
if ($email != $entity->getFetched('emailAddress')) {
$emailAddressNew = $emailAddressRepository->where(array('lower' => strtolower($email)))->findOne();
$isNewEmailAddress = false;
if (!$emailAddressNew) {
$emailAddressNew = $emailAddressRepository->get();
$emailAddressNew->set('name', $email);
$emailAddressRepository->save($emailAddressNew);
$isNewEmailAddress = true;
}
$emailOld = $entity->getFetched('emailAddress');
if (!empty($emailOld)) {
$emailAddressOld = $emailAddressRepository->where(array('lower' => strtolower($emailOld)))->findOne();
$this->unrelate($entity, 'emailAddresses', $emailAddressOld);
}
$this->relate($entity, 'emailAddresses', $emailAddressNew);
$query = "
UPDATE entity_email_address
SET `primary` = 1
WHERE
entity_id = ".$pdo->quote($entity->id)." AND
entity_type = ".$pdo->quote($this->entityName)." AND
email_address_id = ".$pdo->quote($emailAddressNew->id)."
";
$sth = $pdo->prepare($query);
$sth->execute();
}
} else {
$emailOld = $entity->getFetched('emailAddress');
if (!empty($emailOld)) {
$emailAddressOld = $emailAddressRepository->where(array('lower' => strtolower($emailOld)))->findOne();
$this->unrelate($entity, 'emailAddresses', $emailAddressOld);
}
}
{
if ($entity->hasRelation('emailAddresses') && $entity->hasField('emailAddress')) {
$emailAddressRepository = $this->getEntityManager()->getRepository('EmailAddress')->storeEntityEmailAddress($entity);
}
}

View File

@@ -269,7 +269,7 @@ class Base
return $part;
}
protected function getBoolFilterWhere($filterName, $entityName)
protected function getBoolFilterWhere($filterName)
{
$method = 'getBoolFilterWhere' . ucfirst($filterName);
if (method_exists($this, $method)) {

View File

@@ -22,6 +22,8 @@
namespace Espo\Core;
use Espo\Core\Exceptions\Error;
class UpgradeManager extends Upgrades\Base
{
protected $packagePath = 'data/upload/upgrades';
@@ -31,6 +33,4 @@ class UpgradeManager extends Upgrades\Base
'after' => 'AfterUpgrade',
);
}

View File

@@ -255,7 +255,7 @@ abstract class Base
return;
}
$beforeInstallScript = Util::concatPath( array($upgradePath, $this->paths['scripts'], $scriptName) );
$beforeInstallScript = Util::concatPath( array($upgradePath, $this->paths['scripts'], $scriptName) ) . '.php';
if (file_exists($beforeInstallScript)) {
require_once($beforeInstallScript);

View File

@@ -51,9 +51,12 @@ class Auth extends \Slim\Middleware
$espoAuth = $req->headers('HTTP_ESPO_AUTHORIZATION');
if (isset($espoAuth)) {
$credentials = explode(':', base64_decode($espoAuth));
$authUsername = $credentials[0];
$authPassword = $credentials[1];
list($authUsername, $authPassword) = explode(':', base64_decode($espoAuth));
}
$espoCgiAuth = $req->headers('HTTP_ESPO_CGI_AUTH');
if ( !isset($authUsername) && !isset($authPassword) && isset($espoCgiAuth) ) {
list($authUsername, $authPassword) = explode(':' , base64_decode(substr($espoCgiAuth, 6)));
}
if (is_null($this->authRequired)) {

View File

@@ -51,21 +51,59 @@ class Auth
{
$GLOBALS['log']->debug('AUTH: Try to authenticate');
$hash = md5($password);
$entityManager = $this->container->get('entityManager');
$authToken = $entityManager->getRepository('AuthToken')->where(array('token' => $password))->findOne();
if ($authToken) {
$hash = $authToken->get('hash');
}
$user = $entityManager->getRepository('User')->findOne(array(
'whereClause' => array(
'userName' => $username,
'password' => md5($password)
'password' => $hash
),
));
if ($user instanceof \Espo\Entities\User) {
if ($user) {
$entityManager->setUser($user);
$this->container->setUser($user);
$GLOBALS['log']->debug('AUTH: Result of authenticate is [true]');
if (!$authToken) {
$authToken = $entityManager->getEntity('AuthToken');
$token = $this->createToken($user);
$authToken->set('token', $token);
$authToken->set('hash', $user->get('password'));
$authToken->set('ipAddress', $_SERVER['REMOTE_ADDR']);
$authToken->set('userId', $user->id);
}
$authToken->set('lastAccess', date('Y-m-d H:i:s'));
$entityManager->saveEntity($authToken);
$user->set('token', $authToken->get('token'));
return true;
}
}
protected function createToken($user)
{
return md5(uniqid($user->get('password')));
}
public function destroyAuthToken($token)
{
$entityManager = $this->container->get('entityManager');
$authToken = $entityManager->getRepository('AuthToken')->where(array('token' => $token))->findOne();
if ($authToken) {
$entityManager->removeEntity($authToken);
return true;
}
}
}

View File

@@ -32,6 +32,8 @@ class Config
*/
private $defaultConfigPath = 'application/Espo/Core/defaults/config.php';
private $systemConfigPath = 'application/Espo/Core/defaults/systemConfig.php';
protected $configPath = 'data/config.php';
private $cacheTimestamp = 'cacheTimestamp';
@@ -153,6 +155,9 @@ class Config
$this->configData = $this->getFileManager()->getContents($configPath);
$systemConfig = $this->getFileManager()->getContents($this->systemConfigPath);
$this->configData = Util::merge($systemConfig, $this->configData);
return $this->configData;
}

View File

@@ -70,7 +70,7 @@ class Converter
}
public function getSchemaFromMetadata($entityList = array())
public function getSchemaFromMetadata($entityList = null)
{
$ormMeta = $this->getMetadata()->getOrmMetadata();
$entityDefs = $this->getMetadata()->get('entityDefs');

View File

@@ -31,4 +31,9 @@ class JsonArray extends \Doctrine\DBAL\Types\JsonArrayType
return self::JSON_ARRAY;
}
public static function getDbTypeName()
{
return 'TEXT';
}
}

View File

@@ -39,6 +39,10 @@ class Email extends \Espo\Core\Utils\Database\Orm\Base
),
'orderBy' => 'email_address.name {direction}',
),
$field['name'] .'Data' => array(
'type' => 'text',
'notStorable' => true
),
),
'relations' => array(
$field['name'].'es' => array(
@@ -69,4 +73,4 @@ class Email extends \Espo\Core\Utils\Database\Orm\Base
}
}
}

View File

@@ -49,4 +49,4 @@ class EmailEmailAddress extends \Espo\Core\Utils\Database\Orm\Relations\HasMany
return $relation;
}
}
}

View File

@@ -0,0 +1,44 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
class NoteAttachments extends \Espo\Core\Utils\Database\Orm\Relations\HasChildren
{
public function load($params, $foreignParams)
{
$parentRelation = parent::load($params, $foreignParams);
$relation = array(
$params['entityName'] => array (
'fields' => array(
$params['link']['name'].'Types' => array(
'type' => 'varchar',
'notStorable' => true,
),
),
),
);
$relation = \Espo\Core\Utils\Util::merge($parentRelation, $relation);
return $relation;
}
}

View File

@@ -84,7 +84,7 @@ class Converter
}
public function process(array $ormMeta, $entityDefs, $entityList = array())
public function process(array $ormMeta, $entityDefs, $entityList = null)
{
$GLOBALS['log']->debug('Schema\Converter - Start: building schema');
@@ -97,7 +97,7 @@ class Converter
unset($ormMeta['unset']);
} //END: unset some keys in orm
if (!empty($entityList)) {
if (isset($entityList)) {
$entityList = is_string($entityList) ? (array) $entityList : $entityList;
$dependentEntities = $this->getDependentEntities($entityList, $ormMeta);
@@ -203,7 +203,6 @@ class Converter
}
//END: check and create columns/tables for relations
$GLOBALS['log']->debug('Schema\Converter - End: building schema');
return $schema;

View File

@@ -181,7 +181,7 @@ class Schema
/*
* Rebuild database schema
*/
public function rebuild($entityList = array())
public function rebuild($entityList = null)
{
if ($this->getConverter()->process() === false) {
return false;

View File

@@ -22,7 +22,8 @@
namespace Espo\Core\Utils;
use \Espo\Core\Exceptions\Error;
use \Espo\Core\Exceptions\Error,
\Espo\Core\Exceptions\Conflict;
class FieldManager
{
@@ -74,7 +75,7 @@ class FieldManager
{
$existingField = $this->getFieldDef($name, $scope);
if (isset($existingField)) {
throw new Error('Field ['.$name.'] exists in '.$scope);
throw new Conflict('Field ['.$name.'] exists in '.$scope);
}
return $this->update($name, $fieldDef, $scope);

View File

@@ -29,9 +29,17 @@ class Manager
{
private $permission;
public function __construct(array $params = null)
public function __construct(\Espo\Core\Utils\Config $config = null)
{
$this->permission = new Permission($params);
$params = null;
if (isset($config)) {
$params = array(
'defaultPermissions' => $config->get('defaultPermissions'),
'permissionMap' => $config->get('permissionMap'),
);
}
$this->permission = new Permission($this, $params);
}
public function getPermissionUtils()
@@ -39,8 +47,6 @@ class Manager
return $this->permission;
}
/**
* Get a list of files in specified directory
*
@@ -173,7 +179,12 @@ class Manager
throw new Error('Permission denied in '. $path);
}
return (file_put_contents($fullPath, $data, $flags, $context) !== FALSE);
$res = (file_put_contents($fullPath, $data, $flags, $context) !== FALSE);
if ($res && function_exists('opcache_invalidate')) {
opcache_invalidate($fullPath);
}
return $res;
}
/**

View File

@@ -18,7 +18,7 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\File;
@@ -27,71 +27,119 @@ use Espo\Core\Utils,
class Permission
{
private $fileManager;
/**
* Last permission error
*
* @var array | string
*/
protected $permissionError = null;
protected $permissionErrorRules = null;
protected $params = array(
'defaultPermissions' => array (
'dir' => '0775',
'file' => '0664',
'user' => '',
'group' => '',
'dir' => '0775',
'file' => '0664',
'user' => '',
'group' => '',
),
'permissionMap' => array(
/** array('0664', '0775') */
'writable' => array(
'data',
'custom',
),
/** array('0644', '0755') */
'readable' => array(
'api',
'application',
'client',
'vendor',
'index.php',
'cron.php',
'rebuild.php',
'main.html',
'reset.html',
),
),
);
protected $permissionRules = array(
'writable' => array('0664', '0775'),
'readable' => array('0644', '0755'),
);
public function __construct(array $params = null)
public function __construct(Manager $fileManager, array $params = null)
{
$this->fileManager = $fileManager;
if (isset($params)) {
$this->params = $params;
}
}
protected function getFileManager()
{
return $this->fileManager;
}
protected function getParams()
{
return $this->params;
}
/**
* Get default settings
/**
* Get default settings
*
* @return object
*/
public function getDefaultPermissions()
public function getDefaultPermissions()
{
$params = $this->getParams();
return $params['defaultPermissions'];
}
public function getPermissionRules()
{
return $this->permissionRules;
}
/**
* Set default permission
* Set default permission
*
* @param string $path
* @param bool $recurse
*
* @return bool
*/
public function setDefaultPermissions($path, $recurse = false)
public function setDefaultPermissions($path, $recurse = false)
{
if (!file_exists($path)) {
return false;
}
$permission = $this->getDefaultPermissions();
$permission = $this->getDefaultPermissions();
$result = $this->chmod($path, array($permission['file'], $permission['dir']), $recurse);
$result = $this->chmod($path, array($permission['file'], $permission['dir']), $recurse);
if (!empty($permission['user'])) {
$result &= $this->chown($path, $permission['user'], $recurse);
$result &= $this->chown($path, $permission['user'], $recurse);
}
if (!empty($permission['group'])) {
$result &= $this->chgrp($path, $permission['group'], $recurse);
$result &= $this->chgrp($path, $permission['group'], $recurse);
}
return $result;
return $result;
}
/**
* Get current permissions
* Get current permissions
*
* @param string $filename
* @return string | bool
@@ -108,7 +156,7 @@ class Permission
}
/**
* Change permissions
* Change permissions
*
* @param string $filename
* @param int | array $octal - ex. 0755, array(0644, 0755), array('file'=>0644, 'dir'=>0755)
@@ -118,7 +166,7 @@ class Permission
*/
public function chmod($path, $octal, $recurse = false)
{
if (!file_exists($path)) {
if (!file_exists($path)) {
return false;
}
@@ -130,17 +178,17 @@ class Permission
foreach ($octal as $key => $val) {
$pKey= strval($key);
if (!in_array($pKey, $rule)) {
$pKey= $rule[$count];
$pKey= $rule[$count];
}
if (!empty($pKey)) {
$permission[$pKey]= $val;
$permission[$pKey]= $val;
}
$count++;
$count++;
}
}
elseif (is_int((int)$octal)) {
$permission= array(
$permission= array(
'file' => $octal,
'dir' => $octal,
);
@@ -152,25 +200,25 @@ class Permission
//conver to octal value
foreach($permission as $key => $val) {
if (is_string($val)) {
$permission[$key]= base_convert($val,8,10);
$permission[$key]= base_convert($val,8,10);
}
}
//Set permission for non-recursive request
if (!$recurse) {
if (is_dir($path)) {
return $this->chmodReal($path, $permission['dir']);
return $this->chmodReal($path, $permission['dir']);
}
return $this->chmodReal($path, $permission['file']);
return $this->chmodReal($path, $permission['file']);
}
//Recursive permission
return $this->chmodRecurse($path, $permission['file'], $permission['dir']);
return $this->chmodRecurse($path, $permission['file'], $permission['dir']);
}
/**
* Change permissions recursive
/**
* Change permissions recursive
*
* @param string $filename
* @param int $fileOctal - ex. 0644
@@ -189,8 +237,7 @@ class Permission
}
if (is_dir($path)) {
$allFiles = scandir($path);
$items = array_slice($allFiles, 2);
$allFiles = $this->getFileManager()->getFileList($path);
foreach ($items as $item) {
$this->chmodRecurse($path. Utils\Util::getSeparator() .$item, $fileOctal, $dirOctal);
@@ -203,11 +250,11 @@ class Permission
}
/**
* Change owner permission
* Change owner permission
*
* @param string $path
* @param int | string $user
@@ -217,7 +264,7 @@ class Permission
*/
public function chown($path, $user='', $recurse=false)
{
if (!file_exists($path)) {
if (!file_exists($path)) {
return false;
}
@@ -227,15 +274,15 @@ class Permission
//Set chown for non-recursive request
if (!$recurse) {
return $this->chownReal($path, $user);
return $this->chownReal($path, $user);
}
//Recursive chown
return $this->chownRecurse($path, $user);
return $this->chownRecurse($path, $user);
}
/**
* Change owner permission recursive
* Change owner permission recursive
*
* @param string $path
* @param string $user
@@ -248,8 +295,7 @@ class Permission
return false;
}
$allFiles = scandir($path);
$items = array_slice($allFiles, 2);
$allFiles = $this->getFileManager()->getFileList($path);
foreach ($items as $item) {
$this->chownRecurse($path. Utils\Util::getSeparator() .$item, $user);
@@ -259,7 +305,7 @@ class Permission
}
/**
* Change group permission
* Change group permission
*
* @param string $path
* @param int | string $group
@@ -269,7 +315,7 @@ class Permission
*/
public function chgrp($path, $group = null, $recurse = false)
{
if (!file_exists($path)) {
if (!file_exists($path)) {
return false;
}
@@ -279,15 +325,15 @@ class Permission
//Set chgrp for non-recursive request
if (!$recurse) {
return $this->chgrpReal($path, $group);
return $this->chgrpReal($path, $group);
}
//Recursive chown
return $this->chgrpRecurse($path, $group);
return $this->chgrpRecurse($path, $group);
}
/**
* Change group permission recursive
* Change group permission recursive
*
* @param string $filename
* @param int $fileOctal - ex. 0644
@@ -301,8 +347,7 @@ class Permission
return false;
}
$allFiles = scandir($path);
$items = array_slice($allFiles, 2);
$allFiles = $this->getFileManager()->getFileList($path);
foreach ($items as $item) {
$this->chgrpRecurse($path. Utils\Util::getSeparator() .$item, $group);
@@ -313,17 +358,17 @@ class Permission
/**
* Change permissions recursive
* Change permissions recursive
*
* @param string $filename
* @param int $mode - ex. 0644
*
* @return bool
*/
protected function chmodReal($filename, $mode)
protected function chmodReal($filename, $mode)
{
try {
$result = chmod($filename, $mode);
$result = chmod($filename, $mode);
} catch (\Exception $e) {
$result = false;
}
@@ -333,39 +378,39 @@ class Permission
$this->chgrp($filename, $this->getDefaultGroup(true));
try {
$result = chmod($filename, $mode);
$result = chmod($filename, $mode);
} catch (\Exception $e) {
throw new Error($e->getMessage());
}
}
}
return $result;
return $result;
}
protected function chownReal($path, $user)
{
try {
$result = chown($path, $user);
$result = chown($path, $user);
} catch (\Exception $e) {
throw new Error($e->getMessage());
throw new Error($e->getMessage());
}
return $result;
return $result;
}
protected function chgrpReal($path, $group)
{
try {
$result = chgrp($path, $group);
$result = chgrp($path, $group);
} catch (\Exception $e) {
throw new Error($e->getMessage());
throw new Error($e->getMessage());
}
return $result;
return $result;
}
/**
* Get default owner user
* Get default owner user
*
* @return int - owner id
*/
@@ -374,19 +419,19 @@ class Permission
$defaultPermissions = $this->getDefaultPermissions();
$owner = $defaultPermissions['user'];
if (empty($owner) && $usePosix) {
$owner = posix_getuid();
}
if (empty($owner) && $usePosix) {
$owner = posix_getuid();
}
if (empty($owner)) {
return false;
}
return $owner;
return $owner;
}
/**
* Get default group user
* Get default group user
*
* @return int - group id
*/
@@ -395,15 +440,98 @@ class Permission
$defaultPermissions = $this->getDefaultPermissions();
$group = $defaultPermissions['group'];
if (empty($group) && $usePosix) {
$group = posix_getegid();
}
if (empty($group) && $usePosix) {
$group = posix_getegid();
}
if (empty($group)) {
return false;
}
return $group;
return $group;
}
/**
* Set permission regarding defined in permissionMap
*
* @return bool
*/
public function setMapPermission($mode = null)
{
$this->permissionError = array();
$this->permissionErrorRules = array();
$params = $this->getParams();
$permissionRules = $this->permissionRules;
if (isset($mode)) {
foreach ($permissionRules as &$value) {
$value = $mode;
}
}
$result = true;
foreach ($params['permissionMap'] as $type => $items) {
$permission = $permissionRules[$type];
foreach ($items as $item) {
if (file_exists($item)) {
try {
$res = $this->chmod($item, $permission, true);
} catch (\Exception $e) {
$res = false;
}
/** check is wtitable */
if ($type == 'writable') {
$res &= is_writable($item);
if (is_dir($item)) {
$name = uniqid();
try {
$res &= $this->getFileManager()->putContents(array($item, $name), 'test');
$res &= $this->getFileManager()->removeFile($name, $item);
} catch (\Exception $e) {
$res = false;
}
}
}
if (!$res) {
$result = false;
$this->permissionError[] = $item;
$this->permissionErrorRules[$item] = $permission;
}
}
}
}
return $result;
}
/**
* Get last permission error
*
* @return array | string
*/
public function getLastError()
{
return $this->permissionError;
}
/**
* Get last permission error rules
*
* @return array | string
*/
public function getLastErrorRules()
{
return $this->permissionErrorRules;
}

View File

@@ -142,6 +142,8 @@ class Language
if (is_array($translated) && isset($requiredOptions)) {
$translated = array_intersect_key($translated, array_flip($requiredOptions));
$optionKeys = array_keys($translated);
foreach ($requiredOptions as $option) {
if (!in_array($option, $optionKeys)) {
@@ -152,6 +154,15 @@ class Language
return $translated;
}
public function translateOption($value, $field, $scope)
{
$options = $this->get($scope. '.options.' . $field);
if (array_key_exists($value, $options)) {
return $options[$value];
}
return $value;
}
public function get($key = null, $returns = null)

View File

@@ -25,6 +25,7 @@ return array (
array (
'driver' => 'pdo_mysql',
'host' => 'localhost',
'port' => '',
'dbname' => '',
'user' => '',
'password' => '',
@@ -40,6 +41,7 @@ return array (
'weekStart' => 0,
'thousandSeparator' => ',',
'decimalMark' => '.',
'exportDelimiter' => ',',
'currencyList' =>
array (
),
@@ -62,6 +64,7 @@ return array (
'languageList' => array(
'en_US',
'de_DE',
'es_ES',
),
'language' => 'en_US',
'logger' =>
@@ -71,18 +74,6 @@ return array (
'isRotate' => true, /** rotate log files every day */
'maxRotateFiles' => 30, /** max number of rotate files */
),
'defaultPermissions' =>
array (
'dir' => '0775',
'file' => '0664',
'user' => '',
'group' => '',
),
'cron' => array(
'maxJobNumber' => 15, /** Max number of jobs per one execution */
'jobPeriod' => 7800, /** Period for jobs, ex. if cron executed at 15:35, it will execute all pending jobs for times from 14:05 to 15:35 */
'minExecutionTime' => 50, /** to avoid too frequency execution **/
),
'globalSearchEntityList' =>
array (
0 => 'Account',
@@ -93,46 +84,6 @@ return array (
),
"tabList" => array("Account", "Contact", "Lead", "Opportunity", "Calendar", "Meeting", "Call", "Task", "Case", "Prospect", "Email"),
"quickCreateList" => array("Account", "Contact", "Lead", "Opportunity", "Meeting", "Call", "Task", "Case", "Prospect"),
'crud' => array(
'get' => 'read',
'post' => 'create',
'put' => 'update',
'patch' => 'patch',
'delete' => 'delete',
),
'systemUser' => array(
'id' => 'system',
'userName' => 'system',
'firstName' => '',
'lastName' => 'System',
),
'systemItems' =>
array (
'systemItems',
'adminItems',
'configPath',
'cachePath',
'database',
'crud',
'logger',
'isInstalled',
'defaultPermissions',
'systemUser',
),
'adminItems' =>
array (
'devMode',
'outboundEmailIsShared',
'outboundEmailFromName',
'outboundEmailFromAddress',
'smtpServer',
'smtpPort',
'smtpAuth',
'smtpSecurity',
'smtpUsername',
'smtpPassword',
'cron',
),
'isInstalled' => false,
);

View File

@@ -0,0 +1,102 @@
<?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/.
************************************************************************/
return array (
'defaultPermissions' =>
array (
'dir' => '0775',
'file' => '0664',
'user' => '',
'group' => '',
),
'permissionMap' => array(
/** array('0664', '0775') */
'writable' => array(
'data',
'custom',
),
/** array('0644', '0755') */
'readable' => array(
'api',
'application',
'client',
'vendor',
'index.php',
'cron.php',
'rebuild.php',
'main.html',
'reset.html',
),
),
'cron' => array(
'maxJobNumber' => 15, /** Max number of jobs per one execution */
'jobPeriod' => 7800, /** Period for jobs, ex. if cron executed at 15:35, it will execute all pending jobs for times from 14:05 to 15:35 */
'minExecutionTime' => 50, /** to avoid too frequency execution **/
),
'crud' => array(
'get' => 'read',
'post' => 'create',
'put' => 'update',
'patch' => 'patch',
'delete' => 'delete',
),
'systemUser' => array(
'id' => 'system',
'userName' => 'system',
'firstName' => '',
'lastName' => 'System',
),
'systemItems' =>
array (
'systemItems',
'adminItems',
'configPath',
'cachePath',
'database',
'crud',
'logger',
'isInstalled',
'defaultPermissions',
'systemUser',
'permissionMap',
'permissionRules',
),
'adminItems' =>
array (
'devMode',
'outboundEmailIsShared',
'outboundEmailFromName',
'outboundEmailFromAddress',
'smtpServer',
'smtpPort',
'smtpAuth',
'smtpSecurity',
'smtpUsername',
'smtpPassword',
'cron',
),
'isInstalled' => false,
);

View File

@@ -18,21 +18,12 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
ob_start();
$result = array('success' => false, 'errors' => array());
namespace Espo\Entities;
class AuthToken extends \Espo\Core\ORM\Entity
{
if (!empty($_REQUEST['url'])) {
if ($installer->fixAjaxPermission($_REQUEST['url'])) {
$result['success'] = true;
}
else {
$result['success'] = false;
$result['errorMsg'] = $_REQUEST['url'];
$result['errorFixInstruction'] = $systemHelper->getPermissionCommands('', array('644', '755'));
}
}
ob_clean();
echo json_encode($result);

View File

@@ -24,5 +24,21 @@ namespace Espo\Entities;
class Note extends \Espo\Core\ORM\Entity
{
public function loadAttachments()
{
$collection = $this->get('attachments');
$ids = array();
$names = 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);
}
}

View File

@@ -25,19 +25,45 @@ namespace Espo\EntryPoints;
use \Espo\Core\Exceptions\NotFound;
use \Espo\Core\Exceptions\Forbidden;
use \Espo\Core\Exceptions\BadRequest;
use \Espo\Core\Exceptions\Error;
class Image extends \Espo\Core\EntryPoints\Base
{
public static $authRequired = false;
public static $authRequired = true;
protected $allowedFileTypes = array(
'image/jpeg',
'image/png',
'image/gif',
);
protected $imageSizes = array(
'x-small' => array(64, 64),
'small' => array(128, 128),
'medium' => array(256, 256),
'large' => array(512, 512),
'x-large' => array(864, 864),
'xx-large' => array(1024, 1024),
);
public function run()
{
{
$id = $_GET['id'];
if (empty($id)) {
throw new BadRequest();
}
}
$size = null;
if (!empty($_GET['size'])) {
$size = $_GET['size'];
}
$this->show($id, $size);
}
protected function show($id, $size)
{
$attachment = $this->getEntityManager()->getEntity('Attachment', $id);
if (!$attachment) {
@@ -51,29 +77,118 @@ class Image extends \Espo\Core\EntryPoints\Base
}
}
$fileName = "data/upload/{$attachment->id}";
$filePath = "data/upload/{$attachment->id}";
if (!file_exists($fileName)) {
$fileType = $attachment->get('type');
if (!file_exists($filePath)) {
throw new NotFound();
}
if (!$attachment->get('global')) {
throw new Forbidden();
}
if ($attachment->get('type')) {
header('Content-Type: ' . $attachment->get('type'));
if (!in_array($fileType, $this->allowedFileTypes)) {
throw new Error();
}
if (!empty($size)) {
if (!empty($this->imageSizes[$size])) {
$thumbFilePath = "data/upload/thumbs/{$attachment->id}_{$size}";
if (!file_exists($thumbFilePath)) {
$targetImage = $this->getThumbImage($filePath, $fileType, $size);
ob_start();
switch ($fileType) {
case 'image/jpeg':
imagejpeg($targetImage);
break;
case 'image/png':
imagepng($targetImage);
break;
case 'image/gif':
imagegif($targetImage);
break;
}
$contents = ob_get_contents();
ob_end_clean();
imagedestroy($targetImage);
$this->getContainer()->get('fileManager')->putContents($thumbFilePath, $contents);
}
$filePath = $thumbFilePath;
} else {
throw new Error();
}
}
if (!empty($size)) {
$fileName = $attachment->id . '_' . $size . '.jpg';
} else {
$fileName = $attachment->get('name');
}
header('Content-Disposition:inline;filename="'.$fileName.'"');
if (!empty($fileType)) {
header('Content-Type: ' . $fileType);
}
header('Pragma: public');
header('Content-Length: ' . filesize($fileName));
$fileSize = filesize($filePath);
if ($fileSize) {
header('Content-Length: ' . $fileSize);
}
ob_clean();
flush();
readfile($fileName);
exit;
}
readfile($filePath);
exit;
}
protected function getThumbImage($filePath, $fileType, $size)
{
list($originalWidth, $originalHeight) = getimagesize($filePath);
list($width, $height) = $this->imageSizes[$size];
if ($originalWidth <= $width && $originalHeight <= $height) {
$targetWidth = $originalWidth;
$targetHeight = $originalHeight;
} else {
if ($originalWidth > $originalHeight) {
$targetWidth = $width;
$targetHeight = $originalHeight / ($originalWidth / $width);
if ($targetHeight > $height) {
$targetHeight = $height;
$targetWidth = $originalWidth / ($originalHeight / $height);
}
} else {
$targetHeight = $height;
$targetWidth = $originalWidth / ($originalHeight / $height);
if ($targetWidth > $width) {
$targetWidth = $width;
$targetHeight = $originalHeight / ($originalWidth / $width);
}
}
}
$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
switch ($fileType) {
case 'image/jpeg':
$sourceImage = imagecreatefromjpeg($filePath);
imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight);
break;
case 'image/png':
$sourceImage = imagecreatefrompng($filePath);
imagealphablending($targetImage, false);
imagesavealpha($targetImage, true);
$transparent = imagecolorallocatealpha($targetImage, 255, 255, 255, 127);
imagefilledrectangle($targetImage, 0, 0, $targetWidth, $targetHeight, $transparent);
imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight);
break;
case 'image/gif':
$sourceImage = imagecreatefromgif($filePath);
imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight);
break;
}
return $targetImage;
}
}

View File

@@ -0,0 +1,52 @@
<?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 LogoImage extends Image
{
public static $authRequired = false;
public function run()
{
$this->imageSizes['small-logo'] = array(173, 38);
$id = $this->getConfig()->get('companyLogoId');
if (empty($id)) {
throw new NotFound();
}
$size = null;
if (!empty($_GET['size'])) {
$size = $_GET['size'];
}
$this->show($id, $size);
}
}

View File

@@ -32,13 +32,14 @@ class InboundEmail extends \Espo\Core\Controllers\Record
}
public function actionGetFolders($params, $data, $request)
{
{
return $this->getRecordService()->getFolders(array(
'host' => $request->get('host'),
'port' => $request->get('port'),
'ssl' => $request->get('ssl'),
'username' => $request->get('username'),
'password' => $request->get('password'),
'id' => $request->get('id')
));
}

View File

@@ -36,5 +36,8 @@
"IMAP": "IMAP",
"Actions": "Actions",
"Main": "Main"
},
"messages": {
"couldNotConnectToImap": "Could not connect to IMAP server"
}
}

View File

@@ -4,7 +4,7 @@
"account": "Account",
"stage": "Stage",
"amount": "Amount",
"probability": "Probability",
"probability": "Probability, %",
"leadSource": "Lead Source",
"doNotCall": "Do Not Call",
"closeDate": "Close Date",

View File

@@ -0,0 +1,40 @@
{
"fields": {
"name": "Nombre",
"emailAddress": "Correo electrónico",
"website": "Sito Web",
"phone": "Teléfono",
"fax": "Fax",
"billingAddress": "Dirección de Facturación",
"shippingAddress": "Dirección de Envío",
"description": "Descripción",
"sicCode": "Sic Code",
"industry": "Industria",
"type": "Tipo"
},
"links": {
"contacts": "Contactos",
"opportunities": "Oportunidades",
"cases": "Casos"
},
"options": {
"type": {
"Customer": "Cliente",
"Investor": "Inversor",
"Partner": "Partner",
"Reseller": "REvendedor"
},
"industry": {
"Apparel": "Apparel",
"Banking": "Banking",
"Computer Software": "Software",
"Education": "Educación",
"Electronics": "Electrónicos",
"Finance": "Finanzas",
"Insurance": "Seguros"
}
},
"labels": {
"Create Account": "Crear Cuenta"
}
}

View File

@@ -0,0 +1,13 @@
{
"modes": {
"month": "Mes",
"week": "Semana",
"day": "Día",
"agendaWeek": "Semana",
"agendaDay": "Día"
},
"labels": {
"Today": "Hoy",
"Create": "Crear"
}
}

View File

@@ -0,0 +1,34 @@
{
"fields": {
"name": "Nombre",
"parent": "Padre",
"status": "Estado",
"dateStart": "Fecha de Comienzo",
"dateEnd": "Fecha de Finalización",
"direction": "Dirección",
"duration": "Duración",
"description": "Descripción",
"users": "Usuarios",
"contacts": "Contactos",
"leads": "Potenciales"
},
"links": {
},
"options": {
"status": {
"Planned": "Planeada",
"Held": "Celebrada",
"Not Held": "Sin Celebrar"
},
"direction": {
"Outbound": "Saliente",
"Inbound": "Entrante"
}
},
"labels": {
"Create Call": "Crear Llamada",
"Set Held": "Establecer Celebrada",
"Set Not Held": "Establecer no Celebrada",
"Send Invitations": "Enviar Invitaciones"
}
}

View File

@@ -0,0 +1,38 @@
{
"fields": {
"name": "Nombre",
"number": "Número",
"status": "Estado",
"account": "Cuenta",
"contact": "Contacto",
"priority": "Prioridad",
"type": "Tipo",
"description": "Descripción"
},
"links": {
},
"options": {
"status": {
"New": "Nuevo",
"Assigned": "Asignado",
"Pending": "Pendiente",
"Closed": "Cerrado",
"Rejected": "Rechazado",
"Duplicate": "Duplicado"
},
"priority" : {
"Low": "Baja",
"Normal": "Normal",
"High": "Alta",
"Urgent": "Urgente"
},
"type": {
"Question": "Pregunta",
"Incident": "Incidente",
"Problem": "Problema"
}
},
"labels": {
"Create Case": "Crear Caso"
}
}

View File

@@ -0,0 +1,22 @@
{
"fields": {
"name": "Nombre",
"emailAddress": "Correo electrónico",
"title": "Título",
"account": "Cuenta",
"phone": "Teléfono",
"phoneOffice": "Phone (Office)",
"fax": "Fax",
"accountType": "Cuenta Tipo",
"doNotCall": "No Llamar",
"address": "Dirección",
"description": "Descripción"
},
"links": {
"opportunities": "Oportunidades",
"cases": "Casos"
},
"labels": {
"Create Contact": "Crear Contacto"
}
}

View File

@@ -0,0 +1,79 @@
{
"scopeNames": {
"Account": "Cuenta",
"Contact": "Contacto",
"Lead": "Potenciales",
"Prospect": "Prospecto",
"Opportunity": "Opportunidad",
"Meeting": "Reunión",
"Calendar": "Calendario",
"Call": "Llamada",
"Task": "Tarea",
"Case": "Caso",
"InboundEmail": "Correo Entrante"
},
"scopeNamesPlural": {
"Account": "Cuentas",
"Contact": "Contactos",
"Lead": "Potenciales",
"Prospect": "Prospectos",
"Opportunity": "Oportunidades",
"Meeting": "Reuniones",
"Calendar": "Calendario",
"Call": "Llamadas",
"Task": "Tareas",
"Case": "Casos",
"InboundEmail": "Correos Entrantes"
},
"dashlets": {
"Leads": "Mis potenciales",
"Opportunities": "Mis Opportunidades",
"Tasks": "Mis Tareas",
"Cases": "Mis Casos",
"Calendar": "Calendario",
"OpportunitiesByStage": "Oportunidades por Etapa",
"OpportunitiesByLeadSource": "Oportunidades de origen de cliente potencial",
"SalesByMonth": "Ventas por Mes",
"SalesPipeline": "Canalización de ventas"
},
"labels": {
"Create InboundEmail": "Crear Correo Entrante",
"Activities": "Actividades",
"History": "Historia",
"Attendees": "Los asistentes",
"Schedule Meeting": "Reunión Programada",
"Schedule Call": "Llamada Programada",
"Compose Email": "Componer Correo",
"Log Meeting": "Log de Reunión",
"Log Call": "Log de Llamada",
"Archive Email": "Archivar Correo",
"Create Task": "Crear Tarea",
"Tasks": "Tareas"
},
"fields": {
"billingAddressCity": "Ciudad",
"billingAddressCountry": "país",
"billingAddressPostalCode": "Código Postal",
"billingAddressState": "Estado/Distrito",
"billingAddressStreet": "Calle",
"addressCity": "Ciudad",
"addressStreet": "Calle",
"addressCountry": "país",
"addressState": "Estado/Distrito",
"addressPostalCode": "Código Postal",
"shippingAddressCity": "City (Shipping)",
"shippingAddressStreet": "Street (Shipping)",
"shippingAddressCountry": "Country (Shipping)",
"shippingAddressState": "State (Shipping)",
"shippingAddressPostalCode": "Postal Code (Shipping)"
},
"links": {
"contacts": "Contactos",
"opportunities": "Oportunidades",
"leads": "Potenciales",
"meetings": "Reuniones",
"calls": "Llamadas",
"tasks": "Tareas",
"emails": "Correos"
}
}

View File

@@ -0,0 +1,43 @@
{
"fields": {
"name": "Nombre",
"team": "Equipo",
"status": "Estado",
"assignToUser": "Asignado a Usuario",
"host": "Host",
"username": "Nombre de Usuario",
"password": "Contraseña",
"port": "Puerto",
"monitoredFolders": "Carpetas supervisadas",
"trashFolder": "Carpeta Basura",
"ssl": "SSL",
"createCase": "Crear Caso",
"reply": "Responder",
"caseDistribution": "Caso Distribución",
"replyEmailTemplate": "Responder De Plantilla",
"replyFromAddress": "Responder De Dirección",
"replyFromName": "Responder De Nombre"
},
"links": {
},
"options": {
"status": {
"Active": "Activo",
"Inactive": "Inactivo"
},
"caseDistribution": {
"Direct-Assignment": "Asignación-Directa",
"Round-Robin": "Round-Robin",
"Least-Busy": "Least-Busy"
}
},
"labels": {
"Create InboundEmail": "Crear Correo Entrante",
"IMAP": "IMAP",
"Actions": "Acciones",
"Main": "Principal"
},
"messages": {
"couldNotConnectToImap": "No se pudo conectar con el servidor IMAP"
}
}

View File

@@ -0,0 +1,48 @@
{
"labels": {
"Converted To": "Convertido a",
"Create Lead": "Crear Principal",
"Convert": "Convertir"
},
"fields": {
"name": "Nombre",
"emailAddress": "Correo electrónico",
"title": "Título",
"website": "Sito Web",
"phone": "Teléfono",
"phoneOffice": "Phone (Office)",
"fax": "Fax",
"accountName": "Nombre de Cuenta",
"doNotCall": "No Llamar",
"address": "Dirección",
"status": "Estado",
"source": "Fuente",
"opportunityAmount": "Oportunidad Cantidad",
"description": "Descripción",
"createdAccount": "Cuenta",
"createdContact": "Contacto",
"createdOpportunity": "Opportunidad"
},
"links": {
},
"options": {
"status": {
"New": "Nuevo",
"Assigned": "Asignado",
"In Process": "En Proceso",
"Converted": "Convertido",
"Recycled": "Reciclado",
"Dead": "Muerto"
},
"source": {
"Call": "Llamada",
"Email": "Correo electrónico",
"Existing Customer": "Cliente Existente",
"Partner": "Partner",
"Public Relations": "Relaciones Públicas",
"Web Site": "Sitio Web",
"Campaign": "Campaña",
"Other": "Otro"
}
}
}

View File

@@ -0,0 +1,29 @@
{
"fields": {
"name": "Nombre",
"parent": "Padre",
"status": "Estado",
"dateStart": "Fecha de Comienzo",
"dateEnd": "Fecha de Finalización",
"duration": "Duración",
"description": "Descripción",
"users": "Usuarios",
"contacts": "Contactos",
"leads": "Potenciales"
},
"links": {
},
"options": {
"status": {
"Planned": "Planeada",
"Held": "Celebrada",
"Not Held": "Sin Celebrar"
}
},
"labels": {
"Create Meeting": "Crear Reunión",
"Set Held": "Establecer Celebrada",
"Set Not Held": "Establecer no Celebrada",
"Send Invitations": "Enviar Invitaciones"
}
}

View File

@@ -0,0 +1,43 @@
{
"fields": {
"name": "Nombre",
"account": "Cuenta",
"stage": "Etapa",
"amount": "Cantidad",
"probability": "Probabilidad, %",
"leadSource": "Fuente Principal",
"doNotCall": "No Llamar",
"closeDate": "Fecha de cierre",
"description": "Descripción"
},
"links": {
"contacts": "Contactos"
},
"options": {
"stage": {
"Prospecting": "Prospección",
"Qualification": "Calificación",
"Needs Analysis": "Análisis de Necesidades",
"Value Proposition": "Valor de la Propuesta",
"Id. Decision Makers": "Id. Tomadores de Decisiones",
"Perception Analysis": "Análisis de la Percepción",
"Proposal/Price Quote": "Propuesta/precio Presupuesto",
"Negotiation/Review": "Negociación/Revisión",
"Closed Won": "Cerrado Ganado",
"Closed Lost": "Cerrado Perdido"
},
"leadSource": {
"Call": "Llamada",
"Email": "Correo electrónico",
"Existing Customer": "Cliente Existente",
"Partner": "Partner",
"Public Relations": "Relaciones Públicas",
"Web Site": "Sitio Web",
"Campaign": "Campaña",
"Other": "Otro"
}
},
"labels": {
"Create Opportunity": "Crear Oportunidad"
}
}

View File

@@ -0,0 +1,21 @@
{
"fields": {
"name": "Nombre",
"emailAddress": "Correo electrónico",
"title": "Título",
"website": "Sito Web",
"accountName": "Nombre de Cuenta",
"phone": "Teléfono",
"phoneOffice": "Phone (Office)",
"fax": "Fax",
"doNotCall": "No Llamar",
"address": "Dirección",
"description": "Descripción"
},
"links": {
},
"labels": {
"Create Prospect": "Crear Prospecto",
"Convert to Lead": "Convertir en Lider"
}
}

View File

@@ -0,0 +1,31 @@
{
"fields": {
"name": "Nombre",
"parent": "Padre",
"status": "Estado",
"dateStart": "Fecha de Comienzo",
"dateEnd": "Fecha de vencimiento",
"priority": "Prioridad",
"description": "Descripción",
"isOverdue": "Atrasado"
},
"links": {
},
"options": {
"status": {
"Not Started": "Sin Empezar",
"Started": "Comenzado",
"Completed": "Completado",
"Canceled": "Cancelado"
},
"priority" : {
"Low": "Baja",
"Normal": "Normal",
"High": "Alta",
"Urgent": "Urgente"
}
},
"labels": {
"Create Task": "Crear Tarea"
}
}

View File

@@ -32,7 +32,9 @@
"type": "address"
},
"billingAddressStreet": {
"type": "varchar"
"type": "text",
"maxLength": 255,
"dbType": "varchar"
},
"billingAddressCity": {
"type": "varchar"
@@ -50,7 +52,9 @@
"type": "address"
},
"shippingAddressStreet": {
"type": "varchar"
"type": "text",
"maxLength": 255,
"dbType": "varchar"
},
"shippingAddressCity": {
"type": "varchar"

View File

@@ -47,7 +47,9 @@
"type": "address"
},
"addressStreet": {
"type": "varchar"
"type": "text",
"maxLength": 255,
"dbType": "varchar"
},
"addressCity": {
"type": "varchar"

View File

@@ -48,7 +48,9 @@
"type": "address"
},
"addressStreet": {
"type": "varchar"
"type": "text",
"maxLength": 255,
"dbType": "varchar"
},
"addressCity": {
"type": "varchar"

View File

@@ -33,7 +33,9 @@
"type": "address"
},
"addressStreet": {
"type": "varchar"
"type": "text",
"maxLength": 255,
"dbType": "varchar"
},
"addressCity": {
"type": "varchar"

View File

@@ -30,6 +30,38 @@ use \Zend\Mime\Mime as Mime;
class InboundEmail extends \Espo\Services\Record
{
public function createEntity($data)
{
$entity = parent::createEntity($data);
$entity->clear('password');
return $entity;
}
public function getEntity($id = null)
{
$entity = parent::getEntity($id);
$entity->clear('password');
return $entity;
}
public function updateEntity($id, $data)
{
$entity = parent::updateEntity($id, $data);
$entity->clear('password');
return $entity;
}
public function findEntities($params)
{
$result = parent::findEntities($params);
foreach ($result['collection'] as $entity) {
$entity->clear('password');
}
return $result;
}
protected function init()
{
$this->dependencies[] = 'fileManager';
@@ -58,12 +90,20 @@ class InboundEmail extends \Espo\Services\Record
public function getFolders($params)
{
$password = $params['password'];
if (!empty($params['id'])) {
$entity = $this->getEntityManager()->getEntity('InboundEmail', $params['id']);
if ($entity) {
$password = $entity->get('password');
}
}
$imapParams = array(
'host' => $params['host'],
'port' => $params['port'],
'user' => $params['username'],
'password' => $params['password'],
'password' => $password,
);
if (!empty($params['ssl'])) {
@@ -83,7 +123,7 @@ class InboundEmail extends \Espo\Services\Record
public function fetchFromMailServer($id)
{
$inboundEmail = $this->getEntity($id);
$inboundEmail = $this->getEntityManager()->getEntity('InboundEmail', $id);
if ($inboundEmail->get('status') != 'Active') {
throw new Error();

View File

@@ -24,6 +24,7 @@ namespace Espo\Modules\Crm\Services;
use \Espo\Core\Exceptions\Error;
use \Espo\Core\Exceptions\Forbidden;
use \Espo\ORM\Entity;
class Prospect extends \Espo\Services\Record
{

View File

@@ -282,27 +282,7 @@ abstract class Mapper implements IMapper
if (!$totalCount) {
$selectPart = $this->getSelect($relEntity);
$joinsPart = $this->getBelongsToJoins($relEntity);
$orderPart = $this->getOrder($relEntity, $orderBy, $order);
if (!empty($joins) && is_array($joins)) {
$joinsRelated = $this->getJoins($relEntity, $joins, false, $joinConditions);
if (!empty($joinsRelated)) {
if (!empty($joinsPart)) {
$joinsPart .= ' ';
}
$joinsPart .= $joinsRelated;
}
}
if (!empty($leftJoins) && is_array($leftJoins)) {
$joinsRelated = $this->getJoins($relEntity, $leftJoins, true, $joinConditions);
if (!empty($joinsRelated)) {
if (!empty($joinsPart)) {
$joinsPart .= ' ';
}
$joinsPart .= $joinsRelated;
}
}
$orderPart = $this->getOrder($relEntity, $orderBy, $order);
} else {
$selectPart = $this->getAggregationSelect($relEntity, 'COUNT', 'id');
@@ -312,6 +292,26 @@ abstract class Mapper implements IMapper
$limit = null;
}
if (!empty($joins) && is_array($joins)) {
$joinsRelated = $this->getJoins($relEntity, $joins, false, $joinConditions);
if (!empty($joinsRelated)) {
if (!empty($joinsPart)) {
$joinsPart .= ' ';
}
$joinsPart .= $joinsRelated;
}
}
if (!empty($leftJoins) && is_array($leftJoins)) {
$joinsRelated = $this->getJoins($relEntity, $leftJoins, true, $joinConditions);
if (!empty($joinsRelated)) {
if (!empty($joinsPart)) {
$joinsPart .= ' ';
}
$joinsPart .= $joinsRelated;
}
}
$relType = $relOpt['type'];
$keySet = $this->getKeys($entity, $relationName);

View File

@@ -245,7 +245,9 @@ abstract class Entity implements IEntity
if ($field == 'id') {
continue;
}
$arr[$field] = $this->get($field);
if ($this->has($field)) {
$arr[$field] = $this->get($field);
}
}
return $arr;

View File

@@ -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\ORM;
@@ -36,7 +36,7 @@ class EntityManager
protected $metadata;
protected $repositoryHash = array();
protected $params = array();
public function __construct($params)
@@ -54,17 +54,17 @@ class EntityManager
$entityFactoryClassName = $params['entityFactoryClassName'];
}
$this->entityFactory = new $entityFactoryClassName($this, $this->metadata);
$repositoryFactoryClassName = '\\Espo\\ORM\\RepositoryFactory';
if (!empty($params['repositoryFactoryClassName'])) {
$repositoryFactoryClassName = $params['repositoryFactoryClassName'];
}
$this->repositoryFactory = new $repositoryFactoryClassName($this, $this->entityFactory);
$this->init();
}
public function getMapper($className)
{
if (empty($this->mappers[$className])) {
@@ -77,7 +77,9 @@ class EntityManager
{
$params = $this->params;
$this->pdo = new \PDO('mysql:host='.$params['host'].';dbname=' . $params['dbname'] . ';charset=utf8', $params['user'], $params['password']);
$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']);
$this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
}
@@ -85,13 +87,13 @@ class EntityManager
{
return $this->getRepository($name)->get($id);
}
public function saveEntity(Entity $entity)
{
$entityName = $entity->getEntityName();
return $this->getRepository($entityName)->save($entity);
}
public function removeEntity(Entity $entity)
{
$entityName = $entity->getEntityName();
@@ -110,7 +112,7 @@ class EntityManager
{
$this->metadata->setData($data);
}
public function getMetadata()
{
return $this->metadata;
@@ -133,14 +135,14 @@ class EntityManager
{
return $name;
}
public function createCollection($entityName, $data = array())
{
$seed = $this->getEntity($entityName);
$collection = new EntityCollection($data, $seed, $this->entityFactory);
$seed = $this->getEntity($entityName);
$collection = new EntityCollection($data, $seed, $this->entityFactory);
return $collection;
}
protected function init()
{
}

View File

@@ -58,5 +58,255 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
}
return $ids;
}
public function getEmailAddressData(Entity $entity)
{
$data = array();
$pdo = $this->getEntityManager()->getPDO();
$sql = "
SELECT email_address.name, email_address.invalid, email_address.opt_out AS optOut, entity_email_address.primary
FROM entity_email_address
JOIN email_address ON email_address.id = entity_email_address.email_address_id AND email_address.deleted = 0
WHERE
entity_email_address.entity_id = ".$pdo->quote($entity->id)." AND
entity_email_address.entity_type = ".$pdo->quote($entity->getEntityName())." AND
entity_email_address.deleted = 0
ORDER BY entity_email_address.primary DESC
";
$sth = $pdo->prepare($sql);
$sth->execute();
if ($rows = $sth->fetchAll()) {
foreach ($rows as $row) {
$obj = new \StdClass();
$obj->emailAddress = $row['name'];
$obj->primary = ($row['primary'] == '1') ? true : false;
$obj->optOut = ($row['optOut'] == '1') ? true : false;
$obj->invalid = ($row['invalid'] == '1') ? true : false;
$data[] = $obj;
}
}
return $data;
}
public function getByAddress($address)
{
return $this->where(array('lower' => strtolower($address)))->findOne();
}
public function storeEntityEmailAddress(Entity $entity)
{
$email = trim($entity->get('emailAddress'));
$emailAddressData = null;
if ($entity->has('emailAddressData')) {
$emailAddressData = $entity->get('emailAddressData');
}
$pdo = $this->getEntityManager()->getPDO();
if ($emailAddressData !== null && is_array($emailAddressData)) {
$previousEmailAddressData = array();
if (!$entity->isNew()) {
$previousEmailAddressData = $this->getEmailAddressData($entity);
}
$hash = array();
foreach ($emailAddressData as $row) {
$key = $row->emailAddress;
if (!empty($key)) {
$hash[$key] = array(
'primary' => $row->primary ? true : false,
'optOut' => $row->optOut ? true : false,
'invalid' => $row->invalid ? true : false,
);
}
}
$hashPrev = array();
foreach ($previousEmailAddressData as $row) {
$key = $row->emailAddress;
if (!empty($key)) {
$hashPrev[$key] = array(
'primary' => $row->primary ? true : false,
'optOut' => $row->optOut ? true : false,
'invalid' => $row->invalid ? true : false,
);
}
}
$primary = false;
$toCreate = array();
$toUpdate = array();
$toRemove = array();
foreach ($hash as $key => $data) {
$new = true;
$changed = false;
if ($hash[$key]['primary']) {
$primary = $key;
}
if (array_key_exists($key, $hashPrev)) {
$new = false;
$changed = $hash[$key]['optOut'] != $hashPrev[$key]['optOut'] || $hash[$key]['invalid'] != $hashPrev[$key]['invalid'];
if ($hash[$key]['primary']) {
if ($hash[$key]['primary'] == $hashPrev[$key]['primary']) {
$primary = false;
}
}
}
if ($new) {
$toCreate[] = $key;
}
if ($changed) {
$toUpdate[] = $key;
}
}
foreach ($hashPrev as $key => $data) {
if (!array_key_exists($key, $hash)) {
$toRemove[] = $key;
}
}
foreach ($toRemove as $address) {
$emailAddress = $this->getByAddress($address);
if ($emailAddress) {
$query = "
UPDATE entity_email_address
SET `deleted` = 1, `primary` = 0
WHERE
entity_id = ".$pdo->quote($entity->id)." AND
entity_type = ".$pdo->quote($entity->getEntityName())." AND
email_address_id = ".$pdo->quote($emailAddress->id)."
";
$sth = $pdo->prepare($query);
$sth->execute();
}
}
foreach ($toUpdate as $address) {
$emailAddress = $this->getByAddress($address);
if ($emailAddress) {
$emailAddress->set(array(
'optOut' => $hash[$address]['optOut'],
'invalid' => $hash[$address]['invalid'],
));
$this->save($emailAddress);
}
}
foreach ($toCreate as $address) {
$emailAddress = $this->getByAddress($address);
if (!$emailAddress) {
$emailAddress = $this->get();
$emailAddress->set(array(
'name' => $address,
'optOut' => $hash[$address]['optOut'],
'invalid' => $hash[$address]['invalid'],
));
$this->save($emailAddress);
} else {
if ($emailAddress->get('optOut') != $hash[$address]['optOut'] || $emailAddress->get('invalid') != $hash[$address]['invalid']) {
$emailAddress->set(array(
'optOut' => $hash[$address]['optOut'],
'invalid' => $hash[$address]['invalid'],
));
$this->save($emailAddress);
}
}
$query = "
INSERT entity_email_address
(entity_id, entity_type, email_address_id, `primary`)
VALUES
(
".$pdo->quote($entity->id).",
".$pdo->quote($entity->getEntityName()).",
".$pdo->quote($emailAddress->id).",
".$pdo->quote($address === $primary)."
)
";
$sth = $pdo->prepare($query);
$sth->execute();
}
if ($primary) {
$emailAddress = $this->getByAddress($primary);
if ($emailAddress) {
$query = "
UPDATE entity_email_address
SET `primary` = 0
WHERE
entity_id = ".$pdo->quote($entity->id)." AND
entity_type = ".$pdo->quote($entity->getEntityName())." AND
`primary` = 1 AND
deleted = 0
";
$sth = $pdo->prepare($query);
$sth->execute();
$query = "
UPDATE entity_email_address
SET `primary` = 1
WHERE
entity_id = ".$pdo->quote($entity->id)." AND
entity_type = ".$pdo->quote($entity->getEntityName())." AND
email_address_id = ".$pdo->quote($emailAddress->id)." AND
deleted = 0
";
$sth = $pdo->prepare($query);
$sth->execute();
}
}
} else {
$entityRepository = $this->getEntityManager()->getRepository($entity->getEntityName());
if (!empty($email)) {
if ($email != $entity->getFetched('emailAddress')) {
$emailAddressNew = $this->where(array('lower' => strtolower($email)))->findOne();
$isNewEmailAddress = false;
if (!$emailAddressNew) {
$emailAddressNew = $this->get();
$emailAddressNew->set('name', $email);
$this->save($emailAddressNew);
$isNewEmailAddress = true;
}
$emailOld = $entity->getFetched('emailAddress');
if (!empty($emailOld)) {
$emailAddressOld = $this->getByAddress($emailOld);
$entityRepository->unrelate($entity, 'emailAddresses', $emailAddressOld);
}
$entityRepository->relate($entity, 'emailAddresses', $emailAddressNew);
$query = "
UPDATE entity_email_address
SET `primary` = 1
WHERE
entity_id = ".$pdo->quote($entity->id)." AND
entity_type = ".$pdo->quote($entity->getEntityName())." AND
email_address_id = ".$pdo->quote($emailAddressNew->id)."
";
$sth = $pdo->prepare($query);
$sth->execute();
}
} else {
$emailOld = $entity->getFetched('emailAddress');
if (!empty($emailOld)) {
$emailAddressOld = $this->getByAddress($emailOld);
$entityRepository->unrelate($entity, 'emailAddresses', $emailAddressOld);
}
}
}
}
}

View File

@@ -29,6 +29,19 @@ class Preferences extends \Espo\Core\ORM\Repository
protected $dependencies = array(
'fileManager',
'metadata',
'config',
);
protected $defaultAttributesFromSettings = array(
'defaultCurrency',
'dateFormat',
'timeFormat',
'decimalMark',
'thousandSeparator',
'weekStart',
'timeZone',
'language',
'exportDelimiter'
);
protected $data = array();
@@ -45,6 +58,11 @@ class Preferences extends \Espo\Core\ORM\Repository
return $this->getInjection('metadata');
}
protected function getConfig()
{
return $this->getInjection('config');
}
protected function getFilePath($id)
{
return 'data/preferences/' . $id . '.json';
@@ -69,6 +87,10 @@ class Preferences extends \Espo\Core\ORM\Repository
$defaults[$field] = $d['default'];
}
}
foreach ($this->defaultAttributesFromSettings as $attr) {
$defaults[$attr] = $this->getConfig()->get($attr);
}
$this->data[$id] = $defaults;
}
}

View File

@@ -103,7 +103,8 @@
"First Name": "Vorname",
"Last Name": "Nachname",
"You": "Sie",
"you": "Sie"
"you": "Sie",
"change": "ändern"
},
"messages": {
"notModified": "Sie haben den Datensatz nicht geändert",

View File

@@ -63,7 +63,9 @@
"phone": "Phone",
"text": "Text",
"url": "Url",
"varchar": "Varchar"
"varchar": "Varchar",
"file": "File",
"image": "Image"
},
"fields": {
"type": "Type",
@@ -79,7 +81,8 @@
"field": "Field",
"min": "Min",
"max": "Max",
"translation": "Translation"
"translation": "Translation",
"previewSize": "Preview Size"
},
"messages": {
"upgradeVersion": "Your EspoCRM will be upgraded to version <strong>{version}</strong>. This can take some time.",
@@ -107,5 +110,13 @@
"layoutManager": "Customize layouts (list, detail, edit, search, mass update).",
"fieldManager": "Create new fields or customize existing ones.",
"userInterface": "Configure UI."
},
"options": {
"previewSize": {
"x-small": "X-Small",
"small": "Small",
"medium": "Medium",
"large": "Large"
}
}
}

View File

@@ -0,0 +1,7 @@
{
"labels": {
"Primary": "Primary",
"Opted Out": "Opted Out",
"Invalid": "Invalid"
}
}

View File

@@ -18,6 +18,7 @@
"ScheduledJob": "Scheduled Jobs"
},
"labels": {
"Misc": "Misc",
"Merge": "Merge",
"None": "None",
"by": "by",
@@ -103,8 +104,10 @@
"Person": "Person",
"First Name": "First Name",
"Last Name": "Last Name",
"Original": "Original",
"You": "You",
"you": "you"
"you": "you",
"change": "change"
},
"messages": {
"notModified": "You have not modified the record",

View File

@@ -17,7 +17,9 @@
"smtpUsername": "Username",
"emailAddress": "Email",
"smtpPassword": "Password",
"smtpEmailAddress": "Email Address"
"smtpEmailAddress": "Email Address",
"exportDelimiter": "Export Delimiter"
},
"links": {
},

View File

@@ -11,6 +11,8 @@
"currencyList": "Currency List",
"language": "Language",
"companyLogo": "Company Logo",
"smtpServer": "Server",
"smtpPort": "Port",
"smtpAuth": "Auth",
@@ -25,7 +27,9 @@
"recordsPerPage": "Records Per Page",
"recordsPerPageSmall": "Records Per Page (Small)",
"tabList": "Tab List",
"quickCreateList": "Quick Create List"
"quickCreateList": "Quick Create List",
"exportDelimiter": "Export Delimiter"
},
"options": {
"weekStart": {

View File

@@ -7,15 +7,26 @@
"defaultTeam": "Default Team",
"emailAddress": "Email",
"phone": "Phone",
"roles": "Roles",
"roles": "Roles",
"password": "Password",
"passwordConfirm": "Confirm Password"
"passwordConfirm": "Confirm Password",
"newPassword": "New Password"
},
"links": {
"teams": "Teams",
"roles": "Roles"
},
"labels": {
"Create User": "Create User"
"Create User": "Create User",
"Generate": "Generate",
"Access": "Access",
"Preferences": "Preferences",
"Change Password": "Change Password"
},
"messages": {
"passwordWillBeSent": "Password will be sent to user's email address.",
"accountInfoEmailSubject": "Account info",
"accountInfoEmailBody": "Your account information:\n\nUsername: {userName}\nPassword: {password}\n\n{siteUrl}",
"passwordChanged": "Password has been changed"
}
}

View File

@@ -0,0 +1,122 @@
{
"labels": {
"Enabled": "Activado",
"Disabled": "Desactivado",
"System": "Sistema",
"Users": "Usuarios",
"Email": "Correo electrónico",
"Data": "Datos",
"Customization": "Personalizar",
"Available Fields": "Campos Disponibles",
"Layout": "Diseño",
"Enabled": "Activado",
"Disabled": "Desactivado",
"Add Panel": "Añadir Panel",
"Add Field": "Añadir Campo",
"Settings": "Opciones",
"Scheduled Jobs": "Tareas Programadas",
"Upgrade": "Actualizar",
"Clear Cache": "Limpiar Cache",
"Rebuild": "Reconstruir",
"Users": "Usuarios",
"Teams": "Equipos",
"Roles": "Roles",
"Outbound Emails": "Correos Salientes",
"Inbound Emails": "Correos Entrantes",
"Email Templates": "Platillas de Correo",
"Import": "Importar",
"Layout Manager": "Administrador de Diseño",
"Field Manager": "Administrador de Campos",
"User Interface": "Interfaz de Usuario"
},
"layouts": {
"list": "Lista",
"detail": "Detalle",
"listSmall": "List (Small)",
"detailSmall": "Detail (Small)",
"filters": "Filtros de Búsqueda",
"massUpdate": "Actualización Masiva",
"relationships": "Relaciones"
},
"fieldTypes": {
"address": "Dirección",
"array": "Array",
"foreign": "Foreign",
"duration": "Duración",
"password": "Contraseña",
"parsonName": "Nombre",
"autoincrement": "Auto incrementar",
"bool": "Booleano",
"currency": "Moneda",
"date": "Fecha",
"datetime": "Fecha/Hora",
"email": "Correo electrónico",
"enum": "Enum",
"enumInt": "Enum Integer",
"enumFloat": "Enum Float",
"float": "Float",
"int": "Int",
"link": "Enlace",
"linkMultiple": "Enlace Múltiple",
"linkParent": "Enlace Padre",
"multienim": "Multienum",
"phone": "Teléfono",
"text": "Texto",
"url": "Url",
"varchar": "Varchar",
"file": "Archivo",
"image": "Imagen"
},
"fields": {
"type": "Tipo",
"name": "Nombre",
"label": "Etiqueta",
"required": "Requerido",
"default": "Por Defecto",
"maxLength": "Longitud máxima",
"options": "Options (raw values, not translated)",
"after": "After (field)",
"before": "Before (field)",
"link": "Enlace",
"field": "Campo",
"min": "Mínimo",
"max": "Máximo",
"translation": "Traducción",
"previewSize": "Tamaño de vista previa"
},
"messages": {
"upgradeVersion": "Su EspoCRM será actualizado a la versión <strong>{version}</strong>. Tomará algún tiempo.",
"upgradeDone": "Su EspoCRM ha sido actualizado a la versión <strong>{version}</strong>. Refresque su ventana del navegador.",
"upgradeBackup": "Le recomendamos que haga copias de seguridad de sus archivos y datos EspoCRM antes de la actualización.",
"thousandSeparatorEqualsDecimalMark": "El separador de miles no puede ser la misma que marca decimal",
"userHasNoEmailAddress": "El usuario no tiene la dirección de correo electrónico.",
"selectEntityType": "Seleccione el tipo de entidad en el menú de la izquierda.",
"selectUpgradePackage": "Seleccione Actualizar Paquete",
"selectLayout": "Seleccione el diseño necesario en el menú de la izquierda y editarlo."
},
"descriptions": {
"settings": "Configuración del sistema de aplicación.",
"scheduledJob": "Trabajos que se ejecutan por cron.(cron Jobs)",
"upgrade": "Actualiza EspoCRM.",
"clearCache": "Limpiar cache de Administración.",
"rebuild": "Reconstruir y limpiar el cache de Administración.",
"users": "Gestión de usuarios.",
"teams": "Gestión de Equipos",
"roles": "Gestión de Roles",
"outboundEmails": "Opciones SMTP para correo saliente.",
"inboundEmails": "Cuentas de correo IMAP Grupo. Importación-correo y dirección de correo electrónico a la sentencia.",
"emailTemplates": "Plantillas para mensajes de correo electrónico salientes.",
"import": "Importar datos desde CSV.",
"layoutManager": "Customize layouts (list, detail, edit, search, mass update).",
"fieldManager": "Crear nuevos campos o personalizar los ya existentes.",
"userInterface": "Configurar UI."
},
"options": {
"previewSize": {
"x-small": "X-Small",
"small": "Pequeño",
"medium": "Mediano",
"large": "Grande"
}
}
}

View File

@@ -0,0 +1,32 @@
{
"fields": {
"name": "Asunto",
"parent": "Padre",
"status": "Estado",
"dateSent": "Enviado",
"from": "De",
"to": "a",
"cc": "CC",
"bcc": "BCC",
"isHtml": "Es Html",
"body": "Cuerpo",
"subject": "Asunto",
"attachments": "Adjuntos",
"selectTemplate": "Seleccione una Plantilla",
"fromEmailAddress": "De la dirección",
"toEmailAddresses": "a la Dirección",
"emailAddress": "Correo Electrónico"
},
"links": {
},
"options": {
"Draft": "Borrador",
"Sending": "Enviando",
"Sent": "Enviado",
"Archived": "Archivado"
},
"labels": {
"Create Email": "Archivar Correo",
"Compose": "Componer"
}
}

View File

@@ -0,0 +1,7 @@
{
"labels": {
"Primary": "Primario",
"Opted Out": "optado por no",
"Invalid": "Inválido"
}
}

View File

@@ -0,0 +1,16 @@
{
"fields": {
"name": "Nombre",
"status": "Estado",
"isHtml": "Es Html",
"body": "Cuerpo",
"subject": "Asunto",
"attachments": "Adjuntos",
"insertField": ""
},
"links": {
},
"labels": {
"Create EmailTemplate": "Crear Plantilla de Correo"
}
}

View File

@@ -0,0 +1,395 @@
{
"scopeNames": {
"Email": "Correo electrónico",
"User": "Usuario",
"Team": "Equipo",
"Role": "Rol",
"EmailTemplate": "Plantilla de Correo",
"OutboundEmail": "Correo Saliente",
"ScheduledJob": "Tarea Programada"
},
"scopeNamesPlural": {
"Email": "Correos",
"User": "Usuarios",
"Team": "Equipos",
"Role": "Roles",
"EmailTemplate": "Platillas de Correo",
"OutboundEmail": "Correos Salientes",
"ScheduledJob": "Tareas Programadas"
},
"labels": {
"Misc": "Misc",
"Merge": "Fundir",
"None": "Ninguno",
"by": "por",
"Saved": "Guardado",
"Error": "Error",
"Select": "Seleccionar",
"Not valid": "Inválido",
"Please wait...": "Por favor espere...",
"Please wait": "Por favor espere",
"Loading...": "Cargando...",
"Uploading...": "Subiendo...",
"Sending...": "Enviando...",
"Posted": "Publicado",
"Linked": "Enlazado",
"Unlinked": "Desenlazado",
"Access denied": "Acceso denegado",
"Access": "Acceso",
"Are you sure?": "Are you sure?",
"Record has been removed": "Registro Eliminado",
"Wrong username/password": "Nombre de usuario/contraseña incorrectos",
"Post cannot be empty": "La entrada no puede estar vacia",
"Removing...": "Removiendo...",
"Unlinking...": "Desenlazando...",
"Posting...": "Publicando...",
"Username can not be empty!": "Nombre de usuario no puede estar vacío!",
"Cache is not enabled": "Cache no está habilitado",
"Cache has been cleared": "Cache Limpiado Correctamente",
"Rebuild has been done": "Se ha reconstruido",
"Saving...": "Guardando...",
"Modified": "Modificado",
"Created": "Creado",
"Create": "Crear",
"create": "crear",
"Overview": "Vista",
"Details": "Detalles",
"Add Filter": "Añadir Filtro",
"Add Dashlet": "Añadir Dashlet",
"Add": "Añadir",
"Reset": "Resetear",
"Menu": "Menú",
"More": "Más",
"Search": "Buscar",
"Only My": "Solo Yo",
"Open": "Abrir",
"Admin": "Administrador",
"About": "Acerca",
"Refresh": "Refrescar",
"Remove": "Remover",
"Options": "Optiones",
"Username": "Nombre de Usuario",
"Password": "Contraseña",
"Login": "Entrar",
"Log Out": "Salir",
"Preferences": "Preferencias",
"State": "Estado/Distrito",
"Street": "Calle",
"Country": "país",
"City": "Ciudad",
"PostalCode": "Código Postal",
"Followed": "Seguido",
"Follow": "Seguir",
"Clear Local Cache": "Borrar Cache Local",
"Actions": "Acciones",
"Delete": "Borrar",
"Update": "Actualizar",
"Save": "Guardar",
"Edit": "Editar",
"Cancel": "Cancelar",
"Unlink": "Desenlazar",
"Mass Update": "Actualización Masiva",
"Export": "Exportar",
"No Data": "Sin Datos",
"All": "Todos",
"Active": "Activo",
"Inactive": "Inactivo",
"Write your comment here": "Escriba su comentario aquí",
"Post": "Entrada",
"Stream": "Stream",
"Show more": "Mostrar mas",
"Dashlet Options": "Opciones Dashlet",
"Full Form": "Formulario Completo",
"Insert": "Insertar",
"Person": "Persona",
"First Name": "Primer Nombre",
"Last Name": "Apellidos",
"Original": "Original",
"You": "Tu",
"you": "tu",
"change": "cambiar"
},
"messages": {
"notModified": "Usted no ha modificado el registro",
"duplicate": "El registro que está creando parece ser un duplicado",
"fieldIsRequired": "{field} es requerido",
"fieldShouldBeEmail": "{field} debe se un correo electrónico válido",
"fieldShouldBeFloat": "{field} debe se un decimal válido",
"fieldShouldBeInt": "{field} debe se un entero válido",
"fieldShouldBeDate": "{field} debe se una fecha válida",
"fieldShouldBeDatetime": "{field} debe se una fecha válida fecha/hora",
"fieldShouldAfter": "{field} debe estar después {otherField}",
"fieldShouldBefore": "{field} debe estar antes {otherField}",
"fieldShouldBeBetween": "{field} debe estar entre {min} and {max}",
"fieldShouldBeLess": "{field} debe ser menor que {value}",
"fieldShouldBeGreater": "{field} debe ser mayor que {value}",
"fieldBadPasswordConfirm": "{field} confirmado de forma incorrecta"
},
"boolFilters": {
"onlyMy": "Solo Yo",
"open": "Abrir",
"active": "Activo"
},
"fields": {
"name": "Nombre",
"firstName": "Primer Nombre",
"lastName": "Apellidos",
"salutationName": "Saludo",
"assignedUser": "Usuario Asignado",
"emailAddress": "Correo electrónico",
"assignedUserName": "Nombre de Usuario Asignado",
"teams": "Equipos",
"createdAt": "Creado el",
"modifiedAt": "Modificado el",
"createdBy": "Creado Por",
"modifiedBy": "Modificado Por",
"title": "Título",
"dateFrom": "Fecha de",
"dateTo": "Fecha Para",
"autorefreshInterval": "Intervalo de Auto-Refrescar",
"displayRecords": "Mostrar Registros"
},
"links": {
"teams": "Equipos",
"users": "Usuarios"
},
"dashlets": {
"Stream": "Stream"
},
"streamMessages": {
"create": "{user} creado {entityType} {entity}",
"createAssigned": "{user} creado {entityType} {entity} asignado a {assignee}",
"assign": "{user} asignado {entityType} {entity} a {assignee}",
"post": "{user} publicado en {entityType} {entity}",
"attach": "{user} adjunto en {entityType} {entity}",
"status": "{user} actualizado {field} on {entityType} {entity}",
"update": "{user} actualizado {entityType} {entity}",
"createRelated": "{user} creado {relatedEntityType} {relatedEntity} enlazado a {entityType} {entity}",
"emailReceived": "{entity} ha sido recibido por {entityType} {entity}",
"createThis": "{user} crear este {entityType}",
"createAssignedThis": "{user} crear este {entityType} asignado a {assignee}",
"assignThis": "{user} asignar este {entityType} a {assignee}",
"postThis": "{user} publicado",
"attachThis": "{user} adjunto",
"statusThis": "{user} actualizado {field}",
"updateThis": "{user} actualizado a este {entityType}",
"createRelatedThis": "{user} creado {relatedEntityType} {relatedEntity} enlazado a este {entityType}",
"emailReceivedThis": "{entity} se ha recibido"
},
"lists": {
"monthNames": ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
"monthNamesShort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
"dayNames": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
"dayNamesShort": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
"dayNamesMin": ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
},
"options": {
"salutationName": {
"Mr.": "Sr.",
"Mrs.": "Sra.",
"Dr.": "Dr.",
"Drs.": "Drs."
},
"language": {
"af_ZA": "Afrikaans",
"az_AZ": "Azerbaijani",
"be_BY": "Belarusian",
"bg_BG": "Bulgarian",
"bn_IN": "Bengali",
"bs_BA": "Bosnian",
"ca_ES": "Catalan",
"cs_CZ": "Czech",
"cy_GB": "Welsh",
"da_DK": "Danish",
"de_DE": "German",
"el_GR": "Greek",
"en_GB":"English (UK)",
"en_US":"English (US)",
"es_ES":"Spanish (Spain)",
"et_EE": "Estonian",
"eu_ES": "Basque",
"fa_IR": "Persian",
"fi_FI": "Finnish",
"fo_FO": "Faroese",
"fr_CA":"French (Canada)",
"fr_FR":"French (France)",
"ga_IE": "Irish",
"gl_ES": "Galician",
"gn_PY": "Guarani",
"he_IL": "Hebrew",
"hi_IN": "Hindi",
"hr_HR": "Croatian",
"hu_HU": "Hungarian",
"hy_AM": "Armenian",
"id_ID": "Indonesian",
"is_IS": "Icelandic",
"it_IT": "Italian",
"ja_JP": "Japanese",
"ka_GE": "Georgian",
"km_KH": "Khmer",
"ko_KR": "Korean",
"ku_TR": "Kurdish",
"lt_LT": "Lithuanian",
"lv_LV": "Latvian",
"mk_MK": "Macedonian",
"ml_IN": "Malayalam",
"ms_MY": "Malay",
"nb_NO":"Norwegian Bokmål",
"nn_NO": "Norwegian Nynorsk",
"ne_NP": "Nepali",
"nl_NL": "Dutch",
"pa_IN": "Punjabi",
"pl_PL": "Polish",
"ps_AF": "Pashto",
"pt_BR":"Portuguese (Brazil)",
"pt_PT":"Portuguese (Portugal)",
"ro_RO": "Romanian",
"ru_RU": "Russian",
"sk_SK": "Slovak",
"sl_SI": "Slovene",
"sq_AL": "Albanian",
"sr_RS": "Serbian",
"sv_SE": "Swedish",
"sw_KE": "Swahili",
"ta_IN": "Tamil",
"te_IN": "Telugu",
"th_TH": "Thai",
"tl_PH": "Tagalog",
"tr_TR": "Turkish",
"uk_UA": "Ukrainian",
"ur_PK": "Urdu",
"vi_VN": "Vietnamese",
"zh_CN":"Simplified Chinese (China)",
"zh_HK":"Traditional Chinese (Hong Kong)",
"zh_TW":"Traditional Chinese (Taiwan)"
},
"dateSearchRanges": {
"on": "Está en",
"notOn": "No está en",
"after": "Después",
"before": "Antes",
"between": "Entre"
},
"intSearchRanges": {
"equals": "Iguales",
"notEquals": "Diferentes",
"greaterThan": "Mayor que",
"lessThan": "Menor que",
"greaterThanOrEquals": "Mayor o igual que",
"lessThanOrEquals": "Menor o igual que",
"between": "Entre"
},
"autorefreshInterval": {
"0": "Ninguno",
"0.5": "30 segundos",
"1": "1 minuto",
"2": "2 minutos",
"5": "5 minutos",
"10": "10 minutos"
}
},
"sets": {
"summernote": {
"NOTICE": "Usted puede encontrar aquí la traducción: https://github.com/HackerWins/summernote/tree/master/lang",
"font":{
"bold": "Negrita",
"italic": "Itálico",
"underline": "Subrayado",
"strike": "Tachado",
"clear": "Quitar Estilo de Fuente",
"height": "Alto de línea",
"name": "Familia de Fuente",
"size": "Tamaño de Fuente"
},
"image":{
"image": "Imagen",
"insert": "Insertar Imagen",
"resizeFull": "Cambiar el tamaño a completo",
"resizeHalf": "Cambiar el tamaño a la mitad",
"resizeQuarter": "Cambiar el tamaño a un cuarto",
"floatLeft": "Flotar Izquierda",
"floatRight": "Flotar Derecha",
"floatNone": "Sin Flotar",
"dragImageHere": "Arrastrar una imagen aquí",
"selectFromFiles": "Seleccionar desde Archivo",
"url": "Url de Imagen",
"remove": "Remover Imagen"
},
"link":{
"link": "Enlace",
"insert": "Insertar Enlace",
"unlink": "Desenlazar",
"edit": "Editar",
"textToDisplay": "TExto a mostrar",
"url":"To what URL should this link go?",
"openInNewWindow": "Abrir en nueva ventana"
},
"video":{
"video": "Vídeo",
"videoLink": "Enlace al Vídeo",
"insert": "Insertar Vídeo",
"url":"Video URL?",
"providers":"(YouTube, Vimeo, Vine, Instagram, or DailyMotion)"
},
"table":{
"table": "Tabla"
},
"hr":{
"insert": "Insertar regla horizontal"
},
"style":{
"style": "Estilo",
"normal": "Normal",
"blockquote": "Cita",
"pre": "Código",
"h1": "Header 1",
"h2": "Header 2",
"h3": "Header 3",
"h4": "Header 4",
"h5": "Header 5",
"h6": "Header 6"
},
"lists":{
"unordered": "Lista sin Ordenar",
"ordered": "Lista Ordenada"
},
"options":{
"help": "Ayuda",
"fullscreen": "Pantalla Completa",
"codeview": "Ver Código"
},
"paragraph":{
"paragraph": "Párrafo",
"outdent": "Anular sangría",
"indent": "Sangría",
"left": "Alinear Izquierda",
"center": "Alinear Centro",
"right": "Alinear Derecha",
"justify": "Justificado"
},
"color":{
"recent": "Color Reciente",
"more": "Mas Colores",
"background": "Color de Fondo",
"foreground": "Color de Fuente",
"transparent": "Transparente",
"setTransparent": "Establecer transparente",
"reset": "Resetear",
"resetToDefault": "Restablecer a (por defecto)"
},
"shortcut":{
"shortcuts": "Atajos de teclado",
"close": "Cerrar",
"textFormatting": "Formato de texto",
"action": "Acción",
"paragraphFormatting": "Formato de párrafo",
"documentStyle": "Estilo de Documento"
},
"history":{
"undo": "Deshacer",
"redo": "Rehacer"
}
}
}
}

View File

@@ -0,0 +1,6 @@
{
"fields": {
"post": "Entrada",
"attachments": "Adjuntos"
}
}

View File

@@ -0,0 +1,32 @@
{
"fields": {
"dateFormat": "Formato de fecha",
"timeFormat": "Formato de tiempo",
"timeZone": "Zona Horaria",
"weekStart": "Primer día de la semana",
"thousandSeparator": "Separador de miles",
"decimalMark": "Separador decimal",
"defaultCurrency": "Moneda por Defecto",
"currencyList": "Lista de Moneda",
"language": "Lenguaje",
"smtpServer": "Servidor",
"smtpPort": "Puerto",
"smtpAuth": "Autenticación",
"smtpSecurity": "Securidad",
"smtpUsername": "Nombre de Usuario",
"emailAddress": "Correo electrónico",
"smtpPassword": "Contraseña",
"smtpEmailAddress": "Correo Electrónico",
"exportDelimiter": "Export Delimiter"
},
"links": {
},
"options": {
"weekStart": {
"0": "Domingo",
"1": "Lunes"
}
}
}

View File

@@ -0,0 +1,32 @@
{
"fields": {
"name": "Nombre",
"roles": "Roles"
},
"links": {
"users": "Usuarios",
"teams": "Equipos"
},
"labels": {
"Access": "Acceso",
"Create Role": "Crear Rol"
},
"options": {
"accessList": {
"not-set": "sin establecer",
"enabled": "activado",
"disabled": "desactivado"
},
"levelList": {
"all": "todos",
"team": "equipo",
"own": "propio",
"no": "no"
}
},
"actions": {
"read": "Leer",
"edit": "Editar",
"delete": "Borrar"
}
}

View File

@@ -0,0 +1,30 @@
{
"fields": {
"name": "Nombre",
"status": "Estado",
"job": "Trabajo",
"scheduling": "Scheduling (crontab notation)"
},
"links": {
"log": "Registro de Log"
},
"labels": {
"Create ScheduledJob": "Crear Tarea programado"
},
"options": {
"job": {
"CheckInboundEmails": "Comprobar Correos Entrantes",
"Cleanup": "Limpiar"
},
"cronSetup": {
"linux": "Nota: Añada esta línea al archivo crontab para ejecutar trabajos Espo programadas:",
"mac": "Nota: Añada esta línea al archivo crontab para ejecutar trabajos Espo programadas:",
"windows": "Nota: Crear un archivo por lotes con los siguientes comandos para ejecutar tareas programadas usando Espo tareas programadas de Windows:",
"default": "Note: Add this command to Cron Job (Scheduled Task):"
},
"status": {
"Active": "Activo",
"Inactive": "Inactivo"
}
}
}

View File

@@ -0,0 +1,6 @@
{
"fields": {
"status": "Estado",
"executionTime": "Tiempo de Ejecución"
}
}

View File

@@ -0,0 +1,44 @@
{
"fields": {
"useCache": "Usar Cache",
"dateFormat": "Formato de fecha",
"timeFormat": "Formato de tiempo",
"timeZone": "Zona Horaria",
"weekStart": "Primer día de la semana",
"thousandSeparator": "Separador de miles",
"decimalMark": "Separador decimal",
"defaultCurrency": "Moneda por Defecto",
"currencyList": "Lista de Moneda",
"language": "Lenguaje",
"smtpServer": "Servidor",
"smtpPort": "Puerto",
"smtpAuth": "Autenticación",
"smtpSecurity": "Securidad",
"smtpUsername": "Nombre de Usuario",
"emailAddress": "Correo electrónico",
"smtpPassword": "Contraseña",
"outboundEmailFromName": "De Nombre",
"outboundEmailFromAddress": "De la dirección",
"outboundEmailIsShared": "Es Compartido",
"recordsPerPage": "Registros por Página",
"recordsPerPageSmall": "Records Per Page (Small)",
"tabList": "Lista Pestaña",
"quickCreateList": "Crear Lista Rápido",
"exportDelimiter": "Export Delimiter"
},
"options": {
"weekStart": {
"0": "Domingo",
"1": "Lunes"
}
},
"labels": {
"System": "Sistema",
"Locale": "Localización",
"SMTP": "SMTP",
"Configuration": "Configuración"
}
}

View File

@@ -0,0 +1,12 @@
{
"fields": {
"name": "Nombre",
"roles": "Roles"
},
"links": {
"users": "Usuarios"
},
"labels": {
"Create Team": "Crear Equipo"
}
}

View File

@@ -0,0 +1,21 @@
{
"fields": {
"name": "Nombre",
"userName": "Nombre de Usuario",
"title": "Título",
"isAdmin": "Es Administrador",
"defaultTeam": "Equipo por Defecto",
"emailAddress": "Correo electrónico",
"phone": "Teléfono",
"roles": "Roles",
"password": "Contraseña",
"passwordConfirm": "Confirmar Contraseña"
},
"links": {
"teams": "Equipos",
"roles": "Roles"
},
"labels": {
"Create User": "Crear Usuario"
}
}

View File

@@ -6,7 +6,7 @@
{"name":"post"}
],
[
{"name":"attachments","type": "attachmentMultiple"}
{"name":"attachments"}
]
]
}

View File

@@ -6,7 +6,7 @@
{"name":"post"}
],
[
{"name":"attachments","type": "attachmentMultiple"}
{"name":"attachments"}
]
]
}

View File

@@ -22,5 +22,11 @@
[{"name": "smtpUsername"}],
[{"name": "smtpPassword"}]
]
},
{
"label": "Misc",
"rows": [
[{"name": "exportDelimiter"}]
]
}
]

View File

@@ -2,9 +2,10 @@
{
"label": "System",
"rows": [
[{"name": "useCache"}]
[{"name": "useCache"},{"name": "companyLogo"}]
]
},{
},
{
"label": "Locale",
"rows": [
[{"name": "dateFormat"}, {"name": "timeZone"}],

View File

@@ -1 +1,11 @@
[{"label":"Overview","rows":[[{"name":"userName"},{"name":"isAdmin"}],[{"name":"name"},{"name":"title"}],[{"name":"defaultTeam"}],[{"name":"emailAddress"},{"name":"phone"}]]}]
[
{
"label":"Overview",
"rows":[
[{"name":"userName"},{"name":"isAdmin"}],
[{"name":"name"},{"name":"title"}],
[{"name":"defaultTeam"}],
[{"name":"emailAddress"},{"name":"phone"}]
]
}
]

View File

@@ -0,0 +1,32 @@
{
"fields": {
"token": {
"type": "varchar",
"maxLength": "36"
},
"hash": {
"type": "varchar",
"maxLength": "36",
"index": true
},
"userId": {
"type": "varchar",
"maxLength": "36"
},
"ipAddress": {
"type": "varchar",
"maxLength": "36"
},
"lastAccess": {
"type": "datetime"
},
"createdAt": {
"type": "datetime",
"readOnly": true
},
"modifiedAt": {
"type": "datetime",
"readOnly": true
}
}
}

View File

@@ -13,7 +13,8 @@
"type": "linkParent"
},
"attachments": {
"type": "linkMultiple"
"type": "linkMultiple",
"view": "Stream.Fields.AttachmentMultiple"
},
"createdAt": {
"type": "datetime",
@@ -44,6 +45,7 @@
"attachments": {
"type": "hasChildren",
"entity": "Attachment",
"relationName": "NoteAttachments",
"foreign": "parent"
},
"parent": {

View File

@@ -74,6 +74,12 @@
"language": {
"type": "enum",
"default": "en_US"
},
"exportDelimiter": {
"type": "varchar",
"default": ",",
"required": true,
"maxLength": 1
}
}
}

View File

@@ -113,6 +113,15 @@
"type": "enum",
"options": ["en_US"],
"default": "en_US"
},
"exportDelimiter": {
"type": "varchar",
"default": ",",
"required": true,
"maxLength": 1
},
"companyLogo": {
"type": "image"
}
}
}

View File

@@ -42,6 +42,10 @@
"type": "phone",
"maxLength": 50
},
"token": {
"type": "varchar",
"notStorable": true
},
"defaultTeam": {
"type": "link"
},

View File

@@ -8,7 +8,9 @@
],
"fields":{
"street":{
"type":"varchar"
"type": "text",
"maxLength": 255,
"dbType": "varchar"
},
"city":{
"type":"varchar"
@@ -24,7 +26,7 @@
}
},
"mergable":false,
"notCreatable": true,
"notCreatable": false,
"search":{
"basic":false,
"advanced":true

View File

@@ -1,11 +0,0 @@
{
"notCreatable": true,
"fieldDefs": {
"type": "linkMultiple"
},
"linkDefs": {
"type": "hasChildren",
"entity": "Attachment",
"foreign": "parent"
}
}

View File

@@ -4,10 +4,6 @@
"name":"required",
"type":"bool",
"default":false
},
{
"name":"maxLength",
"type":"int"
}
],
"notCreatable": true,

View File

@@ -0,0 +1,26 @@
{
"params":[
{
"name":"required",
"type":"bool",
"default":false
}
],
"actualFields":[
"id"
],
"notActualFields":[
"name"
],
"fieldDefs":{
"skip":true
},
"search":{
"basic":false,
"advanced":false
},
"linkDefs": {
"type": "belongsTo",
"entity": "Attachment"
}
}

View File

@@ -0,0 +1,32 @@
{
"params":[
{
"name":"required",
"type":"bool",
"default":false
},
{
"name":"previewSize",
"type":"enum",
"default":"small",
"options": ["x-small", "small", "medium", "large"]
}
],
"actualFields":[
"id"
],
"notActualFields":[
"name"
],
"fieldDefs":{
"skip":true
},
"search":{
"basic":false,
"advanced":false
},
"linkDefs": {
"type": "belongsTo",
"entity": "Attachment"
}
}

View File

@@ -8,6 +8,10 @@
{
"name":"default",
"type":"text"
},
{
"name":"maxLength",
"type":"int"
}
],
"search":{

View File

@@ -0,0 +1,7 @@
{
"entity": true,
"layouts": false,
"tab": false,
"acl": false,
"customizable":false
}

Some files were not shown because too many files have changed in this diff Show More