Compare commits

..

493 Commits
1.0.1 ... 2.5.2

Author SHA1 Message Date
Yuri Kuznetsov
0a2c79ba81 version 2014-09-11 18:17:15 +03:00
Yuri Kuznetsov
5360ba0147 fix dutch 2014-09-11 18:14:30 +03:00
Yuri Kuznetsov
6620254d00 fix lang 2014-09-11 18:12:27 +03:00
Yuri Kuznetsov
f6eb0bcce8 Merge branch 'hotfix/2.5.2' of ssh://172.20.0.1/var/git/espo/backend into hotfix/2.5.2 2014-09-11 18:06:10 +03:00
Yuri Kuznetsov
c1116ff5dc fix email account 2014-09-11 18:05:58 +03:00
Taras Machyshyn
7dcdfcd231 DBAL fixed changing column length 2014-09-11 15:20:18 +03:00
Taras Machyshyn
0eadb9af69 log filename if invalid json file 2014-09-11 14:07:12 +03:00
Yuri Kuznetsov
3c3518b857 fix global search panel 2014-09-10 11:19:14 +03:00
Yuri Kuznetsov
f3ab0a734c css 2014-09-09 15:11:01 +03:00
Yuri Kuznetsov
33adc67dee version 2014-09-09 15:06:12 +03:00
Yuri Kuznetsov
18e475e1b6 fix clear cache 2014-09-09 15:05:18 +03:00
Yuri Kuznetsov
438c0f7edd upgrade full calendar 2014-09-09 12:20:56 +03:00
Yuri Kuznetsov
3159c9d288 libs to metadata 2014-09-09 11:50:11 +03:00
Yuri Kuznetsov
fe0f93784b fix lib loader 2014-09-09 11:21:54 +03:00
Yuri Kuznetsov
2d237eae29 remove isHtml dependency 2014-09-09 11:14:29 +03:00
Yuri Kuznetsov
747aa2d882 dashlet ch 2014-09-09 11:07:24 +03:00
Yuri Kuznetsov
46a7119ce1 month names in sales by month dashlet 2014-09-09 11:00:19 +03:00
Yuri Kuznetsov
c18342694f change max resolution 2014-09-09 10:54:02 +03:00
Yuri Kuznetsov
bb47b70f31 fix tooltip 2014-09-09 10:48:02 +03:00
Yuri Kuznetsov
07767b2dae fix ref 2014-09-05 17:26:21 +03:00
Yuri Kuznetsov
88037c8291 Merge branch 'release/2.5' into stable 2014-09-05 17:05:40 +03:00
Taras Machyshyn
ee03c686ca cron job chnages: remove duplicate jobs, check if ruuning 2014-09-05 15:27:17 +03:00
Yuri Kuznetsov
78140f7d5e change default dashlet layout 2014-09-05 14:59:33 +03:00
Yuri Kuznetsov
549acfd032 copy billing address 2014-09-05 14:52:43 +03:00
Yuri Kuznetsov
e4dab33792 acceptance status 2014-09-05 12:41:28 +03:00
Yuri Kuznetsov
287f95a8ac sort entity list in field/layout manager 2014-09-05 11:30:20 +03:00
Yuri Kuznetsov
4951f8464e role acl table 2014-09-05 11:27:28 +03:00
Yuri Kuznetsov
8ed9b9ebd2 fix get user Acl 2014-09-05 11:20:12 +03:00
Yuri Kuznetsov
96ed9612d4 email address lookup minChar 1 2014-09-05 11:11:35 +03:00
Yuri Kuznetsov
1fd77a4c13 link field can be w/o link 2014-09-05 10:58:04 +03:00
Yuri Kuznetsov
2390ac10a8 dont rerender if edit inline edit 2014-09-05 10:46:58 +03:00
Yuri Kuznetsov
03572ecaad footer padding 2014-09-05 10:28:43 +03:00
Yuri Kuznetsov
c1ac692304 version 2014-09-05 10:21:23 +03:00
Yuri Kuznetsov
f371090bde Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-09-05 10:20:45 +03:00
Yuri Kuznetsov
e28341f154 pl_PL 2014-09-05 10:20:27 +03:00
Taras Machyshyn
870f871ceb changed allowed params of 'link' metadata 2014-09-04 15:55:54 +03:00
Yuri Kuznetsov
c18d892a4e bottom panel label 2014-09-04 13:05:27 +03:00
Yuri Kuznetsov
c8bfd1c6dd fix side field label 2014-09-04 13:01:49 +03:00
Yuri Kuznetsov
c582860d5c fix notification about link appears twice 2014-09-04 13:00:11 +03:00
Yuri Kuznetsov
1796db30fa external account 1 2014-09-02 18:26:48 +03:00
Yuri Kuznetsov
25aa0ec564 show/hide integration fields 2014-09-01 18:17:35 +03:00
Yuri Kuznetsov
f3dc904c65 helpText 2014-09-01 17:36:54 +03:00
Yuri Kuznetsov
343d33e741 integrations 1 2014-09-01 16:59:59 +03:00
Yuri Kuznetsov
276480dcfa opp reports 2014-08-29 11:40:28 +03:00
Yuri Kuznetsov
b00b725af5 text earch 2014-08-29 11:26:50 +03:00
Yuri Kuznetsov
ab71ced531 full form keeps attributes 2014-08-29 11:06:09 +03:00
Yuri Kuznetsov
ba7988a842 ssl-port dependance 2014-08-29 10:51:46 +03:00
Yuri Kuznetsov
e1355acda1 email account 5 2014-08-28 17:15:44 +03:00
Yuri Kuznetsov
1853f4f113 fix 2014-08-27 18:00:14 +03:00
Yuri Kuznetsov
da677cfae8 fix 2014-08-27 17:56:37 +03:00
Yuri Kuznetsov
272bccc2fd fix 2014-08-27 17:41:29 +03:00
Yuri Kuznetsov
5372155773 email account 3 2014-08-27 17:34:32 +03:00
Yuri Kuznetsov
e1579295da email account 2014-08-27 17:01:31 +03:00
Yuri Kuznetsov
cc708e03d1 email account 1 2014-08-27 12:07:59 +03:00
Yuri Kuznetsov
34e91958d6 hide preferences password 2014-08-27 10:55:08 +03:00
Yuri Kuznetsov
928e4c2fb5 allowQuickEdit 2014-08-26 17:19:14 +03:00
Yuri Kuznetsov
cf86fcda85 email resrict fields 2014-08-26 15:39:56 +03:00
Yuri Kuznetsov
db3b36a639 fix email fields view 2014-08-26 13:35:33 +03:00
Yuri Kuznetsov
a4a731437e fix email fields 2014-08-26 13:19:35 +03:00
Yuri Kuznetsov
51f4c7fa09 fix field re-render 2014-08-26 13:19:25 +03:00
Yuri Kuznetsov
cbce4fc327 fix datetime short 2014-08-26 12:06:02 +03:00
Yuri Kuznetsov
4e953f6fa8 add user to address seek 2014-08-26 11:26:56 +03:00
Yuri Kuznetsov
0ed0420a4b fix email 2014-08-26 11:20:49 +03:00
Yuri Kuznetsov
16961795af email address field 2014-08-25 17:00:55 +03:00
Yuri Kuznetsov
c52c7fed59 acl check 2014-08-22 18:23:57 +03:00
Yuri Kuznetsov
95c00fc49d reply action 2014-08-22 18:22:52 +03:00
Yuri Kuznetsov
9f8606dd06 fix datetime 2014-08-22 18:05:03 +03:00
Yuri Kuznetsov
b33dc9baae link multiple select 2014-08-22 17:38:04 +03:00
Yuri Kuznetsov
8cb95f1b0e user filter by teams 2014-08-22 17:32:59 +03:00
Yuri Kuznetsov
86cd1ab864 blockquote size 2014-08-22 17:14:29 +03:00
Yuri Kuznetsov
df842f3e3e forward attachments 2014-08-22 17:10:04 +03:00
Yuri Kuznetsov
572455ecf6 attachment roles 2014-08-22 16:45:01 +03:00
Yuri Kuznetsov
7692f9e3ad align list 2014-08-22 16:16:00 +03:00
Yuri Kuznetsov
be0c1d8ab1 stream date 2014-08-22 15:53:00 +03:00
Yuri Kuznetsov
4a6c3d9e18 date time short fix and side 2014-08-22 15:50:11 +03:00
Yuri Kuznetsov
e0fdbd90fd datetime short 2014-08-22 15:37:22 +03:00
Yuri Kuznetsov
18a3f2658a email improve 2014-08-22 14:45:49 +03:00
Yuri Kuznetsov
80ee06ec1d email reply 2014-08-22 12:34:26 +03:00
Yuri Kuznetsov
f16adeed99 fornawesome 2014-08-22 11:33:08 +03:00
Yuri Kuznetsov
9ca39f3559 email create in menu 2014-08-22 11:06:00 +03:00
Yuri Kuznetsov
19285372d6 default search data 2014-08-22 11:02:21 +03:00
Yuri Kuznetsov
61df6bec45 cleanup 2014-08-22 10:41:34 +03:00
Yuri Kuznetsov
8904d4ddaf acl solid in metadata 2014-08-22 10:20:24 +03:00
Yuri Kuznetsov
ca5fba97df Merge branch 'hotfix/2.4.1' 2014-08-21 18:14:30 +03:00
Yuri Kuznetsov
fa755efefb email layouts 2014-08-21 18:14:21 +03:00
Yuri Kuznetsov
d6085f4985 plain text email 2014-08-21 16:02:57 +03:00
Yuri Kuznetsov
4c01e9329d timeout 0 2014-08-21 12:37:28 +03:00
Yuri Kuznetsov
9813eeb5bc nl lang 2014-08-21 11:32:11 +03:00
Yuri Kuznetsov
09d571a639 de lang 2014-08-21 11:30:09 +03:00
Yuri Kuznetsov
fffd44316e Merge branch 'hotfix/2.4.1' 2014-08-20 16:55:24 +03:00
Yuri Kuznetsov
a704830b86 fix inline edit for hidden fields 2014-08-20 16:55:05 +03:00
Yuri Kuznetsov
7910f71428 Merge branch 'hotfix/2.4.1' 2014-08-20 15:51:37 +03:00
Yuri Kuznetsov
52dcc51f4f version 2014-08-20 14:20:44 +03:00
Yuri Kuznetsov
f870ded9e0 rename default and class properties 2014-08-20 11:45:02 +03:00
Yuri Kuznetsov
224c72c875 remove upload timeout 2014-08-20 10:51:51 +03:00
Yuri Kuznetsov
ed50802073 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-19 17:34:10 +03:00
Yuri Kuznetsov
1f5036eb5f small refactor utils/database 2014-08-19 16:19:54 +03:00
Yuri Kuznetsov
701a60a07f autocomlate off 2014-08-19 12:38:24 +03:00
Yuri Kuznetsov
c760f7364c some refactor 2014-08-19 12:25:41 +03:00
Yuri Kuznetsov
4c28409a36 showNewRecords for stream 2014-08-19 11:59:30 +03:00
Taras Machyshyn
e932681166 install improvements (fix 'pdo_mysql' checking, turkish lang file) 2014-08-18 16:09:35 +03:00
Taras Machyshyn
a8209488ee install improvements (fix 'pdo_mysql' checking, turkish lang file) 2014-08-18 16:07:46 +03:00
Taras Machyshyn
d48642ca81 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-18 16:03:14 +03:00
Taras Machyshyn
6561c4b6c2 fix PATCH method 2014-08-18 16:02:58 +03:00
Yuri Kuznetsov
4f5f84c8f7 add phone/email button manage 2014-08-18 15:42:06 +03:00
Yuri Kuznetsov
56a04336fe Merge branch 'master' into stable 2014-08-15 17:43:02 +03:00
Yuri Kuznetsov
1814529d3e Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-15 17:13:52 +03:00
Taras Machyshyn
1dbe2d9eac installer: missing files 2014-08-15 17:12:26 +03:00
Taras Machyshyn
4ca099afc4 fix installation problem 2014-08-15 16:57:13 +03:00
Yuri Kuznetsov
7ca09bc893 grunt change 2014-08-15 16:22:44 +03:00
Yuri Kuznetsov
0a4a8c956a Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-15 16:17:28 +03:00
Yuri Kuznetsov
6f2a7ae08f fix Show More 2014-08-15 16:17:23 +03:00
Taras Machyshyn
45a9dd1226 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-15 16:10:52 +03:00
Taras Machyshyn
9d904171c9 added block rules for IIS 2014-08-15 16:10:23 +03:00
Yuri Kuznetsov
53abea7cdd fix reports 2014-08-15 16:01:35 +03:00
Yuri Kuznetsov
6427604724 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-15 15:33:07 +03:00
Taras Machyshyn
0d72dc7c2f changes rules for nginx server 2014-08-15 15:32:33 +03:00
Yuri Kuznetsov
9ee5a98ff4 fix label 2014-08-15 15:06:01 +03:00
Taras Machyshyn
3f0c92744c install improvements 2014-08-15 13:27:19 +03:00
Taras Machyshyn
7a87749c4c fix problem with MySQL 'int' 2014-08-15 13:18:44 +03:00
Yuri Kuznetsov
0eaab6b7ee userName unique fix 2014-08-15 11:22:57 +03:00
Yuri Kuznetsov
b52722565a Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-14 17:13:12 +03:00
Yuri Kuznetsov
80fd2a2006 fix tooltips 2014-08-14 17:13:08 +03:00
Yuri Kuznetsov
1c1fdffb7d some padding 2014-08-14 16:29:50 +03:00
Yuri Kuznetsov
53481890db pdf shown 2014-08-14 16:25:54 +03:00
Yuri Kuznetsov
b82a3d0f31 stream post padding 2014-08-14 16:17:39 +03:00
Yuri Kuznetsov
1700b27501 fix revert 2014-08-14 15:30:14 +03:00
Yuri Kuznetsov
635064e116 revert import imporve 2014-08-14 14:46:54 +03:00
Yuri Kuznetsov
f6e45d8a68 fix import id 2014-08-14 13:40:41 +03:00
Yuri Kuznetsov
ee0cf4bca5 fix see more 2014-08-14 13:31:04 +03:00
Taras Machyshyn
ae98290721 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-14 13:20:40 +03:00
Taras Machyshyn
24bbcf0e0a installer minor fixes 2014-08-14 13:20:06 +03:00
Yuri Kuznetsov
23b1945a3e change label 2014-08-14 13:19:42 +03:00
Yuri Kuznetsov
e1fe3c03dd Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-14 13:17:05 +03:00
Yuri Kuznetsov
7e0034f674 see more 2014-08-14 13:13:05 +03:00
Yuri Kuznetsov
d73cfbca53 strem post 2014-08-14 12:40:53 +03:00
Taras Machyshyn
3eec2b2a33 fixed wrong default TLS port 2014-08-14 11:58:43 +03:00
Yuri Kuznetsov
d60dc744e6 no clean js 2014-08-14 11:29:54 +03:00
Yuri Kuznetsov
bd66211c3c grunt fix 2014-08-14 11:27:58 +03:00
Yuri Kuznetsov
2f341c8967 fix grunt 2014-08-14 11:21:01 +03:00
Yuri Kuznetsov
5c7612c9cf version and grunt 2014-08-14 11:19:46 +03:00
Taras Machyshyn
b41c0f34aa Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-14 11:17:26 +03:00
Taras Machyshyn
14eebc7392 added indexes for EmailAddress.lower and PhoneNumber.name 2014-08-14 11:17:09 +03:00
Yuri Kuznetsov
5a86d0e396 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-13 17:08:44 +03:00
Yuri Kuznetsov
a4e0c8107d fix modals 2014-08-13 17:08:26 +03:00
Yuri Kuznetsov
1652de16a7 muted tooltip text 2014-08-13 15:36:29 +03:00
Yuri Kuznetsov
ad539e19a2 fix lang 2014-08-13 15:34:31 +03:00
Yuri Kuznetsov
592f073bf9 tooltips 2014-08-13 15:32:11 +03:00
Taras Machyshyn
d5c1d1b86e added no-suPHP support 2014-08-13 15:27:37 +03:00
Yuri Kuznetsov
bd70e2424c isRequired fix 2014-08-13 14:21:03 +03:00
Taras Machyshyn
06d6299d7f fixed language merge issue 2014-08-13 12:52:38 +03:00
Yuri Kuznetsov
d00d2bdb0f login css 2014-08-13 12:20:22 +03:00
Yuri Kuznetsov
9f481f6887 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-13 11:37:55 +03:00
Yuri Kuznetsov
47d0501828 rowactions 2014-08-13 11:37:31 +03:00
Yuri Kuznetsov
a4cd8dccfe fix dutch 2014-08-12 18:28:39 +03:00
Taras Machyshyn
eee0f0eb13 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-12 18:23:45 +03:00
Taras Machyshyn
67b9600341 added getRequestMethod() method for Controller 2014-08-12 18:22:14 +03:00
Yuri Kuznetsov
4c0329e6be Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-12 17:14:58 +03:00
Yuri Kuznetsov
ff6cd18411 nl_NL lang 2014-08-12 17:10:27 +03:00
Taras Machyshyn
8d4219802b added rebuild for Currency Settings 2014-08-12 13:44:23 +03:00
Taras Machyshyn
07e7374a18 added 'remove' possibility to config 2014-08-12 13:04:08 +03:00
Taras Machyshyn
060f517591 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-12 12:56:36 +03:00
Taras Machyshyn
1af5e93bd3 added test file to ignore list 2014-08-12 12:56:17 +03:00
Yuri Kuznetsov
38df3162b3 fix xss 2014-08-12 12:12:27 +03:00
Yuri Kuznetsov
e03298b041 opportunity currency converted 2014-08-12 11:54:09 +03:00
Yuri Kuznetsov
80278b7213 quote {value} and lead currency converted 2014-08-12 11:47:37 +03:00
Yuri Kuznetsov
a701905e9c required inbound \email template 2014-08-11 18:06:34 +03:00
Yuri Kuznetsov
59b896e594 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-08-11 17:36:16 +03:00
Taras Machyshyn
ba4c8e0afd config: possibility to save StdClass 2014-08-11 17:35:49 +03:00
Yuri Kuznetsov
9175d8c7ce change layout 2014-08-11 17:26:00 +03:00
Yuri Kuznetsov
052fee6ba2 fix css input group 2014-08-11 17:24:17 +03:00
Yuri Kuznetsov
aae3afc895 currency 1 2014-08-11 17:11:30 +03:00
Yuri Kuznetsov
1892ff6cae Merge branch 'hotfix/2.3.1' 2014-08-11 15:49:34 +03:00
Yuri Kuznetsov
aa3e9fd8b0 Merge branch 'hotfix/2.3.1' of ssh://172.20.0.1/var/git/espo/backend into hotfix/2.3.1 2014-08-11 14:14:33 +03:00
Yuri Kuznetsov
2863092911 compose email from case 2014-08-11 14:13:52 +03:00
Taras Machyshyn
1c36421157 chnaged currencyRate in config 2014-08-11 13:58:33 +03:00
Yuri Kuznetsov
77f7da0ba5 case and email improvoments 2014-08-11 12:45:04 +03:00
Yuri Kuznetsov
a5f858dda2 fix detail view false field 2014-08-11 11:44:04 +03:00
Taras Machyshyn
a5b7bfc00e fixed access LOGs issue 2014-08-11 11:30:28 +03:00
Yuri Kuznetsov
4d2cb6c38e varchar search 2014-08-11 10:53:40 +03:00
Yuri Kuznetsov
b6bd70d47c currency symbol 2014-08-11 10:49:34 +03:00
Yuri Kuznetsov
ef3ed38b97 Merge branch 'master' into stable 2014-08-08 16:58:08 +03:00
Yuri Kuznetsov
a38b86b2c6 dashlet sorting 2014-08-08 14:13:24 +03:00
Yuri Kuznetsov
a87044623c diff fix 2014-08-08 11:45:13 +03:00
Yuri Kuznetsov
44a96ddece isFieldChanged 2014-08-07 18:30:52 +03:00
Yuri Kuznetsov
b0e911870b git fix lang 2014-08-07 16:19:55 +03:00
Yuri Kuznetsov
96bb421b0a Delete label 2014-08-07 15:24:32 +03:00
Yuri Kuznetsov
c281d7b2d9 fix lang 2014-08-07 12:08:51 +03:00
Yuri Kuznetsov
dc5766088f confirm messages 2014-08-07 12:03:54 +03:00
Yuri Kuznetsov
fe69f97b1e fix acl issue and mappen IN issue 2014-08-07 11:28:52 +03:00
Yuri Kuznetsov
b7bc1e3622 services changes 2014-08-06 16:07:04 +03:00
Yuri Kuznetsov
b3c4123669 email notifications 2014-08-06 15:57:30 +03:00
Yuri Kuznetsov
0795f6f6f2 clear cache messag in role 2014-08-06 10:50:26 +03:00
Yuri Kuznetsov
c3cd909063 version 2014-08-05 17:34:39 +03:00
Yuri Kuznetsov
0e37c26b9f fix issue with this 2014-08-05 17:12:15 +03:00
Yuri Kuznetsov
80937f8d09 convert lead fix 2014-08-05 15:57:37 +03:00
Yuri Kuznetsov
380cdeba35 use cache false 2014-08-05 15:27:47 +03:00
Yuri Kuznetsov
1eabce0d2e change record detail #build 2014-08-05 15:27:34 +03:00
Yuri Kuznetsov
3cd5f801a5 use cache false 2014-08-05 14:42:01 +03:00
Yuri Kuznetsov
c1cfd75bd6 fix notice 2014-08-05 14:38:47 +03:00
Yuri Kuznetsov
dd5fabdfa4 contacts select in meetings 2014-08-05 11:44:10 +03:00
Yuri Kuznetsov
3e9c7056b0 improve mark all read 2014-08-05 10:54:19 +03:00
Yuri Kuznetsov
26188879b6 fix client acl 2014-08-05 10:49:29 +03:00
Yuri Kuznetsov
488717c6a1 dashlet changes 2014-08-04 17:05:24 +03:00
Yuri Kuznetsov
b8476d7335 fix import 2014-08-04 15:23:41 +03:00
Yuri Kuznetsov
1cfad615c0 not team restricion for admin 2014-08-04 13:35:35 +03:00
Yuri Kuznetsov
e3a3547a54 prevent error if field name is empty in layout 2014-08-04 12:36:51 +03:00
Yuri Kuznetsov
e6948aba2e mark all read 2014-08-04 12:19:09 +03:00
Yuri Kuznetsov
d4943e4d1c Merge branch 'stable' 2014-08-01 11:06:01 +03:00
Yuri Kuznetsov
af5e7d99b2 Merge branch 'release/2.2' into stable 2014-08-01 11:05:46 +03:00
Yuri Kuznetsov
667a46f141 text field search 2014-07-31 17:36:48 +03:00
Yuri Kuznetsov
67f65492de version 2014-07-31 12:21:58 +03:00
Yuri Kuznetsov
b6a98e7121 change show more count 2014-07-30 17:33:59 +03:00
Yuri Kuznetsov
9669ff91bb footer fix 2014-07-30 12:20:16 +03:00
Yuri Kuznetsov
acb6e245a2 show total 2014-07-30 11:43:14 +03:00
Yuri Kuznetsov
b5e015e9c9 vi_VN to config 2014-07-30 10:49:36 +03:00
Yuri Kuznetsov
70d2e311e5 vi_VN lang 2014-07-30 10:46:36 +03:00
Yuri Kuznetsov
6c7e5c0d02 update ro lang 2014-07-30 10:45:12 +03:00
Yuri Kuznetsov
d4558d73b3 lang 2014-07-30 10:35:59 +03:00
Yuri Kuznetsov
e2257f6cfd footer 2014-07-29 18:06:08 +03:00
Yuri Kuznetsov
149fa41e2b textFilter 2014-07-29 17:19:00 +03:00
Yuri Kuznetsov
71e4c2fca0 Merge branch 'hotfix/2.1.1' 2014-07-29 16:37:15 +03:00
Yuri Kuznetsov
5a4613617c fix diff 2014-07-29 16:07:25 +03:00
Yuri Kuznetsov
cbf9dd458e diff change 2014-07-29 13:06:15 +03:00
Yuri Kuznetsov
08553bdf9d diff changes 2014-07-28 15:37:46 +03:00
Yuri Kuznetsov
d0b61b42e0 fix diff 2014-07-28 12:54:33 +03:00
Yuri Kuznetsov
3e3348c4a7 version 2014-07-28 12:51:17 +03:00
Yuri Kuznetsov
c32b0f365b diff.js 2014-07-28 12:50:25 +03:00
Yuri Kuznetsov
8fd0554714 fix null filter issue 2014-07-28 11:17:21 +03:00
Yuri Kuznetsov
982f0e1f62 change filter defs 2014-07-28 10:54:01 +03:00
Yuri Kuznetsov
c87f5dfab3 bool filter change 2014-07-28 10:34:39 +03:00
Yuri Kuznetsov
b335462aa4 Merge branch 'release/2.1' into stable 2014-07-25 15:21:50 +03:00
Yuri Kuznetsov
97c951484d fix add dashlet 2014-07-25 15:18:37 +03:00
Yuri Kuznetsov
2215f15aaf lang 2014-07-25 12:58:26 +03:00
Yuri Kuznetsov
65f38a4906 Merge branch 'release/2.1' into stable 2014-07-25 12:27:30 +03:00
Yuri Kuznetsov
6429823cc3 version 2014-07-25 11:28:50 +03:00
Yuri Kuznetsov
2a71bb2ea1 duplicate 2014-07-25 11:24:20 +03:00
Yuri Kuznetsov
1674c2221e disableExport 2014-07-24 18:48:03 +03:00
Yuri Kuznetsov
e3b448f520 style preset 2014-07-24 17:48:49 +03:00
Yuri Kuznetsov
a04c973817 css 2014-07-24 16:21:17 +03:00
Yuri Kuznetsov
01c9939215 fix css 2014-07-24 16:08:32 +03:00
Yuri Kuznetsov
2d57824cb0 fix css 2014-07-24 15:33:23 +03:00
Yuri Kuznetsov
878385f14b fix import UI 2014-07-24 15:27:27 +03:00
Yuri Kuznetsov
8b82058d06 fix import 2014-07-24 15:20:17 +03:00
Yuri Kuznetsov
68e05f0935 datetime edit more nice 2014-07-24 15:00:49 +03:00
Yuri Kuznetsov
cb7492c042 email to case: dont copy email body 2014-07-24 14:41:05 +03:00
Yuri Kuznetsov
beb811755f improve bool filters ui 2014-07-24 11:21:21 +03:00
Yuri Kuznetsov
7c7fc4ee0f impreove preset search 2014-07-24 11:01:47 +03:00
Yuri Kuznetsov
aeef25f7ec fix preset ok 2014-07-23 17:19:35 +03:00
Yuri Kuznetsov
6856ff97b1 fix previous commit 2014-07-23 17:11:09 +03:00
Yuri Kuznetsov
10f6f7600c create notifications via cron 2014-07-23 17:04:03 +03:00
Yuri Kuznetsov
a0b678a3d9 remove some files from grunt uglify 2014-07-23 16:17:30 +03:00
Yuri Kuznetsov
f78e558a33 fix search 2014-07-23 15:56:06 +03:00
Yuri Kuznetsov
e205ef3370 improve fields tpls 2014-07-23 15:38:38 +03:00
Yuri Kuznetsov
8b6e4d469e onlyMy for meetings and calls 2014-07-23 12:49:10 +03:00
Yuri Kuznetsov
a63ec2710b fix filter 2014-07-23 12:20:16 +03:00
Yuri Kuznetsov
6895fac58c date filters 2014-07-23 11:57:48 +03:00
Yuri Kuznetsov
ea3c8f2d35 fix preset 2014-07-23 09:56:42 +03:00
Yuri Kuznetsov
0f2c050537 lang 2014-07-22 18:22:38 +03:00
Yuri Kuznetsov
2cd8866c73 Merge branch 'stable' 2014-07-22 18:07:44 +03:00
Yuri Kuznetsov
86a5e19b55 version 2014-07-22 17:46:38 +03:00
Yuri Kuznetsov
61f435812d fix timezones 2014-07-22 17:42:55 +03:00
Yuri Kuznetsov
217d0f6540 preset filters 4 2014-07-22 17:37:21 +03:00
Yuri Kuznetsov
f0e7a8f029 preset filters 2 2014-07-22 16:25:56 +03:00
Yuri Kuznetsov
d2954483d9 preset filters 2014-07-21 16:45:18 +03:00
Yuri Kuznetsov
999b88cba1 Merge branch 'stable' 2014-07-18 17:04:59 +03:00
Yuri Kuznetsov
717df30063 Merge branch 'release/2.0' into stable 2014-07-18 17:04:35 +03:00
Yuri Kuznetsov
d889c78f0c fix query 2014-07-18 10:31:01 +03:00
Yuri Kuznetsov
4737c506f2 do not pass phone to new contact 2014-07-17 15:50:45 +03:00
Yuri Kuznetsov
78cb1a8052 label css 2014-07-15 14:46:38 +03:00
Yuri Kuznetsov
dac8ca5a6d search by email and phone fix 2014-07-15 12:55:22 +03:00
Yuri Kuznetsov
e04ac6778a fix email phone fields 2014-07-15 12:34:12 +03:00
Yuri Kuznetsov
5f34d4f2fd change duplication where clause 2014-07-15 12:24:30 +03:00
Yuri Kuznetsov
ca7c0f07e9 fix fields 2014-07-15 12:20:26 +03:00
Yuri Kuznetsov
af26f29bec status 2014-07-15 11:11:09 +03:00
Taras Machyshyn
0c44f78ea1 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-07-15 11:01:00 +03:00
Taras Machyshyn
bed62e2e71 orm convertation chnages 2014-07-15 11:00:38 +03:00
Yuri Kuznetsov
6d61db86df fix url field 2014-07-14 14:59:40 +03:00
Yuri Kuznetsov
4feb055256 fr_FR lang 2014-07-14 11:29:31 +03:00
Yuri Kuznetsov
10a44239ed fix tpls 2014-07-14 11:18:17 +03:00
Yuri Kuznetsov
8a78eda520 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-07-11 14:36:48 +03:00
Yuri Kuznetsov
891b159b30 view parameter for fields 2014-07-11 14:36:34 +03:00
Taras Machyshyn
0d06770e80 LDAP changes 2014-07-11 13:57:03 +03:00
Yuri Kuznetsov
f8675bd45c languages 2014-07-11 12:24:10 +03:00
Yuri Kuznetsov
c35136b524 pt_BR lang 2014-07-11 12:21:31 +03:00
Yuri Kuznetsov
a0384deb00 ro_RO lang 2014-07-11 12:19:37 +03:00
Yuri Kuznetsov
e35fb15a31 de_DE lang 2014-07-11 12:13:43 +03:00
Yuri Kuznetsov
fe86807091 fix email template 2014-07-10 18:08:14 +03:00
Yuri Kuznetsov
e12a15ecdb fix notice 2014-07-10 17:53:40 +03:00
Yuri Kuznetsov
24dcd46d6f change currency field look 2014-07-10 17:22:51 +03:00
Yuri Kuznetsov
15196f2062 fix linkMultiple fields 2014-07-10 17:00:09 +03:00
Yuri Kuznetsov
1ae1b20111 phone and email fields change 2014-07-10 16:35:31 +03:00
Yuri Kuznetsov
84de477be0 ldap password 2014-07-10 14:49:42 +03:00
Yuri Kuznetsov
97407de17d remove SAML 2014-07-10 13:22:49 +03:00
Yuri Kuznetsov
84bc5beed2 preferences dynamic form 2014-07-10 13:20:22 +03:00
Yuri Kuznetsov
6974b1637d ldap form 2014-07-10 13:08:16 +03:00
Yuri Kuznetsov
dc89aff7b1 dynamic forms 2014-07-10 13:08:10 +03:00
Yuri Kuznetsov
2bfea69fe3 calendar remove event 2014-07-09 14:52:30 +03:00
Yuri Kuznetsov
0e1e481546 calendar timezone 2014-07-09 14:42:16 +03:00
Yuri Kuznetsov
52e938888d Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-07-09 14:30:08 +03:00
Yuri Kuznetsov
a2ef1656fb fix email template 2014-07-09 14:27:52 +03:00
Yuri Kuznetsov
c168c3ff9b fix field-manager 2014-07-09 14:27:45 +03:00
Yuri Kuznetsov
56af0baea2 entityFactory changhe 2014-07-09 14:15:27 +03:00
Taras Machyshyn
35ecf2e144 update tests 2014-07-09 13:33:42 +03:00
Taras Machyshyn
d25692b15e added manifest.json checking for upgrade process 2014-07-09 12:13:34 +03:00
Taras Machyshyn
59a66cb8fa LDAP authorization 2014-07-09 11:53:30 +03:00
Yuri Kuznetsov
75ce454b2a tr_TR language 2014-07-09 11:39:03 +03:00
Yuri Kuznetsov
b94134a35a data-panel-name 2014-07-08 16:59:41 +03:00
Yuri Kuznetsov
4b09f055e4 snap duration 2014-07-08 15:40:04 +03:00
Yuri Kuznetsov
d743eca6a3 calendar 2014-07-08 15:33:07 +03:00
Yuri Kuznetsov
0e3c872310 calendar 2 2014-07-08 15:30:17 +03:00
Yuri Kuznetsov
f8b56cba24 get rid of form on edit view 2014-07-08 11:45:15 +03:00
Yuri Kuznetsov
b506cd726c fix modal close 2014-07-08 11:31:47 +03:00
Yuri Kuznetsov
998aaec170 upgrade bootstrap to 3.2 2014-07-08 11:20:53 +03:00
Yuri Kuznetsov
4c30507a85 link role css 2014-07-08 11:05:57 +03:00
Yuri Kuznetsov
a55f1aca58 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-07-07 17:49:57 +03:00
Yuri Kuznetsov
868cf4e22c fix inline edit 2014-07-07 17:47:45 +03:00
Taras Machyshyn
2decd9016e fixed rebuild.php issue 2014-07-07 17:45:31 +03:00
Yuri Kuznetsov
9cba465473 fix prev commit 2014-07-07 17:24:12 +03:00
Yuri Kuznetsov
b9344afb27 linkMultipleWithRole css fix 2014-07-07 17:11:06 +03:00
Yuri Kuznetsov
7074991771 email and phone fields remove button 2014-07-07 16:30:36 +03:00
Yuri Kuznetsov
b43d37ac79 change layout 2014-07-07 16:21:11 +03:00
Yuri Kuznetsov
18b393b286 activities new logic 2014-07-07 16:17:44 +03:00
Yuri Kuznetsov
728fce75d7 fix linkMultiple css 2014-07-07 14:09:52 +03:00
Yuri Kuznetsov
50d441aea0 account - contact - 5 2014-07-07 11:32:01 +03:00
Yuri Kuznetsov
d75f9e5acd fix handleSelectParams 2014-07-04 18:26:52 +03:00
Yuri Kuznetsov
3c96cf240e account - contact 4 2014-07-04 18:13:54 +03:00
Yuri Kuznetsov
2583c77108 accoun - contact 3 2014-07-04 17:37:01 +03:00
Yuri Kuznetsov
a3ad210ec2 account - contact 2 2014-07-04 14:55:02 +03:00
Yuri Kuznetsov
6bd7d2398d account - contact 1 2014-07-03 19:12:34 +03:00
Yuri Kuznetsov
017cd3d978 fix rerender fields 2014-07-03 19:12:22 +03:00
Yuri Kuznetsov
a3af86d248 fix primary button 2014-07-03 11:19:16 +03:00
Yuri Kuznetsov
99e9cbde84 email and phone fields: hide primary button 2014-07-03 10:44:47 +03:00
Yuri Kuznetsov
85d60d2555 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-07-02 17:31:31 +03:00
Yuri Kuznetsov
1fe4555209 phone number 3 2014-07-02 17:19:14 +03:00
Yuri Kuznetsov
8b80df2f91 phone number 2 2014-07-02 16:33:02 +03:00
Yuri Kuznetsov
3d7d4eb7db clone deep in model 2014-07-02 15:53:31 +03:00
Taras Machyshyn
4215621eb7 FieldManager fixes 2014-07-02 13:01:16 +03:00
Yuri Kuznetsov
d138a5d0b7 phone number 1 2014-07-02 12:24:42 +03:00
Yuri Kuznetsov
b3023192d0 fix search field view and lead source 2014-07-01 18:18:16 +03:00
Yuri Kuznetsov
7cc0c527e0 merge manual with stable 2014-07-01 18:09:52 +03:00
Yuri Kuznetsov
f3f36e87a4 Merge branch 'hotfix/1.2.1' into stable 2014-07-01 18:06:29 +03:00
Yuri Kuznetsov
b55b133ddf lead source 2 2014-07-01 18:05:38 +03:00
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
Yuri Kuznetsov
a60378a9bd lead source 1 2014-07-01 17:42:25 +03:00
Taras Machyshyn
30b246f67c fixed issue with Basic Authorization for cgi/fastcgi 2014-07-01 17:41:26 +03:00
Yuri Kuznetsov
3a23b28657 convert layout 2014-07-01 16:29:34 +03:00
Yuri Kuznetsov
42e21d585f bug with follow button and lead convert 2014-07-01 16:18:27 +03:00
Yuri Kuznetsov
a30ab9a1a0 fix notification in admin panel 2014-07-01 15:33:40 +03:00
Yuri Kuznetsov
4510295792 change opp layout 2014-07-01 15:09:22 +03:00
Yuri Kuznetsov
ed5de64cd3 roles dev 2014-07-01 15:04:59 +03:00
Yuri Kuznetsov
1c89187c49 update Role 2014-07-01 12:55:43 +03:00
Yuri Kuznetsov
169a3f6e6d -20px for panel 2014-07-01 11:36:27 +03:00
Yuri Kuznetsov
7e2ead7949 clonedeep role 2014-07-01 11:24:58 +03:00
Yuri Kuznetsov
8413067194 role field dev 2014-07-01 10:45:42 +03:00
Yuri Kuznetsov
81c7dcaa63 roles dev 2014-06-30 18:10:13 +03:00
Yuri Kuznetsov
3b12c7f1cf role field dev 2014-06-30 17:17:06 +03:00
Yuri Kuznetsov
cdab200898 fix linkMultiple 2014-06-30 16:46:21 +03:00
Yuri Kuznetsov
0f9c3e1c1c getSelectFilters 2014-06-30 16:42:47 +03:00
Yuri Kuznetsov
fe5a5b76ca fix linkMultiple fields 2014-06-30 16:23:03 +03:00
Yuri Kuznetsov
0e3720c038 columns for linkMultiple 2014-06-30 16:01:57 +03:00
Yuri Kuznetsov
99f1ba8987 fix layout manager 2014-06-30 12:06:49 +03:00
Yuri Kuznetsov
8ff5d79788 fix array fiel tpl 2014-06-30 11:52:28 +03:00
Yuri Kuznetsov
9d6485194f table header font weight 2014-06-30 11:28:11 +03:00
Yuri Kuznetsov
21e306774e link multiple li padding 2014-06-30 11:25:45 +03:00
Yuri Kuznetsov
ffa340f255 contacts field in opportunity 2014-06-30 11:21:31 +03:00
Yuri Kuznetsov
d6b65edfb1 fix select related 2014-06-30 11:12:08 +03:00
Yuri Kuznetsov
a3ed33a443 filters for select related 2014-06-30 11:09:21 +03:00
Yuri Kuznetsov
38ff477cef stick stream panel 2014-06-27 18:21:40 +03:00
Yuri Kuznetsov
c5c638b007 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-06-27 18:06:12 +03:00
Yuri Kuznetsov
181fd8dc73 record panel margin 2014-06-27 17:59:46 +03:00
Taras Machyshyn
e57f58bec3 fixed label string for .po file 2014-06-27 16:47:10 +03:00
Taras Machyshyn
5c2067f61a chnaged 'php version' label 2014-06-27 16:36:55 +03:00
Yuri Kuznetsov
3ec5cf259b refactor auth 2014-06-27 12:15:54 +03:00
Yuri Kuznetsov
e5e898222b Authentification refactor 2014-06-27 12:01:30 +03:00
Yuri Kuznetsov
18b2876853 ability to remove entity in calendar 2014-06-26 17:51:50 +03:00
Yuri Kuznetsov
cec4ffcb6c Merge branch 'hotfix/1.2.1' 2014-06-26 17:13:14 +03:00
Yuri Kuznetsov
1063aa74dd fix create related 2014-06-26 17:12:54 +03:00
Yuri Kuznetsov
b59dba0e6d fix lang 2014-06-26 16:47:36 +03:00
Yuri Kuznetsov
0d9a182833 change version 2014-06-26 16:45:50 +03:00
Yuri Kuznetsov
8674f66b4d Merge branch 'hotfix/1.2.1' 2014-06-26 16:44:35 +03:00
Yuri Kuznetsov
605a720694 auth tokens page title 2014-06-26 16:44:21 +03:00
Yuri Kuznetsov
aa761d5ef7 auth tokens in admin 2014-06-26 16:32:18 +03:00
Yuri Kuznetsov
3d4d8aa7d3 prepareEntityForOutput 2014-06-26 15:19:43 +03:00
Yuri Kuznetsov
556b72edb2 fix install lang 2014-06-24 18:31:10 +03:00
Yuri Kuznetsov
be372b90f9 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2014-06-24 18:19:41 +03:00
Yuri Kuznetsov
846e93741f disable targets 2014-06-24 18:15:40 +03:00
Yuri Kuznetsov
b82af3a0c6 prospects to targets 2014-06-24 18:13:35 +03:00
Taras Machyshyn
02b429cb32 installer: design changes 2014-06-24 11:43:37 +03:00
Taras Machyshyn
3332469c35 chnaged Config.php . Now use ->save() to save the configuration 2014-06-19 12:42:57 +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
371f243a6d Merge branch 'stable' 2014-06-13 12:35:28 +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
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
948 changed files with 38629 additions and 10460 deletions

1
.gitignore vendored
View File

@@ -15,3 +15,4 @@
/client
/test.php
/main.html
/tests/testData/Utils/Config/config.php

View File

@@ -1,8 +1,27 @@
<ifModule mod_headers.c>
Header always set Access-Control-Allow-Methods "POST, GET, PUT, PATCH, DELETE"
</ifModule>
DirectoryIndex index.php index.html
RedirectMatch 403 \.config$
# PROTECTED DIRECTORIES
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule (?i)(data|api) - [F]
</IfModule>
RedirectMatch 403 (?i)/data/config\.php$
RedirectMatch 403 (?i)/data/logs
RedirectMatch 403 (?i)/data/cache
RedirectMatch 403 (?i)/data/upload
RedirectMatch 403 (?i)/application
RedirectMatch 403 (?i)/custom
RedirectMatch 403 (?i)/vendor
#END PROTECTED DIRECTORIES
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule reset/?$ reset.html [QSA,L]
RewriteEngine On
RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}]
RewriteRule reset/?$ reset.html [QSA,L]
</IfModule>

View File

@@ -1,4 +1,50 @@
module.exports = function (grunt) {
var jsFilesToMinify = [
'client/lib/jquery-2.0.2.min.js',
'client/lib/underscore-min.js',
'client/lib/backbone-min.js',
'client/lib/handlebars.js',
'client/lib/base64.js',
'client/lib/jquery-ui.min.js',
'client/lib/moment.min.js',
'client/lib/moment-timezone-with-data.min.js',
'client/lib/jquery.timepicker.min.js',
'client/lib/jquery.autocomplete.js',
'client/lib/bootstrap.min.js',
'client/lib/bootstrap-datepicker.js',
'client/lib/bull.min.js',
'client/src/namespace.js',
'client/src/exceptions.js',
'client/src/app.js',
'client/src/utils.js',
'client/src/storage.js',
'client/src/loader.js',
'client/src/pre-loader.js',
'client/src/ui.js',
'client/src/acl.js',
'client/src/model.js',
'client/src/model-offline.js',
'client/src/metadata.js',
'client/src/language.js',
'client/src/cache.js',
'client/src/controller.js',
'client/src/router.js',
'client/src/date-time.js',
'client/src/field-manager.js',
'client/src/search-manager.js',
'client/src/collection.js',
'client/src/multi-collection.js',
'client/src/view-helper.js',
'client/src/layout-manager.js',
'client/src/model-factory.js',
'client/src/collection-factory.js',
'client/src/models/settings.js',
'client/src/models/user.js',
'client/src/models/preferences.js',
'client/src/controllers/base.js',
'client/src/view.js',
];
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
@@ -44,57 +90,9 @@ module.exports = function (grunt) {
mangle: false,
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
},
'build/tmp/client/espo.min.js': [
'frontend/client/lib/jquery-2.0.2.min.js',
'frontend/client/lib/underscore-min.js',
'frontend/client/lib/backbone-min.js',
'frontend/client/lib/handlebars.js',
'frontend/client/lib/base64.js',
'frontend/client/lib/jquery-ui.min.js',
'frontend/client/lib/moment.min.js',
'frontend/client/lib/moment-timezone.min.js',
'frontend/client/lib/moment-timezone-data.js',
'frontend/client/lib/jquery.timepicker.min.js',
'frontend/client/lib/jquery.autocomplete.js',
'frontend/client/lib/bootstrap.min.js',
'frontend/client/lib/bootstrap-datepicker.js',
'frontend/client/lib/bull.min.js',
'frontend/client/src/namespace.js',
'frontend/client/src/exceptions.js',
'frontend/client/src/app.js',
'frontend/client/src/utils.js',
'frontend/client/src/storage.js',
'frontend/client/src/loader.js',
'frontend/client/src/pre-loader.js',
'frontend/client/src/ui.js',
'frontend/client/src/acl.js',
'frontend/client/src/model.js',
'frontend/client/src/model-offline.js',
'frontend/client/src/metadata.js',
'frontend/client/src/language.js',
'frontend/client/src/cache.js',
'frontend/client/src/controller.js',
'frontend/client/src/router.js',
'frontend/client/src/date-time.js',
'frontend/client/src/field-manager.js',
'frontend/client/src/search-manager.js',
'frontend/client/src/collection.js',
'frontend/client/src/multi-collection.js',
'frontend/client/src/view-helper.js',
'frontend/client/src/layout-manager.js',
'frontend/client/src/model-factory.js',
'frontend/client/src/collection-factory.js',
'frontend/client/src/models/settings.js',
'frontend/client/src/models/user.js',
'frontend/client/src/models/preferences.js',
'frontend/client/src/controllers/base.js',
'frontend/client/src/controllers/record.js',
'frontend/client/src/controllers/role.js',
'frontend/client/src/controllers/admin.js',
'frontend/client/src/view.js',
'frontend/client/src/views/base.js',
'frontend/client/src/views/login.js',
]
'build/tmp/client/espo.min.js': jsFilesToMinify.map(function (item) {
return 'frontend/' + item;
})
},
copy: {
frontendFolders: {
@@ -134,10 +132,11 @@ module.exports = function (grunt) {
'vendor/**',
'bootstrap.php',
'cron.php',
'rebuild.php',
'index.php',
'LICENSE.txt',
'.htaccess',
'Web.config',
'web.config',
],
dest: 'build/tmp/',
},
@@ -146,9 +145,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 +191,7 @@ module.exports = function (grunt) {
patterns: [
{
match: 'version',
replacement: '<%= pkg.espoVersion %>'
replacement: '<%= pkg.version %>'
}
]
},
@@ -186,12 +206,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 +224,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 +238,8 @@ module.exports = function (grunt) {
'copy:backend',
'replace',
'copy:final',
'chmod',
'clean:final',
//'compress',
]);
};

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="rule 1X" stopProcessing="true">
<match url="reset/?$" />
<action type="Rewrite" url="reset.html" appendQueryString="true" />
</rule>
</rules>
</rewrite>
<defaultDocument>
<files>
<clear />
<add value="index.php" />
</files>
</defaultDocument>
</system.webServer>
</configuration>

View File

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

@@ -1,2 +0,0 @@
Order Deny,Allow
Deny from all

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

@@ -0,0 +1,66 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Controllers;
use \Espo\Core\Exceptions\Forbidden;
class AuthToken extends \Espo\Core\Controllers\Record
{
protected function checkControllerAccess()
{
if (!$this->getUser()->isAdmin()) {
throw new Forbidden();
}
}
public function actionUpdate($params, $data)
{
throw new Forbidden();
}
public function actionCreate($params, $data)
{
throw new Forbidden();
}
public function actionListLinked($params, $data)
{
throw new Forbidden();
}
public function actionMassUpdate($params, $data)
{
throw new Forbidden();
}
public function actionCreateLink($params, $data)
{
throw new Forbidden();
}
public function actionRemoveLink($params, $data)
{
throw new Forbidden();
}
}

View File

@@ -24,5 +24,11 @@ namespace Espo\Controllers;
class Email extends \Espo\Core\Controllers\Record
{
public function actionGetCopiedAttachments($params, $data, $request)
{
$id = $request->get('id');
return $this->getRecordService()->getCopiedAttachments($id);
}
}

View File

@@ -0,0 +1,40 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Controllers;
class EmailAccount 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

@@ -24,5 +24,14 @@ namespace Espo\Controllers;
class EmailAddress extends \Espo\Core\Controllers\Record
{
public function actionSearchInAddressBook($params, $data, $request)
{
$q = $request->get('q');
$limit = intval($request->get('limit'));
if (empty($limit) || $limit > 30) {
$limit = 5;
}
return $this->getRecordService()->searchInAddressBook($q, $limit);
}
}

View File

@@ -0,0 +1,104 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Controllers;
use \Espo\Core\Exceptions\Error;
use \Espo\Core\Exceptions\Forbidden;
class ExternalAccount extends \Espo\Core\Controllers\Record
{
public static $defaultAction = 'list';
public function actionList($params, $data, $request)
{
$integrations = $this->getEntityManager()->getRepository('Integration')->find();
$arr = array();
foreach ($integrations as $entity) {
if ($entity->get('enabled') && $this->getMetadata()->get('integrations.' . $entity->id .'.allowUserAccounts')) {
$arr[] = array(
'id' => $entity->id
);
}
}
return array(
'list' => $arr
);
}
public function actionGetOAuthCredentials($params, $data, $request)
{
$id = $request->get('id');
list($integration, $userId) = explode('__', $id);
if (!$this->getUser()->isAdmin()) {
if ($this->getUser()->id != $userId) {
throw new Forbidden();
}
}
$entity = $this->getEntityManager()->getEntity('Integration', $integration);
if ($entity) {
return array(
'clientId' => $entity->get('clientId'),
'redirectUri' => $this->getConfig()->get('siteUrl') . '/oauthcallback'
);
}
}
public function actionRead($params, $data, $request)
{
list($integration, $userId) = explode('__', $params['id']);
if (!$this->getUser()->isAdmin()) {
if ($this->getUser()->id != $userId) {
throw new Forbidden();
}
}
$entity = $this->getEntityManager()->getEntity('ExternalAccount', $params['id']);
return $entity->toArray();
}
public function actionUpdate($params, $data)
{
return $this->actionPatch($params, $data);
}
public function actionPatch($params, $data)
{
list($integration, $userId) = explode('__', $params['id']);
if (!$this->getUser()->isAdmin()) {
if ($this->getUser()->id != $userId) {
throw new Forbidden();
}
}
$entity = $this->getEntityManager()->getEntity('ExternalAccount', $params['id']);
$entity->set($data);
$this->getEntityManager()->saveEntity($entity);
return $entity->toArray();
}
}

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

@@ -34,7 +34,7 @@ class GlobalSearch extends \Espo\Core\Controllers\Base
$offset = $request->get('offset');
$maxSize = $request->get('maxSize');
return $this->getService('GlobalSearch')->find($query, $offset);
return $this->getService('GlobalSearch')->find($query, $offset, $maxSize);
}
}

View File

@@ -44,7 +44,8 @@ class Import extends \Espo\Core\Controllers\Base
$contents = $data;
$attachment = $this->getEntityManager()->getEntity('Attachment');
$attachment->set('type', 'text/csv');
$attachment->set('type', 'text/csv');
$attachment->set('role', 'Import File');
$this->getEntityManager()->saveEntity($attachment);
$this->getFileManager()->putContents('data/upload/' . $attachment->id, $contents);

View File

@@ -0,0 +1,61 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Controllers;
use \Espo\Core\Exceptions\Error;
class Integration extends \Espo\Core\Controllers\Record
{
protected function checkControllerAccess()
{
if (!$this->getUser()->isAdmin()) {
throw new Forbidden();
}
}
public function actionIndex($params, $data, $request)
{
return false;
}
public function actionRead($params, $data, $request)
{
$entity = $this->getEntityManager()->getEntity('Integration', $params['id']);
return $entity->toArray();
}
public function actionUpdate($params, $data)
{
return $this->actionPatch($params, $data);
}
public function actionPatch($params, $data)
{
$entity = $this->getEntityManager()->getEntity('Integration', $params['id']);
$entity->set($data);
$this->getEntityManager()->saveEntity($entity);
return $entity->toArray();
}
}

View File

@@ -25,6 +25,7 @@ namespace Espo\Controllers;
use Espo\Core\Utils as Utils;
use \Espo\Core\Exceptions\NotFound;
use \Espo\Core\Exceptions\Error;
use \Espo\Core\Exceptions\Forbidden;
class Layout extends \Espo\Core\Controllers\Base
{
@@ -39,6 +40,10 @@ class Layout extends \Espo\Core\Controllers\Base
public function actionUpdate($params, $data)
{
if (!$this->getUser()->isAdmin()) {
throw new Forbidden();
}
$result = $this->getContainer()->get('layout')->set($data, $params['scope'], $params['name']);
if ($result === false) {

View File

@@ -54,7 +54,13 @@ class Notification extends \Espo\Core\Controllers\Base
public function actionNotReadCount()
{
$userId = $this->getUser()->id;
return $this->getService('Notification')->getNotReadCount($userId);
return $this->getService('Notification')->getNotReadCount($userId);
}
public function actionMarkAllRead($params, $data, $request)
{
$userId = $this->getUser()->id;
return $this->getService('Notification')->markAllRead($userId);
}
}

View File

@@ -68,6 +68,8 @@ class Preferences extends \Espo\Core\Controllers\Base
$entity->set('smtpEmailAddress', $user->get('emailAddress'));
$entity->set('name', $user->get('name'));
$entity->clear('smtpPassword');
return $entity->toArray();
}
throw new Error();
@@ -83,6 +85,9 @@ class Preferences extends \Espo\Core\Controllers\Base
$entity->set('smtpEmailAddress', $user->get('emailAddress'));
$entity->set('name', $user->get('name'));
$entity->clear('smtpPassword');
if ($entity) {
return $entity->toArray();
}

View File

@@ -30,9 +30,9 @@ class Settings extends \Espo\Core\Controllers\Base
protected function getConfigData()
{
$data = $this->getConfig()->getData($this->getUser()->isAdmin());
$fieldDefs = $this->getMetadata()->get('entityDefs.Settings.fields');
foreach ($fieldDefs as $field => $d) {
if ($d['type'] == 'password') {
unset($data[$field]);
@@ -40,7 +40,7 @@ class Settings extends \Espo\Core\Controllers\Base
}
return $data;
}
public function actionRead($params, $data)
{
return $this->getConfigData();
@@ -52,16 +52,23 @@ class Settings extends \Espo\Core\Controllers\Base
}
public function actionPatch($params, $data)
{
{
if (!$this->getUser()->isAdmin()) {
throw new Forbidden();
}
$result = $this->getConfig()->setData($data, $this->getUser()->isAdmin());
$this->getConfig()->setData($data, $this->getUser()->isAdmin());
$result = $this->getConfig()->save();
if ($result === false) {
throw new Error('Cannot save settings');
}
/** Rebuild for Currency Settings */
if (isset($data['baseCurrency']) || isset($data['currencyRates'])) {
$this->getContainer()->get('dataManager')->rebuildDatabase(array());
}
/** END Rebuild for Currency Settings */
return $this->getConfigData();
}
}

View File

@@ -44,8 +44,14 @@ class User extends \Espo\Core\Controllers\Record
throw new NotFound();
}
$acl = new \Espo\Core\Acl($user);
$acl = new \Espo\Core\Acl($user, $this->getConfig(), $this->getContainer()->get('fileManager'), $this->getMetadata());
return $acl->toArray();
}
public function actionChangeOwnPassword($params, $data)
{
return $this->getService('User')->changePassword($this->getUser()->id, $data['password']);
}
}

View File

@@ -34,11 +34,15 @@ class Acl
private $levelList = array('all', 'team', 'own', 'no');
private $fileManager;
protected $fileManager;
protected $metadata;
public function __construct(\Espo\Entities\User $user, $config = null, $fileManager = null)
public function __construct(\Espo\Entities\User $user, $config = null, $fileManager = null, $metadata = null)
{
$this->user = $user;
$this->user = $user;
$this->metadata = $metadata;
if (!$this->user->isFetched()) {
throw new Error();
@@ -54,6 +58,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 +68,6 @@ class Acl
}
}
}
public function checkScope($scope, $action = null, $isOwner = null, $inTeam = null)
@@ -196,27 +201,11 @@ class Acl
private function initSolid()
{
$this->data['User'] = array(
'read' => 'all',
'edit' => 'no',
'delete' => 'no',
);
$this->data['Team'] = array(
'read' => 'all',
'edit' => 'no',
'delete' => 'no',
);
$this->data['Role'] = false;
$this->data['Note'] = array(
'read' => 'own',
'edit' => 'own',
'delete' => 'own',
);
$this->data['EmailAddress'] = array(
'read' => 'no',
'edit' => 'no',
'delete' => 'no',
);
$data = $this->metadata->get('app.acl.solid', array());
foreach ($data as $entityName => $item) {
$this->data[$entityName] = $item;
}
}
private function merge($tables)

View File

@@ -129,6 +129,12 @@ class Application
$cronManager->run();
}
public function runRebuild()
{
$dataManager = $this->getContainer()->get('dataManager');
$dataManager->rebuild();
}
public function isInstalled()
{
$config = $this->getContainer()->get('config');

View File

@@ -51,7 +51,6 @@ class Container
$obj = $this->$loadMethod();
$this->data[$name] = $obj;
} else {
//external loader class \Espo\Core\Loaders\<className> or \Espo\Custom\Core\Loaders\<className> with load() method
$className = '\Espo\Custom\Core\Loaders\\'.ucfirst($name);
if (!class_exists($className)) {
$className = '\Espo\Core\Loaders\\'.ucfirst($name);
@@ -63,22 +62,25 @@ class Container
}
}
// TODO throw an exception
return null;
}
protected function getServiceClassName($name, $default)
{
$metadata = $this->get('metadata');
$className = $metadata->get('app.serviceContainer.classNames.' . $name, $default);
return $className;
}
private function loadSlim()
{
//return new \Slim\Slim();
return new \Espo\Core\Utils\Api\Slim();
}
private function loadFileManager()
{
return new \Espo\Core\Utils\File\Manager(
array(
'defaultPermissions' => $this->get('config')->get('defaultPermissions'),
)
$this->get('config')
);
}
@@ -110,7 +112,8 @@ class Container
private function loadMailSender()
{
return new \Espo\Core\Mail\Sender(
$className = $this->getServiceClassName('mailSernder', '\\Espo\\Core\\Mail\\Sender');
return new $className(
$this->get('config')
);
}
@@ -159,10 +162,12 @@ class Container
private function loadAcl()
{
return new \Espo\Core\Acl(
$className = $this->getServiceClassName('acl', '\\Espo\\Core\\Acl');
return new $className(
$this->get('user'),
$this->get('config'),
$this->get('fileManager')
$this->get('fileManager'),
$this->get('metadata')
);
}

View File

@@ -78,7 +78,7 @@ class ControllerManager
throw new NotFound("Controller '$controllerName' is not found");
}
$controller = new $controllerClassName($this->container);
$controller = new $controllerClassName($this->container, $request->getMethod());
if ($actionName == 'index') {
$actionName = $controllerClassName::$defaultAction;

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\Controllers;
@@ -29,15 +29,21 @@ use \Espo\Core\Utils\Util;
abstract class Base
{
protected $name;
private $container;
private $requestMethod;
public static $defaultAction = 'index';
public function __construct(Container $container)
public function __construct(Container $container, $requestMethod = null)
{
$this->container = $container;
if (isset($requestMethod)) {
$this->setRequestMethod($requestMethod);
}
if (empty($this->name)) {
$name = get_class($this);
if (preg_match('@\\\\([\w]+)$@', $name, $matches)) {
@@ -45,40 +51,55 @@ abstract class Base
}
$this->name = $name;
}
$this->checkControllerAccess();
}
protected function checkControllerAccess()
{
return;
}
protected function getContainer()
{
return $this->container;
}
/**
* Get request method name (Uppercase)
*
* @return string
*/
protected function getRequestMethod()
{
return $this->requestMethod;
}
protected function setRequestMethod($requestMethod)
{
$this->requestMethod = strtoupper($requestMethod);
}
protected function getUser()
{
return $this->container->get('user');
}
protected function getAcl()
{
return $this->container->get('acl');
}
protected function getConfig()
{
return $this->container->get('config');
}
protected function getPreferences()
{
return $this->container->get('preferences');
}
protected function getMetadata()
{
return $this->container->get('metadata');
@@ -88,7 +109,7 @@ abstract class Base
{
return $this->container->get('serviceFactory');
}
protected function getService($name)
{
return $this->getServiceFactory()->create($name);

View File

@@ -38,13 +38,17 @@ class Record extends Base
return $this->getContainer()->get('entityManager');
}
protected function getRecordService()
protected function getRecordService($name = null)
{
if ($this->getServiceFactory()->checkExists($this->name)) {
$service = $this->getServiceFactory()->create($this->name);
if (empty($name)) {
$name = $this->name;
}
if ($this->getServiceFactory()->checkExists($name)) {
$service = $this->getServiceFactory()->create($name);
} else {
$service = $this->getServiceFactory()->create('Record');
$service->setEntityName($this->name);
$service->setEntityName($name);
}
return $service;
@@ -178,8 +182,10 @@ class Record extends Base
}
public function actionExport($params, $data, $request)
{
// TODO move to service
{
if ($this->getConfig()->get('disableExport') && !$this->getUser()->isAdmin()) {
throw new Forbidden();
}
if (!$this->getAcl()->check($this->name, 'read')) {
throw new Forbidden();

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\Cron;
@@ -46,22 +46,22 @@ class Service
$serviceName = $job['service_name'];
if (!$this->getServiceFactory()->checkExists($serviceName)) {
throw new NotFound();
throw new NotFound();
}
$service = $this->getServiceFactory()->create($serviceName);
$serviceMethod = $job['method'];
$service = $this->getServiceFactory()->create($serviceName);
$serviceMethod = $job['method'];
if (!method_exists($service, $serviceMethod)) {
throw new NotFound();
}
throw new NotFound();
}
$data = $job['data'];
if (Json::isJSON($data)) {
$data = Json::decode($data, true);
}
$service->$serviceMethod($data);
$service->$serviceMethod($data);
}
}

View File

@@ -34,6 +34,11 @@ class CronManager
private $jobService;
private $scheduledJobService;
const PENDING = 'Pending';
const RUNNING = 'Running';
const SUCCESS = 'Success';
const FAILED = 'Failed';
protected $lastRunTime = 'data/cache/application/cronLastRunTime.php';
@@ -128,13 +133,12 @@ class CronManager
//Check scheduled jobs and create related jobs
$this->createJobsFromScheduledJobs();
$pendingJobs = $this->getJobService()->getPendingJobs();
foreach ($pendingJobs as $job) {
$this->getJobService()->updateEntity($job['id'], array(
'status' => 'Running',
'status' => self::RUNNING,
));
$isSuccess = true;
@@ -150,7 +154,7 @@ class CronManager
$GLOBALS['log']->error('Failed job running, job ['.$job['id'].']. Error Details: '.$e->getMessage());
}
$status = $isSuccess ? 'Success' : 'Failed';
$status = $isSuccess ? self::SUCCESS : self::FAILED;
$this->getJobService()->updateEntity($job['id'], array(
'status' => $status,
@@ -180,7 +184,6 @@ class CronManager
$cronExpression = \Cron\CronExpression::factory($scheduling);
try {
//$nextDate = $cronExpression->getNextRunDate()->format('Y-m-d H:i:s');
$prevDate = $cronExpression->getPreviousRunDate()->format('Y-m-d H:i:s');
} catch (\Exception $e) {
$GLOBALS['log']->error('ScheduledJob ['.$scheduledJob['id'].']: CronExpression - Impossible CRON expression ['.$scheduling.']');
@@ -197,7 +200,7 @@ class CronManager
//create a job
$data = array(
'name' => $scheduledJob['name'],
'status' => 'Pending',
'status' => self::PENDING,
'scheduledJobId' => $scheduledJob['id'],
'executeTime' => $prevDate,
'method' => $scheduledJob['job'],

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);
@@ -121,8 +121,9 @@ class DataManager
*/
public function updateCacheTimestamp()
{
return $this->getContainer()->get('config')->updateCacheTimestamp();
$this->getContainer()->get('config')->updateCacheTimestamp();
$this->getContainer()->get('config')->save();
return true;
}
}
}

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

@@ -25,7 +25,7 @@ namespace Espo\Core\Loaders;
use Doctrine\ORM\Tools\Setup,
Espo\Core\Doctrine\ORM\Mapping\Driver\EspoPHPDriver;
class EntityManager
class EntityManager implements Loader
{
private $container;
@@ -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

@@ -0,0 +1,31 @@
<?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\Loaders;
interface Loader
{
public function load();
}

View File

@@ -25,7 +25,7 @@ namespace Espo\Core\Loaders;
use Espo\Core\Utils,
Espo\Core\Utils\Log\Monolog\Handler;
class Log
class Log implements Loader
{
private $container;

View File

@@ -0,0 +1,244 @@
<?php
namespace Espo\Core\Mail;
use \Zend\Mime\Mime as Mime;
class Importer
{
private $entityManager;
private $fileManager;
public function __construct($entityManager, $fileManager)
{
$this->entityManager = $entityManager;
$this->fileManager = $fileManager;
}
protected function getEntityManager()
{
return $this->entityManager;
}
protected function getFileManager()
{
return $this->fileManager;
}
public function importMessage($message, $userId, $teamsIds = array())
{
try {
$email = $this->getEntityManager()->getEntity('Email');
$email->set('isHtml', false);
$email->set('name', $message->subject);
$email->set('status', 'Archived');
$email->set('attachmentsIds', array());
$email->set('assignedUserId', $userId);
$email->set('teamsIds', $teamsIds);
$fromArr = $this->getAddressListFromMessage($message, 'from');
if (isset($message->from)) {
$email->set('fromName', $message->from);
}
$email->set('from', $fromArr[0]);
$email->set('to', implode(';', $this->getAddressListFromMessage($message, 'to')));
$email->set('cc', implode(';', $this->getAddressListFromMessage($message, 'cc')));
if (isset($message->messageId) && !empty($message->messageId)) {
$email->set('messageId', $message->messageId);
if (isset($message->deliveredTo)) {
$email->set('messageIdInternal', $message->messageId . '-' . $message->deliveredTo);
}
}
if ($this->checkIsDuplicate($email)) {
return false;
}
if (isset($message->date)) {
$dt = new \DateTime($message->date);
if ($dt) {
$dateSent = $dt->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
$email->set('dateSent', $dateSent);
}
}
if (isset($message->deliveryDate)) {
$dt = new \DateTime($message->deliveryDate);
if ($dt) {
$deliveryDate = $dt->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
$email->set('deliveryDate', $deliveryDate);
}
}
$inlineIds = array();
if ($message->isMultipart()) {
foreach (new \RecursiveIteratorIterator($message) as $part) {
$this->importPartDataToEmail($email, $part, $inlineIds);
}
} else {
$this->importPartDataToEmail($email, $message, $inlineIds);
}
$body = $email->get('body');
if (!empty($body)) {
foreach ($inlineIds as $cid => $attachmentId) {
$body = str_replace('cid:' . $cid, '?entryPoint=attachment&amp;id=' . $attachmentId, $body);
}
$email->set('body', $body);
}
$this->getEntityManager()->saveEntity($email);
return $email;
} catch (\Exception $e) {}
}
protected function checkIsDuplicate($email)
{
if ($email->get('messageIdInternal')) {
$duplicate = $this->getEntityManager()->getRepository('Email')->where(array(
'messageIdInternal' => $email->get('messageIdInternal')
))->findOne();
if ($duplicate) {
return true;
}
}
}
protected function getAddressListFromMessage($message, $type)
{
$addressList = array();
if (isset($message->$type)) {
$list = $message->getHeader($type)->getAddressList();
foreach ($list as $address) {
$addressList[] = $address->getEmail();
}
}
return $addressList;
}
protected function importPartDataToEmail(\Espo\Entities\Email $email, $part, &$inlineIds = array())
{
try {
$type = strtok($part->contentType, ';');
$encoding = null;
switch ($type) {
case 'text/plain':
$content = $this->getContentFromPart($part);
if (!$email->get('body')) {
$email->set('body', $content);
}
$email->set('bodyPlain', $content);
break;
case 'text/html':
$content = $this->getContentFromPart($part);
$email->set('body', $content);
$email->set('isHtml', true);
break;
default:
$content = $part->getContent();
$disposition = null;
$fileName = null;
$contentId = null;
if (isset($part->ContentDisposition)) {
if (strpos($part->ContentDisposition, 'attachment') === 0) {
if (preg_match('/filename="?([^"]+)"?/i', $part->ContentDisposition, $m)) {
$fileName = $m[1];
$disposition = 'attachment';
}
} else if (strpos($part->ContentDisposition, 'inline') === 0) {
$contentId = trim($part->contentID, '<>');
$fileName = $contentId;
$disposition = 'inline';
}
}
if (isset($part->contentTransferEncoding)) {
$encoding = strtolower($part->getHeader('Content-Transfer-Encoding')->getTransferEncoding());
}
$attachment = $this->getEntityManager()->getEntity('Attachment');
$attachment->set('name', $fileName);
$attachment->set('type', $type);
if ($disposition == 'inline') {
$attachment->set('role', 'Inline Attachment');
} else {
$attachment->set('role', 'Attachment');
}
if ($encoding == 'base64') {
$content = base64_decode($content);
}
$attachment->set('size', strlen($content));
$this->getEntityManager()->saveEntity($attachment);
$path = 'data/upload/' . $attachment->id;
$this->getFileManager()->putContents($path, $content);
if ($disposition == 'attachment') {
$attachmentsIds = $email->get('attachmentsIds');
$attachmentsIds[] = $attachment->id;
$email->set('attachmentsIds', $attachmentsIds);
} else if ($disposition == 'inline') {
$inlineIds[$contentId] = $attachment->id;
}
}
} catch (\Exception $e) {}
}
protected function getContentFromPart($part)
{
if ($part instanceof \Zend\Mime\Part) {
$content = $part->getRawContent();
if (strtolower($part->charset) != 'utf-8') {
$content = mb_convert_encoding($content, 'UTF-8', $part->charset);
}
} else {
$content = $part->getContent();
$encoding = null;
if (isset($part->contentTransferEncoding)) {
$cteHeader = $part->getHeader('Content-Transfer-Encoding');
$encoding = strtolower($cteHeader->getTransferEncoding());
}
if ($encoding == 'base64') {
$content = base64_decode($content);
}
$charset = 'UTF-8';
if (isset($part->contentType)) {
$ctHeader = $part->getHeader('Content-Type');
$charsetParamValue = $ctHeader->getParameter('charset');
if (!empty($charsetParamValue)) {
$charset = strtoupper($charsetParamValue);
}
}
if ($charset !== 'UTF-8') {
$content = mb_convert_encoding($content, 'UTF-8', $charset);
}
if (isset($part->contentTransferEncoding)) {
$cteHeader = $part->getHeader('Content-Transfer-Encoding');
if ($cteHeader->getTransferEncoding() == 'quoted-printable') {
$content = quoted_printable_decode($content);
}
}
}
return $content;
}
}

View File

@@ -124,23 +124,25 @@ class Sender
return $this;
}
public function send(Email $email)
public function send(Email $email, $params = array())
{
$message = new Message();
$config = $this->config;
$params = $this->params + $params;
if ($email->get('from')) {
$fromName = null;
if (!empty($this->params['fromName'])) {
$fromName = $this->params['fromName'];
if (!empty($params['fromName'])) {
$fromName = $params['fromName'];
} else {
$fromName = $config->get('outboundEmailFromName');
}
$message->addFrom(trim($email->get('from')), $fromName);
} else {
if (!empty($this->params['fromAddress'])) {
$fromAddress = $this->params['fromAddress'];
if (!empty($params['fromAddress'])) {
$fromAddress = $params['fromAddress'];
} else {
if (!$config->get('outboundEmailFromAddress')) {
throw new Error('outboundEmailFromAddress is not specified in config.');
@@ -148,14 +150,22 @@ class Sender
$fromAddress = $config->get('outboundEmailFromAddress');
}
if (!empty($this->params['fromName'])) {
$fromName = $this->params['fromName'];
if (!empty($params['fromName'])) {
$fromName = $params['fromName'];
} else {
$fromName = $config->get('outboundEmailFromName');
}
$message->addFrom($fromAddress, $fromName);
}
if (!empty($params['replyToAddress'])) {
$replyToName = null;
if (!empty($params['replyToName'])) {
$replyToName = $params['replyToName'];
}
$message->setReplyTo($params['replyToAddress'], $replyToName);
}
$value = $email->get('to');
if ($value) {
@@ -191,23 +201,21 @@ class Sender
$body = new MimeMessage;
$parts = array();
$bodyPart = new MimePart($email->getBodyPlainForSending());
$bodyPart->type = 'text/plain';
$bodyPart->charset = 'utf-8';
$parts[] = $bodyPart;
if ($email->get('isHtml')) {
$bodyPart = new MimePart($email->getBodyForSending());
$bodyPart->type = 'text/html';
$bodyPart->charset = 'utf-8';
} else {
if ($email->get('bodyPlain')) {
$bodyPart = new MimePart($email->get('bodyPlain'));
} else {
$bodyPart = new MimePart($email->get('body'));
}
$bodyPart->type = 'text/plain';
$bodyPart->charset = 'utf-8';
$parts[] = $bodyPart;
}
$parts[] = $bodyPart;
$aCollection = $email->get('attachments');
if (!empty($aCollection)) {
@@ -241,9 +249,19 @@ class Sender
$body->setParts($parts);
$message->setBody($body);
if ($email->get('isHtml')) {
$message->getHeaders()->get('content-type')->setType('multipart/alternative');
}
try {
$this->transport->send($message);
$headers = $message->getHeaders();
if ($headers->has('messageId')) {
$email->set('messageId', $headers->get('messageId')->getId());
}
$email->set('status', 'Sent');
$email->set('dateSent', date("Y-m-d H:i:s"));
} catch (\Exception $e) {

View File

@@ -0,0 +1,19 @@
<?php
namespace Espo\Core\Mail\Storage;
class Imap extends \Zend\Mail\Storage\Imap
{
public function getIdsFromUID($uid)
{
$uid = intval($uid) + 1;
return $this->protocol->search(array('UID ' . $uid . ':*'));
}
public function getIdsFromDate($date)
{
return $this->protocol->search(array('SINCE "' . $date . '"'));
}
}

View File

@@ -24,19 +24,39 @@ namespace Espo\Core\ORM;
class Entity extends \Espo\ORM\Entity
{
public function loadLinkMultipleField($field)
public function loadLinkMultipleField($field, $columns = null)
{
if ($this->hasRelation($field) && $this->hasField($field . 'Ids')) {
$collection = $this->get($field);
$defs = array();
if (!empty($columns)) {
$defs['additionalColumns'] = $columns;
}
$collection = $this->get($field, $defs);
$ids = array();
$names = new \stdClass();
$names = new \stdClass();
if (!empty($columns)) {
$columnsData = new \stdClass();
}
foreach ($collection as $e) {
$id = $e->id;
$ids[] = $id;
$names->$id = $e->get('name');
if (!empty($columns)) {
$columnsData->$id = new \stdClass();
foreach ($columns as $column => $f) {
$columnsData->$id->$column = $e->get($f);
}
}
}
$this->set($field . 'Ids', $ids);
$this->set($field . 'Names', $names);
if (!empty($columns)) {
$this->set($field . 'Columns', $columnsData);
}
}
}
}

View File

@@ -56,7 +56,12 @@ class EntityManager extends \Espo\ORM\EntityManager
public function getUser()
{
return $this->user;
}
}
public function getEspoMetadata()
{
return $this->espoMetadata;
}
public function setEspoMetadata($espoMetadata)
{

View File

@@ -59,16 +59,15 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
return $this->getInjection('metadata');
}
protected function handleSelectParams(&$params, $entityName = false)
public function handleSelectParams(&$params)
{
$this->handleEmailAddressParams($params, $entityName);
$this->handleEmailAddressParams($params);
$this->handlePhoneNumberParams($params);
}
protected function handleEmailAddressParams(&$params, $entityName = false)
protected function handleEmailAddressParams(&$params)
{
if (empty($entityName)) {
$entityName = $this->entityName;
}
$entityName = $this->entityName;
$defs = $this->getEntityManager()->getMetadata()->get($entityName);
if (!empty($defs['relations']) && array_key_exists('emailAddresses', $defs['relations'])) {
@@ -81,11 +80,31 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
if (empty($params['joinConditions'])) {
$params['joinConditions'] = array();
}
$params['leftJoins'] = array('emailAddresses');
$params['joinConditions'] = array(
'emailAddresses' => array(
'primary' => 1
)
$params['leftJoins'][] = 'emailAddresses';
$params['joinConditions']['emailAddresses'] = array(
'primary' => 1
);
}
}
protected function handlePhoneNumberParams(&$params)
{
$entityName = $this->entityName;
$defs = $this->getEntityManager()->getMetadata()->get($entityName);
if (!empty($defs['relations']) && array_key_exists('phoneNumbers', $defs['relations'])) {
if (empty($params['leftJoins'])) {
$params['leftJoins'] = array();
}
if (empty($params['whereClause'])) {
$params['whereClause'] = array();
}
if (empty($params['joinConditions'])) {
$params['joinConditions'] = array();
}
$params['leftJoins'][] = 'phoneNumbers';
$params['joinConditions']['phoneNumbers'] = array(
'primary' => 1
);
}
}
@@ -172,56 +191,23 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
$entity->set($restoreData);
$this->handleEmailAddressSave($entity);
$this->handlePhoneNumberSave($entity);
$this->handleSpecifiedRelations($entity);
return $result;
}
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);
}
}
protected function handlePhoneNumberSave(Entity $entity)
{
if ($entity->hasRelation('phoneNumbers') && $entity->hasField('phoneNumber')) {
$emailAddressRepository = $this->getEntityManager()->getRepository('PhoneNumber')->storeEntityPhoneNumber($entity);
}
}
@@ -236,22 +222,60 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
if (is_array($specifiedIds)) {
$toRemoveIds = array();
$existingIds = array();
foreach ($entity->get($name) as $foreignEntity) {
$toUpdateIds = array();
$existingColumnsData = new \stdClass();
$defs = array();
$columns = $this->getMetadata()->get("entityDefs." . $entity->getEntityName() . ".fields.{$name}.columns");
if (!empty($columns)) {
$columnData = $entity->get($name . 'Columns');
$defs['additionalColumns'] = $columns;
}
foreach ($entity->get($name, $defs) as $foreignEntity) {
$existingIds[] = $foreignEntity->id;
if (!empty($columns)) {
$data = new \stdClass();
foreach ($columns as $columnName => $columnField) {
$foreignId = $foreignEntity->id;
$data->$columnName = $foreignEntity->get($columnField);
}
$existingColumnsData->$foreignId = $data;
}
}
foreach ($existingIds as $id) {
if (!in_array($id, $specifiedIds)) {
$toRemoveIds[] = $id;
} else {
if (!empty($columns)) {
foreach ($columns as $columnName => $columnField) {
if ($columnData->$id->$columnName != $existingColumnsData->$id->$columnName) {
$toUpdateIds[] = $id;
}
}
}
}
}
foreach ($specifiedIds as $id) {
if (!in_array($id, $existingIds)) {
$this->relate($entity, $name, $id);
$data = null;
if (!empty($columns)) {
$data = $columnData->$id;
}
$this->relate($entity, $name, $id, $data);
}
}
foreach ($toRemoveIds as $id) {
$this->unrelate($entity, $name, $id);
}
if (!empty($columns)) {
foreach ($toUpdateIds as $id) {
$data = $columnData->$id;
$this->updateRelation($entity, $name, $id, $data);
}
}
}
}
}

View File

@@ -39,6 +39,8 @@ class Base
protected $entityName;
protected $metadata;
const MIN_LENGTH_FOR_CONTENT_SEARCH = 4;
public function __construct($entityManager, \Espo\Entities\User $user, Acl $acl, $metadata)
{
@@ -82,6 +84,11 @@ class Base
}
}
}
protected function getTextFilterFields()
{
return $this->metadata->get("entityDefs.{$this->entityName}.collection.textFilterFields", array('name'));
}
protected function where($params, &$result)
{
@@ -96,6 +103,27 @@ class Base
$params['where'][] = $p;
}
}
} else if ($item['type'] == 'textFilter' && !empty($item['value'])) {
if (!empty($item['value'])) {
if (empty($result['whereClause'])) {
$result['whereClause'] = array();
}
$fieldDefs = $this->entityManager->getEntity($this->entityName)->getFields();
$fieldList = $this->getTextFilterFields();
$d = array();
foreach ($fieldList as $field) {
if (
strlen($item['value']) >= self::MIN_LENGTH_FOR_CONTENT_SEARCH
&&
!empty($fieldDefs[$field]['type']) && $fieldDefs[$field]['type'] == 'text'
) {
$d[$field . '*'] = '%' . $item['value'] . '%';
} else {
$d[$field . '*'] = $item['value'] . '%';
}
}
$where['OR'] = $d;
}
}
}
@@ -108,7 +136,7 @@ class Base
$where[] = $part;
}
} else {
if ($item['type'] == 'linkedWith') {
if ($item['type'] == 'linkedWith' && !empty($item['value'])) {
$linkedWith[$item['field']] = $item['value'];
}
}
@@ -159,18 +187,23 @@ class Base
}
$result['whereClause']['assignedUserId'] = $this->user->id;
}
if ($this->acl->checkReadOnlyTeam($this->entityName)) {
if (!$this->user->isAdmin() && $this->acl->checkReadOnlyTeam($this->entityName)) {
if (!array_key_exists('whereClause', $result)) {
$result['whereClause'] = array();
}
$result['distinct'] = true;
if (!array_key_exists('joins', $result)) {
$result['joins'] = array();
}
if (!in_array('teams', $result['joins'])) {
$result['joins'][] = 'teams';
$result['leftJoins'][] = 'teams';
}
$result['whereClause']['Team.id'] = $this->user->get('teamsIds');
$result['whereClause']['OR'] = array(
'Team.id' => $this->user->get('teamsIds'),
'assignedUserId' => $this->user->id
);
//$result['whereClause']['Team.id'] = $this->user->get('teamsIds');
}
}
@@ -255,6 +288,15 @@ class Base
case 'isFalse':
$part[$item['field'] . '='] = false;
break;
case 'today':
$part[$item['field'] . '='] = date('Y-m-d');
break;
case 'past':
$part[$item['field'] . '<'] = date('Y-m-d');
break;
case 'future':
$part[$item['field'] . '>'] = date('Y-m-d');
break;
case 'between':
if (is_array($item['value'])) {
$part['AND'] = array(
@@ -269,7 +311,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

@@ -26,7 +26,11 @@ use \Espo\Core\Interfaces\Injectable;
abstract class Base implements Injectable
{
protected $dependencies = array();
protected $dependencies = array(
'config',
'entityManager',
'user',
);
protected $injections = array();
@@ -53,5 +57,20 @@ abstract class Base implements Injectable
{
return $this->dependencies;
}
protected function getEntityManager()
{
return $this->getInjection('entityManager');
}
protected function getConfig()
{
return $this->getInjection('config');
}
protected function getUser()
{
return $this->getInjection('user');
}
}

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);
@@ -316,7 +316,13 @@ abstract class Base
{
if (!isset($this->data['manifest'])) {
$upgradePath = $this->getUpgradePath();
$manifestJson = $this->getFileManager()->getContents(array($upgradePath, $this->manifestName));
$manifestPath = Util::concatPath($upgradePath, $this->manifestName);
if (!file_exists($manifestPath)) {
throw new Error('It\'s not an upgrade package.');
}
$manifestJson = $this->getFileManager()->getContents($manifestPath);
$this->data['manifest'] = Json::decode($manifestJson, true);
if (!$this->data['manifest']) {
@@ -375,10 +381,13 @@ abstract class Base
$manifest = $this->getManifest();
$res = $this->getConfig()->set('version', $manifest['version']);
if (method_exists($this->getConfig(), 'save')) {
$res = $this->getConfig()->save();
}
$res &= $this->getContainer()->get('dataManager')->rebuild();
return $res;
}
}
}

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

@@ -18,52 +18,94 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils;
use \Espo\Core\Exceptions\Error;
class Auth
class Auth
{
protected $container;
protected $authentication;
protected $config;
protected $entityManager;
public function __construct(\Espo\Core\Container $container)
{
$this->container = $container;
$this->entityManager = $this->container->get('entityManager');
$this->config = $this->container->get('config');
$authenticationMethod = $this->config->get('authenticationMethod', 'Espo');
$authenticationClassName = "\\Espo\\Core\\Utils\\Authentication\\" . $authenticationMethod;
$this->authentication = new $authenticationClassName($this->config, $this->entityManager, $this);
}
public function useNoAuth($isAdmin = false)
{
$entityManager = $this->container->get('entityManager');
$entityManager = $this->container->get('entityManager');
$user = $entityManager->getRepository('User')->get('system');
$user->set('isAdmin', $isAdmin);
if (!$user) {
throw new Error('System user is not found');
throw new Error('System user is not found');
}
$user->set('isAdmin', $isAdmin);
$entityManager->setUser($user);
$this->container->setUser($user);
}
public function login($username, $password)
{
$GLOBALS['log']->debug('AUTH: Try to authenticate');
$entityManager = $this->container->get('entityManager');
$user = $entityManager->getRepository('User')->findOne(array(
'whereClause' => array(
'userName' => $username,
'password' => md5($password)
),
));
if ($user instanceof \Espo\Entities\User) {
$entityManager = $this->entityManager;
$authToken = $entityManager->getRepository('AuthToken')->where(array('token' => $password))->findOne();
$user = $this->authentication->login($username, $password, $authToken);
if ($user) {
$entityManager->setUser($user);
$this->container->setUser($user);
$GLOBALS['log']->debug('AUTH: Result of authenticate is [true]');
if (!$authToken) {
$authToken = $entityManager->getEntity('AuthToken');
$token = $this->createToken($user);
$authToken->set('token', $token);
$authToken->set('hash', $user->get('password'));
$authToken->set('ipAddress', $_SERVER['REMOTE_ADDR']);
$authToken->set('userId', $user->id);
}
$authToken->set('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('id')));
}
public function destroyAuthToken($token)
{
$entityManager = $this->container->get('entityManager');
$authToken = $entityManager->getRepository('AuthToken')->where(array('token' => $token))->findOne();
if ($authToken) {
$entityManager->removeEntity($authToken);
return true;
}
}

View File

@@ -20,18 +20,41 @@
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
ob_start();
$result = array('success' => true, 'errorMsg' => '');
namespace Espo\Core\Utils\Authentication;
use \Espo\Core\Utils\Config;
use \Espo\Core\ORM\EntityManager;
use \Espo\Core\Utils\Auth;
abstract class Base
{
private $config;
private $entityManager;
private $auth;
public function __construct(Config $config, EntityManager $entityManager, Auth $auth)
{
$this->config = $config;
$this->entityManager = $entityManager;
$this->auth = $auth;
}
protected function getConfig()
{
return $this->config;
}
protected function getEntityManager()
{
return $this->entityManager;
}
protected function getAuth()
{
return $this->auth;
}
if (!$installer->isWritable()) {
$result['success'] = false;
$urls = $installer->getLastWritableError();
foreach ($urls as &$url) {
$url = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'.$url;
}
$result['errorMsg'] = $langs['messages']['Permission denied to files'].':<br>'.implode('<br>', $urls);
$result['errorFixInstruction'] = $systemHelper->getPermissionCommands('', array('644', '755'));
}
ob_clean();
echo json_encode($result);

View File

@@ -0,0 +1,48 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Core\Utils\Authentication;
use \Espo\Core\Exceptions\Error;
class Espo extends Base
{
public function login($username, $password, \Espo\Entities\AuthToken $authToken = null)
{
if ($authToken) {
$hash = $authToken->get('hash');
} else {
$hash = md5($password);
}
$user = $this->getEntityManager()->getRepository('User')->findOne(array(
'whereClause' => array(
'userName' => $username,
'password' => $hash
),
));
return $user;
}
}

View File

@@ -0,0 +1,201 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Core\Utils\Authentication;
use Espo\Core\Exceptions\Error,
Espo\Core\Utils\Config,
Espo\Core\ORM\EntityManager,
Espo\Core\Utils\Auth;
class LDAP extends Base
{
private $utils;
private $zendLdap;
/**
* Espo => LDAP name
*
* @var array
*/
private $fields = array(
'userName' => 'cn',
'firstName' => 'givenname',
'lastName' => 'sn',
'title' => 'title',
'emailAddress' => 'mail',
'phoneNumber' => 'telephonenumber',
);
public function __construct(Config $config, EntityManager $entityManager, Auth $auth)
{
parent::__construct($config, $entityManager, $auth);
$this->zendLdap = new LDAP\LDAP();
$this->utils = new LDAP\Utils($config);
}
protected function getZendLdap()
{
return $this->zendLdap;
}
protected function getUtils()
{
return $this->utils;
}
/**
* LDAP login
*
* @param string $username
* @param string $password
* @param \Espo\Entities\AuthToken $authToken
* @return \Espo\Entities\User | null
*/
public function login($username, $password, \Espo\Entities\AuthToken $authToken = null)
{
if ($authToken) {
return $this->loginByToken($username, $authToken);
}
$options = $this->getUtils()->getZendOptions();
$ldap = $this->getZendLdap();
$ldap = $ldap->setOptions($options);
try {
$ldap->bind($username, $password);
$dn = $ldap->getDn($username);
$loginFilter = $this->getUtils()->getOption('userLoginFilter');
$userData = $ldap->searchByLoginFilter($loginFilter, $dn, 3);
} catch (\Zend\Ldap\Exception\LdapException $zle) {
$admin = $this->adminLogin($username, $password);
if (!isset($admin)) {
$GLOBALS['log']->info('LDAP Authentication: ' . $zle->getMessage());
return null;
}
$GLOBALS['log']->info('LDAP Authentication: Administrator login by username ['.$username.']');
}
$user = $this->getEntityManager()->getRepository('User')->findOne(array(
'whereClause' => array(
'userName' => $username,
),
));
$isCreateUser = $this->getUtils()->getOption('createEspoUser');
if (!isset($user) && $isCreateUser) {
$this->getAuth()->useNoAuth(); /** Required to fix Acl "isFetched()" error */
$user = $this->createUser($userData);
}
return $user;
}
/**
* Login by authorization token
*
* @param string $username
* @param \Espo\Entities\AuthToken $authToken
* @return \Espo\Entities\User | null
*/
protected function loginByToken($username, \Espo\Entities\AuthToken $authToken = null)
{
if (!isset($authToken)) {
return null;
}
$userId = $authToken->get('userId');
$user = $this->getEntityManager()->getEntity('User', $userId);
$tokenUsername = $user->get('userName');
if ($username != $tokenUsername) {
$GLOBALS['log']->alert('Unauthorized access attempt for user ['.$username.'] from IP ['.$_SERVER['REMOTE_ADDR'].']');
return null;
}
$user = $this->getEntityManager()->getRepository('User')->findOne(array(
'whereClause' => array(
'userName' => $username,
),
));
return $user;
}
/**
* Login user with administrator rights
*
* @param string $username
* @param string $password
* @return \Espo\Entities\User | null
*/
protected function adminLogin($username, $password)
{
$hash = md5($password);
$user = $this->getEntityManager()->getRepository('User')->findOne(array(
'whereClause' => array(
'userName' => $username,
'password' => $hash,
'isAdmin' => 1
),
));
return $user;
}
/**
* Create Espo user with data gets from LDAP server
*
* @param array $userData LDAP entity data
* @return \Espo\Entities\User
*/
protected function createUser(array $userData)
{
$data = array();
foreach ($this->fields as $espo => $ldap) {
if (isset($userData[$ldap][0])) {
$data[$espo] = $userData[$ldap][0];
}
}
$user = $this->getEntityManager()->getEntity('User');
$user->set($data);
$this->getEntityManager()->saveEntity($user);
return $user;
}
}

View File

@@ -0,0 +1,123 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Core\Utils\Authentication\LDAP;
class LDAP extends \Zend\Ldap\Ldap
{
protected $usernameAttribute = 'cn';
/**
* Get DN depends on options, ex. "cn=test,ou=People,dc=maxcrc,dc=com"
*
* @return string DN format
*/
public function getDn($acctname)
{
return $this->getAccountDn($acctname, \Zend\Ldap\Ldap::ACCTNAME_FORM_DN);
}
/**
* Fix a bug, ex. CN=Alice Baker,CN=Users,DC=example,DC=com
*
* @param string $acctname
* @return string - Account DN
*/
protected function getAccountDn($acctname)
{
$baseDn = $this->getBaseDn();
if ($this->getBindRequiresDn() && isset($baseDn)) {
try {
return parent::getAccountDn($acctname);
} catch (\Zend\Ldap\Exception\LdapException $zle) {
if ($zle->getCode() != \Zend\Ldap\Exception\LdapException::LDAP_NO_SUCH_OBJECT) {
throw $zle;
}
}
$acctname = $this->usernameAttribute . '=' . \Zend\Ldap\Filter\AbstractFilter::escapeValue($acctname) . ',' . $baseDn;
}
return parent::getAccountDn($acctname);
}
/**
* Search a user using userLoginFilter
*
* @param string $filter
* @param string $basedn
* @param int $scope
* @param array $attributes
* @return array
*/
public function searchByLoginFilter($filter, $basedn = null, $scope = self::SEARCH_SCOPE_SUB, array $attributes = array())
{
$filter = $this->getLoginFilter($filter);
$result = $this->search($filter, $basedn, $scope, $attributes);
if ($result->count() > 0) {
return $result->getFirst();
}
throw new \Zend\Ldap\Exception\LdapException($this, 'searching: ' . $filter);
}
/**
* Get login filter in LDAP format
*
* @param string $filter
* @return string
*/
protected function getLoginFilter($filter)
{
$baseFilter = '(objectClass=*)';
if (!empty($filter)) {
$baseFilter = '(&' . $baseFilter . $this->convertToFilterFormat($filter). ')';
}
return $baseFilter;
}
/**
* Check and convert filter item in LDAP format
*
* @param string $filter [description]
* @return string
*/
protected function convertToFilterFormat($filter)
{
$filter = trim($filter);
if (substr($filter, 0, 1) != '(') {
$filter = '(' . $filter;
}
if (substr($filter, -1) != ')') {
$filter = $filter . ')';
}
return $filter;
}
}

View File

@@ -0,0 +1,155 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Core\Utils\Authentication\LDAP;
use \Espo\Core\Utils\Config;
class Utils
{
private $config;
protected $options = null;
/**
* Association between LDAP and Espo fields
* @var array
*/
protected $fieldMap = array(
'host' => 'ldapHost',
'port' => 'ldapPort',
'useSsl' => 'ldapSecurity',
'useStartTls' => 'ldapSecurity',
'username' => 'ldapUsername',
'password' => 'ldapPassword',
'bindRequiresDn' => 'ldapBindRequiresDn',
'baseDn' => 'ldapBaseDn',
'accountCanonicalForm' => 'ldapAccountCanonicalForm',
'accountDomainName' => 'ldapAccountDomainName',
'accountDomainNameShort' => 'ldapAccountDomainNameShort',
'accountFilterFormat' => 'ldapAccountFilterFormat',
'optReferrals' => 'ldapOptReferrals',
'tryUsernameSplit' => 'ldapTryUsernameSplit',
'networkTimeout' => 'ldapNetworkTimeout',
'createEspoUser' => 'ldapCreateEspoUser',
'userLoginFilter' => 'ldapUserLoginFilter',
);
/**
* Permitted Espo Options
*
* @var array
*/
protected $permittedEspoOptions = array(
'createEspoUser' => false,
'userLoginFilter' => null,
);
/**
* accountCanonicalForm Map between Espo and Zend value
*
* @var array
*/
protected $accountCanonicalFormMap = array(
'Dn' => 1,
'Username' => 2,
'Backslash' => 3,
'Principal' => 4,
);
public function __construct(Config $config)
{
$this->config = $config;
}
protected function getConfig()
{
return $this->config;
}
/**
* Get Options from espo config according to $this->fieldMap
*
* @return array
*/
public function getOptions()
{
if (isset($this->options)) {
return $this->options;
}
$options = array();
foreach ($this->fieldMap as $ldapName => $espoName) {
$option = $this->getConfig()->get($espoName);
if (isset($option)) {
$options[$ldapName] = $option;
}
}
/** peculiar fields */
$options['useSsl'] = (bool) ($options['useSsl'] == 'SSL');
$options['useStartTls'] = (bool) ($options['useStartTls'] == 'TLS');
$options['accountCanonicalForm'] = $this->accountCanonicalFormMap[ $options['accountCanonicalForm'] ];
$this->options = $options;
return $this->options;
}
/**
* Get an ldap option
*
* @param string $name
* @param mixed $returns Return value
* @return mixed
*/
public function getOption($name, $returns = null)
{
if (isset($this->options)) {
$this->getOptions();
}
if (isset($this->options[$name])) {
return $this->options[$name];
}
return $returns;
}
/**
* Get Zend options for using Zend\Ldap
*
* @return array
*/
public function getZendOptions()
{
$options = $this->getOptions();
$espoOptions = array_keys($this->permittedEspoOptions);
$zendOptions = array_diff_key($options, array_flip($espoOptions));
return $zendOptions;
}
}

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';
@@ -51,7 +53,10 @@ class Config
* @access private
* @var array
*/
private $configData;
private $data;
private $changedData = array();
private $removeData = array();
private $fileManager;
@@ -107,28 +112,50 @@ class Config
$name = array($name => $value);
}
return $this->setArray($name);
foreach ($name as $key => $value) {
if (is_object($value)) {
$value = (array) $value;
}
$this->data[$key] = $value;
$this->changedData[$key] = $value;
}
}
/**
* Set options from array
* Remove an option in config
*
* @param array $values
* @return bool
* @param string $name
* @return bool | null - null if an option doesn't exist
*/
protected function setArray($values)
public function remove($name)
{
if (!is_array($values)) {
return false;
if (array_key_exists($name, $this->data)) {
unset($this->data[$name]);
$this->removeData[] = $name;
return true;
}
return null;
}
public function save()
{
$values = $this->changedData;
if (!isset($values[$this->cacheTimestamp])) {
$values = array_merge($this->updateCacheTimestamp(true), $values);
}
$result = $this->getFileManager()->mergeContentsPHP($this->configPath, $values, true);
$this->loadConfig(true);
$removeData = empty($this->removeData) ? null : $this->removeData;
$result = $this->getFileManager()->mergeContentsPHP($this->configPath, $values, 1, $removeData);
if ($result) {
$this->changedData = array();
$this->removeData = array();
$this->loadConfig(true);
}
return $result;
}
@@ -145,15 +172,18 @@ class Config
*/
protected function loadConfig($reload = false)
{
if (!$reload && isset($this->configData) && !empty($this->configData)) {
return $this->configData;
if (!$reload && isset($this->data) && !empty($this->data)) {
return $this->data;
}
$configPath = file_exists($this->configPath) ? $this->configPath : $this->defaultConfigPath;
$this->configData = $this->getFileManager()->getContents($configPath);
$this->data = $this->getFileManager()->getContents($configPath);
return $this->configData;
$systemConfig = $this->getFileManager()->getContents($this->systemConfigPath);
$this->data = Util::merge($systemConfig, $this->data);
return $this->data;
}
@@ -165,9 +195,9 @@ class Config
*/
public function getData($isAdmin = false)
{
$configData = $this->loadConfig();
$data = $this->loadConfig();
$restrictedConfig = $configData;
$restrictedConfig = $data;
foreach($this->getRestrictItems($isAdmin) as $name) {
if (isset($restrictedConfig[$name])) {
unset($restrictedConfig[$name]);
@@ -195,7 +225,7 @@ class Config
}
}
return $this->setArray($values);
return $this->set($values);
}
/**
@@ -224,14 +254,14 @@ class Config
*/
protected function getRestrictItems($onlySystemItems = false)
{
$configData = $this->loadConfig();
$data = $this->loadConfig();
if ($onlySystemItems) {
return $configData['systemItems'];
return $data['systemItems'];
}
if (empty($this->adminItems)) {
$this->adminItems= Util::merge($configData['systemItems'], $configData['adminItems']);
$this->adminItems= Util::merge($data['systemItems'], $data['adminItems']);
}
return $this->adminItems;

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

@@ -18,15 +18,13 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\Database\DBAL\FieldTypes;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\BooleanType;
class Bool extends Type
class Bool extends BooleanType
{
const BOOL = 'bool';
@@ -39,27 +37,4 @@ class Bool extends Type
{
return 'TINYINT';
}
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getBooleanTypeDeclarationSQL($fieldDeclaration);
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return $platform->convertBooleans($value);
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return (null === $value) ? null : (bool) $value;
}
public function getBindingType()
{
return \PDO::PARAM_BOOL;
}
}

View File

@@ -18,38 +18,18 @@
*
* 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\DBAL\FieldTypes;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\IntegerType;
class Int extends Type
class Int extends IntegerType
{
const INTtype = 'int';
public function getName()
{
return self::INTtype;
}
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getIntegerTypeDeclarationSQL($fieldDeclaration);
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return (null === $value) ? null : (int) $value;
}
public function getBindingType()
{
return \PDO::PARAM_INT;
}
}

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

@@ -18,14 +18,13 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\Database\DBAL\FieldTypes;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\StringType;
class Password extends Type
class Password extends StringType
{
const PASSWORD = 'password';
@@ -38,23 +37,5 @@ class Password extends Type
{
return 'VARCHAR';
}
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
//return "MD5";
}
/*public function convertToPHPValue($value, AbstractPlatform $platform)
{
return $value;
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return $value;
} */
}

View File

@@ -18,15 +18,13 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\Database\DBAL\FieldTypes;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\StringType;
class Varchar extends Type
class Varchar extends StringType
{
const VARCHAR = 'varchar';
@@ -34,16 +32,4 @@ class Varchar extends Type
{
return self::VARCHAR;
}
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
//return 'varchar';
}
public function getDefaultLength(AbstractPlatform $platform)
{
return $platform->getVarcharDefaultLength();
}
}

View File

@@ -26,18 +26,21 @@ use Espo\Core\Utils\Util;
class Base
{
private $itemName = null;
private $entityName = null;
private $metadata;
private $params;
private $ormEntityDefs;
private $foreignParams;
private $entityDefs;
protected $allowParams = array();
public function __construct(\Espo\Core\Utils\Metadata $metadata)
public function __construct(\Espo\Core\Utils\Metadata $metadata, array $ormEntityDefs, array $entityDefs)
{
$this->metadata = $metadata;
$this->ormEntityDefs = $ormEntityDefs;
$this->entityDefs = $entityDefs;
}
protected function getMetadata()
@@ -45,102 +48,223 @@ class Base
return $this->metadata;
}
protected function getParams()
protected function getOrmEntityDefs()
{
return $this->params;
return $this->ormEntityDefs;
}
protected function getForeignParams()
protected function getEntityDefs()
{
return $this->foreignParams;
return $this->entityDefs;
}
protected function setParams(array $params)
/**
* Set current Field name OR Link name
*
* @param void
*/
protected function setItemName($itemName)
{
$this->params = $params;
$this->itemName = $itemName;
}
protected function setForeignParams(array $foreignParams)
/**
* Get current Field name
*
* @return string
*/
protected function getFieldName()
{
$this->foreignParams = $foreignParams;
return $this->itemName;
}
public function process($params, $foreignParams)
/**
* Get current Link name
*
* @return string
*/
protected function getLinkName()
{
$this->setParams($params);
$this->setForeignParams($foreignParams);
$loads = $this->load($params, $foreignParams);
$loads = $this->mergeAllowedParams($loads);
return $loads;
return $this->itemName;
}
private function mergeAllowedParams($loads)
/**
* Set current Entity Name
*
* @param void
*/
protected function setEntityName($entityName)
{
$params = $this->getParams();
$this->entityName = $entityName;
}
if (!empty($this->allowParams)) {
$linkParams = &$loads[$params['entityName']] ['relations'] [$params['link']['name']];
/**
* Get current Entity Name
*
* @return string
*/
protected function getEntityName()
{
return $this->entityName;
}
foreach ($this->allowParams as $name) {
$additionalParrams = $this->getAllowedAdditionalParams($name);
if (isset($additionalParrams) && !isset($linkParams[$name])) {
$linkParams[$name] = $additionalParrams;
}
protected function setMethods(array $keyValueList)
{
foreach ($keyValueList as $key => $value) {
$methodName = 'set' . ucfirst($key);
if (method_exists($this, $methodName)) {
$this->$methodName($value);
}
}
return $loads;
}
private function getAllowedAdditionalParams($allowedItemName)
/**
* Start process Orm converting for fields/relations
*
* @param string $itemName Field name OR Link name
* @param string $entityName
* @return array
*/
public function process($itemName, $entityName)
{
$params = $this->getParams();
$foreignParams = $this->getForeignParams();
$inputs = array(
'itemName' => $itemName,
'entityName' => $entityName,
);
$this->setMethods($inputs);
$linkParams = isset($params['link']['params'][$allowedItemName]) ? $params['link']['params'][$allowedItemName] : null;
$foreignLinkParams = isset($foreignParams['link']['params'][$allowedItemName]) ? $foreignParams['link']['params'][$allowedItemName] : null;
$convertedDefs = $this->load($itemName, $entityName);
$additionalParrams = null;
$inputs = $this->setArrayValue(null, $inputs);
$this->setMethods($inputs);
if (isset($linkParams) && isset($foreignLinkParams)) {
$additionalParrams = Util::merge($linkParams, $foreignLinkParams);
} else if (isset($linkParams)) {
$additionalParrams = $linkParams;
} else if (isset($foreignLinkParams)) {
$additionalParrams = $foreignLinkParams;
return $convertedDefs;
}
/**
* Get Entity Defs by type (entity/orm)
*
* @param boolean $isOrmEntityDefs
* @return array
*/
protected function getDefs($isOrmEntityDefs = false)
{
$entityDefs = $isOrmEntityDefs ? $this->getOrmEntityDefs() : $this->getEntityDefs();
return $entityDefs;
}
/**
* Get entity params by name
*
* @param string $entityName
* @param bool $isOrmEntityDefs
* @param mixed $returns
* @return mixed
*/
protected function getEntityParams($entityName = null, $isOrmEntityDefs = false, $returns = null)
{
if (!isset($entityName)) {
$entityName = $this->getEntityName();
}
return $additionalParrams;
$entityDefs = $this->getDefs($isOrmEntityDefs);
if (isset($entityDefs[$entityName])) {
return $entityDefs[$entityName];
}
return $returns;
}
/**
* Get field params by name for a specified entity
*
* @param string $fieldName
* @param string $entityName
* @param bool $isOrmEntityDefs
* @param mixed $returns
* @return mixed
*/
protected function getFieldParams($fieldName = null, $entityName = null, $isOrmEntityDefs = false, $returns = null)
{
if (!isset($fieldName)) {
$fieldName = $this->getFieldName();
}
if (!isset($entityName)) {
$entityName = $this->getEntityName();
}
$entityDefs = $this->getDefs($isOrmEntityDefs);
if (isset($entityDefs[$entityName]) && isset($entityDefs[$entityName]['fields'][$fieldName])) {
return $entityDefs[$entityName]['fields'][$fieldName];
}
return $returns;
}
/**
* Get relation params by name for a specified entity
*
* @param string $linkName
* @param string $entityName
* @param bool $isOrmEntityDefs
* @param mixed $returns
* @return mixed
*/
protected function getLinkParams($linkName = null, $entityName = null, $isOrmEntityDefs = false, $returns = null)
{
if (!isset($linkName)) {
$linkName = $this->getLinkName();
}
if (!isset($entityName)) {
$entityName = $this->getEntityName();
}
$entityDefs = $this->getDefs($isOrmEntityDefs);
$relationKeyName = $isOrmEntityDefs ? 'relations' : 'links';
if (isset($entityDefs[$entityName]) && isset($entityDefs[$entityName][$relationKeyName][$linkName])) {
return $entityDefs[$entityName][$relationKeyName][$linkName];
}
return $returns;
}
/**
* Get Foreign field
*
* @param string $name
* @param string $entityName
* @return string
*/
protected function getForeignField($name, $entityName)
{
$foreignField = $this->getMetadata()->get('entityDefs.'.$entityName.'.fields.'.$name);
if ($foreignField['type'] != 'varchar') {
$fieldDefs = $this->getMetadata()->get('fields.'.$foreignField['type']);
$naming = isset($fieldDefs['naming']) ? $fieldDefs['naming'] : 'postfix';
if (isset($fieldDefs['actualFields']) && is_array($fieldDefs['actualFields'])) {
$foreignFieldArray = array();
foreach($fieldDefs['actualFields'] as $fieldName) {
if ($fieldName != 'salutation') {
$foreignFieldArray[] = Util::getNaming($name, $fieldName, $naming);
}
}
return explode('|', implode('| |', $foreignFieldArray)); //add an empty string between items
if ($foreignField['type'] == 'personName') {
return array('first' . ucfirst($name), ' ', 'last' . ucfirst($name));
}
}
return $name;
}
/**
* Set a value for all elements of array. So, in result all elements will have the same values
*
* @param string $value
* @param array $array
*/
protected function setArrayValue($inputValue, array $array)
{
foreach ($array as &$value) {
$value = $inputValue;
}
return $array;
}
}

View File

@@ -33,6 +33,8 @@ class Converter
private $relationManager;
private $entityDefs;
protected $defaultFieldType = 'varchar';
protected $defaultNaming = 'postfix';
@@ -55,6 +57,7 @@ class Converter
'len' => 'len',
'notNull' => 'notNull',
'autoincrement' => 'autoincrement',
'entity' => 'entity',
'notStorable' => 'notStorable',
'link' => 'relation',
'field' => 'foreign', //todo change "foreign" to "field"
@@ -69,6 +72,9 @@ class Converter
'default' => '{0}',
),
),
'select' => 'select',
'orderBy' => 'orderBy',
'where' => 'where',
);
protected $idParams = array(
@@ -85,6 +91,8 @@ class Converter
$this->relationManager = new RelationManager($this->metadata);
$this->metadataUtils = new \Espo\Core\Utils\Metadata\Utils($this->metadata);
$this->entityDefs = $this->getMetadata()->get('entityDefs');
}
@@ -93,6 +101,11 @@ class Converter
return $this->metadata;
}
protected function getEntityDefs()
{
return $this->entityDefs;
}
protected function getFileManager()
{
return $this->fileManager;
@@ -108,11 +121,9 @@ class Converter
return $this->metadataUtils;
}
public function process()
{
$entityDefs = $this->getMetadata()->get('entityDefs');
$entityDefs = $this->getEntityDefs();
$ormMeta = array();
foreach($entityDefs as $entityName => $entityMeta) {
@@ -122,7 +133,7 @@ class Converter
continue;
}
$ormMeta = Util::merge($ormMeta, $this->convertEntity($entityName, $entityMeta, $entityDefs));
$ormMeta = Util::merge($ormMeta, $this->convertEntity($entityName, $entityMeta));
}
$ormMeta = $this->afterProcess($ormMeta);
@@ -130,10 +141,7 @@ class Converter
return $ormMeta;
}
//convertToDatabaseFormat
protected function convertEntity($entityName, $entityMeta, $entityDefs)
protected function convertEntity($entityName, $entityMeta)
{
$ormMeta = array();
$ormMeta[$entityName] = array(
@@ -145,18 +153,19 @@ class Converter
$ormMeta[$entityName]['fields'] = $this->convertFields($entityName, $entityMeta);
$convertedLinks = $this->convertLinks($entityName, $entityMeta, $entityDefs);
$convertedLinks = $this->convertLinks($entityName, $entityMeta, $ormMeta);
$ormMeta = Util::merge($ormMeta, $convertedLinks);
return $ormMeta;
}
public function afterProcess(array $meta)
public function afterProcess(array $ormMeta)
{
$entityDefs = $this->getEntityDefs();
//load custom field definitions and customCodes
foreach($meta as $entityName => &$entityParams) {
foreach($ormMeta as $entityName => &$entityParams) {
foreach($entityParams['fields'] as $fieldName => $fieldParams) {
//load custom field definitions
@@ -167,17 +176,14 @@ class Converter
}
if (class_exists($className) && method_exists($className, 'load')) {
$helperClass = new $className($this->metadata);
$fieldResult = $helperClass->load(
array('name' => $entityName, 'params' => $entityParams),
array('name' => $fieldName, 'params' => $fieldParams)
);
$helperClass = new $className($this->metadata, $ormMeta, $entityDefs);
$fieldResult = $helperClass->process( $fieldName, $entityName );
if (isset($fieldResult['unset'])) {
$meta = Util::unsetInArray($meta, $fieldResult['unset']);
$ormMeta = Util::unsetInArray($ormMeta, $fieldResult['unset']);
unset($fieldResult['unset']);
}
$meta = Util::merge($meta, $fieldResult);
$ormMeta = Util::merge($ormMeta, $fieldResult);
} //END: load custom field definitions
@@ -196,7 +202,7 @@ class Converter
}
}
foreach($meta as $entityName => &$entityParams) {
foreach($ormMeta as $entityName => &$entityParams) {
foreach($entityParams['fields'] as $fieldName => &$fieldParams) {
switch ($fieldParams['type']) {
@@ -224,10 +230,9 @@ class Converter
}
return $meta;
return $ormMeta;
}
/**
* Metadata conversion from Espo format into Doctrine
*
@@ -293,8 +298,6 @@ class Converter
return $outputMeta;
}
protected function convertField($entityName, $fieldName, array $fieldParams, $fieldTypeMeta = null)
{
/** set default type if exists */
@@ -376,34 +379,20 @@ class Converter
return $subField;
}
protected function convertLinks($entityName, $entityMeta, array $entityDefs)
protected function convertLinks($entityName, $entityMeta, $ormMeta)
{
if (!isset($entityMeta['links'])) {
return array();
}
$entityDefs = $this->getEntityDefs();
$relationships = array();
foreach($entityMeta['links'] as $linkName => $linkParams) {
$linkEntityName = $this->getRelationManager()->getLinkEntityName($entityName, $linkParams);
$convertedLink = $this->getRelationManager()->convert($linkName, $linkParams, $entityName, $ormMeta);
$currentType = $linkParams['type'];
$foreignLink = $this->getForeignLink($linkName, $linkParams, $entityDefs[$linkEntityName]);
$method = $currentType;
if ($foreignLink !== false) {
$method .= '-'.$foreignLink['params']['type'];
}
$method = Util::toCamelCase($method);
if ( $this->getRelationManager()->isRelationExists($method) ) { //ex. hasManyHasMany
$convertedLink = $this->getRelationManager()->process($method, $entityName, array('name'=>$linkName, 'params'=>$linkParams), $foreignLink);
} else { //ex. hasMany
$convertedLink = $this->getRelationManager()->process($currentType, $entityName, array('name'=>$linkName, 'params'=>$linkParams), $foreignLink);
}
if ($convertedLink !== false) {
if (isset($convertedLink)) {
$relationships = Util::merge($convertedLink, $relationships);
}
}
@@ -411,27 +400,6 @@ class Converter
return $relationships;
}
/**
* Get foreign Link
*
* @param string $parentLinkName
* @param array $parentLinkParams
* @param array $currentEntityDefs
*
* @return array - in format array('name', 'params')
*/
protected function getForeignLink($parentLinkName, $parentLinkParams, $currentEntityDefs)
{
if (isset($parentLinkParams['foreign']) && isset($currentEntityDefs['links'][$parentLinkParams['foreign']])) {
return array(
'name' => $parentLinkParams['foreign'],
'params' => $currentEntityDefs['links'][$parentLinkParams['foreign']],
);
}
return false;
}
protected function getInitValues(array $fieldParams)
{
$values = array();
@@ -460,4 +428,4 @@ class Converter
return $values;
}
}
}

View File

@@ -18,30 +18,55 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Fields;
class Email extends \Espo\Core\Utils\Database\Orm\Base
{
public function load($entity, $field)
protected function load($fieldName, $entityName)
{
return array(
$entity['name'] => array(
'fields' => array(
$field['name'] => array(
return array(
$entityName => array(
'fields' => array(
$fieldName => array(
'select' => 'email_address.name',
'where' =>
array (
'LIKE' => 'email_address.name LIKE \'{text}\'',
'=' => 'email_address.name = \'{text}\'',
),
'orderBy' => 'email_address.name {direction}',
'where' =>
array (
'LIKE' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
SELECT entity_id
FROM entity_email_address
JOIN email_address ON email_address.id = entity_email_address.email_address_id
WHERE
entity_email_address.deleted = 0 AND entity_email_address.entity_type = '{$entityName}' AND
email_address.deleted = 0 AND email_address.name LIKE {value}
)",
'=' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
SELECT entity_id
FROM entity_email_address
JOIN email_address ON email_address.id = entity_email_address.email_address_id
WHERE
entity_email_address.deleted = 0 AND entity_email_address.entity_type = '{$entityName}' AND
email_address.deleted = 0 AND email_address.name = {value}
)",
'<>' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
SELECT entity_id
FROM entity_email_address
JOIN email_address ON email_address.id = entity_email_address.email_address_id
WHERE
entity_email_address.deleted = 0 AND entity_email_address.entity_type = '{$entityName}' AND
email_address.deleted = 0 AND email_address.name <> {value}
)"
),
'orderBy' => 'email_address.name {direction}',
),
$fieldName .'Data' => array(
'type' => 'text',
'notStorable' => true
),
),
'relations' => array(
$field['name'].'es' => array(
$fieldName.'es' => array(
'type' => 'manyMany',
'entity' => 'EmailAddress',
'relationName' => 'entityEmailAddress',
@@ -50,16 +75,16 @@ class Email extends \Espo\Core\Utils\Database\Orm\Base
'email_address_id',
),
'conditions' => array(
'entityType' => $entity['name'],
'entityType' => $entityName,
),
'additionalColumns' => array(
'entityType' => array(
'entityType' => array(
'type' => 'varchar',
'len' => 100,
'len' => 100,
),
'primary' => array(
'type' => 'bool',
'default' => false,
'default' => false,
),
),
),
@@ -69,4 +94,4 @@ class Email extends \Espo\Core\Utils\Database\Orm\Base
}
}
}

View File

@@ -18,35 +18,44 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Fields;
class LinkMultiple extends \Espo\Core\Utils\Database\Orm\Base
{
public function load($entity, $field)
protected function load($fieldName, $entityName)
{
return array(
$entity['name'] => array (
'fields' => array(
$field['name'].'Ids' => array(
$data = array(
$entityName => array (
'fields' => array(
$fieldName.'Ids' => array(
'type' => 'varchar',
'notStorable' => true,
),
$field['name'].'Names' => array(
$fieldName.'Names' => array(
'type' => 'varchar',
'notStorable' => true,
),
),
),
'unset' => array(
$entity['name'] => array(
'fields.'.$field['name'],
),
),
'unset' => array(
$entityName => array(
'fields.'.$fieldName,
),
),
);
$columns = $this->getMetadata()->get("entityDefs.{$entityName}.fields.{$fieldName}.columns");
if (!empty($columns)) {
$data[$entityName]['fields'][$fieldName . 'Columns'] = array(
'type' => 'varchar',
'notStorable' => true,
);
}
return $data;
}
}
}

View File

@@ -24,28 +24,27 @@ namespace Espo\Core\Utils\Database\Orm\Fields;
class LinkParent extends \Espo\Core\Utils\Database\Orm\Base
{
public function load($entity, $field)
protected function load($fieldName, $entityName)
{
return array(
$entity['name'] => array (
'fields' => array(
$field['name'].'Id' => array(
return array(
$entityName => array (
'fields' => array(
$fieldName.'Id' => array(
'type' => 'foreignId',
'index' => $field['name'],
'index' => $fieldName,
),
$field['name'].'Type' => array(
$fieldName.'Type' => array(
'type' => 'foreignType',
'notNull' => false,
'index' => $field['name'],
'index' => $fieldName,
),
$field['name'].'Name' => array(
$fieldName.'Name' => array(
'type' => 'varchar',
'notStorable' => true,
),
),
)
);
),
);
}

View File

@@ -26,11 +26,11 @@ use Espo\Core\Utils\Util;
class PersonName extends \Espo\Core\Utils\Database\Orm\Base
{
public function load($entity, $field)
protected function load($fieldName, $entityName)
{
$foreignField = $this->getForeignField($field['name'], $entity['name']);
$tableName = Util::toUnderScore($entity['name']);
$foreignField = array('first' . ucfirst($fieldName), ' ', 'last' . ucfirst($fieldName));
$tableName = Util::toUnderScore($entityName);
$fullList = array(); //contains empty string (" ") like delimiter
$fullListReverse = array(); //reverse of $fullList
@@ -38,31 +38,31 @@ class PersonName extends \Espo\Core\Utils\Database\Orm\Base
$like = array();
$equal = array();
foreach($foreignField as $fieldName) {
foreach($foreignField as $foreignFieldName) {
$fieldNameTrimmed = trim($fieldName);
$fieldNameTrimmed = trim($foreignFieldName);
if (!empty($fieldNameTrimmed)) {
$columnName = $tableName.'.'.Util::toUnderScore($fieldNameTrimmed);
$fullList[] = $fieldList[] = $columnName;
$like[] = $columnName." LIKE '{text}'";
$equal[] = $columnName." = '{text}'";
$like[] = $columnName." LIKE {value}";
$equal[] = $columnName." = {value}";
} else {
$fullList[] = "'".$fieldName."'";
$fullList[] = "'".$foreignFieldName."'";
}
}
$fullListReverse = array_reverse($fullList);
return array(
$entity['name'] => array (
$entityName => array (
'fields' => array(
$field['name'] => array(
$fieldName => array(
'type' => 'varchar',
'select' => $this->getSelect($fullList),
'where' => array(
'LIKE' => "(".implode(" OR ", $like)." OR CONCAT(".implode(", ", $fullList).") LIKE '{text}' OR CONCAT(".implode(", ", $fullListReverse).") LIKE '{text}')",
'=' => "(".implode(" OR ", $equal)." OR CONCAT(".implode(", ", $fullList).") = '{text}' OR CONCAT(".implode(", ", $fullListReverse).") = '{text}')",
'LIKE' => "(".implode(" OR ", $like)." OR CONCAT(".implode(", ", $fullList).") LIKE {value} OR CONCAT(".implode(", ", $fullListReverse).") LIKE {value})",
'=' => "(".implode(" OR ", $equal)." OR CONCAT(".implode(", ", $fullList).") = {value} OR CONCAT(".implode(", ", $fullListReverse).") = {value})",
),
'orderBy' => implode(", ", array_map(function ($item) {return $item . ' {direction}';}, $fieldList)),
),
@@ -87,4 +87,4 @@ class PersonName extends \Espo\Core\Utils\Database\Orm\Base
return $select;
}
}
}

View File

@@ -0,0 +1,97 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Fields;
class Phone extends \Espo\Core\Utils\Database\Orm\Base
{
protected function load($fieldName, $entityName)
{
return array(
$entityName => array(
'fields' => array(
$fieldName => array(
'select' => 'phone_number.name',
'where' =>
array (
'LIKE' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
SELECT entity_id
FROM entity_phone_number
JOIN phone_number ON phone_number.id = entity_phone_number.phone_number_id
WHERE
entity_phone_number.deleted = 0 AND entity_phone_number.entity_type = '{$entityName}' AND
phone_number.deleted = 0 AND phone_number.name LIKE {value}
)",
'=' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
SELECT entity_id
FROM entity_phone_number
JOIN phone_number ON phone_number.id = entity_phone_number.phone_number_id
WHERE
entity_phone_number.deleted = 0 AND entity_phone_number.entity_type = '{$entityName}' AND
phone_number.deleted = 0 AND phone_number.name = {value}
)",
'<>' => \Espo\Core\Utils\Util::toUnderScore($entityName) . ".id IN (
SELECT entity_id
FROM entity_phone_number
JOIN phone_number ON phone_number.id = entity_phone_number.phone_number_id
WHERE
entity_phone_number.deleted = 0 AND entity_phone_number.entity_type = '{$entityName}' AND
phone_number.deleted = 0 AND phone_number.name <> {value}
)"
),
'orderBy' => 'phone_number.name {direction}',
),
$fieldName .'Data' => array(
'type' => 'text',
'notStorable' => true
),
),
'relations' => array(
$fieldName.'s' => array(
'type' => 'manyMany',
'entity' => 'PhoneNumber',
'relationName' => 'entityPhoneNumber',
'midKeys' => array(
'entity_id',
'phone_number_id',
),
'conditions' => array(
'entityType' => $entityName,
),
'additionalColumns' => array(
'entityType' => array(
'type' => 'varchar',
'len' => 100,
),
'primary' => array(
'type' => 'bool',
'default' => false,
),
),
),
),
),
);
}
}

View File

@@ -28,10 +28,14 @@ class RelationManager
{
private $metadata;
private $entityDefs;
public function __construct(\Espo\Core\Utils\Metadata $metadata)
{
$this->metadata = $metadata;
$this->entityDefs = $this->getMetadata()->get('entityDefs');
}
protected function getMetadata()
@@ -39,14 +43,15 @@ class RelationManager
return $this->metadata;
}
public function getLinkEntityName($entityName, $link)
protected function getEntityDefs()
{
if (isset($link['params'])) {
return isset($link['params']['entity']) ? $link['params']['entity'] : $entityName;
}
return $this->entityDefs;
}
return isset($link['entity']) ? $link['entity'] : $entityName;
public function getLinkEntityName($entityName, $linkParams)
{
return isset($linkParams['entity']) ? $linkParams['entity'] : $entityName;
}
public function isRelationExists($relationName)
@@ -81,33 +86,58 @@ class RelationManager
return method_exists($className, 'load');
}
public function process($method, $entityName, $link, $foreignLink = array())
/**
* Get foreign Link
*
* @param string $parentLinkName
* @param array $parentLinkParams
* @param array $currentEntityDefs
*
* @return array - in format array('name', 'params')
*/
private function getForeignLink($parentLinkName, $parentLinkParams, $currentEntityDefs)
{
$params = array();
$params['entityName'] = $entityName;
$params['link'] = $link;
$foreignParams = array();
$foreignParams['entityName'] = $this->getLinkEntityName($entityName, $link);
$foreignParams['link'] = $foreignLink;
$params['targetEntity'] = $foreignParams['entityName'];
$foreignParams['targetEntity'] = $params['entityName'];
//relationDefs defined in separate file
if (isset($link['params']['relationName']) && $this->isMethodExists($link['params']['relationName'])) {
$className = $this->getRelationClass($link['params']['relationName']);
} else if ($this->isMethodExists($method)) {
$className = $this->getRelationClass($method);
if (isset($parentLinkParams['foreign']) && isset($currentEntityDefs['links'][$parentLinkParams['foreign']])) {
return array(
'name' => $parentLinkParams['foreign'],
'params' => $currentEntityDefs['links'][$parentLinkParams['foreign']],
);
}
if (isset($className) && $className !== false) {
$helperClass = new $className($this->metadata);
return $helperClass->process($params, $foreignParams);
}
//END: relationDefs defined in separate file
return false;
}
public function convert($linkName, $linkParams, $entityName, $ormMeta)
{
$entityDefs = $this->getEntityDefs();
$foreignEntityName = $this->getLinkEntityName($entityName, $linkParams);
$foreignLink = $this->getForeignLink($linkName, $linkParams, $entityDefs[$foreignEntityName]);
$currentType = $linkParams['type'];
$method = $currentType;
if ($foreignLink !== false) {
$method .= '-'.$foreignLink['params']['type'];
}
$method = Util::toCamelCase($method);
$relationName = $this->isRelationExists($method) ? $method /*hasManyHasMany*/ : $currentType /*hasMany*/;
//relationDefs defined in separate file
if (isset($linkParams['relationName']) && $this->isMethodExists($linkParams['relationName'])) {
$className = $this->getRelationClass($linkParams['relationName']);
} else if ($this->isMethodExists($relationName)) {
$className = $this->getRelationClass($relationName);
}
if (isset($className) && $className !== false) {
$helperClass = new $className($this->metadata, $ormMeta, $entityDefs);
return $helperClass->process($linkName, $entityName, $foreignLink['name'], $foreignEntityName);
}
//END: relationDefs defined in separate file
return null;
}
}

View File

@@ -0,0 +1,151 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
class Base extends \Espo\Core\Utils\Database\Orm\Base
{
private $params;
private $foreignParams;
protected $foreignLinkName = null;
protected $foreignEntityName = null;
protected $allowedParams = array(
'relationName',
'conditions',
'additionalColumns',
'midKeys',
);
protected function getParams()
{
return $this->params;
}
protected function getForeignParams()
{
return $this->foreignParams;
}
protected function setParams(array $params)
{
$this->params = $params;
}
protected function setForeignParams(array $foreignParams)
{
$this->foreignParams = $foreignParams;
}
protected function setForeignLinkName($foreignLinkName)
{
$this->foreignLinkName = $foreignLinkName;
}
protected function getForeignLinkName()
{
return $this->foreignLinkName;
}
protected function setForeignEntityName($foreignEntityName)
{
$this->foreignEntityName = $foreignEntityName;
}
protected function getForeignEntityName()
{
return $this->foreignEntityName;
}
protected function getForeignLinkParams()
{
$foreignLinkName = $this->getForeignLinkName();
$foreignEntityName = $this->getForeignEntityName();
$foreignLinkParams = $this->getLinkParams($foreignLinkName, $foreignEntityName);
return $foreignLinkParams;
}
public function process($linkName, $entityName, $foreignLinkName, $foreignEntityName)
{
$inputs = array(
'itemName' => $linkName,
'entityName' => $entityName,
'foreignLinkName' => $foreignLinkName,
'foreignEntityName' => $foreignEntityName,
);
$this->setMethods($inputs);
$convertedDefs = $this->load($linkName, $entityName);
$convertedDefs = $this->mergeAllowedParams($convertedDefs);
$inputs = $this->setArrayValue(null, $inputs);
$this->setMethods($inputs);
return $convertedDefs;
}
private function mergeAllowedParams($loads)
{
$linkName = $this->getLinkName();
$entityName = $this->getEntityName();
if (!empty($this->allowedParams)) {
$linkParams = &$loads[$entityName]['relations'][$linkName];
foreach ($this->allowedParams as $name) {
$additionalParrams = $this->getAllowedAdditionalParams($name);
if (isset($additionalParrams) && !isset($linkParams[$name])) {
$linkParams[$name] = $additionalParrams;
}
}
}
return $loads;
}
private function getAllowedAdditionalParams($allowedItemName)
{
$linkParams = $this->getLinkParams();
$foreignLinkParams = $this->getForeignLinkParams();
$itemLinkParams = isset($linkParams[$allowedItemName]) ? $linkParams[$allowedItemName] : null;
$itemForeignLinkParams = isset($foreignLinkParams[$allowedItemName]) ? $foreignLinkParams[$allowedItemName] : null;
$additionalParrams = null;
if (isset($itemLinkParams) && isset($itemForeignLinkParams)) {
$additionalParrams = Util::merge($itemLinkParams, $itemForeignLinkParams);
} else if (isset($itemLinkParams)) {
$additionalParrams = $itemLinkParams;
} else if (isset($itemForeignLinkParams)) {
$additionalParrams = $itemForeignLinkParams;
}
return $additionalParrams;
}
}

View File

@@ -18,33 +18,34 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
class BelongsTo extends \Espo\Core\Utils\Database\Orm\Base
class BelongsTo extends Base
{
public function load($params, $foreignParams)
protected function load($linkName, $entityName)
{
$foreignEntityName = $this->getForeignEntityName();
return array (
$params['entityName'] => array (
$entityName => array (
'fields' => array(
$params['link']['name'].'Name' => array(
$linkName.'Name' => array(
'type' => 'foreign',
'relation' => $params['link']['name'],
'foreign' => $this->getForeignField('name', $foreignParams['entityName']),
'relation' => $linkName,
'foreign' => $this->getForeignField('name', $foreignEntityName),
),
$params['link']['name'].'Id' => array(
$linkName.'Id' => array(
'type' => 'foreignId',
'index' => true,
),
),
'relations' => array(
$params['link']['name'] => array(
$linkName => array(
'type' => 'belongsTo',
'entity' => $params['targetEntity'],
'key' => $params['link']['name'].'Id',
'entity' => $foreignEntityName,
'key' => $linkName.'Id',
'foreignKey' => 'id', //????
),
),
@@ -52,5 +53,4 @@ class BelongsTo extends \Espo\Core\Utils\Database\Orm\Base
);
}
}

View File

@@ -18,35 +18,34 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
class EmailEmailAddress extends \Espo\Core\Utils\Database\Orm\Relations\HasMany
class EmailEmailAddress extends HasMany
{
public function load($params, $foreignParams)
protected function load($linkName, $entityName)
{
$parentRelation = parent::load($linkName, $entityName);
$parentRelation = parent::load($params, $foreignParams);
$foreignEntityName = $this->getForeignEntityName();
$relation = array(
$params['entityName'] => array (
$entityName => array (
'relations' => array(
$params['link']['name'] => array(
$linkName => array(
'midKeys' => array(
lcfirst($params['entityName']).'Id',
lcfirst($foreignParams['entityName']).'Id',
lcfirst($entityName).'Id',
lcfirst($foreignEntityName).'Id',
),
),
),
),
);
$relation = \Espo\Core\Utils\Util::merge($parentRelation, $relation);
return $relation;
}
}
}

View File

@@ -18,28 +18,30 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
class EntityTeam extends \Espo\Core\Utils\Database\Orm\Base
class EntityTeam extends Base
{
public function load($params, $foreignParams)
protected function load($linkName, $entityName)
{
$linkParams = $this->getLinkParams();
$foreignEntityName = $this->getForeignEntityName();
return array(
$params['entityName'] => array(
$entityName => array(
'relations' => array(
$params['link']['name'] => array(
$linkName => array(
'type' => 'manyMany',
'entity' => $params['targetEntity'],
'relationName' => lcfirst($params['link']['params']['relationName']),
'entity' => $foreignEntityName,
'relationName' => lcfirst($linkParams['relationName']),
'midKeys' => array(
'entity_id',
'team_id',
),
'conditions' => array(
'entityType' => $params['entityName'],
'entityType' => $entityName,
),
'additionalColumns' => array(
'entityType' => array(

View File

@@ -18,33 +18,35 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
class HasChildren extends \Espo\Core\Utils\Database\Orm\Base
class HasChildren extends Base
{
public function load($params, $foreignParams)
protected function load($linkName, $entityName)
{
$foreignLinkName = $this->getForeignLinkName();
$foreignEntityName = $this->getForeignEntityName();
return array(
$params['entityName'] => array (
$entityName => array (
'fields' => array(
$params['link']['name'].'Ids' => array(
$linkName.'Ids' => array(
'type' => 'varchar',
'notStorable' => true,
),
$params['link']['name'].'Names' => array(
$linkName.'Names' => array(
'type' => 'varchar',
'notStorable' => true,
),
),
'relations' => array(
$params['link']['name'] => array(
$linkName => array(
'type' => 'hasChildren',
'entity' => $params['targetEntity'],
'foreignKey' => $foreignParams['link']['name'].'Id', //???: 'foreignKey' => $params['link']['name'].'Id',
'foreignType' => $foreignParams['link']['name'].'Type', //???: 'foreignKey' => $params['link']['name'].'Id',
'entity' => $foreignEntityName,
'foreignKey' => $foreignLinkName.'Id',
'foreignType' => $foreignLinkName.'Type',
),
),
),

View File

@@ -18,44 +18,41 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
class HasMany extends \Espo\Core\Utils\Database\Orm\Base
class HasMany extends Base
{
protected $allowParams = array(
'relationName',
'conditions',
'additionalColumns',
);
public function load($params, $foreignParams)
protected function load($linkName, $entityName)
{
$relationType = isset($params['link']['params']['relationName']) ? 'manyMany' : 'hasMany';
$linkParams = $this->getLinkParams();
$foreignLinkName = $this->getForeignLinkName();
$foreignEntityName = $this->getForeignEntityName();
$relationType = isset($linkParams['relationName']) ? 'manyMany' : 'hasMany';
$relation = array(
$params['entityName'] => array (
$entityName => array (
'fields' => array(
$params['link']['name'].'Ids' => array(
$linkName.'Ids' => array(
'type' => 'varchar',
'notStorable' => true,
),
$params['link']['name'].'Names' => array(
$linkName.'Names' => array(
'type' => 'varchar',
'notStorable' => true,
),
),
'relations' => array(
$params['link']['name'] => array(
//'type' => 'hasMany',
$linkName => array(
'type' => $relationType,
'entity' => $params['targetEntity'],
'foreignKey' => lcfirst($foreignParams['link']['name'].'Id'), //???: 'foreignKey' => $params['link']['name'].'Id',
'entity' => $foreignEntityName,
'foreignKey' => lcfirst($foreignLinkName.'Id'),
),
),
),
);
);
return $relation;
}

View File

@@ -18,45 +18,40 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
use Espo\Core\Utils\Util;
class ManyMany extends \Espo\Core\Utils\Database\Orm\Base
class ManyMany extends Base
{
protected $allowParams = array(
'relationName',
'conditions',
'additionalColumns',
);
public function load($params, $foreignParams)
protected function load($linkName, $entityName)
{
$foreignEntityName = $this->getForeignEntityName();
return array(
$params['entityName'] => array(
$entityName => array(
'fields' => array(
$params['link']['name'].'Ids' => array(
$linkName.'Ids' => array(
'type' => 'varchar',
'notStorable' => true,
),
$params['link']['name'].'Names' => array(
$linkName.'Names' => array(
'type' => 'varchar',
'notStorable' => true,
),
),
'relations' => array(
$params['link']['name'] => array(
$linkName => array(
'type' => 'manyMany',
'entity' => $params['targetEntity'],
'relationName' => $this->getJoinTable($params['entityName'], $foreignParams['entityName']),
'entity' => $foreignEntityName,
'relationName' => $this->getJoinTable($entityName, $foreignEntityName),
'key' => 'id', //todo specify 'key'
'foreignKey' => 'id', //todo specify 'foreignKey'
'midKeys' => array(
lcfirst($params['entityName']).'Id',
lcfirst($foreignParams['entityName']).'Id',
lcfirst($entityName).'Id',
lcfirst($foreignEntityName).'Id',
),
),
),

View File

@@ -20,19 +20,28 @@
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
ob_start();
$result = array('success' => false, 'errors' => array());
namespace Espo\Core\Utils\Database\Orm\Relations;
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'));
class NoteAttachments extends HasChildren
{
protected function load($linkName, $entityName)
{
$parentRelation = parent::load($linkName, $entityName);
$relation = array(
$entityName => array (
'fields' => array(
$linkName.'Types' => array(
'type' => 'varchar',
'notStorable' => true,
),
),
),
);
$relation = \Espo\Core\Utils\Util::merge($parentRelation, $relation);
return $relation;
}
}
ob_clean();
echo json_encode($result);

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;
@@ -276,7 +275,9 @@ class Converter
switch ($fieldParams['type']) {
case 'array':
case 'jsonArray':
$dbFieldParams['default'] = ''; //for db type TEXT can't be defined a default value
case 'text':
case 'longtext':
unset($dbFieldParams['default']); //for db type TEXT can't be defined a default value
break;
case 'bool':
@@ -361,4 +362,4 @@ class Converter
}
}
}

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

@@ -18,24 +18,32 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\Database\Schema\rebuildActions;
class Currency extends \Espo\Core\Utils\Database\Schema\BaseRebuildActions
{
public function afterRebuild()
{
$currencyConfig = $this->getConfig()->get('currency');
$currencyConfig['rate'][ $currencyConfig['base'] ] = '1.00';
$pdo = $this->getEntityManager()->getPDO();
public function afterRebuild()
{
$defaultCurrency = $this->getConfig()->get('defaultCurrency');
$baseCurrency = $this->getConfig()->get('baseCurrency');
$currencyRates = $this->getConfig()->get('currencyRates');
if ($defaultCurrency != $baseCurrency) {
$currencyRates = $this->exchangeRates($baseCurrency, $defaultCurrency, $currencyRates);
}
$currencyRates[$defaultCurrency] = '1.00';
$pdo = $this->getEntityManager()->getPDO();
$sql = "TRUNCATE `currency`";
$pdo->prepare($sql)->execute();
foreach ($currencyConfig['rate'] as $currencyName => $rate) {
foreach ($currencyRates as $currencyName => $rate) {
$sql = "
INSERT INTO `currency`
@@ -43,9 +51,34 @@ class Currency extends \Espo\Core\Utils\Database\Schema\BaseRebuildActions
VALUES
(".$pdo->quote($currencyName) . ", " . $pdo->quote($rate) . ")
";
$pdo->prepare($sql)->execute();
}
}
$pdo->prepare($sql)->execute();
}
}
/**
* Calculate exchange rates if defaultCurrency doesn't equals baseCurrency
*
* @param string $baseCurrency
* @param string $defaultCurrency
* @param array $currencyRates [description]
* @return array - List of new currency rates
*/
protected function exchangeRates($baseCurrency, $defaultCurrency, array $currencyRates)
{
$precision = 5;
$defaultCurrencyRate = round(1 / $currencyRates[$defaultCurrency], $precision);
$exchangedRates = array();
$exchangedRates[$baseCurrency] = $defaultCurrencyRate;
unset($currencyRates[$baseCurrency], $currencyRates[$defaultCurrency]);
foreach ($currencyRates as $currencyName => $rate) {
$exchangedRates[$currencyName] = round($rate * $defaultCurrencyRate, $precision);
}
return $exchangedRates;
}
}

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);
@@ -165,7 +166,7 @@ class FieldManager
}
foreach ($fieldDef as $defName => $defValue) {
if (!isset($defValue)) {
if (!isset($defValue) || (is_string($defValue) && $defValue == '') ) {
unset($fieldDef[$defName]);
}
}

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
*
@@ -170,10 +176,15 @@ class Manager
$fullPath = $this->concatPaths($path); //todo remove after changing the params
if ($this->checkCreateFile($fullPath) === false) {
throw new Error('Permission denied in '. $path);
throw new Error('Permission denied in '. $fullPath);
}
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;
}
/**
@@ -214,22 +225,33 @@ class Manager
* @param string | array $path
* @param string $content JSON string
* @param bool $isJSON
* @param array $mergeOptions
* @param string | array $mergeOptions
* @param string | array $removeOptions - List of unset keys from content
* @param bool $isReturn - Is result to be returned or stored
*
* @return bool
* @return bool | array
*/
public function mergeContents($path, $content, $isJSON = false, $mergeOptions = null)
public function mergeContents($path, $content, $isJSON = false, $mergeOptions = null, $removeOptions = null, $isReturn = false)
{
$fileContent = $this->getContents($path);
$savedDataArray = Utils\Json::getArrayData($fileContent);
$newDataArray = Utils\Json::getArrayData($content);
if (isset($removeOptions)) {
$savedDataArray = Utils\Util::unsetInArray($savedDataArray, $removeOptions);
$newDataArray = Utils\Util::unsetInArray($newDataArray, $removeOptions);
}
$data = Utils\Util::merge($savedDataArray, $newDataArray, $mergeOptions);
if ($isJSON) {
$data = Utils\Json::encode($data, JSON_PRETTY_PRINT);
}
if ($isReturn) {
return $data;
}
return $this->putContents($path, $data);
}
@@ -237,26 +259,14 @@ class Manager
* Merge PHP content and save it to a file
*
* @param string | array $path
* @param string $content
* @param bool $onlyFirstLevel - Merge only first level. Ex. current: array('test'=>array('item1', 'item2')). $content= array('test'=>array('item1'),). Result will be array('test'=>array('item1')).
*
* @param string $content JSON string
* @param string | array $mergeOptions
* @param string | array $removeOptions - List of unset keys from content
* @return bool
*/
public function mergeContentsPHP($path, $content, $onlyFirstLevel = false, $mergeOptions = null)
public function mergeContentsPHP($path, $content, $mergeOptions = null, $removeOptions = null)
{
$fileContent = $this->getContents($path);
$savedDataArray = Utils\Json::getArrayData($fileContent);
$newDataArray = Utils\Json::getArrayData($content);
if ($onlyFirstLevel) {
foreach($newDataArray as $key => $val) {
$setVal = is_array($val) ? array() : '';
$savedDataArray[$key] = $setVal;
}
}
$data = Utils\Util::merge($savedDataArray, $newDataArray, $mergeOptions);
$data = $this->mergeContents($path, $content, false, $mergeOptions, $removeOptions, true);
return $this->putContentsPHP($path, $data);
}

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,99 @@ 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 {
$this->chmod($item, $permission, true);
} catch (\Exception $e) {
}
$res = is_readable($item);
/** 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

@@ -101,8 +101,8 @@ class Unifier
$dirName = $this->getFileManager()->getDirName($dirPath, false);
$defaultValues = $this->loadDefaultValues($dirName, $type);
$content= array();
$unsets= array();
$content = array();
$unsets = array();
foreach($fileList as $dirName => $fileName) {
if (is_array($fileName)) { /*get content from files in a sub directory*/
@@ -125,7 +125,7 @@ class Unifier
}
//unset content
$content= Utils\Util::unsetInArray($content, $unsets);
$content = Utils\Util::unsetInArray($content, $unsets);
//END: unset content
return $content;
@@ -141,27 +141,16 @@ class Unifier
*/
protected function unifyGetContents($paths, $defaults)
{
$fileContent= $this->getFileManager()->getContents($paths);
$decoded= Utils\Json::getArrayData($fileContent);
$fileContent = $this->getFileManager()->getContents($paths);
if (empty($decoded) && !is_array($decoded)) {
$GLOBALS['log']->emergency('Syntax error or empty file - '.Utils\Util::concatPath($folderPath, $fileName));
} else {
//Default values
if (is_string($defaults) && !empty($defaults)) {
$defType= $defaults;
unset($defaults);
$name= $this->getFileManager()->getFileName($fileName, '.json');
$decoded = Utils\Json::getArrayData($fileContent, null);
$defaults= $this->loadDefaultValues($name, $defType);
}
$mergedValues= Utils\Util::merge($defaults, $decoded);
//END: Default values
return $mergedValues;
if (!isset($decoded)) {
$GLOBALS['log']->emergency('Syntax error in '.Utils\Util::concatPath($paths));
return array();
}
return array();
return $decoded;
}
/**
@@ -174,10 +163,10 @@ class Unifier
*/
protected function loadDefaultValues($name, $type='metadata')
{
$defaultPath= $this->params['defaultsPath'];
$defaultPath = $this->params['defaultsPath'];
$defaultValue= $this->getFileManager()->getContents( array($defaultPath, $type, $name.'.json') );
if ($defaultValue!==false) {
$defaultValue = $this->getFileManager()->getContents( array($defaultPath, $type, $name.'.json') );
if ($defaultValue !== false) {
//return default array
return Utils\Json::decode($defaultValue, true);
}

View File

@@ -118,7 +118,7 @@ class Json
*
* @return array
*/
public static function getArrayData($data)
public static function getArrayData($data, $returns = array())
{
if (is_array($data)) {
return $data;
@@ -127,7 +127,7 @@ class Json
return static::decode($data, true);
}
return array();
return $returns;
}

View File

@@ -155,6 +155,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)
{
@@ -232,7 +241,7 @@ class Language
$i18nCacheFile = str_replace('{*}', $i18nName, $this->cacheFile);
if ($i18nName != $this->defaultLanguage) {
$i18nData = Util::merge($this->fullData[$this->defaultLanguage], $i18nData);
$i18nData = Util::merge($this->fullData[$this->defaultLanguage], $i18nData, null, null, true);
}
$result &= $this->getFileManager()->putContentsPHP($i18nCacheFile, $i18nData);
}

View File

@@ -142,13 +142,13 @@ class Metadata
* Get Metadata
*
* @param string $key
* @param mixed $return
* @param mixed $default
*
* @return array
*/
public function get($key = null, $returns = null)
public function get($key = null, $default = null)
{
return Util::getValueByKey($this->getData(), $key, $returns);
return Util::getValueByKey($this->getData(), $key, $default);
}
@@ -430,4 +430,4 @@ class Metadata
return false;
}
}
}

View File

@@ -125,10 +125,13 @@ class Util
* ),
* )
* @param $rewriteKeyName string - Rewrite key name. It is ignored if $rewriteLevel is NULL.
* @param $rewriteArrays bool - Rewrite single arrays. Examples:
* TRUE: array is [0, 1, 2], main array is [3, 4, 5], Result is [3, 4, 5].
* FALSE: array is [0, 1, 2], main array is [3, 4, 5], Result is [0, 1, 2, 3, 4, 5].
*
* @return array
*/
public static function merge($array, $mainArray, $rewriteLevel = null, $rewriteKeyName = null)
public static function merge($array, $mainArray, $rewriteLevel = null, $rewriteKeyName = null, $rewriteArrays = false)
{
if (is_array($array) && !is_array($mainArray)) {
return $array;
@@ -169,7 +172,7 @@ class Util
} /** END: check the $rewriteKeyName */
if (!isset($rowRewriteLevel) || $rowRewriteLevel != 1) {
$array[$mainKey] = static::merge((array) $value, (array) $mainValue, --$rowRewriteLevel, $rewriteKeyName);
$array[$mainKey] = static::merge((array) $value, (array) $mainValue, --$rowRewriteLevel, $rewriteKeyName, $rewriteArrays);
continue;
}
@@ -185,7 +188,11 @@ class Util
$array[$mainKey] = $mainValue;
}
elseif (!in_array($mainValue, $array)) {
$array[] = $mainValue;
if ($rewriteArrays) {
$array[$mainKey] = $mainValue;
} else {
$array[] = $mainValue;
}
} /** END: merge logic */
break;
@@ -359,11 +366,17 @@ class Util
if (!empty($unsetSett)){
$keyItems = explode('.', $unsetSett);
$currVal = isset($content[$rootKey]) ? "\$content['{$rootKey}']" : "\$content";
$lastKey = array_pop($keyItems);
foreach($keyItems as $keyItem){
$currVal .= "['{$keyItem}']";
}
$currVal = "if (isset({$currVal})) unset({$currVal});";
$unsetElem = $currVal . "['{$lastKey}']";
$currVal = "
if (isset({$unsetElem}) || array_key_exists({$lastKey}, {$currVal})) {
unset({$unsetElem});
} ";
eval($currVal);
}
}
@@ -395,10 +408,10 @@ class Util
*
* @param array $array
* @param string $key Ex. of key is "entityDefs", "entityDefs.User"
* @param mixed $returns
* @param mixed $default
* @return mixed
*/
public static function getValueByKey(array $array, $key = null, $returns = null)
public static function getValueByKey(array $array, $key = null, $default = null)
{
if (!isset($key) || empty($key)) {
return $array;
@@ -411,7 +424,7 @@ class Util
if (isset($lastItem[$keyName]) && is_array($lastItem)) {
$lastItem = $lastItem[$keyName];
} else {
return $returns;
return $default;
}
}

View File

@@ -25,6 +25,7 @@ return array (
array (
'driver' => 'pdo_mysql',
'host' => 'localhost',
'port' => '',
'dbname' => '',
'user' => '',
'password' => '',
@@ -40,15 +41,13 @@ return array (
'weekStart' => 0,
'thousandSeparator' => ',',
'decimalMark' => '.',
'exportDelimiter' => ',',
'currencyList' =>
array (
),
'defaultCurrency' => 'USD',
'currency' =>
array(
'base' => 'USD',
'rate' => array(
),
'baseCurrency' => 'USD',
'currencyRates' => array(
),
'outboundEmailIsShared' => true,
'outboundEmailFromName' => 'EspoCRM',
@@ -62,6 +61,14 @@ return array (
'languageList' => array(
'en_US',
'de_DE',
'es_ES',
'fr_FR',
'nl_NL',
'tr_TR',
'ro_RO',
'pl_PL',
'pt_BR',
'vi_VN'
),
'language' => 'en_US',
'logger' =>
@@ -71,68 +78,21 @@ 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 **/
),
'authenticationMethod' => 'Espo',
'globalSearchEntityList' =>
array (
0 => 'Account',
1 => 'Contact',
2 => 'Lead',
3 => 'Prospect',
4 => 'Opportunity',
),
"tabList" => array("Account", "Contact", "Lead", "Opportunity", "Calendar", "Meeting", "Call", "Task", "Case", "Prospect", "Email"),
"quickCreateList" => array("Account", "Contact", "Lead", "Opportunity", "Meeting", "Call", "Task", "Case", "Prospect"),
'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',
3 => 'Opportunity',
),
"tabList" => array("Account", "Contact", "Lead", "Opportunity", "Calendar", "Meeting", "Call", "Task", "Case", "Email"),
"quickCreateList" => array("Account", "Contact", "Lead", "Opportunity", "Meeting", "Call", "Task", "Case"),
'calendarDefaultEntity' => 'Meeting',
'disableExport' => false,
'assignmentEmailNotifications' => false,
'assignmentEmailNotificationsEntityList' => array('Lead', 'Opportunity', 'Task', 'Case'),
'emailMessageMaxSize' => 10,
'isInstalled' => false,
);

View File

@@ -1 +1 @@
[{"name":"name"},{"name":"email","type":"base","sortable":false,"params":{}},{"name":"city"}]
[{"name":"name"}]

View File

@@ -0,0 +1,119 @@
<?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',
'authenticationMethod',
'ldapHost',
'ldapPort',
'ldapSecurity',
'ldapAuth',
'ldapUsername',
'ldapPassword',
'ldapBindRequiresDn',
'ldapBaseDn',
'ldapUserLoginFilter',
'ldapAccountCanonicalForm',
'ldapAccountDomainName',
'ldapAccountDomainNameShort',
'ldapAccountFilterFormat',
'ldapTryUsernameSplit',
'ldapOptReferrals',
'ldapCreateEspoUser',
),
'isInstalled' => false,
);

View File

@@ -0,0 +1,29 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Entities;
class AuthToken extends \Espo\Core\ORM\Entity
{
}

View File

@@ -46,6 +46,21 @@ class Email extends \Espo\Core\ORM\Entity
}
}
public function getBodyPlainForSending()
{
$bodyPlain = $this->get('bodyPlain');
if (!empty($bodyPlain)) {
return $bodyPlain;
}
$body = $this->get('body');
$breaks = array("<br />","<br>","<br/>","<br />","&lt;br /&gt;","&lt;br/&gt;","&lt;br&gt;");
$body = str_ireplace($breaks, "\r\n", $body);
$body = strip_tags($body);
return $body;
}
public function getBodyForSending()
{
$body = $this->get('body');
@@ -55,6 +70,7 @@ class Email extends \Espo\Core\ORM\Entity
$body = str_replace("?entryPoint=attachment&amp;id={$attachment->id}", "cid:{$attachment->id}", $body);
}
}
$body = str_replace("<table class=\"table table-bordered\">", "<table class=\"table table-bordered\" width=\"100%\">", $body);
return $body;

View File

@@ -0,0 +1,30 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Entities;
class EmailAccount extends \Espo\Core\ORM\Entity
{
}

View File

@@ -0,0 +1,28 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Entities;
class ExternalAccount extends Integration
{
}

View File

@@ -0,0 +1,152 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Entities;
class Integration extends \Espo\Core\ORM\Entity
{
public function get($name)
{
if ($name == 'id') {
return $this->id;
}
if ($this->hasField($name)) {
if (array_key_exists($name, $this->valuesContainer)) {
return $this->valuesContainer[$name];
}
} else {
if ($this->get('data')) {
$data = json_decode($this->get('data'), true);
} else {
$data = array();
}
if (isset($data[$name])) {
return $data[$name];
}
}
return null;
}
public function set($p1, $p2)
{
if (is_array($p1)) {
if ($p2 === null) {
$p2 = false;
}
$this->populateFromArray($p1, $p2);
return;
}
$name = $p1;
$value = $p2;
if ($name == 'id') {
$this->id = $value;
return;
}
if ($this->hasField($name)) {
$this->valuesContainer[$name] = $value;
} else {
$data = json_decode($this->get('data'), true);
if (empty($data)) {
$data = array();
}
$data[$name] = $value;
$this->set('data', json_encode($data));
}
}
public function populateFromArray(array $arr, $onlyAccessible = true, $reset = false)
{
if ($reset) {
$this->reset();
}
foreach ($arr as $field => $value) {
if (is_string($field)) {
if (is_array($value)) {
$value = json_encode($value);
}
if ($this->hasField($field)) {
$fields = $this->getFields();
$fieldDefs = $fields[$field];
if (!is_null($value)) {
switch ($fieldDefs['type']) {
case self::VARCHAR:
break;
case self::BOOL:
$value = ($value === 'true' || $value === '1' || $value === true);
break;
case self::INT:
$value = intval($value);
break;
case self::FLOAT:
$value = floatval($value);
break;
case self::JSON_ARRAY:
$value = is_string($value) ? json_decode($value) : $value;
if (!is_array($value)) {
$value = null;
}
break;
default:
break;
}
}
}
$this->set($field, $value);
}
}
}
public function toArray()
{
$arr = array();
if (isset($this->id)) {
$arr['id'] = $this->id;
}
foreach ($this->fields as $field => $defs) {
if ($field == 'id') {
continue;
}
if ($this->has($field)) {
$arr[$field] = $this->get($field);
}
}
$data = json_decode($this->get('data'), true);
if (empty($data)) {
$data = array();
}
$arr = array_merge($arr, $data);
return $arr;
}
}

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

@@ -0,0 +1,37 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Entities;
use Espo\Core\Exceptions\Error;
class PhoneNumber extends \Espo\Core\ORM\Entity
{
protected function setName($value)
{
if (empty($value)) {
throw new Error("Phone number can't be empty");
}
$this->valuesContainer['name'] = $value;
}
}

View File

@@ -30,6 +30,10 @@ class Download extends \Espo\Core\EntryPoints\Base
{
public static $authRequired = true;
protected $fileTypesToShowInline = array(
'application/pdf',
);
public function run()
{
$id = $_GET['id'];
@@ -54,13 +58,21 @@ class Download extends \Espo\Core\EntryPoints\Base
if (!file_exists($fileName)) {
throw new NotFound();
}
}
$type = $attachment->get('type');
$disposition = 'attachment';
if (in_array($type, $this->fileTypesToShowInline)) {
$disposition = 'inline';
}
header('Content-Description: File Transfer');
if ($attachment->get('type')) {
header('Content-Type: ' . $attachment->get('type'));
if ($type) {
header('Content-Type: ' . $type);
}
header('Content-Disposition: attachment; filename=' . $attachment->get('name'));
header('Content-Disposition: ' . $disposition . '; filename=' . $attachment->get('name'));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');

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);
}
}

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