Compare commits

..

1169 Commits
5.0.2 ... 5.4.5

Author SHA1 Message Date
yuri
374413eaae version 2018-10-29 10:23:19 +02:00
yuri
96538a2b6f fix order by address 2018-10-29 10:16:07 +02:00
yuri
39a3a6dbd2 users nonAdminReadOnlyAttributeList 2018-10-29 10:15:37 +02:00
yuri
e0705293e1 Merge branch 'hotfix/5.4.4' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.4.4 2018-10-12 15:40:23 +03:00
Taras Machyshyn
29f3f7c330 Bug fixes for utf8mb4 2018-10-12 15:39:09 +03:00
yuri
0e0e81f5ae Merge branch 'hotfix/5.4.4' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.4.4 2018-10-10 17:03:27 +03:00
Taras Machyshyn
bf503db267 LDAP: hide new options 2018-10-09 12:38:09 +03:00
Taras Machyshyn
028ad25fc6 LDAP: bug fixes for portal users 2018-10-09 12:09:00 +03:00
yuri
950d98528a fic ics summary 2018-10-01 13:45:28 +03:00
yuri
8b2d62d27a css navbar fix 2018-10-01 11:13:25 +03:00
yuri
15d5985ec4 Merge branch 'hotfix/5.4.4' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.4.4 2018-09-28 17:20:36 +03:00
Taras Machyshyn
bd94543b71 PHP path 2018-09-28 17:19:58 +03:00
yuri
c54bc30bda validation popover error fix 2018-09-28 12:41:31 +03:00
yuri
f2138a4e23 field view fix 2018-09-28 12:06:46 +03:00
yuri
0e3b3c4193 email address lookup fix 2018-09-26 11:21:39 +03:00
yuri
58c767c0a6 Merge branch 'hotfix/5.4.4' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.4.4 2018-09-25 12:55:29 +03:00
yuri
19b4e91e25 lt_LT lang 2018-09-25 10:56:11 +03:00
yuri
67635f0b20 Merge branch 'hotfix/5.4.4' of github.com:espocrm/espocrm into hotfix/5.4.4 2018-09-25 10:44:17 +03:00
yuri
5d90b4f070 multi-enum w/o option list 2018-09-25 10:43:47 +03:00
yuri
c212eb1f20 array search by not defined options 2018-09-25 10:39:57 +03:00
Taras Machyshyn
5ae0b5a3f2 Case insensitive for LDAP 2018-09-24 16:01:12 +03:00
Xiaolu Hong
06d907d633 update zh_CN (#1054) 2018-09-24 14:26:56 +03:00
Xiaolu Hong
737c5ff2ba update zh_CN (#1052) 2018-09-24 11:03:49 +03:00
yuri
ba19934c06 selectize filter height 2018-09-21 17:01:41 +03:00
yuri
8885bb87be account role 100 2018-09-21 13:29:17 +03:00
yuri
690c873291 account role length 2018-09-21 13:22:11 +03:00
Taras Machyshyn
158cdd27bc LDAP Auth for portal users 2018-09-21 12:35:33 +03:00
yuri
3181e54aa6 lead capture send Access-Control-Allow-Origin on posting 2018-09-19 14:52:56 +03:00
yuri
8028a153af fix max portal user count 2018-09-19 14:27:25 +03:00
yuri
0a03750d26 Merge branch 'hotfix/5.4.4' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.4.4 2018-09-19 14:23:31 +03:00
yuri
e9b1a91180 massUpdate is portal user disabled 2018-09-19 14:23:25 +03:00
Taras Machyshyn
8677dd48ad Bug fixes for portal user limit 2018-09-19 14:18:52 +03:00
yuri
c3d309d07e lead capture config leadCaptureAllowOrigin 2018-09-19 13:32:27 +03:00
yuri
f3d2f0b453 cleanup deleted fix 2018-09-18 16:39:04 +03:00
yuri
fe638db414 orm mid key name fix 2018-09-18 16:37:16 +03:00
yuri
e51be3fd85 lead capture options 2018-09-18 12:49:47 +03:00
yuri
4fd345cb88 Merge branch 'hotfix/5.4.4' of github.com:espocrm/espocrm into hotfix/5.4.4 2018-09-17 12:29:23 +03:00
yuri
41e2de18aa email template disable quick create 2018-09-17 12:29:13 +03:00
yuri
df567a0603 email template placeholder list translation 2018-09-17 12:26:53 +03:00
Yuri Kuznetsov
419fb93a91 Update README.md 2018-09-14 16:48:06 +03:00
yuri
c7473be8c7 readme update 2018-09-14 16:01:21 +03:00
yuri
311a01ef41 lead capture php 5.6 compatibility 2018-09-14 14:02:16 +03:00
yuri
1a163907a3 version 2018-09-14 13:43:17 +03:00
yuri
2acdc00547 fix admin panel iframe height 2018-09-14 13:37:13 +03:00
yuri
b622d8865c fix merge 2018-09-14 13:00:03 +03:00
yuri
786fcfb580 fix email assignment permissin 2018-09-13 16:32:34 +03:00
yuri
eec8512f96 fix import 2018-09-13 14:09:19 +03:00
yuri
be62caef2b fix wysiwyg xss 2018-09-13 14:03:01 +03:00
yuri
eabd52b186 fix xss in global search 2018-09-13 13:44:25 +03:00
yuri
101087680b version 2018-09-12 15:33:04 +03:00
yuri
372f1770e0 kanban move over 2018-09-12 13:07:56 +03:00
yuri
a44dcdc9ff disable kanban dragging on touch devices 2018-09-11 15:57:04 +03:00
yuri
d44b172602 tooltip 2018-09-11 15:06:42 +03:00
yuri
241d7610ba email listen to isRepied 2018-09-11 12:16:42 +03:00
yuri
6929b2d717 mass update skipStreamNotesAcl 2018-09-10 15:24:42 +03:00
yuri
e743f61913 version 2018-09-10 12:17:15 +03:00
yuri
7f4e5dd01a note acl populate script 2018-09-10 12:15:42 +03:00
yuri
8a1b58cf7c fix kanban css 2018-09-10 11:22:22 +03:00
yuri
2a20766912 fix UniquId 2018-09-10 10:29:34 +03:00
yuri
b49679eb90 fix notification id 2018-09-10 10:27:09 +03:00
yuri
b2ea073c16 fix notifications 2018-09-10 10:24:09 +03:00
yuri
54085a59c3 fix meeting acl 2018-09-07 14:38:02 +03:00
yuri
858658768d version 2018-09-07 14:21:18 +03:00
yuri
86421010b9 fix meeting/call select manager 2018-09-07 14:20:01 +03:00
yuri
8675db36f3 stream sql optimization 2018-09-07 11:02:49 +03:00
yuri
f36a98a824 lead capture payload see more disabled 2018-09-06 15:21:45 +03:00
yuri
3c71ff05f3 css fix 2018-09-05 12:53:51 +03:00
yuri
6039939308 css fix 2018-09-05 12:19:06 +03:00
yuri
1ddea9938b fix stream list 2018-09-04 16:56:09 +03:00
yuri
5d3b515ef1 cleanup 2018-09-04 12:08:56 +03:00
yuri
31b7db4033 fix sales pipeline 2018-09-04 12:06:51 +03:00
yuri
6a7d59ba20 sales pipilent labels 2018-09-04 11:55:03 +03:00
yuri
0ab0e46d67 css cleanup 2018-09-03 15:55:21 +03:00
yuri
2777fe49d9 strem note acl fix 2018-09-03 15:17:29 +03:00
yuri
1e246e8197 fix stream acl 2018-09-03 14:41:12 +03:00
yuri
d8eec1068d fix tpl 2018-09-03 14:07:08 +03:00
yuri
0021e16962 stream acl 2018-09-03 13:39:32 +03:00
yuri
b046da1d79 fix css 2018-08-31 16:29:00 +03:00
yuri
2ca8f3af6f fix icon 2018-08-31 15:30:47 +03:00
yuri
b180ac2314 lang fix 2018-08-31 15:14:16 +03:00
yuri
9cc646e3b8 ua lang 2018-08-31 15:07:06 +03:00
yuri
a2fee68732 icon change 2018-08-31 14:24:17 +03:00
yuri
dc0d150000 de lang 2018-08-31 12:58:13 +03:00
yuri
76cc4a8d2c icons change 2018-08-31 12:55:07 +03:00
yuri
6e4c097dee fix image preview 2018-08-30 16:55:26 +03:00
yuri
af398cb5d4 css fix 2018-08-30 15:52:34 +03:00
yuri
3865bba926 css fix 2018-08-30 15:49:40 +03:00
yuri
3ad39d3337 icon change 2018-08-30 15:30:16 +03:00
yuri
1dfe1eb9bf image preview do not resize 2018-08-30 15:15:33 +03:00
yuri
7885a9cac3 fix reminder after save 2018-08-30 14:53:28 +03:00
yuri
bb63751332 entity set as being saved 2018-08-30 14:30:17 +03:00
yuri
083770f705 icon fixes 2018-08-30 12:55:16 +03:00
yuri
a65862325f follow icon change 2018-08-30 12:13:42 +03:00
yuri
9465ca46b2 css fix 2018-08-30 11:50:15 +03:00
yuri
62f05f370f navbar item titles 2018-08-30 11:44:50 +03:00
yuri
8e408d93cb css fix 2018-08-30 11:39:40 +03:00
yuri
7c1d587ae0 search by opted out and bool where redefinition in ORM 2018-08-30 11:30:33 +03:00
yuri
cb42bfe8e7 fix typo 2018-08-30 11:10:30 +03:00
yuri
32a340afe0 icons 2018-08-29 16:39:04 +03:00
yuri
0ff8246a00 font awesome 2018-08-29 16:35:50 +03:00
yuri
c9c58d373a update bootstrap to 3.3.7 2018-08-28 16:49:02 +03:00
yuri
af7aea720b css fixes 2018-08-28 16:15:07 +03:00
yuri
dee488a9de fix lang 2018-08-28 15:06:04 +03:00
yuri
88ec71400a config params 2018-08-28 13:27:30 +03:00
yuri
10ad5a804a note edit delete period 2018-08-28 13:24:26 +03:00
yuri
45f948d96c Merge branch 'hotfix/5.3.7' of ssh://172.20.0.1/var/git/espo/backend 2018-08-27 14:39:54 +03:00
yuri
e5e6a32ce5 email: use mailto if no access to create email 2018-08-27 10:41:09 +03:00
yuri
cf5202a065 calendar: apply acl 2018-08-27 10:32:40 +03:00
yuri
f37a49ddaf fix typo 2018-08-27 10:23:15 +03:00
yuri
4858f964c8 case and target list dynamic logic 2018-08-23 15:27:02 +03:00
yuri
5b50215242 fix json format 2018-08-23 15:25:46 +03:00
yuri
461e356419 lead capture test 2018-08-23 15:08:31 +03:00
yuri
7146f3d3aa fix lead capture 2018-08-23 15:08:24 +03:00
yuri
43d289bc56 es_MX lang 2018-08-23 14:22:48 +03:00
yuri
65c843b581 fix lang 2018-08-23 14:06:23 +03:00
Taras Machyshyn
d08704c95c Warning fixes 2018-08-23 13:00:11 +03:00
yuri
fb9100efdc maintenanceMode param 2018-08-23 12:41:03 +03:00
yuri
ee2182638a service unavalable exception 2018-08-23 12:32:30 +03:00
yuri
8ba9fb4693 cronDisabled param 2018-08-23 12:32:16 +03:00
yuri
b427d8cade fix date time optional fetch 2018-08-23 12:07:21 +03:00
yuri
89de19fd2e css 2018-08-22 12:23:35 +03:00
yuri
2f4df63281 foreign bool 2018-08-21 14:52:37 +03:00
yuri
e12eade143 fix template form 2018-08-21 12:05:59 +03:00
yuri
15b0d147d9 fix attachment 2018-08-21 11:48:41 +03:00
yuri
4901b8c5a0 template fonts labels 2018-08-20 16:30:21 +03:00
yuri
8c4f3b1103 template: ability to pick font 2018-08-20 16:16:10 +03:00
yuri
2225906eac fix kanban 2018-08-20 15:40:17 +03:00
yuri
895b3aa7c9 lang 2018-08-20 12:34:03 +03:00
yuri
67b359ff18 kanban css fix 2018-08-20 12:27:34 +03:00
yuri
62200d393e fix css formatting 2018-08-20 10:50:51 +03:00
yuri
166522e4e6 layout fixes 2018-08-20 10:38:42 +03:00
yuri
cc3d7a9f20 css grid-auto-fill 2018-08-17 16:19:56 +03:00
yuri
81ce479293 Merge branch 'hotfix/5.3.7' 2018-08-17 14:57:16 +03:00
yuri
afa6591903 dashboard fix 2018-08-17 14:48:48 +03:00
yuri
e89cb2547e preferences: ability to reset dashboard to default 2018-08-17 14:20:24 +03:00
yuri
7b982acc3e fix button helper 2018-08-17 12:42:35 +03:00
yuri
e24fc19314 preferences layout change 2018-08-17 12:11:57 +03:00
yuri
0d9473b1e9 version 2018-08-17 12:00:28 +03:00
yuri
db4ccbe590 clean up deleted records 2018-08-17 11:39:58 +03:00
yuri
f085d2140c fix strip url 2018-08-16 16:47:16 +03:00
yuri
4f2117453d lang 2018-08-16 15:49:21 +03:00
yuri
919fff6cd5 activities compose email change 2018-08-16 12:59:42 +03:00
yuri
b77f0a705e css fix 2018-08-16 12:04:22 +03:00
yuri
73699894be update window title after save 2018-08-16 11:50:39 +03:00
yuri
4282d1766b fix flotr2 with touch enabled 2018-08-16 11:43:05 +03:00
yuri
3ebb9ea8fc import acl check edit 2018-08-15 16:18:55 +03:00
yuri
5635fddf3d import for regular users 2018-08-15 15:59:46 +03:00
yuri
9501e116cb app error log 2018-08-15 15:45:19 +03:00
yuri
c0997f1d97 fix remove fail 2018-08-15 15:15:22 +03:00
yuri
106961ff03 import fix 2018-08-15 13:56:42 +03:00
yuri
fd2b9cc818 import acl 2018-08-15 13:52:35 +03:00
yuri
d90853ff73 fix lead capture 2018-08-15 13:51:52 +03:00
yuri
a8bcd1dc2f import naming fixes 2018-08-15 13:26:31 +03:00
yuri
1f4ae0f07c date list title 2018-08-15 12:54:30 +03:00
yuri
cf0a9fd808 attachments fixes 2018-08-15 12:47:41 +03:00
yuri
036e10cbf7 fix test 2018-08-15 12:21:48 +03:00
yuri
0a22510566 orm fixes 2018-08-15 12:02:20 +03:00
yuri
44f14c1d29 amount weighted filter 2018-08-15 11:21:10 +03:00
yuri
e6796390db fix login logo 2018-08-14 17:29:15 +03:00
yuri
c11d52cef6 css fix 2018-08-14 16:35:37 +03:00
yuri
33e8b8b0c1 fix email phone add button 2018-08-14 15:35:18 +03:00
yuri
04dbe9129a Merge branch 'hotfix/5.3.7' 2018-08-14 15:22:09 +03:00
yuri
8e1a4ba368 IRR currency 2018-08-14 15:19:41 +03:00
yuri
920b5244a8 attachment filter fix 2018-08-14 14:53:17 +03:00
yuri
cd57f6c600 fix color icon linebreak issue 2018-08-14 14:29:09 +03:00
yuri
7e6a32ab06 attachmets list view 2018-08-14 13:36:04 +03:00
yuri
ee0dc257b2 lang 2018-08-14 11:58:37 +03:00
yuri
a8e6421517 cleanup attachments 15 days 2018-08-14 11:17:17 +03:00
yuri
1c5d2bd756 cleanup attachment limit 5000 2018-08-14 11:14:48 +03:00
yuri
1fc59b28aa Merge branch 'hotfix/5.3.7' 2018-08-14 11:09:31 +03:00
yuri
ed603c5f98 email template skip acl 2018-08-14 10:40:13 +03:00
yuri
0b7743419e array value cleanup 2018-08-14 10:25:10 +03:00
yuri
81ff01e9be array value 2018-08-13 15:43:44 +03:00
yuri
4845622949 fix iframe scroll on mobile 2018-08-13 14:48:18 +03:00
yuri
122cd9c56d orm: join table, join conditions, where not value conditions 2018-08-13 12:46:34 +03:00
yuri
379562b0d7 code style fix 2018-08-10 16:45:54 +03:00
yuri
c72d6d928a Merge branch 'hotfix/5.3.7' 2018-08-10 16:08:12 +03:00
yuri
b09c1366e3 fix email folder select manager 2018-08-10 15:11:56 +03:00
yuri
00e0427fdd options max length 2018-08-10 14:52:05 +03:00
yuri
85f888d60b relatin name max length 2018-08-10 14:46:28 +03:00
yuri
f22856dd91 field max length 100 2018-08-10 14:43:31 +03:00
yuri
5673d253e4 entity manager name maxlength 2018-08-10 14:41:37 +03:00
yuri
27ce836d4a currency entity class 2018-08-10 14:33:51 +03:00
yuri
a490ded36a fix field view fetch 2018-08-10 14:33:10 +03:00
yuri
bd54195403 Merge branch 'hotfix/5.3.7' 2018-08-10 11:08:59 +03:00
yuri
21d8e291e4 array field search type 2018-08-09 16:25:58 +03:00
yuri
b4fa62b403 parentName in assignment notification 2018-08-09 13:11:58 +03:00
yuri
1f3d7063d2 fix lead capture 2018-08-09 11:58:27 +03:00
yuri
e5709571e4 Merge branch 'hotfix/5.3.7' 2018-08-09 11:50:11 +03:00
yuri
a80d847f44 meeting duration list view 2018-08-09 11:38:40 +03:00
yuri
9de7105cde date field list link 2018-08-09 11:33:25 +03:00
yuri
cd7cc188e1 valueIsSet fields 2018-08-09 11:15:02 +03:00
yuri
e68a5f1979 fix phone number ui 2018-08-09 11:01:27 +03:00
yuri
c3e16a896e css fix 2018-08-08 14:52:48 +03:00
yuri
eafd0c3840 hide followers if empty 2018-08-08 13:18:16 +03:00
yuri
d5b5bb31c7 css fix 2018-08-08 13:03:00 +03:00
yuri
eaab96732a version 2018-08-08 12:52:30 +03:00
yuri
0dfed7279e css fix 2018-08-08 12:52:08 +03:00
yuri
b0e973d8ba fix multi enum 2018-08-08 12:07:37 +03:00
yuri
1d809c10b0 css fix 2018-08-08 11:33:01 +03:00
yuri
e0279f403f update font awesome icons 2018-08-08 11:16:48 +03:00
yuri
fa75da658c css fix 2018-08-08 10:57:13 +03:00
yuri
d23689aab7 cleanup 2018-08-08 10:35:32 +03:00
yuri
d4cc305265 fix account tasks panel 2018-08-08 10:34:22 +03:00
yuri
695d4b0cda lead capture job rename 2018-08-07 15:57:08 +03:00
yuri
2107d93cd2 phone number numeric 2018-08-07 15:55:06 +03:00
yuri
fb256ca29f orm noSelect param 2018-08-07 15:17:14 +03:00
yuri
557bcb4ecd lead capture 2018-08-07 13:18:43 +03:00
yuri
50a272473b fix formula modal 2018-08-06 12:31:11 +03:00
yuri
0eb9544371 jquery ui sortable on touch screens 2018-08-06 10:51:05 +03:00
yuri
620fa607d4 css fix 2018-08-06 10:39:40 +03:00
yuri
304d216b0e move to folder max size 2018-08-06 10:30:04 +03:00
yuri
ce2fe9d50c Merge branch 'stable' 2018-08-03 14:15:01 +03:00
yuri
eadf7835db fix css 2018-08-03 13:16:22 +03:00
yuri
048f65c8f6 record view ref 2018-08-03 11:57:35 +03:00
yuri
c30c4163a6 increase container max size 2018-08-02 16:21:40 +03:00
yuri
8d6db72516 icons fix 2018-08-02 15:08:32 +03:00
yuri
71864056bc navbar panel height 2018-08-02 15:05:00 +03:00
yuri
e375105a5f Merge branch 'hotfix/5.3.6' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.3.6 2018-08-02 13:28:18 +03:00
Taras Machyshyn
e066f4c6b0 Merge branch 'hotfix/5.3.6' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.3.6 2018-08-02 13:27:08 +03:00
Taras Machyshyn
b032aa4d8d Upgrades bug fixes 2018-08-02 13:26:46 +03:00
yuri
342a18e0ac fix installer css 2018-08-02 12:59:12 +03:00
yuri
e27e9de701 attachment preview resize 2018-08-02 12:37:16 +03:00
yuri
b14b199d43 preview resize fix 2018-08-02 12:28:14 +03:00
yuri
f77a7c32d5 link multiple preview size param 2018-08-02 12:04:33 +03:00
yuri
9f84d3f233 notifications attachment preview small size 2018-08-02 11:56:00 +03:00
yuri
be82244c6b showing attachments in notifications 2018-08-02 11:30:28 +03:00
yuri
7fed72d391 fix image sized download extension 2018-08-02 10:55:39 +03:00
yuri
54d615b64d fix attachment preview in list 2018-08-02 10:46:16 +03:00
yuri
2dbbd1e23d Merge branch 'hotfix/5.3.6' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.3.6 2018-08-02 10:30:55 +03:00
Taras Machyshyn
cba8867389 Bug fixes for MySQL 8 2018-08-01 18:49:40 +03:00
yuri
32d47db15a emailFolderMaxCount 2018-08-01 11:16:50 +03:00
yuri
2c65c9ff9f modal select attributes 2018-08-01 11:13:00 +03:00
yuri
fa5d63253b naming fix 2018-08-01 10:46:48 +03:00
yuri
b7ae252d3d modal forceSelectAllAttributes 2018-08-01 10:24:41 +03:00
yuri
f07b43abda version 2018-07-30 16:05:13 +03:00
yuri
276db37baf required extensions change 2018-07-30 16:03:20 +03:00
yuri
6adad84a29 installer config formatting 2018-07-30 15:52:16 +03:00
yuri
f137298c49 add exif extension 2018-07-30 15:50:17 +03:00
yuri
f8839518d5 avatar check exif read data exists 2018-07-30 15:48:00 +03:00
yuri
1ae39d1a40 fix campaign revenue empty 2018-07-30 10:20:45 +03:00
yuri
94f920324e fix case compose email 2018-07-30 10:14:17 +03:00
yuri
dbc3f7c7d6 Merge branch 'hotfix/5.3.5' 2018-07-27 12:35:42 +03:00
yuri
94c00e2901 orm: revert forcing updating json object 2018-07-27 11:59:22 +03:00
yuri
7de988104b link multiple attachment multiple list view fixes 2018-07-27 11:55:19 +03:00
yuri
03bc90968c fix email sending 2 2018-07-27 11:32:29 +03:00
yuri
a5401a22b9 fix email sending 2018-07-27 11:13:49 +03:00
yuri
4c1375d8b2 user buttons links 2018-07-27 10:46:18 +03:00
yuri
bab4a3b0d6 fix full text 2018-07-27 10:40:48 +03:00
yuri
33e135f227 fix email fetching 2018-07-27 10:03:26 +03:00
yuri
56b9d8d5c1 fix campaign 2018-07-26 17:56:35 +03:00
yuri
38ec88e302 fix formatting 2018-07-26 17:02:31 +03:00
yuri
10be208d8d fix linkedWith filter 2018-07-26 12:26:25 +03:00
yuri
38d227a948 fix model sync 2018-07-26 10:55:55 +03:00
yuri
1a8e4435e2 use put istead of patch 2018-07-25 15:04:33 +03:00
yuri
12febbdff5 version 2018-07-25 12:44:45 +03:00
yuri
ebea168350 field ui fixes 2018-07-25 12:41:48 +03:00
yuri
704519f80b fix setFetched link multiple and link one 2018-07-25 11:38:48 +03:00
yuri
5f1000ddd3 fix audited 2018-07-25 11:04:17 +03:00
yuri
2ee7e6cf4a orm: isUnordered param 2018-07-25 10:57:53 +03:00
yuri
2989975829 audited fix 2018-07-25 10:41:39 +03:00
yuri
a4c068427d cleanup 2018-07-24 18:22:54 +03:00
yuri
e1a76b9924 orm: isAttributeChanged improvement 2018-07-24 18:22:04 +03:00
yuri
1f2efcd716 link multiple available in list fix 2018-07-23 12:59:04 +03:00
yuri
576dfe068f fix array field setOptionList 2018-07-20 15:51:21 +03:00
yuri
f76860cdfd Merge branch 'stable' 2018-07-19 17:01:24 +03:00
yuri
56f8e68599 fix wysiwyg width 2018-07-19 14:56:28 +03:00
yuri
e8d75808ef fix email scrolling 2018-07-19 14:43:35 +03:00
yuri
bc8bf89d6e css fixes 2018-07-19 12:14:06 +03:00
yuri
91385cc3f0 fix naming 2018-07-19 11:49:43 +03:00
yuri
ad21511c72 email list is replied fix 2018-07-19 11:44:40 +03:00
yuri
938a24f102 fix assignment email notificaiotion 2018-07-19 10:59:32 +03:00
yuri
43b041ed6c fix replied icon 2018-07-18 15:37:37 +03:00
yuri
5e3f048795 replied email icon 2018-07-18 14:57:12 +03:00
yuri
3aec3ef6d2 formula higher 2018-07-18 11:37:55 +03:00
yuri
712a450734 formula mb string functions 2018-07-18 11:35:31 +03:00
yuri
5675b6721b sort by list comma fix 2018-07-18 11:25:58 +03:00
yuri
a4e23b8adb formula parser fix 2018-07-18 10:29:06 +03:00
yuri
9d49f418c8 orm fix order list 2018-07-18 10:11:36 +03:00
yuri
ea9f70dffa global search ability to select text 2018-07-17 17:26:06 +03:00
yuri
b624accbe8 version 2018-07-17 17:07:50 +03:00
yuri
12f974635e global search fixes 2018-07-17 17:07:32 +03:00
yuri
cfce68eb7e default panel complex fields 2018-07-17 15:38:44 +03:00
yuri
db8fbd1ed3 hide default panel if empty 2018-07-17 14:39:54 +03:00
yuri
7c549556ac Merge branch 'hotfix/5.3.3' 2018-07-17 11:15:22 +03:00
yuri
06395f3ff5 Merge branch 'hotfix/5.3.3' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.3.3 2018-07-16 15:48:49 +03:00
Taras Machyshyn
4065ec5477 Test fixes 2018-07-16 15:48:25 +03:00
yuri
31d45a0583 Merge branch 'hotfix/5.3.3' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.3.3 2018-07-16 14:20:29 +03:00
yuri
696faa4468 fix wysiwyg toolbar 2018-07-16 14:20:19 +03:00
Taras Machyshyn
625876f123 Merge branch 'hotfix/5.3.3' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.3.3 2018-07-16 14:06:54 +03:00
Taras Machyshyn
974cd05276 Integration test for fulltext index 2018-07-16 14:06:37 +03:00
yuri
fb5db991a3 fix vars 2018-07-16 13:37:00 +03:00
yuri
3dafb7e922 fix categories 2018-07-16 13:12:09 +03:00
yuri
ee640273a1 fix stream attachments 2018-07-16 10:51:55 +03:00
yuri
b92de17f72 Merge branch 'hotfix/5.3.3' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.3.3 2018-07-13 16:55:22 +03:00
Taras Machyshyn
abc48ca76f Fulltext bug fixes 2018-07-13 16:52:02 +03:00
yuri
46443aae7e fix full text search 2018-07-13 16:37:32 +03:00
yuri
a88c3283d6 full text search fix 2018-07-13 16:33:19 +03:00
yuri
2b9653ee0b replace tabs 2018-07-13 14:53:37 +03:00
yuri
2cf79abdb1 fix list view remove 2018-07-13 14:49:56 +03:00
yuri
20a000a46c fix full text search 2018-07-13 12:33:21 +03:00
ayman-alkom
95bfd5bace fix typo (#968) 2018-07-13 11:51:34 +03:00
ayman-alkom
a6b5f38aed fix typo (#968) 2018-07-13 11:49:44 +03:00
yuri
da736008f1 version 2018-07-13 11:19:49 +03:00
yuri
1de98d9616 text filter fixes 2018-07-13 11:19:30 +03:00
yuri
31a6143cc3 email template text filter 2018-07-13 11:07:34 +03:00
yuri
8502a84a3f chart mousetick fix 2018-07-12 12:52:05 +03:00
yuri
2234678728 email search tests 2018-07-12 11:31:44 +03:00
yuri
92fedd2c2e Merge branch 'hotfix/5.3.2' of ssh://172.20.0.1/var/git/espo/backend 2018-07-12 10:09:31 +03:00
Taras Machyshyn
0ec450d59d Schema bug fixes 2018-07-12 10:09:01 +03:00
yuri
f0a1634f90 version 2018-07-12 10:03:04 +03:00
Taras Machyshyn
5b5f5c8ab7 Schema bug fixes 2018-07-11 15:16:59 +03:00
yuri
19d37e8081 text filter disabling 2018-07-11 11:04:01 +03:00
yuri
d8ab10fd75 textFilterDisabled param 2018-07-11 10:37:17 +03:00
yuri
312de11a15 smtp local host name 2018-07-10 15:53:15 +03:00
yuri
47a22042b2 fix select records 2 2018-07-10 13:13:07 +03:00
yuri
31cea9e36e fix select records 2018-07-10 12:26:37 +03:00
yuri
2b983ad880 fix attachment multiple 2018-07-10 12:11:45 +03:00
yuri
21b0c2b2eb attachment multiple in list view 2018-07-10 11:58:11 +03:00
yuri
59b4aa61e4 not sortable by default 2018-07-10 11:36:20 +03:00
yuri
25d91a1e73 Merge branch 'hotfix/5.3.1' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.3.1 2018-07-09 13:36:24 +03:00
yuri
6750d32bd6 skip printing x status reason for pdo exception 2018-07-09 13:30:36 +03:00
yuri
70b8fc9ac9 foreign field: supporting number field 2018-07-09 12:52:55 +03:00
yuri
38a1be5ae3 version 2018-07-09 12:04:26 +03:00
yuri
1d9e9752c8 mass remove memory usage 2018-07-09 12:03:45 +03:00
yuri
eb37c1dc47 fix email text filter by email 2018-07-09 11:58:31 +03:00
yuri
1df6ec7f0c mass update improvement memory usage 2018-07-09 11:52:33 +03:00
yuri
1d6ee3e030 clean up 2018-07-09 11:37:39 +03:00
yuri
6eb80b747c login view name in clientDefs 2018-07-09 11:14:28 +03:00
yuri
539c0d22d7 convert lead skip disabled entity types 2018-07-09 10:54:29 +03:00
yuri
8e7d607ad4 fix dynamic logic not has 2018-07-09 10:49:44 +03:00
yuri
59e15eb71f fix select all results modal 2018-07-09 10:48:36 +03:00
Taras Machyshyn
c1ba6d5330 Metadata improvements 2018-07-06 17:02:19 +03:00
yuri
410aec734a lead select name fix 2018-07-05 17:21:58 +03:00
yuri
6078b17d38 export memory usage optimization 2018-07-05 16:47:20 +03:00
yuri
3b36d607ac code style 2018-07-05 16:20:36 +03:00
yuri
156cd85474 export memory usage improvement 2018-07-05 16:18:06 +03:00
yuri
0e29798e2b cleanup 2018-07-05 15:41:03 +03:00
yuri
19dbe81c79 hide followers in portal 2018-07-05 11:13:51 +03:00
yuri
62838961bb record max size limit improvement 2018-07-05 11:09:20 +03:00
yuri
ee84162470 createDisabled for modal select records 2018-07-03 12:22:12 +03:00
yuri
7a76dcce2c email to case copy body and attachments 2018-07-03 12:13:28 +03:00
yuri
0c21ed2e31 fix case 2018-07-03 11:50:53 +03:00
yuri
39daa763ab use numberic format param 2018-07-03 11:41:39 +03:00
yuri
f0c9690152 opp mandatory account 2018-07-03 11:32:10 +03:00
yuri
450091e71f contact mandatory account id 2018-07-03 11:31:28 +03:00
yuri
3a5c64b877 email skip replyTo when adding user 2018-07-02 15:16:33 +03:00
yuri
949d96db7a fix expanded list css 2018-07-02 14:58:16 +03:00
yuri
c974ce8864 entity manager check exists 2018-07-02 11:21:54 +03:00
yuri
caab8e9bbb custom calendar views 2018-07-02 11:05:02 +03:00
Taras Machyshyn
12469ee6f9 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-06-29 16:04:06 +03:00
Taras Machyshyn
dcd90b6f70 AdminNotifications improvements 2018-06-29 16:03:43 +03:00
Taras Machyshyn
f92b3c3d16 Bug fixes in Util 2018-06-29 16:02:45 +03:00
yuri
f3b41783c5 fix campaingn stats 2018-06-29 15:50:31 +03:00
yuri
3ec33c6054 fix currency converted hook 2018-06-29 15:36:34 +03:00
yuri
eb7c0da40c naming fix 2018-06-29 15:30:00 +03:00
yuri
2817c0027e fix campaign log record 2018-06-29 15:28:52 +03:00
yuri
c7457b95d1 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-06-29 14:29:55 +03:00
yuri
05244d598c email teams improvements 2018-06-29 13:08:49 +03:00
Taras Machyshyn
f55e0b2cb0 Minor bug fixes 2018-06-29 12:36:52 +03:00
Taras Machyshyn
ed6256da2c Possibility to check new versions of extensions 2018-06-29 12:10:25 +03:00
Taras Machyshyn
0398137ba7 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-06-28 16:36:03 +03:00
yuri
a6448a2769 kanban support link multiple fields 2018-06-28 13:07:31 +03:00
yuri
71cf0d01f8 fix template 2018-06-28 11:29:49 +03:00
yuri
d2a6d7ee99 fix event confirmation 2018-06-28 11:28:36 +03:00
yuri
a07bc15f00 fix typo 2018-06-28 11:26:22 +03:00
yuri
52ebd35785 supporting link multiple field on the list view 2018-06-28 11:20:13 +03:00
Taras Machyshyn
636d24a117 Check version url for extensions 2018-06-27 17:33:10 +03:00
yuri
8afbfaeb31 view jobs button 2018-06-27 11:19:49 +03:00
yuri
117084f835 fix sorting by index 2018-06-27 11:08:00 +03:00
yuri
eae92d8638 version 2018-06-27 10:52:41 +03:00
yuri
31f5df9db4 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-06-27 10:48:25 +03:00
Taras Machyshyn
00419a4cfc Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-06-26 18:02:05 +03:00
Taras Machyshyn
3f36e5b2e8 Bug fixes 2018-06-26 18:01:52 +03:00
Taras Machyshyn
cc2abc961e Fulltext index Fixes 2018-06-26 16:47:44 +03:00
yuri
bea0398776 grunt clean custom dir 2018-06-26 16:08:13 +03:00
yuri
fd4c55ba9d Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-06-26 15:05:35 +03:00
Taras Machyshyn
fef5edce28 Fulltext index changes 2018-06-26 15:05:21 +03:00
Taras Machyshyn
6423e4cb68 Changing text to medium types for fulltext index fields 2018-06-26 15:01:58 +03:00
yuri
2acaf1f7ff orm: 0 result if not existing attribnure is used in where 2018-06-26 12:35:24 +03:00
yuri
fe31b078f6 full-text search for email 2018-06-26 11:30:55 +03:00
yuri
e3d81f4a61 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-06-26 11:26:18 +03:00
yuri
fb1d1d8fc5 fix import 2018-06-26 11:15:16 +03:00
yuri
cabef5906c fix list view 2018-06-25 14:29:39 +03:00
Taras Machyshyn
2dfffe00d0 Database helper improvements 2018-06-25 13:03:07 +03:00
yuri
78390efe45 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-06-25 11:29:10 +03:00
yuri
8ae0d2da88 email: add teams from replied 2018-06-25 11:24:58 +03:00
Taras Machyshyn
ecb3273883 Possibility to check if table supports fulltext index 2018-06-25 11:08:51 +03:00
yuri
256b94f877 fix panels row actions links 2018-06-25 10:54:21 +03:00
yuri
422f02b5c9 text filter supporting int and autoincrement fields 2018-06-22 17:00:48 +03:00
yuri
7e4c31db1a relationship proper orm attribute type 2018-06-22 16:03:31 +03:00
yuri
c9918c07b8 htmlizer var helper 2018-06-22 15:59:51 +03:00
Taras Machyshyn
ed438b1a31 Code improvements 2018-06-22 15:46:02 +03:00
yuri
83843cfe46 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-06-22 14:47:30 +03:00
yuri
462de7b025 fix fulltext 2018-06-22 12:51:14 +03:00
yuri
01dbc183f8 fix email text search 2018-06-22 12:30:07 +03:00
yuri
8817c82996 fix select attributes 2018-06-22 12:02:03 +03:00
yuri
3493addec5 print pdf mass max 50 2018-06-22 11:20:42 +03:00
yuri
d41a588bb5 disable full text for email 2018-06-22 11:15:16 +03:00
Taras Machyshyn
7953705e30 MEDIUMTEXT is a default text type 2018-06-21 19:00:36 +03:00
Taras Machyshyn
763a1ad96f Possibility to ignore creating fulltext indexes 2018-06-21 18:59:34 +03:00
yuri
b58d958f51 mb string functions 2018-06-21 16:10:16 +03:00
yuri
0b8d43f734 fixes 2018-06-21 14:21:38 +03:00
yuri
87518f33a9 full-text search 3 2018-06-21 12:53:12 +03:00
yuri
d83530bbf6 fix massDelete 2018-06-20 16:53:15 +03:00
yuri
517e1bab7c serach by email address performance improvement 2018-06-20 16:01:37 +03:00
yuri
cd22552e4a entity manager full-text search parameter 2018-06-20 15:24:39 +03:00
yuri
abc394512c Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-06-20 15:07:06 +03:00
yuri
fa0cb01660 full text search 2 2018-06-20 14:51:50 +03:00
Taras Machyshyn
e6d509bd0b Added support fulltext index 2018-06-20 14:37:23 +03:00
yuri
775641aee1 fix globals search name field 2018-06-20 12:20:34 +03:00
yuri
3c51c6bc77 remove test 2018-06-19 18:46:59 +03:00
yuri
9ddd7b1d32 Merge branch 'hotfix/5.2.6' 2018-06-19 18:44:54 +03:00
yuri
6020a01a62 fix orm empty in 2018-06-19 18:44:47 +03:00
yuri
1ad9ee10f6 full text search 2018-06-19 17:29:12 +03:00
yuri
59863b8a91 test 2018-06-19 15:51:22 +03:00
yuri
1a083c247c fix css 2018-06-19 15:48:14 +03:00
yuri
cd7ca31212 orm query: supporting match 2018-06-19 15:35:30 +03:00
yuri
9be9ff3d68 mass print to pdf 2018-06-19 12:16:07 +03:00
yuri
e3b1ead830 fix acl manager empty action 2018-06-19 12:14:11 +03:00
yuri
b6041592ea fix job select attributes 2018-06-19 11:58:15 +03:00
yuri
0fa8b3da0b mail merge only with address 2018-06-18 16:13:36 +03:00
yuri
7dd0fe07ac fixes 2018-06-18 15:23:04 +03:00
yuri
2d1770f439 ignore select attributes 2018-06-18 15:11:50 +03:00
yuri
6be192514a force select all attributes 2018-06-18 15:06:46 +03:00
yuri
63fc42f8cf email mandatory select attributes 2018-06-18 14:47:32 +03:00
yuri
6f8a593f09 list select changes 2018-06-18 14:45:20 +03:00
yuri
b00e8f8900 merge 2018-06-18 14:26:00 +03:00
yuri
4e226ebcb7 select records button disable 2018-06-18 14:23:04 +03:00
yuri
30909c497b record dashlet populate assigned user 2018-06-18 14:14:48 +03:00
yuri
efd5ccfa96 list view select only attributes from layout 2018-06-18 13:23:35 +03:00
yuri
88d159d4c6 field manager load language after save 2018-06-15 15:28:45 +03:00
yuri
29788c353b link manager ui prevent existing link names 2018-06-15 15:18:43 +03:00
yuri
7897272f65 mail merge 2018-06-15 15:03:22 +03:00
yuri
5cabc76782 Merge branch 'hotfix/5.2.6' 2018-06-15 15:02:54 +03:00
yuri
b0ef416a4f target list listed status 2018-06-14 17:23:51 +03:00
yuri
0de0768bfb remove et category from layout manager 2018-06-14 17:16:08 +03:00
yuri
e4ac128a2e cleanup 2018-06-14 15:39:51 +03:00
yuri
2307f21d04 version 2018-06-14 15:15:15 +03:00
yuri
89d706c94f layout manager default panel 2018-06-14 13:00:18 +03:00
yuri
23350a0ffe field manager tpl fix 2018-06-14 12:04:02 +03:00
yuri
65d047f831 skip default opt out for users 2018-06-14 11:58:36 +03:00
yuri
dc40045de6 fix css 2018-06-14 11:57:01 +03:00
yuri
50d91ea6d8 email folder count 200 2018-06-14 11:50:33 +03:00
yuri
3a8865e382 calendar task creating fix 2018-06-14 11:47:47 +03:00
yuri
fddcef284f fix calendar task 2018-06-14 10:48:57 +03:00
yuri
c0854250e4 cleanup 2018-06-12 14:47:27 +03:00
yuri
71c9501354 cleanup 2018-06-12 14:38:25 +03:00
yuri
a85d0f91a2 layout manager panels dynamic logic 2018-06-12 14:34:57 +03:00
yuri
977514f5ef fix panels css 2018-06-12 13:22:17 +03:00
yuri
bf9ad953a1 lead converted panel use dynamic logic 2018-06-12 12:52:32 +03:00
yuri
5b1d96f649 ability to remove notifications for regular users 2018-06-12 11:24:53 +03:00
yuri
bf4ac0c9f3 opp detect closed stages by probability 2018-06-11 15:16:28 +03:00
yuri
3c8b2534eb opp last stage field 2018-06-11 15:06:19 +03:00
yuri
16c9f46583 countRelated subRelated functions 2018-06-11 12:01:52 +03:00
yuri
ef9609b710 target list listed status 2018-06-08 16:00:31 +03:00
yuri
a4c15992a9 fix calendar task 2018-06-08 14:20:35 +03:00
yuri
14d1173a0c calendar prevent drag between allday and hours 2018-06-08 14:01:06 +03:00
yuri
1e7acbdbd2 fix calendar 2018-06-08 12:47:11 +03:00
yuri
35e729b25c Merge branch 'hotfix/5.2.5' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.2.5 2018-06-08 12:12:18 +03:00
Taras Machyshyn
4ee5ea78e3 LDAP bug fixes 2018-06-08 12:11:32 +03:00
yuri
fe971f9f67 outboundEmailBccAddress on ui 2018-06-08 11:30:04 +03:00
yuri
a828523f26 external email client for email address field link 2018-06-08 11:25:32 +03:00
yuri
af9ca6788e re-render header on name change after sync 2018-06-07 16:28:48 +03:00
yuri
36d1c3af63 version 2018-06-07 13:58:52 +03:00
yuri
1853e98209 wysiwyg text filters support 2018-06-07 12:43:38 +03:00
yuri
f526d43798 improve dynamic logic conditions ui 2018-06-07 12:30:38 +03:00
yuri
ae8c76cecb fix select manager 2018-06-07 10:48:48 +03:00
yuri
2b32c94543 Merge branch 'hotfix/5.2.5' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.2.5 2018-06-07 10:45:38 +03:00
Taras Machyshyn
b6f5909df1 MySQL 8 bug fixes 2018-06-06 16:44:06 +03:00
yuri
ef35bbbb63 import: setting null for wrong date time 2018-06-05 13:11:34 +03:00
yuri
64f2cc6c7e fix import varchar length exceeded 2018-06-05 13:03:00 +03:00
yuri
a16635eb26 fix import ui 2018-06-05 13:02:31 +03:00
yuri
6e614f0a7d history has attachment 2018-06-04 16:40:07 +03:00
yuri
859f4eab0a target list panels change order 2018-06-04 14:33:11 +03:00
yuri
104e0b9079 target list changes 2 2018-06-04 14:25:00 +03:00
yuri
612abbf5c0 fix range fields 2018-06-04 12:46:54 +03:00
yuri
2dfbf71806 target list changes 2018-06-04 12:39:57 +03:00
yuri
c43f4d129d fix calendar 2018-06-04 10:47:14 +03:00
yuri
8d47a48f62 lang fix 2018-06-04 10:44:55 +03:00
yuri
9a333e6e38 list layout widthPx preserving 2018-06-01 12:07:45 +03:00
yuri
f6e0ef8cc6 layout manager data attribute list for custom layouts 2018-06-01 11:37:53 +03:00
yuri
36a45717f1 fix excel export varchar 2018-05-31 11:47:34 +03:00
yuri
86f63d72e1 fix list expanded 2018-05-31 11:41:38 +03:00
yuri
ade4078f0d fix kanban sort 2 2018-05-30 16:33:14 +03:00
yuri
fdeac68216 fix kanban sorting 2018-05-30 16:14:15 +03:00
yuri
4c220a5a65 version 2018-05-30 15:50:10 +03:00
yuri
f148bd82c5 fix kanban 2018-05-30 15:48:36 +03:00
yuri
0d983ef34c fix create new field name 2018-05-30 15:40:41 +03:00
yuri
75ad9f5cf2 email body fit height fix 2018-05-30 15:37:33 +03:00
yuri
893efe212e email template category layouts 2018-05-30 12:06:39 +03:00
yuri
4a4d2e473f version 2018-05-30 11:48:36 +03:00
yuri
9d663ad140 email template categories 2018-05-30 11:41:48 +03:00
yuri
f377dfc5b1 wysiwyg use iframe 2018-05-30 10:56:18 +03:00
yuri
a4054f5273 keep initial attachments on forward email 2018-05-30 10:47:20 +03:00
yuri
fcc3ac978f mass email track opened img alt 2018-05-30 10:40:59 +03:00
yuri
2bbeaa8198 es_MX lang fixes 2018-05-30 10:34:41 +03:00
yuri
70308d19ae hu and sk languages 2018-05-30 10:26:58 +03:00
yuri
143897cf18 fix set fetched link multiple 2018-05-30 10:18:44 +03:00
yuri
ddc90a05d9 fix email template insertion 2018-05-25 10:15:14 +03:00
yuri
bbbadb1c32 version 2018-05-24 14:35:10 +03:00
yuri
8995835d8e email attach in toolbox 2018-05-24 14:16:51 +03:00
yuri
df3c119f5f wysywyg stick toolbar 2018-05-24 13:57:48 +03:00
yuri
6a2ba73412 fix orm 2018-05-23 15:22:00 +03:00
yuri
cbee8cc541 version 2018-05-23 15:12:51 +03:00
yuri
22f186af29 fix label manager 2018-05-22 14:41:16 +03:00
yuri
77ab385db8 fix client manager exit 2018-05-22 10:25:48 +03:00
yuri
13495ee32e fix rdb 2018-05-21 11:16:39 +03:00
yuri
254ce7d5d2 email-to-case contact 2018-05-21 10:34:24 +03:00
yuri
4e1053d037 lang fix 2018-05-21 10:31:13 +03:00
yuri
2fcc6e168f orm setAsFetched fix 2018-05-21 10:30:22 +03:00
yuri
96ea0ae690 pl_PL lang fix 2018-05-18 14:40:41 +03:00
yuri
aa66001981 fix personal email account check 2018-05-18 12:00:37 +03:00
yuri
173ff943a4 next number fix 2018-05-18 11:48:51 +03:00
yuri
79ac73bb95 cleanup 2018-05-18 11:43:53 +03:00
yuri
2143832c25 cleanup 2018-05-18 11:42:51 +03:00
yuri
c656e36265 export timeout 2018-05-18 11:41:20 +03:00
yuri
8564adca6a fix portal assinment permission 2018-05-18 11:37:05 +03:00
yuri
19c9922115 fix navbar 2018-05-18 11:19:33 +03:00
yuri
b22a6f204a fix export 2018-05-15 13:33:51 +03:00
yuri
daa0cf9fc9 fix calendar 2018-05-15 12:52:28 +03:00
yuri
6365aa04df fix 2018-05-15 12:23:26 +03:00
yuri
ff20e077b1 fix 2018-05-15 12:19:49 +03:00
yuri
1106aaf18e fix 2018-05-15 12:15:13 +03:00
yuri
872ba225b4 fix 2018-05-15 12:13:15 +03:00
yuri
95c15efa92 fix typo 2018-05-15 11:57:34 +03:00
yuri
c179cec8a0 fix attachment multiple 2018-05-15 11:50:59 +03:00
yuri
97f96396c5 fix 2018-05-15 11:28:08 +03:00
yuri
e05cac1261 fix kanban 2018-05-15 11:21:50 +03:00
yuri
f9d8894f37 fix email field 2018-05-15 11:09:40 +03:00
yuri
5bd5a76722 fix person name 2018-05-15 11:06:09 +03:00
yuri
2fbb4f3725 fix email address 2018-05-15 11:02:29 +03:00
yuri
61e1b18eb9 opted out bool field 2018-05-14 16:50:12 +03:00
yuri
08c1710326 fix erase persoanal data 2018-05-14 15:59:14 +03:00
yuri
39d3baf1b5 fix stream 2018-05-14 15:57:35 +03:00
yuri
fd4753d190 email template info panel fix 2018-05-14 15:48:32 +03:00
yuri
29745367f7 tr_TR lang fix 2018-05-14 12:26:06 +03:00
yuri
25bb4f08ba fix record list dashlet 2018-05-14 11:57:41 +03:00
yuri
40a13c16eb data privacy 2018-05-14 11:49:25 +03:00
yuri
8ad2c425bf fix table get 2018-05-11 17:15:29 +03:00
yuri
2b6c9bc57e fix opp report 2018-05-10 16:35:47 +03:00
yuri
bebbee5abd email: replyTo link 2018-05-10 12:41:42 +03:00
yuri
99156499f1 display opted out on list view 2018-05-08 12:21:30 +03:00
yuri
9ad81581bb email opt out ui change 2018-05-08 11:48:33 +03:00
yuri
1b4cd1478b bc fix 2018-05-08 11:14:16 +03:00
yuri
5fdf2e4403 css fix 2018-05-07 16:33:10 +03:00
yuri
319b523117 css fix 2018-05-07 16:28:01 +03:00
yuri
62823646b0 css fix 2018-05-07 16:12:20 +03:00
yuri
3c16758605 xls float fix 2018-05-07 13:35:56 +03:00
yuri
4705d2e38d link multiple json fields 2018-05-07 13:13:07 +03:00
yuri
05b405f76e attachment multiple order 2018-05-07 12:38:46 +03:00
yuri
f54b2788de fix list tree 2018-05-07 12:05:30 +03:00
yuri
6ac0c7b301 fix task/meeting accountName contactName 2018-05-07 11:57:05 +03:00
yuri
c44cc9906e fix lang 2018-05-04 16:19:12 +03:00
yuri
ecd5671e1a fix panels 2018-05-04 16:00:18 +03:00
yuri
c83f729eea color picker fix 2018-05-04 14:11:09 +03:00
yuri
10afd2dfef update tcpdf 2018-05-04 14:03:38 +03:00
yuri
8229b8320f entity maanger reset to defaults 2018-05-04 13:58:40 +03:00
yuri
50493cf725 user icon 2018-05-04 13:24:04 +03:00
yuri
3937b80254 icons update 2018-05-04 13:18:16 +03:00
yuri
bcb7aaf13c entity manager: ability to select icons 2018-05-04 13:18:04 +03:00
yuri
f9d7ec7f47 fix test 2018-05-04 11:14:19 +03:00
yuri
b7d43edf22 attachment tests 2018-05-04 11:13:05 +03:00
yuri
0f0060f0f6 fix attachment duplicate 2018-05-04 11:00:59 +03:00
yuri
036bad3912 entity manager iconClass backend 2018-05-03 17:09:57 +03:00
yuri
c9d675798b icon color change 2018-05-03 15:08:23 +03:00
yuri
10703750f9 stream icon 2018-05-03 14:10:29 +03:00
yuri
4d942851d3 css fix 2018-05-03 14:01:50 +03:00
yuri
1434c31b2f theme names 2018-05-03 12:01:32 +03:00
yuri
74405b2842 theme order 2018-05-03 12:01:23 +03:00
yuri
1070d18085 icons 2018-05-03 11:45:28 +03:00
yuri
b729c13c7a fix css 2018-05-03 11:37:00 +03:00
yuri
1c99327bfd team tab 2018-05-03 11:18:07 +03:00
yuri
61279b0e59 sidebar width fix 2018-05-03 11:10:07 +03:00
yuri
31cb17a41d sidebar expanded by default 2018-05-03 11:00:45 +03:00
yuri
f9349d5545 icon colors 2018-05-03 10:59:18 +03:00
yuri
c3703494eb icons 2018-05-02 16:42:37 +03:00
yuri
d94ff7c4fa concurrency fix 2 2018-05-02 12:58:25 +03:00
yuri
01e0bf4d6d add GNF currency 2018-05-02 12:02:46 +03:00
yuri
ca5f1a47fd cleanup 2018-05-02 11:54:07 +03:00
yuri
54af8ee7c6 fix concurrency 2018-05-02 11:41:46 +03:00
yuri
8572b565f3 update bull 2018-05-02 11:41:02 +03:00
yuri
ea1cc1c65a fix calendar 2018-04-27 16:19:47 +03:00
yuri
4610c61bd4 fix dashlets 2018-04-27 16:16:37 +03:00
yuri
02f04ea9c4 concurrency race fix 2018-04-27 16:06:23 +03:00
yuri
1ce4db6be4 model abort last fetch 2018-04-27 15:47:21 +03:00
yuri
888291a99d fix 2018-04-27 14:07:10 +03:00
yuri
3f9773a4cf fix htmlizer 2018-04-27 11:59:26 +03:00
yuri
a223c721aa fix nav tab overflow 2018-04-27 11:54:05 +03:00
yuri
5bce57b1f8 fix theme 2018-04-27 11:43:03 +03:00
yuri
3666c34845 tab colors enabled 2018-04-27 11:12:42 +03:00
yuri
0dceccac46 attachment create file before create record 2018-04-27 11:11:23 +03:00
yuri
59a2644e0f email order replies 2018-04-27 10:52:49 +03:00
yuri
6c33a7304d email template skip empty subject 2018-04-27 10:47:31 +03:00
yuri
e89f01a525 person name autocomplete off 2018-04-27 10:42:32 +03:00
yuri
7181b45461 fix campaign stats panel 2018-04-27 10:41:00 +03:00
yuri
b7ce52f476 fix 2018-04-26 18:05:04 +03:00
yuri
d2a8cd961f theme fixes 2018-04-26 18:03:56 +03:00
yuri
c152dbf4bf fix row actions 2018-04-26 11:50:27 +03:00
yuri
594a111bc3 fix import panels 2018-04-26 11:46:09 +03:00
yuri
005be2fe5a impoty fix attribute translation 2018-04-26 11:26:51 +03:00
yuri
8f194e6d9e import currency fix 2018-04-26 10:53:10 +03:00
yuri
e3a5cb464c fix datetime optional 2018-04-25 16:52:12 +03:00
yuri
779f0df83e link parent fix 2018-04-25 16:46:23 +03:00
yuri
086d9bdbb6 kanban fix 2018-04-25 15:52:28 +03:00
yuri
9dcaa46bc7 css fix 2018-04-25 15:00:34 +03:00
yuri
3bca95a4da entity manager color fix 2018-04-25 14:24:26 +03:00
yuri
be09935287 icon fix 2018-04-25 14:10:08 +03:00
yuri
410c338da8 css fix 2018-04-25 13:55:55 +03:00
yuri
be0606ede6 fix css 2018-04-25 13:47:27 +03:00
yuri
f54a84420a color icon change 2018-04-25 13:46:59 +03:00
yuri
6a0d1e3b8b kanban no data 2018-04-25 11:57:39 +03:00
yuri
33127cd1bb version 2018-04-25 11:09:33 +03:00
yuri
5cd03312e1 assigned users notifications 2018-04-24 17:02:14 +03:00
yuri
391c0dcaf8 fix list expanded layout 2018-04-24 16:26:53 +03:00
yuri
0b7b9599d3 multiple assigned users support 2018-04-24 16:18:50 +03:00
yuri
b45ff69376 email account assigned user view 2018-04-24 14:00:17 +03:00
yuri
1836d0a127 css change 2018-04-24 12:13:07 +03:00
yuri
048e156e59 fix kanban 2018-04-23 14:38:18 +03:00
yuri
a85be60e30 fix kanban 2018-04-23 14:29:32 +03:00
yuri
90d5c9eca6 fix kanban 2018-04-23 14:01:17 +03:00
yuri
1c8f0c7d9c css fix 2018-04-23 13:40:29 +03:00
yuri
f8d1c9ce05 opp kanban fix 2018-04-23 13:32:12 +03:00
yuri
28052bac23 layout manager kanban view 2018-04-23 12:14:16 +03:00
yuri
c361a940eb kanban view in entity manager 2018-04-23 11:56:46 +03:00
yuri
fbc1e936db Merge branch 'master' of github.com:espocrm/espocrm 2018-04-23 10:46:20 +03:00
yuri
84661f88fd Merge branch 'hotfix/5.1.3' 2018-04-23 10:45:49 +03:00
yuri
10b4c88872 template variable triple braces 2018-04-23 10:37:04 +03:00
yuri
10ddc7d941 fix send email attachment filename 2018-04-23 10:23:40 +03:00
Yuri Kuznetsov
b1c63e2cb9 Update CONTRIBUTING.md 2018-04-22 20:36:54 +03:00
yuri
3f6544d03b kanban fix 2018-04-20 16:05:40 +03:00
yuri
a9f211dfd5 notify loading 2018-04-20 16:02:25 +03:00
yuri
f2427abbf4 kanban 2018-04-20 15:27:58 +03:00
yuri
a6187f9838 empty date on list view 2018-04-20 15:25:33 +03:00
yuri
384600ed95 Merge branch 'hotfix/5.1.3' 2018-04-20 15:23:02 +03:00
yuri
6d06f03ef9 fix frontend acl 2018-04-20 13:56:09 +03:00
yuri
0829c714fd Merge branch 'hotfix/5.1.3' 2018-04-20 10:57:07 +03:00
yuri
9e2251755f quick view edit icons 2018-04-20 10:55:03 +03:00
yuri
436f871be2 update marked js 2018-04-20 10:45:14 +03:00
yuri
8d09f8e9b2 Merge branch 'hotfix/5.1.3' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.1.3 2018-04-19 13:46:27 +03:00
yuri
e4d43a6790 fix field names conflict with template variables 2018-04-19 13:11:20 +03:00
Taras Machyshyn
bb3d9d3466 ExternalAccount bug fixes 2018-04-19 11:16:08 +03:00
yuri
bd208e259c reset sorting in select modal 2018-04-18 14:42:39 +03:00
yuri
1a1cfec3e5 refactoring 2018-04-16 12:11:13 +03:00
yuri
1e95e98549 calendar dashlet fix 2018-04-16 11:36:00 +03:00
yuri
82056b5650 version 2018-04-16 10:35:44 +03:00
yuri
c0d118ee98 email plain fix 2018-04-16 10:31:31 +03:00
yuri
da13177292 shared calendar dashlet 2018-04-13 16:01:54 +03:00
yuri
4cc38ca564 meeting avatar fix 2018-04-13 15:17:00 +03:00
yuri
fa945c981e nav menu changes 2018-04-13 15:15:41 +03:00
yuri
63d76c6b71 Merge branch 'hotfix/5.1.3' 2018-04-13 14:42:22 +03:00
yuri
9b749a8f67 fix read only 2018-04-13 13:32:12 +03:00
yuri
1ce1d5c79a scope colors changes 2018-04-13 12:14:11 +03:00
yuri
0c2dd73334 password disable autocomplete 2018-04-12 16:15:02 +03:00
yuri
7331f14e0a quick view remove color 2018-04-12 15:38:58 +03:00
yuri
d44f2fd7cd calendar avatars change 2018-04-12 15:20:55 +03:00
yuri
4da7eddc69 event users with avatars 2018-04-12 15:12:16 +03:00
yuri
3ebe30a9c0 entity colors and icons 2018-04-12 14:48:45 +03:00
yuri
e959361df9 createField changes 2018-04-12 14:34:11 +03:00
yuri
7773506361 shared calendar 2018-04-12 13:43:27 +03:00
yuri
9db652a501 fix repository merge select params 2018-04-11 16:03:53 +03:00
yuri
27ebfd7f23 fix link multiple required 2018-04-11 12:09:14 +03:00
yuri
96f80e0008 create field options 2018-04-11 12:03:46 +03:00
yuri
5f3c208161 Merge branch 'hotfix/5.1.3' 2018-04-11 10:56:35 +03:00
yuri
d402f33c74 fix field level acl for json fields 2018-04-10 15:29:46 +03:00
yuri
879da4dca2 fix calls row actions 2018-04-10 14:02:36 +03:00
yuri
3e862790e6 Merge branch 'hotfix/5.1.3' 2018-04-10 12:08:29 +03:00
yuri
425e36bff6 view helper getAvatarHtml 2018-04-10 12:07:58 +03:00
yuri
705ecbdf72 es_MX lang fix 2018-04-10 11:49:28 +03:00
yuri
c658d67ac8 lt_LT lang fix 2018-04-10 11:48:27 +03:00
yuri
c46055b469 hr_HR language 2018-04-10 11:46:03 +03:00
yuri
66e4b89d1a email body plain fix 2018-04-10 11:35:45 +03:00
yuri
38b9f1d68c fix email body plain not filled 2018-04-10 11:17:27 +03:00
yuri
19b8a4e771 fix upload timeout 2018-04-10 10:42:07 +03:00
yuri
937ffea4ab fix upload timeout 2018-04-10 10:41:44 +03:00
yuri
1ae49a3d47 timeline users avatars 2018-04-06 16:48:02 +03:00
yuri
c76daf50db currency rate ui improvement 2018-04-06 14:54:38 +03:00
yuri
9e5c797243 opp currency convert 2018-04-06 14:09:15 +03:00
yuri
662c4afcdf fix mass update 2018-04-06 13:00:08 +03:00
yuri
9b50b97e79 field labelText 2018-04-06 12:09:06 +03:00
yuri
d00cefc37f list mass action all 2018-04-06 11:17:32 +03:00
yuri
1f94c13e25 fix confirm leavout 2018-04-05 17:12:04 +03:00
yuri
75801ea717 calendar fixes 2018-04-05 15:04:48 +03:00
yuri
b845f5086e remove ics tests 2018-04-05 11:57:34 +03:00
yuri
8c8e6ec551 fix ics 2018-04-05 11:50:14 +03:00
yuri
a4aecee18d fix stream parent fields load 2018-04-05 11:49:14 +03:00
Sebastian
3c0d445824 Fix Multiline descriptions for Outlook. (#862)
See https://social.technet.microsoft.com/Forums/lync/en-US/c16cc4aa-0a07-4742-929d-1b01d698066e/ics-file-description-with-colon-and-newline-is-displayed-without-newlines?forum=outlook
2018-04-05 11:48:31 +03:00
yuri
c36c6dc42d wysywyg remove max length 2018-04-04 13:36:40 +03:00
yuri
f7f8f14725 case new note color 2018-04-03 17:44:06 +03:00
yuri
9402bf4baf chart colors fix 2018-04-03 14:33:03 +03:00
yuri
12fcdcdb2d call icon change 2018-04-03 14:24:38 +03:00
yuri
61735ed4aa cleanup 2018-04-03 14:11:49 +03:00
yuri
3c65d252b6 fix image orientation 2018-04-02 15:57:14 +03:00
yuri
6423859195 email move to trash fix 2018-04-02 13:56:31 +03:00
yuri
53df34d6f2 acl read only comment 2018-04-02 13:21:51 +03:00
yuri
ed762c9be3 stream notifications types 2018-04-02 12:44:55 +03:00
yuri
f05f14b12a email fixes 2018-04-02 12:44:44 +03:00
yuri
183b5cb29b clientReadOnly 2018-04-02 12:44:07 +03:00
yuri
07193b1fb2 email send shared name 2018-04-02 12:29:05 +03:00
yuri
b24f8f538b fix auth 2018-03-30 16:21:45 +03:00
yuri
a259174415 outboundEmailBccAddress 2018-03-30 14:43:12 +03:00
yuri
3d93c2a4b1 Merge branch 'hotfix/5.1.2' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.1.2 2018-03-30 14:18:44 +03:00
yuri
8c112791ef external email client support 2018-03-30 14:16:28 +03:00
Taras Machyshyn
0ff4553c94 LDAP fixes 2018-03-30 13:52:22 +03:00
yuri
1e6094b5ee fix wysiwyg 2018-03-29 17:28:14 +03:00
yuri
a646d97aec opp list layout changes 2018-03-29 16:03:18 +03:00
yuri
57f4980802 fix bc 2018-03-29 13:39:12 +03:00
yuri
2477f5b696 fix import float values 2018-03-29 12:33:36 +03:00
yuri
6463422e81 version 2018-03-29 11:48:49 +03:00
yuri
3daf041698 auth improvements 2018-03-29 11:45:57 +03:00
yuri
933456ecdf repository check 2018-03-28 15:55:12 +03:00
yuri
ab18f72f69 schedule meeting for portal user fix 2018-03-28 15:22:55 +03:00
yuri
28465cf2bf acl read only 2018-03-27 17:22:28 +03:00
yuri
4cef5c547e string length and contains functions 2018-03-27 16:16:07 +03:00
yuri
057abf8024 fix email getBodyPlain 2018-03-27 15:00:36 +03:00
yuri
20de5658e9 role fields fixes 2018-03-27 14:43:29 +03:00
yuri
4a2ed2e0f7 kb language options disabled 2018-03-27 14:25:44 +03:00
yuri
3dc574bc48 fix field manager options 2018-03-27 14:23:52 +03:00
yuri
d43a42b646 fix export 2018-03-27 13:18:04 +03:00
yuri
823c46a6df fix email body plain 2018-03-27 12:00:58 +03:00
yuri
919c0bc8ae fix field manager enum 2018-03-27 11:51:22 +03:00
yuri
54d62a19cd tooltip added 2018-03-22 15:28:09 +02:00
yuri
18304fb710 attachment throw error if fie not stored 2018-03-22 13:21:57 +02:00
yuri
cc1afbed5d file field tpl fix 2018-03-22 12:52:51 +02:00
yuri
a195acfee9 fix field name conflict with view helpers 2018-03-22 12:47:24 +02:00
yuri
e22ec4c20b cleanup 2018-03-21 16:00:00 +02:00
yuri
7c8f4f9db8 display ... for not set values in detail views 2018-03-21 12:29:37 +02:00
yuri
d28ff1e438 Merge branch 'hotfix/5.1.2' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.1.2 2018-03-20 16:38:11 +02:00
Taras Machyshyn
5af7499fdb Use utf8mb4 for fresh instances with MySQL 5.7+ 2018-03-20 16:02:40 +02:00
yuri
6588d783cc activities dashlet: next x days 2018-03-20 15:52:09 +02:00
yuri
f1b8279d50 insert template fix 2018-03-20 14:51:31 +02:00
yuri
252d31ffac email template for reply 2018-03-20 14:00:05 +02:00
yuri
8a98cca4fa email insert email confirm 2018-03-20 13:12:30 +02:00
Taras Machyshyn
0b8486c1a7 Merge branch 'hotfix/5.1.2' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.1.2 2018-03-20 12:29:54 +02:00
Taras Machyshyn
b0bd0664f9 Extension installation improvements 2018-03-20 12:29:36 +02:00
yuri
286fd7e0ce template placeholders translation improvement 2018-03-20 12:22:47 +02:00
yuri
42f5d28369 template today now 2018-03-20 12:00:46 +02:00
yuri
ea5d873cc3 fix field manager buttons 2018-03-20 11:09:25 +02:00
yuri
ee8608469e fix css 2018-03-19 14:08:42 +02:00
yuri
f541625318 cache timestamp in dev html 2018-03-19 13:52:58 +02:00
yuri
ee70fb8483 new version notification skip for dev 2018-03-19 13:10:38 +02:00
yuri
f79e093f52 fix base auth split 2018-03-19 12:11:01 +02:00
yuri
254d9280b9 fix login 2018-03-16 15:47:03 +02:00
yuri
ddd9c765b8 Merge branch 'master' of github.com:espocrm/espocrm into hotfix/5.1.2 2018-03-16 15:43:52 +02:00
Ettienne Pitts
080f204eed uninstallConfirmation added to en_US (#834) 2018-03-16 15:43:33 +02:00
tanyalei
f30325849a Activities Dashlet: fix Display Records option (#835) 2018-03-16 14:20:57 +02:00
yuri
8caa5b3e60 image preview original target blank 2018-03-15 16:26:25 +02:00
yuri
0daeed49c1 version 2018-03-15 15:00:27 +02:00
Taras Machyshyn
34540e12f3 getMaxIndexLength() changes 2018-03-15 14:55:27 +02:00
yuri
b954a81630 template: page orientation and format 2018-03-15 12:23:59 +02:00
yuri
56472d6746 textFilterContainsMinLength config param 2018-03-15 11:03:14 +02:00
yuri
2721649313 Merge branch 'hotfix/5.1.1' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.1.1 2018-03-14 17:17:40 +02:00
yuri
24d7de60ab inline edit skip exit 2018-03-14 17:15:44 +02:00
Taras Machyshyn
441f9296ad Fixed file permissions after upgrading 2018-03-14 15:44:24 +02:00
yuri
3116a152e7 fix currency converted 2018-03-14 14:39:54 +02:00
yuri
77784c4224 fix currency converted 2018-03-14 13:02:40 +02:00
yuri
bf13c7ca8c textFilterUseContainsForVarchar on admin ui 2018-03-14 11:19:14 +02:00
yuri
26c779a2c5 fix store sent email 2018-03-14 11:03:03 +02:00
yuri
1bfaf6c3ad model get entity type 2018-03-13 15:11:54 +02:00
yuri
69229ff6af Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-03-13 14:54:12 +02:00
yuri
719164524b naming fix 2018-03-13 13:45:25 +02:00
yuri
5a67b17916 email fix 2018-03-13 13:37:37 +02:00
Taras Machyshyn
db4968b1ca Upgrade: Renamed vendorFiles 2018-03-13 13:11:58 +02:00
Taras Machyshyn
e50f46e38a Installer: fix installation warning 2018-03-13 13:02:30 +02:00
Taras Machyshyn
adc8988f6c Upgrade: copy vendor directory 2018-03-13 12:33:13 +02:00
yuri
a480ad9c11 optimization 2018-03-13 11:35:20 +02:00
Taras Machyshyn
d9be685f89 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-03-13 11:07:45 +02:00
Taras Machyshyn
bd9db140de Added 'deleteAndCopy' directory for upgrade 2018-03-13 10:56:14 +02:00
yuri
74c0204590 keep rootUrl for edit view 2018-03-12 14:59:37 +02:00
yuri
ce9d3299b1 skipTextColumns for email 2018-03-12 12:27:06 +02:00
yuri
8b27bc194d proper naming 2018-03-12 11:19:21 +02:00
yuri
1a6b4a6683 set fetched email address data 2018-03-12 11:11:28 +02:00
yuri
2ae4d6e090 orm converter skip fields w/o type 2018-03-12 10:57:41 +02:00
yuri
9467171c84 fix entity manager labels 2018-03-09 16:37:40 +02:00
yuri
402db729b7 field manager dont resave labels if not changed 2018-03-09 16:05:41 +02:00
yuri
e16be12438 fix field manager 2018-03-09 14:58:24 +02:00
yuri
605912443d fix tests 2018-03-09 14:50:50 +02:00
yuri
62acc14f4a drop php mime mail parser by default 2018-03-09 14:25:28 +02:00
yuri
017066a311 currency part label 2018-03-09 14:21:35 +02:00
yuri
273b122ca8 fix labels in entity manager saving 2018-03-09 13:58:26 +02:00
yuri
ce2ec3dd6c field manager utils get fields by type 2018-03-09 12:28:20 +02:00
yuri
fda22605cc fix repository 2018-03-09 12:16:12 +02:00
yuri
1076fa6230 repositories bypass 2018-03-09 12:01:39 +02:00
yuri
019af59c8a default currency if empty 2018-03-09 12:01:27 +02:00
yuri
08bb644b58 fix notice 2018-03-08 16:36:52 +02:00
yuri
6ec1273e61 update mail parser libs 2018-03-08 16:30:25 +02:00
yuri
ba5df9a4ae fix export time 2018-03-08 15:53:42 +02:00
yuri
050d77ef12 fix activities dashlet 2018-03-08 15:25:31 +02:00
yuri
f8ccaeab08 select manager user 2018-03-08 14:46:42 +02:00
yuri
3c4c464e4a fix email flicker 2018-03-08 12:37:06 +02:00
yuri
2a5730def9 iframe css fix 2018-03-08 11:36:35 +02:00
yuri
48fe3e6b86 fix email size 2018-03-07 16:15:26 +02:00
yuri
eecbc3aa2c lang 2018-03-07 13:52:26 +02:00
yuri
e177f14446 having count 2018-03-07 12:45:29 +02:00
yuri
493ab0396a fix currency 2018-03-07 11:52:31 +02:00
yuri
c776150ce0 rebuild after upgrade 2018-03-06 16:01:50 +02:00
yuri
b6bca982bb default side panel client defs params 2018-03-06 15:25:45 +02:00
yuri
aa8a243bf1 order fixes 2018-03-06 12:36:02 +02:00
yuri
75da037656 fix stream note 2018-03-06 11:25:39 +02:00
yuri
56a06a5581 remove dynamic logic from bottom and side 2018-03-06 11:03:23 +02:00
yuri
0af67bea3a fix dynamic logic 2018-03-06 11:01:38 +02:00
yuri
08b8d899b7 fix typo 2018-03-05 17:03:33 +02:00
yuri
cf07cb39c4 wysiwyg height fix 2018-03-05 17:03:24 +02:00
yuri
810d10c1c2 bottom panels order 2018-03-05 15:24:24 +02:00
yuri
342bdcfaac fix typo 2018-03-05 13:15:28 +02:00
yuri
d933dbb31a fix dynamic logic 2018-03-05 12:41:54 +02:00
yuri
fe61364178 fix panel dynamic logic 2018-03-05 12:32:09 +02:00
yuri
88c3c03f99 dynamic logic detail view 2018-03-05 12:12:41 +02:00
yuri
c21b16f5c7 panel defs dynamic logic 2018-03-05 11:23:11 +02:00
yuri
2481a2504f fix auth token ip length 2018-03-02 16:57:25 +02:00
Taras Machyshyn
dcb1e8040a MySQL charset change improvements 2018-03-02 15:42:26 +02:00
yuri
0e1c611034 update composer 2018-03-02 14:11:33 +02:00
yuri
fccd9d642c ditch php imap dependency 2018-03-02 14:10:48 +02:00
yuri
849f1becc7 version 2018-03-02 13:44:14 +02:00
yuri
be6c4a63ed do not remove mysql character service 2018-03-02 13:02:41 +02:00
yuri
4e48483276 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-03-02 13:01:32 +02:00
Taras Machyshyn
6817a54aa0 Job for changing mysql column characters 2018-03-02 13:00:25 +02:00
yuri
482f235dcc Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-03-02 11:54:04 +02:00
yuri
90b863c4ae update composer 2018-03-02 11:53:57 +02:00
Taras Machyshyn
8541a87d1f Integration tests fixes 2018-03-02 11:35:52 +02:00
Taras Machyshyn
002adeb00e Integration test fixes 2018-03-02 11:15:01 +02:00
Taras Machyshyn
30e7d1ba7c Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-03-02 10:49:35 +02:00
yuri
0923f2e120 Merge branch 'master' of github.com:espocrm/espocrm 2018-03-02 10:37:50 +02:00
Andra Fetele
38a0c8e19f Romanian translation (#823) 2018-03-02 09:31:01 +02:00
yuri
facf90d964 fix event Set Held label 2018-03-01 18:04:00 +02:00
yuri
cca3482bc0 fix query stringifyValue 2018-03-01 17:41:39 +02:00
yuri
6178ca550b import fix 2018-03-01 16:37:22 +02:00
yuri
dc51e467d4 excel export: migrate to phpspreadsheet 2018-03-01 16:01:37 +02:00
yuri
300827c1f0 vendor updates 2018-03-01 15:47:26 +02:00
yuri
aacf09a444 email move to trash from detail view updates list 2018-03-01 15:14:24 +02:00
yuri
0123488828 import revert remove change 2018-03-01 14:50:45 +02:00
yuri
a43b188f36 import action history 2018-02-28 17:06:50 +02:00
Taras Machyshyn
f0285ef8f2 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-02-28 16:19:05 +02:00
yuri
70a0ffbf3d fix list tpl 2018-02-28 11:48:29 +02:00
yuri
f2e6a4fc55 import improvement 2018-02-28 11:43:11 +02:00
yuri
df5fd76ae2 update-all event for model 2018-02-28 11:42:58 +02:00
yuri
f34d258b45 header button title 2018-02-28 11:09:34 +02:00
yuri
28c52763c8 Merge branch 'hotfix/5.0.6' 2018-02-27 17:46:45 +02:00
yuri
ebe22fa7f0 fix htmlizer 2018-02-27 17:44:56 +02:00
yuri
160327e471 Merge branch 'hotfix/5.0.6' 2018-02-27 17:32:51 +02:00
yuri
dd080dbff2 Merge branch 'hotfix/5.0.6' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.0.6 2018-02-27 17:32:33 +02:00
yuri
d509886cd1 sql fixes 2018-02-27 17:31:50 +02:00
Taras Machyshyn
239a8f0af8 Code improvements 2018-02-27 17:14:19 +02:00
Taras Machyshyn
c0565306c3 Code improvements 2018-02-27 17:13:15 +02:00
yuri
79d159511d fix category tree repository 2018-02-27 17:06:53 +02:00
yuri
e123fc7e6f target list layout change 2018-02-27 16:26:33 +02:00
yuri
52fa30f389 event confirmation change 2018-02-27 16:19:23 +02:00
yuri
1d744d5abc cleanup fixes 2018-02-27 16:16:30 +02:00
yuri
2629c12ade fix link and link multiple empty name 2018-02-27 14:27:15 +02:00
yuri
8fb6b1a5a9 fix parent name load 2018-02-27 14:12:48 +02:00
yuri
d4a23c9a4f fix parent 2018-02-27 14:07:58 +02:00
yuri
05d0f982a7 fix select manager 2018-02-26 15:30:42 +02:00
yuri
e3c8a3fcda fix applyFilter 2018-02-26 15:07:41 +02:00
yuri
8cd56d2705 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-02-26 14:23:21 +02:00
Taras Machyshyn
f94d1f3cd8 Metadata: get metadata in object format 2018-02-26 14:22:14 +02:00
yuri
5f64b74fad fix ro_RO 2018-02-26 13:35:54 +02:00
Taras Machyshyn
b422cd6f52 Metadata: getCustom() changes 2018-02-26 13:03:25 +02:00
Andra Fetele
17698409b9 Approx 700 lines, translated into Romanian (#813)
* Romanian translation

* Approx 700 lines, translated into Romanian
2018-02-24 20:07:34 +02:00
Andra Fetele
fb0dabebe1 Romanian translation (#812) 2018-02-23 20:59:55 +02:00
yuri
f81805fbf4 fix dynamic handler 2018-02-23 17:00:48 +02:00
Taras Machyshyn
596c9d4996 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-02-23 15:50:59 +02:00
Taras Machyshyn
a7530dcce9 Bug fixes in File Manager 2018-02-23 15:50:49 +02:00
yuri
55d59eea80 checkAccessDataList allowAllForAdmin 2018-02-23 15:14:22 +02:00
yuri
0c66a1fb7b dynamic handler extend 2018-02-23 13:55:00 +02:00
yuri
ad7ca5d287 dynamic handler 2018-02-23 13:44:24 +02:00
yuri
b34be4730d Merge branch 'master' of github.com:espocrm/espocrm 2018-02-23 11:10:16 +02:00
yuri
1c264055eb Merge branch 'hotfix/5.0.6' 2018-02-23 11:09:59 +02:00
yuri
12f41baff5 file filters 2018-02-23 11:09:42 +02:00
yuri
9a9ad1baa7 lang 2018-02-23 11:03:28 +02:00
Yuri Kuznetsov
46c31278e7 Update README.md 2018-02-22 18:34:37 +02:00
yuri
a08dc3d422 bottom panels isBottom 2018-02-22 15:51:07 +02:00
yuri
158a74f79b fix tests 2018-02-22 15:37:19 +02:00
Taras Machyshyn
bacf85ccf8 Metadata: saveCustom() fixes 2018-02-22 15:33:56 +02:00
Taras Machyshyn
ef683bd7fa Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-02-22 15:02:37 +02:00
yuri
20c233fb8c more user acl tests 2018-02-22 15:01:37 +02:00
Taras Machyshyn
ac21313190 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-02-22 14:56:29 +02:00
Taras Machyshyn
8ba6918139 Metadata: added possibility to work with metadata defined in custom directory 2018-02-22 14:56:20 +02:00
yuri
5e357b460d cleanup 2018-02-22 14:51:04 +02:00
yuri
d660abe1f6 acl tests 2018-02-22 14:48:56 +02:00
yuri
fd9617ec8f Merge branch 'hotfix/5.0.6' 2018-02-22 12:38:41 +02:00
yuri
48ccdaab5e calendar responcive fixes 2018-02-22 12:38:27 +02:00
yuri
52d9548333 select manager: external primary filters 2018-02-22 12:16:25 +02:00
yuri
4706d28560 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-02-21 16:34:58 +02:00
yuri
033f5de85d Merge branch 'hotfix/5.0.6' 2018-02-21 16:34:48 +02:00
yuri
6760f6f03d note type enum 2018-02-21 15:39:29 +02:00
yuri
e1a7862194 xlsx fix 2018-02-21 14:00:46 +02:00
Taras Machyshyn
8ef53d229d Required MySQL version is 5.5.3 2018-02-21 13:01:57 +02:00
yuri
c6d215f87c Merge branch 'hotfix/5.0.6' 2018-02-21 12:10:12 +02:00
yuri
dccaed124c fix duplicate one-to-many issue 2018-02-21 12:10:04 +02:00
yuri
ccfca4a61a activity account contact fiexes 2018-02-21 12:00:10 +02:00
Taras Machyshyn
417a05f24f Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-02-20 17:54:14 +02:00
Taras Machyshyn
7a85f7576d Unit test for copy() of FileManager 2018-02-20 17:54:04 +02:00
yuri
8407ab3a74 Merge branch 'master' of ssh://172.20.0.1/var/git/espo/backend 2018-02-20 16:58:13 +02:00
yuri
c120ebd3ca header fixes 2018-02-20 16:50:24 +02:00
Taras Machyshyn
d0635484a2 Database: default column charset is utf8mb4 2018-02-20 15:56:34 +02:00
yuri
d3c487a28a modal overlaid shadow none 2018-02-20 15:49:22 +02:00
yuri
14f46a5d5d Merge branch 'hotfix/5.0.6' 2018-02-20 15:00:28 +02:00
yuri
00a8ca8273 fix select manager 2018-02-20 14:58:51 +02:00
yuri
deec457728 header fix 2018-02-20 14:34:27 +02:00
yuri
5a5508a973 accessDataList for dashlets 2018-02-20 12:42:38 +02:00
yuri
357b285346 accessDataList for list filters and panels 2018-02-20 12:40:38 +02:00
yuri
f8444b9e67 Merge branch 'hotfix/5.0.6' 2018-02-20 12:18:46 +02:00
yuri
e0a224e414 calendar fixes 2018-02-20 12:18:39 +02:00
yuri
9dfb128e1d calender decrease longPressDelay 2018-02-20 11:58:11 +02:00
yuri
462d1f0274 utils checkAccessDataList 2018-02-20 11:44:10 +02:00
yuri
2e3803eef1 cleanup 2018-02-19 15:32:08 +02:00
yuri
42b186eb94 Merge branch 'hotfix/5.0.6' 2018-02-19 15:31:20 +02:00
yuri
ccdee9ec09 import email unlock tables 2018-02-19 15:00:49 +02:00
yuri
05eeb82efd attendees panel not refreshable 2018-02-19 12:39:13 +02:00
yuri
6eefe64f4c fix frontend tests 2018-02-19 12:26:00 +02:00
yuri
5b96b19735 jasmine test fixes 2018-02-16 16:49:33 +02:00
yuri
3764d877ce Merge branch 'hotfix/5.0.6' 2018-02-16 12:33:46 +02:00
yuri
30e713c161 reminders in detailSmall 2018-02-16 11:49:01 +02:00
yuri
da3a76e441 hack for upgrade 2018-02-16 11:23:19 +02:00
yuri
adff467b50 event confirmation and unsubscribe: use frontend 2018-02-15 14:56:36 +02:00
yuri
d59f05ad8b event confirmation hook 2018-02-15 13:26:19 +02:00
yuri
9c3d124f48 Merge branch 'hotfix/5.0.6' 2018-02-14 15:16:59 +02:00
yuri
4404b0f02e select manager: convertWhere 2018-02-14 11:33:22 +02:00
Andra Fetele
77533fba72 translated ~700 lines into Romanian (#806)
* Partial Romanian translation

* translated ~700 lines into Romanian
2018-02-14 08:49:10 +02:00
yuri
62d36ed0c2 lang 2018-02-13 12:46:40 +02:00
yuri
94ad0123c7 css fix 2018-02-13 11:21:05 +02:00
yuri
109842f0fe contact: hide title if no account 2018-02-13 11:19:38 +02:00
yuri
d931d65cd8 formatting 2018-02-13 11:18:19 +02:00
yuri
b7861a7cb1 htmlizer enum translation 2018-02-13 11:07:19 +02:00
yuri
a49ad3bb48 fix lang 2018-02-13 11:04:05 +02:00
yuri
d94acf5b78 fix activities dashlet tasks 2018-02-12 16:34:45 +02:00
yuri
fd0e1d1460 css fix 2018-02-12 16:21:43 +02:00
yuri
2ed9d5487e chart css fix 2018-02-12 16:12:22 +02:00
yuri
5dc44cb701 fix assignment permission 2018-02-12 14:41:42 +02:00
yuri
9e07c383fe collection abortLastFetch 2018-02-12 14:33:09 +02:00
yuri
9e1ec2768b fix email switch folders 2018-02-12 14:06:55 +02:00
yuri
39674e8c7f htmlspecialchars for unsubscribe page 2018-02-12 12:52:47 +02:00
yuri
5dca4b7061 template aclPortal 2018-02-12 12:44:45 +02:00
yuri
5d3cb25d14 css fix 2018-02-12 12:43:16 +02:00
yuri
6e337affbb fix chart 2018-02-12 11:26:49 +02:00
yuri
87ab8cc15f chart css fix 2018-02-12 10:23:55 +02:00
yuri
b654e5cebd icon class 2018-02-10 15:37:48 +02:00
yuri
11958f2abf icon changes 2018-02-10 15:34:45 +02:00
yuri
2a329ba92d fix next/prev through collection 2018-02-10 14:38:03 +02:00
yuri
b22487ef70 lang fixes 2018-02-10 14:25:21 +02:00
Andra Fetele
bf03a2f540 Partial Romanian translation (#804) 2018-02-09 20:08:08 +02:00
yuri
ece51a6f9f task and activities dashlet fixes 2018-02-09 17:41:34 +02:00
yuri
915dbffe72 activities dashlet: support tasks 2018-02-09 17:22:00 +02:00
yuri
fda0d6df1f fix login appParams 2018-02-09 15:51:05 +02:00
yuri
25891f9dc0 print pdf change 2018-02-09 15:45:24 +02:00
yuri
35902adbdc orm having clause 2018-02-09 14:47:18 +02:00
yuri
981d15ee55 Merge branch 'hotfix/5.0.5' 2018-02-09 13:04:04 +02:00
yuri
adfec3441b template tab 2018-02-09 12:05:01 +02:00
yuri
a208aa051f Merge branch 'hotfix/5.0.5' 2018-02-08 17:44:06 +02:00
yuri
9068302357 version 2018-02-08 16:52:23 +02:00
yuri
1bb0439f19 fix model reset 2018-02-08 16:02:12 +02:00
yuri
f28585e245 mass update ui improvement 2018-02-08 15:37:41 +02:00
yuri
99cfeb25ee fix print to pdf button 2018-02-08 14:18:58 +02:00
yuri
6b7da9a39e fix entity manger and field manager 2018-02-08 13:22:00 +02:00
yuri
18bba7baec entity manager fix 2018-02-08 13:15:49 +02:00
yuri
ec8ffbc090 chart dashlets acl 2018-02-08 12:52:18 +02:00
yuri
60eb1ca236 fix sales by month chart 2018-02-08 12:40:49 +02:00
yuri
5e3756313c fix sales pipeline chart 2018-02-08 12:20:13 +02:00
yuri
d303d5a423 Merge branch 'hotfix/5.0.5' 2018-02-08 11:56:30 +02:00
yuri
938415aa79 cleanup 2018-02-08 11:54:15 +02:00
yuri
9033710e56 Merge branch 'hotfix/5.0.5' 2018-02-07 15:25:24 +02:00
yuri
2fd77e4034 excel export duration 2018-02-07 15:23:06 +02:00
yuri
b733d8205e relationship panel setup list layout method 2018-02-07 14:59:58 +02:00
yuri
f725ad09d7 user: hide mass update and export for non admin users 2018-02-07 13:41:29 +02:00
yuri
e9a53c5b25 list view acl delete check 2018-02-07 12:54:58 +02:00
yuri
43e94cfe68 user acl check 2018-02-07 12:13:23 +02:00
yuri
07d713734f Merge branch 'hotfix/5.0.5' 2018-02-07 11:29:18 +02:00
yuri
4f004b8402 note status styles change 2018-02-07 11:07:24 +02:00
yuri
b1f4131af9 user acl check 2018-02-06 17:36:10 +02:00
yuri
1adb19f427 fix field manager 2018-02-06 17:28:37 +02:00
yuri
fce4a4b1d9 skip additional select params 2018-02-06 17:13:48 +02:00
yuri
61f35bcb5e user editable 2018-02-06 17:04:42 +02:00
yuri
0db68917a1 Merge branch 'hotfix/5.0.5' 2018-02-06 15:13:51 +02:00
yuri
9da8ab9bdb chart fix 2018-02-06 13:46:59 +02:00
yuri
8d1724df84 less opp stages 2018-02-06 13:01:09 +02:00
yuri
cd88d59937 po ability to build po for all languages 2018-02-06 12:28:20 +02:00
yuri
cab4f5ce64 opp stages translation 2018-02-06 12:22:20 +02:00
yuri
62ab1f8d00 fix export 2018-02-06 11:29:17 +02:00
yuri
f0e1439c79 fix chart legend 2018-02-06 11:03:10 +02:00
yuri
5060918087 print pdf for all entity types 2018-02-05 16:42:33 +02:00
yuri
bf6b058152 reset page title on logout 2018-02-05 15:54:13 +02:00
yuri
40b607a73f template change 2018-02-05 15:48:35 +02:00
yuri
2bdbba0eff fix sales chart 2018-02-05 15:42:56 +02:00
yuri
058d821a7c fix chart 2018-02-05 15:32:22 +02:00
yuri
4575ff89ad chart fixes 2018-02-05 12:59:50 +02:00
yuri
608454fcf2 fix css 2018-02-05 12:54:26 +02:00
yuri
58c1bec2da css fix 2018-02-05 12:30:57 +02:00
yuri
e1ce16c399 chart legend title 2018-02-05 12:16:05 +02:00
yuri
2d3a748286 chart fixes 2018-02-05 11:58:21 +02:00
yuri
06834dd8bf fix calendar 2018-02-05 10:18:31 +02:00
yuri
e4c0f19b1c fix css 2018-02-02 16:03:29 +02:00
yuri
84faf7a782 entity manager: supporting templates in modules 2018-02-02 14:27:40 +02:00
yuri
61db675ab1 css fix 2018-02-01 16:48:59 +02:00
yuri
59e72796e3 css fix 2018-02-01 16:43:07 +02:00
yuri
76e61a6358 fix dropdown on small screens 2018-02-01 14:54:04 +02:00
yuri
455eceefa1 Merge branch 'hotfix/5.0.4' 2018-02-01 13:15:41 +02:00
yuri
834e979060 fix css 2018-02-01 12:23:17 +02:00
yuri
ece36c8711 fix test 2018-02-01 11:39:30 +02:00
yuri
9b999a1ec8 fix test email import 2018-02-01 11:22:16 +02:00
yuri
80c53e15e5 fix test 2018-02-01 11:12:15 +02:00
yuri
a37b6077c1 css fix 2018-02-01 11:02:45 +02:00
yuri
fabfa392b7 clear cache page style fixes 2018-02-01 10:55:57 +02:00
yuri
8ff717cfd5 css fixes 2018-02-01 10:53:28 +02:00
yuri
eae042d730 css chages 2018-01-31 15:07:57 +02:00
yuri
f6fda22160 css change 2018-01-31 14:55:43 +02:00
yuri
c120ecab1a css changes 2018-01-31 14:47:26 +02:00
yuri
6afcbe90a1 css change 2018-01-31 14:35:56 +02:00
yuri
130bde63cf Merge branch 'hotfix/5.0.4' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.0.4 2018-01-31 12:19:40 +02:00
Taras Machyshyn
c76e8f96d9 Code fixes 2018-01-31 11:56:47 +02:00
yuri
7b92014249 scheduled job update silent 2018-01-31 11:55:26 +02:00
yuri
33df80559d scheduled job hooks disabled 2018-01-31 11:53:12 +02:00
Taras Machyshyn
c0d9d1e514 Static methods for System utils 2018-01-31 11:51:11 +02:00
yuri
ed2567913b fix show more focus 2018-01-31 11:49:00 +02:00
yuri
9a7bd94ce1 fix collection lengthCorrection 2018-01-31 11:42:44 +02:00
yuri
036aea5c7f fix orm week_1 function 2018-01-31 11:33:09 +02:00
yuri
1bc1311113 fix job 2018-01-30 19:02:06 +02:00
yuri
135fe6f2e6 var name fixes 2018-01-30 18:56:08 +02:00
yuri
f366a1d0dd Merge branch 'hotfix/5.0.4' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.0.4 2018-01-30 18:42:08 +02:00
Taras Machyshyn
b4cda3b349 Code improvements 2018-01-30 18:41:53 +02:00
yuri
0e92ae792c Merge branch 'hotfix/5.0.4' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.0.4 2018-01-30 17:50:56 +02:00
Taras Machyshyn
cf4247321c Installer: changed loading icon 2018-01-30 17:26:03 +02:00
Taras Machyshyn
994be85579 Fixed after install duplicate records 2018-01-30 17:24:33 +02:00
yuri
8cdaf1a534 cleanup 2018-01-30 17:06:23 +02:00
yuri
f9996d3643 css fix 2018-01-30 14:25:36 +02:00
yuri
6b7bcca21b css fix 2018-01-30 14:24:26 +02:00
Taras Machyshyn
c7109906bc Merge branch 'pid' into hotfix/5.0.4 2018-01-30 12:52:15 +02:00
Taras Machyshyn
63583ad630 CronManager: added checking is process active 2018-01-30 12:49:29 +02:00
yuri
4d063194ed font size param in theme 2018-01-30 11:47:04 +02:00
yuri
c579e08614 save error handling supporting 500 error 2018-01-30 11:39:24 +02:00
yuri
40414a0f17 save error handling in frontend 2018-01-29 17:43:29 +02:00
yuri
5e1ee6f06f throw conflict if user name exists 2018-01-29 17:31:38 +02:00
yuri
f885333310 default jobs scheduling change 2018-01-29 17:14:12 +02:00
yuri
72149851cf job config params change 2018-01-29 16:02:10 +02:00
yuri
e2ce971b70 css fix 2018-01-29 14:30:43 +02:00
yuri
802bb9b1c2 fix css 2018-01-29 14:24:08 +02:00
yuri
30ce642d88 reneme check new version job 2018-01-29 13:35:33 +02:00
yuri
bc901fad0b installer style fixes 2018-01-29 13:26:04 +02:00
yuri
dae251fb43 fix show more 2018-01-29 13:13:18 +02:00
yuri
f98a916a55 update libs 2018-01-29 13:13:09 +02:00
yuri
a7fd14ef36 fix job 2018-01-27 13:55:34 +02:00
yuri
5ff2eb1945 number fields title in list view 2018-01-27 13:05:20 +02:00
yuri
a60e82591f default currency format 2 2018-01-27 12:59:47 +02:00
yuri
2ae59a5820 email portions limitation 2018-01-27 12:49:23 +02:00
yuri
1d46427d51 settings layout change 2018-01-27 12:47:08 +02:00
yuri
8bd7009c02 currency decimal places = 2 2018-01-27 12:41:06 +02:00
yuri
cc90d546a5 scheduled jobs fix 2018-01-27 12:36:42 +02:00
yuri
e916ff5a0b system scheduled job change 2018-01-27 12:34:42 +02:00
yuri
54fa8f4867 lang 2018-01-27 12:12:33 +02:00
yuri
7d92ee7d7a email import improvements 2018-01-26 16:23:29 +02:00
yuri
884388d0df email message id index 2018-01-26 15:55:39 +02:00
yuri
50b386388e App service rebuild and clear cache jobs 2018-01-26 15:55:20 +02:00
yuri
f03c0d7c57 entity manager: skipAll, keepNew save options 2018-01-26 15:08:19 +02:00
yuri
83a3552b21 charts date filter ranges 2018-01-26 13:33:17 +02:00
yuri
1462f54a65 sales pipeline fix 2018-01-26 12:55:12 +02:00
yuri
b7cd1657b0 css fix 2018-01-26 12:09:18 +02:00
yuri
9d1ae432d5 chart change 2018-01-26 11:40:08 +02:00
yuri
1e32df5a26 fix layout manager panel name loss 2018-01-25 17:56:04 +02:00
yuri
07128d04b0 dashboard side menu issue fix 2018-01-25 17:42:22 +02:00
yuri
8d0c1348b1 chart fixes 2018-01-25 17:31:22 +02:00
yuri
7bcacdbd27 css fix 2018-01-25 16:25:37 +02:00
yuri
65c3bb3291 chart fixes 2018-01-25 16:08:56 +02:00
yuri
a08fa65fae chart improvements 2018-01-25 15:47:47 +02:00
yuri
85d8c9795a fix calendar warning 2018-01-24 16:41:19 +02:00
yuri
9a17dbbd68 chart overflow fix 2018-01-24 16:26:33 +02:00
yuri
f83827886e chart sales by month fix 2018-01-24 16:07:46 +02:00
yuri
8964e98873 version 2018-01-24 15:10:51 +02:00
yuri
63e17e91bd email import concurrency issue fix 2018-01-24 15:05:52 +02:00
yuri
f95cbe4ed2 fix email replate to email account 2018-01-24 15:05:17 +02:00
yuri
9ddd1dac3a fix typo in email 2018-01-24 14:03:06 +02:00
yuri
5ff0e67392 skipHooks param 2018-01-24 13:16:33 +02:00
yuri
a60a2885e1 fix php mime mail parser 2018-01-24 13:12:34 +02:00
yuri
7e9ddf0c14 user access table: hide mandatory 2018-01-24 11:48:06 +02:00
yuri
5cb82cca42 email store sent fix 2018-01-24 11:40:52 +02:00
yuri
02edc35d3a user mass update fixes 2018-01-24 11:20:10 +02:00
yuri
a30c17ed91 chart fixes 2018-01-23 18:06:04 +02:00
yuri
d2dfd7ddb0 excel export: supporting address 2018-01-23 16:29:54 +02:00
yuri
2a35b9912c target lists exportable 2018-01-23 15:59:37 +02:00
yuri
bc097db09f record grid layout improvement 2018-01-23 15:55:40 +02:00
yuri
75eb49ced3 acl changes 2018-01-23 14:51:28 +02:00
yuri
cd2e3eec08 acl fix 2018-01-23 13:40:39 +02:00
yuri
d72884a0e4 lang 2018-01-23 13:30:23 +02:00
yuri
315e35965c acl gender default 2018-01-23 12:51:07 +02:00
yuri
f2fb3fc077 css fix 2018-01-23 11:30:28 +02:00
yuri
f4d9e3fbc6 fix navbar 2018-01-23 11:01:09 +02:00
yuri
d44f8e7ab4 fix export exception 2018-01-23 10:40:16 +02:00
yuri
b0438991bf entity manager refactoring 2018-01-22 15:52:13 +02:00
yuri
0a23a469e2 loadLinkMultipleField improvement 2018-01-22 15:28:15 +02:00
yuri
2900e8afb7 csv export link multiple 2018-01-22 15:12:40 +02:00
yuri
e3e25785c7 excel export link multiple fields 2018-01-22 14:43:57 +02:00
yuri
7c4e1393fe lang 2018-01-22 12:49:18 +02:00
yuri
b06736351b fix lang 2018-01-22 12:46:25 +02:00
yuri
9c5a8c63ce portal preferences layout fix 2018-01-19 14:44:32 +02:00
yuri
e8c171be92 Merge branch 'stable' 2018-01-19 14:14:25 +02:00
yuri
1b7aa9e48c css fixes 2018-01-19 12:39:59 +02:00
yuri
51fd3e681c css fix 2018-01-18 16:38:17 +02:00
yuri
484510f763 css fix 2018-01-18 15:50:26 +02:00
yuri
7fde7327fe css fixes 2018-01-18 15:14:28 +02:00
yuri
2c8094bf28 Merge branch 'hotfix/5.0.3' 2018-01-18 15:06:34 +02:00
tanyalei
256d30847e PDF: Images rendered not properly in footer FIX (#768) 2018-01-18 14:11:14 +02:00
yuri
0bbfee8716 timeline fixes 2018-01-18 11:53:23 +02:00
yuri
8d58e81d28 email account list fix 2018-01-18 11:41:22 +02:00
yuri
8fb80d12c9 portal hide custom tab list 2018-01-18 11:26:49 +02:00
yuri
2b5eed3a38 Merge branch 'hotfix/5.0.3' 2018-01-17 17:05:38 +02:00
yuri
dccd5305e7 css fix 2018-01-17 17:04:29 +02:00
yuri
bbb418d2af fix select record w/ categories 2018-01-17 15:27:45 +02:00
yuri
a5bae56f8d cleanup 2018-01-17 14:56:28 +02:00
yuri
aa3d2f8787 Merge branch 'hotfix/5.0.3' 2018-01-17 14:39:22 +02:00
yuri
e9750e145f kb: hide side for portal 2018-01-17 14:35:11 +02:00
yuri
d0cdefd972 Merge branch 'hotfix/5.0.3' 2018-01-17 13:34:38 +02:00
yuri
451aa7f5da relatonshipsPortal layout 2018-01-17 13:34:25 +02:00
yuri
43ee6ef8f6 css fix 2018-01-17 13:28:38 +02:00
yuri
c366e8decc search filters disabled for portal 2018-01-17 13:22:48 +02:00
yuri
8610c61c18 fix css 2018-01-17 13:12:07 +02:00
yuri
bee3a3b012 update vis 2018-01-17 12:57:54 +02:00
yuri
dc2d46ca21 noAppCache param for libs 2018-01-17 12:41:22 +02:00
yuri
1b5346e86d Merge branch 'hotfix/5.0.3' 2018-01-17 12:23:35 +02:00
yuri
8bc633aed9 fix preset filter for ie 2018-01-17 12:17:16 +02:00
yuri
ee3dee0570 fixc wysiwyg for ie 2018-01-17 12:11:05 +02:00
yuri
69048d8f89 fix css 2018-01-17 12:04:19 +02:00
yuri
427025c2ed storage fixes 2018-01-17 11:36:33 +02:00
yuri
6deb336115 Merge branch 'hotfix/5.0.3' 2018-01-16 17:15:24 +02:00
yuri
a8be115d4b fix service populateDefaults 2018-01-16 17:12:32 +02:00
yuri
115ae82b17 Merge branch 'hotfix/5.0.3' 2018-01-16 15:40:54 +02:00
yuri
e4b357e8d3 loading and caching impovements 2018-01-16 15:23:51 +02:00
yuri
560a7b2465 markdown disable tables 2018-01-16 12:56:59 +02:00
yuri
acfe05297b cache set try catch 2018-01-16 11:48:55 +02:00
yuri
16579ff1a8 Merge branch 'hotfix/5.0.3' 2018-01-16 11:12:48 +02:00
yuri
2dcf81a516 css fix 2018-01-16 11:12:39 +02:00
yuri
44f379e3d2 fix wysiwyg 2018-01-16 10:49:11 +02:00
yuri
9be406c0a2 fix categories 2018-01-15 16:31:37 +02:00
yuri
a030c50780 Merge branch 'hotfix/5.0.3' 2018-01-15 16:17:00 +02:00
yuri
c9ca3a497f wysywyg resize fix 2018-01-15 16:14:21 +02:00
yuri
71886cd91c role action title 2018-01-15 14:50:00 +02:00
yuri
e60d46b2ec Merge branch 'hotfix/5.0.3' 2018-01-15 14:44:30 +02:00
yuri
9829ca8d28 ff textarea fix 2018-01-15 14:44:22 +02:00
yuri
28c4651599 Merge branch 'hotfix/5.0.3' 2018-01-15 14:23:16 +02:00
yuri
14de81520b job: fix failed attempts 2018-01-15 14:23:05 +02:00
yuri
3a11d335a2 fix css 2018-01-15 12:51:03 +02:00
yuri
0d3554cc49 file upload ready validation 2018-01-15 12:50:48 +02:00
yuri
6b458f3b55 file upload ready validation 2018-01-15 12:46:49 +02:00
yuri
874885671b fix css 2018-01-15 12:38:52 +02:00
yuri
a75f4dacab Merge branch 'hotfix/5.0.3' 2018-01-15 11:56:26 +02:00
yuri
8c5a455f08 fix assigned permission issues 2018-01-15 11:55:21 +02:00
yuri
1b12cd46b2 Merge branch 'hotfix/5.0.3' 2018-01-12 16:46:15 +02:00
yuri
42581469da list in panel margin bottom fix 2 2018-01-12 16:45:06 +02:00
yuri
562fa03c6c list in panel margin bottom fix 2018-01-12 16:42:45 +02:00
yuri
7389acd87f Merge branch 'hotfix/5.0.3' 2018-01-12 16:09:45 +02:00
yuri
8feca2783f fix navbar 2018-01-12 15:45:05 +02:00
yuri
a290f7aba9 Merge branch 'hotfix/5.0.3' 2018-01-12 15:09:44 +02:00
yuri
eb11f9f757 label manager: filter options 2018-01-12 15:08:17 +02:00
yuri
2ace19face horizontal navbar fix 2 2018-01-12 13:43:15 +02:00
yuri
25b6a94fd6 horizontal navbar fix 2018-01-12 13:25:07 +02:00
yuri
d0768b3dce email plain fix 2018-01-11 17:18:09 +02:00
yuri
b4c27f50ea diff change 2018-01-11 17:01:45 +02:00
yuri
669cb10f10 fix email side panel 2018-01-11 16:52:24 +02:00
yuri
e9c0cd6d53 Merge branch 'hotfix/5.0.3' 2018-01-11 16:49:31 +02:00
yuri
06708a8b7e version 2018-01-11 16:44:45 +02:00
yuri
fba8ca7817 css form panel bottom margin fix 2018-01-11 16:31:25 +02:00
yuri
37cae817a7 fix file uploading validate message 2018-01-11 14:26:58 +02:00
yuri
7d847cf179 Merge branch 'hotfix/5.0.3' 2018-01-11 12:29:41 +02:00
yuri
a32c560f60 hide merge action if no remove access 2018-01-11 12:29:34 +02:00
yuri
a4d4e640a2 merge improvements 2018-01-11 12:24:12 +02:00
yuri
74093976db Merge branch 'hotfix/5.0.3' 2018-01-10 15:02:01 +02:00
yuri
76f17e3f95 Merge branch 'hotfix/5.0.3' of ssh://172.20.0.1/var/git/espo/backend into hotfix/5.0.3 2018-01-10 14:46:42 +02:00
Taras Machyshyn
ab4ce21927 Integration test fixes 2018-01-10 14:46:09 +02:00
yuri
eb14dedb63 update tests for phpunit 6 2018-01-10 12:54:44 +02:00
yuri
004dfc1687 Merge branch 'hotfix/5.0.2' 2018-01-09 16:23:56 +02:00
yuri
e429bde5b8 Merge branch 'hotfix/5.0.2' 2018-01-09 16:15:07 +02:00
yuri
3d8bbdd01d Merge branch 'hotfix/5.0.2' of ssh://172.20.0.1/var/git/espo/backend 2018-01-09 11:49:45 +02:00
1795 changed files with 72694 additions and 16033 deletions

View File

@@ -6,4 +6,4 @@ Before we can merge your pull request you need to accept our CLA [here](https://
## Issues
We don't provide developer help or any kind of support on github. Please use our [forum](http://forum.espocrm.com/) for this.
We don't provide developer help or any kind of support on github. Please use our [forum](https://forum.espocrm.com) for this.

View File

@@ -28,6 +28,7 @@ module.exports = function (grunt) {
'client/lib/handlebars.js',
'client/lib/base64.js',
'client/lib/jquery-ui.min.js',
'client/lib/jquery.ui.touch-punch.min.js',
'client/lib/moment.min.js',
'client/lib/moment-timezone-with-data.min.js',
'client/lib/jquery.timepicker.min.js',
@@ -35,10 +36,41 @@ module.exports = function (grunt) {
'client/lib/bootstrap.min.js',
'client/lib/bootstrap-datepicker.js',
'client/lib/bull.js',
'client/lib/marked.min.js',
'client/src/namespace.js',
'client/src/exceptions.js',
'client/src/loader.js',
'client/src/utils.js'
'client/src/utils.js',
'client/src/acl.js',
'client/src/model.js',
'client/src/model-offline.js',
'client/src/ajax.js',
'client/src/controller.js',
'client/src/ui.js',
'client/src/acl-manager.js',
'client/src/cache.js',
'client/src/storage.js',
'client/src/models/settings.js',
'client/src/language.js',
'client/src/metadata.js',
'client/src/field-manager.js',
'client/src/models/user.js',
'client/src/models/preferences.js',
'client/src/model-factory.js',
'client/src/collection-factory.js',
'client/src/pre-loader.js',
'client/src/controllers/base.js',
'client/src/router.js',
'client/src/date-time.js',
'client/src/layout-manager.js',
'client/src/theme-manager.js',
'client/src/session-storage.js',
'client/src/view-helper.js',
'client/src/app.js'
];
function camelCaseToHyphen (string){
@@ -87,6 +119,9 @@ module.exports = function (grunt) {
clean: {
start: ['build/*'],
final: ['build/tmp'],
beforeFinal: {
src: ['build/tmp/custom/Espo/Custom/*', '!build/tmp/custom/Espo/Custom/.htaccess']
}
},
less: lessData,
uglify: {
@@ -259,9 +294,10 @@ module.exports = function (grunt) {
'copy:frontendLib',
'copy:backend',
'replace',
'clean:beforeFinal',
'copy:final',
'chmod',
'clean:final',
'clean:final'
]);
};

View File

@@ -9,7 +9,7 @@ Download the latest release from our [website](http://www.espocrm.com).
### Requirements
* PHP 5.6 or above (with pdo, json, gd, openssl, zip, imap, mbstring, curl extensions);
* MySQL 5.1 or above.
* MySQL 5.5.3 or above.
For more information about server configuration see [this article](https://www.espocrm.com/documentation/administration/server-configuration/).
@@ -17,10 +17,14 @@ For more information about server configuration see [this article](https://www.e
Documentation for administrators, users and developers is available [here](https://www.espocrm.com/documentation/).
### How to report bug
### How to report a bug
Create an issue [here](https://github.com/espocrm/espocrm/issues) or post on our [forum](http://forum.espocrm.com/forum/bug-reports).
### How to install a stable version
[Download](https://www.espocrm.com/download/) the latest version. See the [instructions](https://www.espocrm.com/documentation/administration/installation/) about installation.
### How to get started (for developers)
1. Clone repository to your local computer.
@@ -34,7 +38,7 @@ Now you can build. Build will create compiled css files.
To compose a proper config.php and populate database you can run install by opening `http(s)://{YOUR_CRM_URL}/install` location in a browser. Then open `data/config.php` file and add `isDeveloperMode => true`.
### How to build
### How to build (for developers)
You need to have nodejs and Grunt CLI installed.

View File

@@ -34,6 +34,7 @@ use \Espo\ORM\Entity;
class Email extends \Espo\Core\Acl\Base
{
protected $ownerUserIdAttribute = 'usersIds';
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
{
@@ -118,4 +119,3 @@ class Email extends \Espo\Core\Acl\Base
return false;
}
}

View File

@@ -0,0 +1,63 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Acl;
use \Espo\Entities\User as EntityUser;
use \Espo\ORM\Entity;
class EmailAddress extends \Espo\Core\Acl\Base
{
public function checkEditInEntity(EntityUser $user, Entity $entity, Entity $excludeEntity)
{
$id = $entity->id;
$isFobidden = false;
$repository = $this->getEntityManager()->getRepository('EmailAddress');
if (!$user->isAdmin()) {
$entityWithSameAddressList = $repository->getEntityListByAddressId($id, $excludeEntity);
foreach ($entityWithSameAddressList as $e) {
if (!$this->getAclManager()->check($user, $e, 'edit')) {
$isFobidden = true;
if (
$e->get('isPortalUser') && $excludeEntity->getEntityType() === 'Contact' &&
$e->get('contactId') === $excludeEntity->id
) {
$isFobidden = false;
}
if ($isFobidden) break;
}
}
}
return !$isFobidden;
}
}

View File

@@ -0,0 +1,53 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Acl;
use \Espo\Entities\User as EntityUser;
use \Espo\ORM\Entity;
class Import extends \Espo\Core\Acl\Base
{
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
{
if ($user->isAdmin()) return true;
if ($user->id === $entity->get('createdById')) return true;
return false;
}
public function checkEntityDelete(EntityUser $user, Entity $entity, $data)
{
if ($user->isAdmin()) return true;
if ($user->id === $entity->get('createdById')) return true;
return false;
}
}

View File

@@ -0,0 +1,104 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Acl;
use \Espo\Entities\User as EntityUser;
use \Espo\ORM\Entity;
class Note extends \Espo\Core\Acl\Base
{
protected $deleteThresholdPeriod = '1 month';
protected $editThresholdPeriod = '7 days';
public function checkIsOwner(EntityUser $user, Entity $entity)
{
if ($entity->get('type') === 'Post' && $user->id === $entity->get('createdById')) {
return true;
}
return false;
}
public function checkEntityEdit(EntityUser $user, Entity $entity, $data)
{
if ($user->isAdmin()) {
return true;
}
if ($this->checkEntity($user, $entity, $data, 'edit')) {
if ($this->checkIsOwner($user, $entity)) {
$createdAt = $entity->get('createdAt');
if ($createdAt) {
$noteEditThresholdPeriod = '-' . $this->getConfig()->get('noteEditThresholdPeriod', $this->editThresholdPeriod);
$dt = new \DateTime();
$dt->modify($noteEditThresholdPeriod);
try {
if ($dt->format('U') > (new \DateTime($createdAt))->format('U')) {
return false;
}
} catch (\Exception $e) {
return false;
}
}
}
return true;
}
return false;
}
public function checkEntityDelete(EntityUser $user, Entity $entity, $data)
{
if ($user->isAdmin()) {
return true;
}
if ($this->checkEntity($user, $entity, $data, 'delete')) {
if ($this->checkIsOwner($user, $entity)) {
$createdAt = $entity->get('createdAt');
if ($createdAt) {
$deleteThresholdPeriod = '-' . $this->getConfig()->get('noteDeleteThresholdPeriod', $this->deleteThresholdPeriod);
$dt = new \DateTime();
$dt->modify($deleteThresholdPeriod);
try {
if ($dt->format('U') > (new \DateTime($createdAt))->format('U')) {
return false;
}
} catch (\Exception $e) {
return false;
}
}
}
return true;
}
return false;
}
}

View File

@@ -0,0 +1,63 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Acl;
use \Espo\Entities\User as EntityUser;
use \Espo\ORM\Entity;
class PhoneNumber extends \Espo\Core\Acl\Base
{
public function checkEditInEntity(EntityUser $user, Entity $entity, Entity $excludeEntity)
{
$id = $entity->id;
$isFobidden = false;
$repository = $this->getEntityManager()->getRepository('PhoneNumber');
if (!$user->isAdmin()) {
$entityWithSameNumberList = $repository->getEntityListByPhoneNumberId($id, $excludeEntity);
foreach ($entityWithSameNumberList as $e) {
if (!$this->getAclManager()->check($user, $e, 'edit')) {
$isFobidden = true;
if (
$e->get('isPortalUser') && $excludeEntity->getEntityType() === 'Contact' &&
$e->get('contactId') === $excludeEntity->id
) {
$isFobidden = false;
}
if ($isFobidden) break;
}
}
}
return !$isFobidden;
}
}

View File

@@ -30,6 +30,7 @@
namespace Espo\Acl;
use \Espo\ORM\Entity;
use \Espo\Entities\User as EntityUser;
class User extends \Espo\Core\Acl\Base
{
@@ -37,5 +38,36 @@ class User extends \Espo\Core\Acl\Base
{
return $user->id === $entity->id;
}
}
public function checkEntityCreate(EntityUser $user, Entity $entity, $data)
{
if (!$user->isAdmin()) {
return false;
}
return $this->checkEntity($user, $entity, $data, 'create');
}
public function checkEntityDelete(EntityUser $user, Entity $entity, $data)
{
if ($entity->id === 'system') {
return false;
}
if (!$user->isAdmin()) {
return false;
}
return parent::checkEntityDelete($user, $entity, $data);
}
public function checkEntityEdit(EntityUser $user, Entity $entity, $data)
{
if ($entity->id === 'system') {
return false;
}
if (!$user->isAdmin()) {
if ($user->id !== $entity->id) {
return false;
}
}
return $this->checkEntity($user, $entity, $data, 'edit');
}
}

View File

@@ -34,6 +34,7 @@ use \Espo\ORM\Entity;
class Email extends \Espo\Core\AclPortal\Base
{
protected $ownerUserIdAttribute = 'usersIds';
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
{

View File

@@ -0,0 +1,56 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\AclPortal;
use \Espo\Entities\User as EntityUser;
use \Espo\ORM\Entity;
class EmailAddress extends \Espo\Core\AclPortal\Base
{
public function checkEditInEntity(EntityUser $user, Entity $entity, Entity $excludeEntity)
{
$id = $entity->id;
$isFobidden = false;
$repository = $this->getEntityManager()->getRepository('EmailAddress');
if (!$user->isAdmin()) {
$entityWithSameAddressList = $repository->getEntityListByAddressId($id, $excludeEntity);
foreach ($entityWithSameAddressList as $e) {
if (!$this->getAclManager()->check($user, $e, 'edit')) {
$isFobidden = true;
break;
}
}
}
return !$isFobidden;
}
}

View File

@@ -0,0 +1,45 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\AclPortal;
use \Espo\Entities\User as EntityUser;
use \Espo\ORM\Entity;
class Note extends \Espo\Core\AclPortal\Base
{
public function checkIsOwner(EntityUser $user, Entity $entity)
{
if ($entity->get('type') === 'Post' && $user->id === $entity->get('createdById')) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,57 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\AclPortal;
use \Espo\Entities\User as EntityUser;
use \Espo\ORM\Entity;
class PhoneNumber extends \Espo\Core\AclPortal\Base
{
public function checkEditInEntity(EntityUser $user, Entity $entity, Entity $excludeEntity)
{
$id = $entity->id;
$isFobidden = false;
$repository = $this->getEntityManager()->getRepository('PhoneNumber');
if (!$user->isAdmin()) {
$entityWithSameNumberList = $repository->getEntityListByPhoneNumberId($id, $excludeEntity);
foreach ($entityWithSameNumberList as $e) {
if (!$this->getAclManager()->check($user, $e, 'edit')) {
$isFobidden = true;
break;
}
}
}
return !$isFobidden;
}
}

View File

@@ -34,5 +34,11 @@ use \Espo\Core\Exceptions\BadRequest;
class Attachment extends \Espo\Core\Controllers\Record
{
public function actionList($params, $data, $request)
{
if (!$this->getUser()->isAdmin()) {
throw new Forbidden();
}
return parent::actionList($params, $data, $request);
}
}

View File

@@ -0,0 +1,67 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Controllers;
use \Espo\Core\Exceptions\Forbidden;
class AuthLogRecord extends \Espo\Core\Controllers\Record
{
protected function checkControllerAccess()
{
if (!$this->getUser()->isAdmin()) {
throw new Forbidden();
}
}
public function actionUpdate($params, $data, $request)
{
throw new Forbidden();
}
public function actionMassUpdate($params, $data, $request)
{
throw new Forbidden();
}
public function actionCreate($params, $data, $request)
{
throw new Forbidden();
}
public function actionCreateLink($params, $data, $request)
{
throw new Forbidden();
}
public function actionRemoveLink($params, $data, $request)
{
throw new Forbidden();
}
}

View File

@@ -0,0 +1,55 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Controllers;
use Espo\Core\Exceptions\Error;
use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Exceptions\NotFound;
use Espo\Core\Exceptions\BadRequest;
class DataPrivacy extends \Espo\Core\Controllers\Base
{
protected function checkControllerAccess()
{
if ($this->getAcl()->get('dataPrivacyPermission') === 'no') {
throw new Forbidden();
}
}
public function postActionErase($params, $data)
{
if (empty($data->entityType) || empty($data->id) || empty($data->fieldList) || !is_array($data->fieldList)) {
throw new BadRequest();
}
return $this->getServiceFactory()->create('DataPrivacy')->erase($data->entityType, $data->id, $data->fieldList);
}
}

View File

@@ -0,0 +1,35 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Controllers;
class EmailTemplateCategory extends \Espo\Core\Templates\Controllers\CategoryTree
{
}

View File

@@ -83,6 +83,20 @@ class EntityManager extends \Espo\Core\Controllers\Base
if (isset($data['textFilterFields']) && is_array($data['textFilterFields'])) {
$params['textFilterFields'] = $data['textFilterFields'];
}
if (!empty($data['color'])) {
$params['color'] = $data['color'];
}
if (!empty($data['iconClass'])) {
$params['iconClass'] = $data['iconClass'];
}
if (isset($data['fullTextSearch'])) {
$params['fullTestSearch'] = $data['fullTextSearch'];
}
$params['kanbanViewMode'] = !empty($data['kanbanViewMode']);
if (!empty($data['kanbanStatusIgnoreList'])) {
$params['kanbanStatusIgnoreList'] = $data['kanbanStatusIgnoreList'];
}
$result = $this->getContainer()->get('entityManagerUtil')->create($name, $type, $params);
@@ -245,7 +259,9 @@ class EntityManager extends \Espo\Core\Controllers\Base
$params = array();
foreach ($paramList as $item) {
$params[$item] = filter_var($data[$item], \FILTER_SANITIZE_STRING);
if (array_key_exists($item, $data)) {
$params[$item] = filter_var($data[$item], \FILTER_SANITIZE_STRING);
}
}
foreach ($additionalParamList as $item) {
@@ -322,4 +338,16 @@ class EntityManager extends \Espo\Core\Controllers\Base
return true;
}
public function postActionResetToDefault($params, $data, $request)
{
if (empty($data->scope)) {
throw new BadRequest();
}
$this->getContainer()->get('entityManagerUtil')->resetToDefaults($data->scope);
$this->getContainer()->get('dataManager')->clearCache();
return true;
}
}

View File

@@ -77,6 +77,11 @@ class FieldManager extends \Espo\Core\Controllers\Base
return $fieldManager->read($params['scope'], $data->name);
}
public function patchActionUpdate($params, $data)
{
return $this->putActionUpdate($params, $data);
}
public function putActionUpdate($params, $data)
{
if (empty($params['scope']) || empty($params['name'])) {

View File

@@ -38,7 +38,7 @@ class Import extends \Espo\Core\Controllers\Record
{
protected function checkControllerAccess()
{
if (!$this->getUser()->isAdmin()) {
if (!$this->getAcl()->check('Import')) {
throw new Forbidden();
}
}
@@ -90,10 +90,9 @@ class Import extends \Espo\Core\Controllers\Record
$attachment->set('type', 'text/csv');
$attachment->set('role', 'Import File');
$attachment->set('name', 'import-file.csv');
$attachment->set('contents', $contents);
$this->getEntityManager()->saveEntity($attachment);
$this->getFileStorageManager()->putContents($attachment, $contents);
return array(
'attachmentId' => $attachment->id
);
@@ -127,7 +126,7 @@ class Import extends \Espo\Core\Controllers\Record
throw new BadRequest();
}
if (!isset($data->fieldDelimiter)) {
if (!isset($data->delimiter)) {
throw new BadRequest();
}
@@ -167,7 +166,7 @@ class Import extends \Espo\Core\Controllers\Record
throw new BadRequest();
}
if (!isset($data->fields)) {
if (!isset($data->attributeList)) {
throw new BadRequest();
}
@@ -178,7 +177,7 @@ class Import extends \Espo\Core\Controllers\Record
$importParams = array(
'headerRow' => !empty($data->headerRow),
'fieldDelimiter' => $data->fieldDelimiter,
'delimiter' => $data->delimiter,
'textQualifier' => $data->textQualifier,
'dateFormat' => $data->dateFormat,
'timeFormat' => $data->timeFormat,
@@ -202,7 +201,7 @@ class Import extends \Espo\Core\Controllers\Record
throw new Forbidden();
}
return $this->getService('Import')->import($data->entityType, $data->fields, $attachmentId, $importParams);
return $this->getService('Import')->import($data->entityType, $data->attributeList, $attachmentId, $importParams);
}
public function postActionUnmarkAsDuplicate($params, $data)

View File

@@ -0,0 +1,72 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Controllers;
use \Espo\Core\Exceptions\Forbidden;
use \Espo\Core\Exceptions\BadRequest;
use \Espo\Core\Exceptions\NotFound;
class LeadCapture extends \Espo\Core\Controllers\Record
{
public function postActionLeadCapture($params, $data, $request, $response)
{
if (empty($params['apiKey'])) throw new BadRequest('No API key provided.');
if (empty($data)) throw new BadRequest('No payload provided.');
$allowOrigin = $this->getConfig()->get('leadCaptureAllowOrigin', '*');
$response->headers->set('Access-Control-Allow-Origin', $allowOrigin);
return $this->getRecordService()->leadCapture($params['apiKey'], $data);
}
public function optionsActionLeadCapture($params, $data, $request, $response)
{
if (empty($params['apiKey'])) throw new BadRequest('No API key provided.');
if (!$this->getRecordService()->isApiKeyValid($params['apiKey'])) {
throw new NotFound();
}
$allowOrigin = $this->getConfig()->get('leadCaptureAllowOrigin', '*');
$response->headers->set('Access-Control-Allow-Headers', 'Content-Type, Accept');
$response->headers->set('Access-Control-Allow-Origin', $allowOrigin);
$response->headers->set('Access-Control-Allow-Methods', 'POST');
return true;
}
public function postActionGenerateNewApiKey($params, $data, $request)
{
if (empty($data->id)) throw new BadRequest();
return $this->getRecordService()->generateNewApiKeyForEntity($data->id)->getValueMap();
}
}

View File

@@ -0,0 +1,38 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Controllers;
use \Espo\Core\Exceptions\Forbidden;
use \Espo\Core\Exceptions\BadRequest;
class LeadCaptureLogRecord extends \Espo\Core\Controllers\Record
{
}

View File

@@ -0,0 +1,60 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Controllers;
use \Espo\Core\Exceptions\Forbidden;
use \Espo\Core\Exceptions\BadRequest;
use \Espo\Core\Exceptions\Error;
class Pdf extends \Espo\Core\Controllers\Base
{
public function postActionMassPrint($params, $data)
{
if (empty($data->idList) || !is_array($data->idList)) {
throw new BadRequest();
}
if (empty($data->entityType)) {
throw new BadRequest();
}
if (empty($data->templateId)) {
throw new BadRequest();
}
if (!$this->getAcl()->checkScope('Template')) {
throw new Forbidden();
}
if (!$this->getAcl()->checkScope($data->entityType)) {
throw new Forbidden();
}
return [
'id' => $this->getServiceFactory()->create('Pdf')->massGenerate($data->entityType, $data->idList, $data->templateId, true)
];
}
}

View File

@@ -88,7 +88,7 @@ class Preferences extends \Espo\Core\Controllers\Base
throw new BadRequest();
}
if ($this->getAcl()->getLevel('Preferences', 'read') === 'no') {
if ($this->getAcl()->getLevel('Preferences', 'edit') === 'no') {
throw new Forbidden();
}
@@ -142,5 +142,45 @@ class Preferences extends \Espo\Core\Controllers\Base
return $entity->getValueMap();
}
}
public function postActionResetDashboard($params, $data)
{
if (empty($data->id)) throw new BadRequest();
$userId = $data->id;
$this->handleUserAccess($userId);
$user = $this->getEntityManager()->getEntity('User', $userId);
$preferences = $this->getEntityManager()->getEntity('Preferences', $userId);
if (!$user) throw new NotFound();
if (!$preferences) throw new NotFound();
if ($user->isPortal()) throw new Forbidden();
if ($this->getAcl()->getLevel('Preferences', 'edit') === 'no') {
throw new Forbidden();
}
$forbiddenAttributeList = $this->getAcl()->getScopeForbiddenAttributeList('Preferences', 'edit');
if (in_array('dashboardLayout', $forbiddenAttributeList)) {
throw new Forbidden();
}
$dashboardLayout = $this->getConfig()->get('dashboardLayout');
$dashletsOptions = $this->getConfig()->get('dashletsOptions');
$preferences->set([
'dashboardLayout' => $dashboardLayout,
'dashletsOptions' => $dashletsOptions
]);
$this->getEntityManager()->saveEntity($preferences);
return (object) [
'dashboardLayout' => $preferences->get('dashboardLayout'),
'dashletsOptions' => $preferences->get('dashletsOptions')
];
}
}

View File

@@ -90,11 +90,9 @@ class Settings extends \Espo\Core\Controllers\Base
throw new Error('Cannot save settings');
}
/** Rebuild for Currency Settings */
if (isset($data->baseCurrency) || isset($data->currencyRates)) {
if (isset($data->defaultCurrency) || isset($data->baseCurrency) || isset($data->currencyRates)) {
$this->getContainer()->get('dataManager')->rebuildDatabase([]);
}
/** END Rebuild for Currency Settings */
return $this->getConfigData();
}

View File

@@ -105,5 +105,19 @@ class User extends \Espo\Core\Controllers\Record
return $this->getService('User')->passwordChangeRequest($userName, $emailAddress, $url);
}
public function actionCreateLink($params, $data, $request)
{
if (!$this->getUser()->isAdmin()) throw new Forbidden();
return parent::actionCreateLink($params, $data, $request);
}
public function actionRemoveLink($params, $data, $request)
{
if (!$this->getUser()->isAdmin()) throw new Forbidden();
return parent::actionRemoveLink($params, $data, $request);
}
}

View File

@@ -46,6 +46,8 @@ class Base implements Injectable
protected $injections = array();
protected $ownerUserIdAttribute = null;
public function inject($name, $object)
{
$this->injections[$name] = $object;
@@ -217,7 +219,7 @@ class Base implements Injectable
}
}
if ($entity->hasAttribute('assignedUsersIds') && $entity->hasRelation('assignedUsers')) {
if ($entity->hasLinkMultipleField('assignedUsers')) {
if ($entity->hasLinkMultipleId('assignedUsers', $user->id)) {
return true;
}
@@ -281,5 +283,23 @@ class Base implements Injectable
return false;
}
}
public function getOwnerUserIdAttribute(Entity $entity)
{
if ($this->ownerUserIdAttribute) {
return $this->ownerUserIdAttribute;
}
if ($entity->hasLinkMultipleField('assignedUsers')) {
return 'assignedUsersIds';
}
if ($entity->hasAttribute('assignedUserId')) {
return 'assignedUserId';
}
if ($entity->hasAttribute('createdById')) {
return 'createdById';
}
}
}

View File

@@ -73,6 +73,8 @@ class Table
protected $forbiddenFieldsCache = array();
protected $isStrictModeForced = false;
protected $isStrictMode = false;
public function __construct(User $user, Config $config = null, FileManager $fileManager = null, Metadata $metadata = null, FieldManagerUtil $fieldManager = null)
@@ -83,7 +85,11 @@ class Table
'fieldTableQuickAccess' => (object) [],
];
$this->isStrictMode = $config->get('aclStrictMode', false);
if ($this->isStrictModeForced) {
$this->isStrictMode = true;
} else {
$this->isStrictMode = $config->get('aclStrictMode', false);
}
$this->user = $user;
@@ -163,7 +169,7 @@ class Table
if (isset($this->data->$permission)) {
return $this->data->$permission;
}
return null;
return 'no';
}
public function getLevel($scope, $action)
@@ -204,6 +210,7 @@ class Table
$this->applyDisabled($aclTable, $fieldTable);
$this->applyMandatory($aclTable, $fieldTable);
$this->applyAdditional($aclTable, $fieldTable, $valuePermissionLists);
$this->applyReadOnlyFields($fieldTable);
} else {
$aclTable = (object) [];
foreach ($this->getScopeList() as $scope) {
@@ -405,7 +412,12 @@ class Table
return;
}
$data = $this->metadata->get('app.'.$this->type.'.default.scopeLevel', array());
$defaultsGroupName = 'default';
if ($this->isStrictMode) {
$defaultsGroupName = 'strictDefault';
}
$data = $this->metadata->get(['app', $this->type, $defaultsGroupName, 'scopeLevel'], []);
foreach ($data as $scope => $item) {
if (isset($table->$scope)) continue;
@@ -416,7 +428,7 @@ class Table
$table->$scope = $value;
}
$defaultFieldData = $this->metadata->get('app.'.$this->type.'.default.fieldLevel', array());
$defaultFieldData = $this->metadata->get(['app', $this->type, $defaultsGroupName, 'fieldLevel'], []);
foreach ($this->getScopeList() as $scope) {
if (isset($table->$scope) && $table->$scope === false) continue;
@@ -424,7 +436,7 @@ class Table
$fieldList = array_keys($this->getMetadata()->get("entityDefs.{$scope}.fields", []));
$defaultScopeFieldData = $this->metadata->get('app.'.$this->type.'.default.scopeFieldLevel.' . $scope, array());
$defaultScopeFieldData = $this->metadata->get('app.'.$this->type.'.'.$defaultsGroupName.'.scopeFieldLevel.' . $scope, []);
foreach (array_merge($defaultFieldData, $defaultScopeFieldData) as $field => $f) {
if (!in_array($field, $fieldList)) continue;
@@ -702,25 +714,29 @@ class Table
private function buildCache()
{
$this->fileManager->putPhpContents($this->cacheFilePath, $this->data, true);
/*$contents = '<' . '?'. 'php return ' . $this->varExport($this->data) . ';';
$this->fileManager->putContents($this->cacheFilePath, $contents);*/
}
/*private function varExport($variable)
protected function applyReadOnlyFields(&$fieldTable)
{
if ($variable instanceof \StdClass) {
$result = '(object) ' . $this->varExport(get_object_vars($variable), true);
} else if (is_array($variable)) {
$array = array();
foreach ($variable as $key => $value) {
$array[] = var_export($key, true).' => ' . $this->varExport($value, true);
// TODO Enable in 5.4.0
return;
$scopeList = $this->getScopeWithAclList();
foreach ($scopeList as $scope) {
if (!property_exists($fieldTable, $scope)) continue;
$fieldList = array_keys($this->getMetadata()->get(['entityDefs', $scope, 'fields'], []));
foreach ($fieldList as $field) {
if ($this->getMetadata()->get(['entityDefs', $scope, 'fields', $field, 'readOnly'])) {
if (property_exists($fieldTable->$scope, $field)) {
$fieldTable->$scope->$field->edit = 'no';
} else {
$fieldTable->$scope->$field = (object) [];
foreach ($this->fieldActionList as $action) {
$fieldTable->$scope->$field->$action = 'yes';
}
$fieldTable->$scope->$field->edit = 'no';
}
}
}
$result = '['.implode(', ', $array).']';
} else {
$result = var_export($variable, true);
}
return $result;
}*/
}
}

View File

@@ -47,6 +47,8 @@ class AclManager
protected $tableClassName = '\\Espo\\Core\\Acl\\Table';
protected $userAclClassName = '\\Espo\\Core\\Acl';
public function __construct(Container $container)
{
$this->container = $container;
@@ -180,9 +182,15 @@ class AclManager
$impl = $this->getImplementation($scope);
$methodName = 'checkEntity' . ucfirst($action);
if (method_exists($impl, $methodName)) {
return $impl->$methodName($user, $entity, $data);
if (!$action) {
$action = 'read';
}
if ($action) {
$methodName = 'checkEntity' . ucfirst($action);
if (method_exists($impl, $methodName)) {
return $impl->$methodName($user, $entity, $data);
}
}
return $impl->checkEntity($user, $entity, $data, $action);
@@ -279,5 +287,11 @@ class AclManager
{
return $this->checkUserPermission($user, $target, 'assignmentPermission');
}
}
public function createUserAcl(User $user)
{
$className = $this->userAclClassName;
$acl = new $className($this, $user);
return $acl;
}
}

View File

@@ -50,6 +50,8 @@ class Table extends \Espo\Core\Acl\Table
protected $levelList = ['yes', 'all', 'account', 'contact', 'own', 'no'];
protected $isStrictModeForced = true;
public function __construct(User $user, Portal $portal, Config $config = null, FileManager $fileManager = null, Metadata $metadata = null, FieldManagerUtil $fieldManager = null)
{
if (empty($portal)) {

View File

@@ -81,6 +81,11 @@ class Application
return $this->container;
}
protected function getConfig()
{
return $this->getContainer()->get('config');
}
public function run($name = 'default')
{
$this->routeHooks();
@@ -91,6 +96,7 @@ class Application
public function runClient()
{
$this->getContainer()->get('clientManager')->display();
exit;
}
public function runEntryPoint($entryPoint, $data = array(), $final = false)
@@ -127,12 +133,17 @@ class Application
$slim->run();
} catch (\Exception $e) {
$container->get('output')->processError($e->getMessage(), $e->getCode(), true);
$container->get('output')->processError($e->getMessage(), $e->getCode(), true, $e);
}
}
public function runCron()
{
if ($this->getConfig()->get('cronDisabled')) {
$GLOBALS['log']->warning("Cron is not run because it's disabled with 'cronDisabled' param.");
return;
}
$auth = $this->createAuth();
$auth->useNoAuth();
@@ -154,7 +165,7 @@ class Application
public function isInstalled()
{
$config = $this->getContainer()->get('config');
$config = $this->getConfig();
if (file_exists($config->getConfigPath()) && $config->get('isInstalled')) {
return true;
@@ -176,7 +187,7 @@ class Application
try {
$auth = $this->createAuth();
} catch (\Exception $e) {
$container->get('output')->processError($e->getMessage(), $e->getCode());
$container->get('output')->processError($e->getMessage(), $e->getCode(), false, $e);
}
$apiAuth = $this->createApiAuth($auth);
@@ -223,10 +234,10 @@ class Application
try {
$controllerManager = $this->getContainer()->get('controllerManager');
$result = $controllerManager->process($controllerName, $actionName, $params, $data, $slim->request());
$result = $controllerManager->process($controllerName, $actionName, $params, $data, $slim->request(), $slim->response());
$container->get('output')->render($result);
} catch (\Exception $e) {
$container->get('output')->processError($e->getMessage(), $e->getCode());
$container->get('output')->processError($e->getMessage(), $e->getCode(), false, $e);
}
});
@@ -243,7 +254,7 @@ class Application
protected function getRouteList()
{
$routes = new \Espo\Core\Utils\Route($this->getContainer()->get('config'), $this->getMetadata(), $this->getContainer()->get('fileManager'));
$routes = new \Espo\Core\Utils\Route($this->getConfig(), $this->getMetadata(), $this->getContainer()->get('fileManager'));
return $routes->getAll();
@@ -251,11 +262,11 @@ class Application
protected function initRoutes()
{
$crudList = array_keys($this->getContainer()->get('config')->get('crud'));
$crudList = array_keys($this->getConfig()->get('crud'));
foreach ($this->getRouteList() as $route) {
$method = strtolower($route['method']);
if (!in_array($method, $crudList)) {
if (!in_array($method, $crudList) && $method !== 'options') {
$GLOBALS['log']->error('Route: Method ['.$method.'] does not exist. Please check your route ['.$route['route'].']');
continue;
}
@@ -272,7 +283,7 @@ class Application
protected function initAutoloads()
{
$autoload = new \Espo\Core\Utils\Autoload($this->getContainer()->get('config'), $this->getMetadata(), $this->getContainer()->get('fileManager'));
$autoload = new \Espo\Core\Utils\Autoload($this->getConfig(), $this->getMetadata(), $this->getContainer()->get('fileManager'));
try {
$autoloadList = $autoload->getAll();

View File

@@ -178,7 +178,7 @@ class Container
protected function loadMailSender()
{
$className = $this->getServiceClassName('mailSernder', '\\Espo\\Core\\Mail\\Sender');
$className = $this->getServiceClassName('mailSender', '\\Espo\\Core\\Mail\\Sender');
return new $className(
$this->get('config'),
$this->get('entityManager')
@@ -217,7 +217,8 @@ class Container
$this->get('acl'),
$this->get('aclManager'),
$this->get('metadata'),
$this->get('config')
$this->get('config'),
$this->get('injectableFactory')
);
}
@@ -246,6 +247,14 @@ class Container
);
}
protected function loadInternalAclManager()
{
$className = $this->getServiceClassName('acl', '\\Espo\\Core\\AclManager');
return new $className(
$this->get('container')
);
}
protected function loadAcl()
{
$className = $this->getServiceClassName('acl', '\\Espo\\Core\\Acl');
@@ -272,7 +281,7 @@ class Container
return new \Espo\Core\Utils\Metadata\OrmMetadata(
$this->get('metadata'),
$this->get('fileManager'),
$this->get('config')->get('useCache')
$this->get('config')
);
}
@@ -295,6 +304,16 @@ class Container
);
}
protected function loadBaseLanguage()
{
return new \Espo\Core\Utils\Language(
'en_US',
$this->get('fileManager'),
$this->get('metadata'),
$this->get('useCache')
);
}
protected function loadDefaultLanguage()
{
return new \Espo\Core\Utils\Language(
@@ -329,8 +348,6 @@ class Container
protected function loadFieldManager()
{
return new \Espo\Core\Utils\FieldManager(
$this->get('metadata'),
$this->get('language'),
$this
);
}

View File

@@ -58,7 +58,7 @@ class ControllerManager
return $this->metadata;
}
public function process($controllerName, $actionName, $params, $data, $request)
public function process($controllerName, $actionName, $params, $data, $request, $response)
{
$customClassName = '\\Espo\\Custom\\Controllers\\' . Util::normilizeClassName($controllerName);
if (class_exists($customClassName)) {
@@ -112,13 +112,13 @@ class ControllerManager
}
if (method_exists($controller, $beforeMethodName)) {
$controller->$beforeMethodName($params, $data, $request);
$controller->$beforeMethodName($params, $data, $request, $response);
}
$result = $controller->$primaryActionMethodName($params, $data, $request);
$result = $controller->$primaryActionMethodName($params, $data, $request, $response);
if (method_exists($controller, $afterMethodName)) {
$controller->$afterMethodName($params, $data, $request);
$controller->$afterMethodName($params, $data, $request, $response);
}
if (is_array($result) || is_bool($result) || $result instanceof \StdClass) {

View File

@@ -133,11 +133,12 @@ class Record extends Base
$q = $request->get('q');
$textFilter = $request->get('textFilter');
$maxSizeLimit = $this->getConfig()->get('recordListMaxSizeLimit', self::MAX_SIZE_LIMIT);
if (empty($maxSize)) {
$maxSize = self::MAX_SIZE_LIMIT;
$maxSize = $maxSizeLimit;
}
if (!empty($maxSize) && $maxSize > self::MAX_SIZE_LIMIT) {
throw new Forbidden("Max should should not exceed " . self::MAX_SIZE_LIMIT . ". Use pagination (offset, limit).");
if (!empty($maxSize) && $maxSize > $maxSizeLimit) {
throw new Forbidden("Max should should not exceed " . $maxSizeLimit . ". Use offset and limit.");
}
$params = array(
@@ -160,6 +161,49 @@ class Record extends Base
);
}
public function getActionListKanban($params, $data, $request)
{
if (!$this->getAcl()->check($this->name, 'read')) {
throw new Forbidden();
}
$where = $request->get('where');
$offset = $request->get('offset');
$maxSize = $request->get('maxSize');
$asc = $request->get('asc', 'true') === 'true';
$sortBy = $request->get('sortBy');
$q = $request->get('q');
$textFilter = $request->get('textFilter');
$maxSizeLimit = $this->getConfig()->get('recordListMaxSizeLimit', self::MAX_SIZE_LIMIT);
if (empty($maxSize)) {
$maxSize = $maxSizeLimit;
}
if (!empty($maxSize) && $maxSize > $maxSizeLimit) {
throw new Forbidden("Max should should not exceed " . $maxSizeLimit . ". Use offset and limit.");
}
$params = array(
'where' => $where,
'offset' => $offset,
'maxSize' => $maxSize,
'asc' => $asc,
'sortBy' => $sortBy,
'q' => $q,
'textFilter' => $textFilter
);
$this->fetchListParamsFromRequest($params, $request, $data);
$result = $this->getRecordService()->getListKanban($params);
return (object) [
'total' => $result->total,
'list' => $result->collection->getValueMapList(),
'additionalData' => $result->additionalData
];
}
protected function fetchListParamsFromRequest(&$params, $request, $data)
{
if ($request->get('primaryFilter')) {
@@ -171,6 +215,10 @@ class Record extends Base
if ($request->get('filterList')) {
$params['filterList'] = $request->get('filterList');
}
if ($request->get('select')) {
$params['select'] = explode(',', $request->get('select'));
}
}
public function actionListLinked($params, $data, $request)
@@ -186,11 +234,12 @@ class Record extends Base
$q = $request->get('q');
$textFilter = $request->get('textFilter');
$maxSizeLimit = $this->getConfig()->get('recordListMaxSizeLimit', self::MAX_SIZE_LIMIT);
if (empty($maxSize)) {
$maxSize = self::MAX_SIZE_LIMIT;
$maxSize = $maxSizeLimit;
}
if (!empty($maxSize) && $maxSize > self::MAX_SIZE_LIMIT) {
throw new Forbidden();
if (!empty($maxSize) && $maxSize > $maxSizeLimit) {
throw new Forbidden("Max should should not exceed " . $maxSizeLimit . ". Use offset and limit.");
}
$params = array(

View File

@@ -116,9 +116,10 @@ class CronManager
{
$lastRunData = $this->getFileManager()->getPhpContents($this->lastRunTime);
$lastRunTime = time() - intval($this->getConfig()->get('cron.minExecutionTime')) - 1;
if (is_array($lastRunData) && !empty($lastRunData['time'])) {
$lastRunTime = $lastRunData['time'];
} else {
$lastRunTime = time() - intval($this->getConfig()->get('cronMinInterval', 0)) - 1;
}
return $lastRunTime;
@@ -136,9 +137,9 @@ class CronManager
{
$currentTime = time();
$lastRunTime = $this->getLastRunTime();
$minTime = $this->getConfig()->get('cron.minExecutionTime');
$cronMinInterval = $this->getConfig()->get('cronMinInterval', 0);
if ($currentTime > ($lastRunTime + $minTime) ) {
if ($currentTime > ($lastRunTime + $cronMinInterval)) {
return true;
}
@@ -167,10 +168,30 @@ class CronManager
$pendingJobList = $this->getCronJobUtil()->getPendingJobList();
foreach ($pendingJobList as $job) {
$skip = false;
$this->getEntityManager()->getPdo()->query('LOCK TABLES `job` WRITE');
if ($this->getCronJobUtil()->isJobPending($job->id)) {
if ($job->get('scheduledJobId')) {
if ($this->getCronJobUtil()->isScheduledJobRunning($job->get('scheduledJobId'), $job->get('targetId'), $job->get('targetType'))) {
$skip = true;
}
}
} else {
$skip = true;
}
if ($skip) {
$this->getEntityManager()->getPdo()->query('UNLOCK TABLES');
continue;
}
$job->set('status', self::RUNNING);
$job->set('pid', $this->getCronJobUtil()->getPid());
$this->getEntityManager()->saveEntity($job);
$this->getEntityManager()->getPdo()->query('UNLOCK TABLES');
$isSuccess = true;
$skipLog = false;
try {
if ($job->get('scheduledJobId')) {
@@ -180,7 +201,12 @@ class CronManager
}
} catch (\Exception $e) {
$isSuccess = false;
$GLOBALS['log']->error('CronManager: Failed job running, job ['.$job->id.']. Error Details: '.$e->getMessage());
if ($e->getCode() === -1) {
$job->set('attempts', 0);
$skipLog = true;
} else {
$GLOBALS['log']->error('CronManager: Failed job running, job ['.$job->id.']. Error Details: '.$e->getMessage());
}
}
$status = $isSuccess ? self::SUCCESS : self::FAILED;
@@ -188,7 +214,7 @@ class CronManager
$job->set('status', $status);
$this->getEntityManager()->saveEntity($job);
if ($job->get('scheduledJobId')) {
if ($job->get('scheduledJobId') && !$skipLog) {
$this->getCronScheduledJobUtil()->addLogRecord($job->get('scheduledJobId'), $status, null, $job->get('targetId'), $job->get('targetType'));
}
}

View File

@@ -53,6 +53,8 @@ class DataManager
*/
public function rebuild($entityList = null)
{
$this->populateConfigParameters();
$result = $this->clearCache();
$result &= $this->rebuildMetadata();
@@ -143,13 +145,17 @@ class DataManager
if ($job) {
$entityManager->removeEntity($job);
}
$name = $jobName;
if (!empty($defs['name'])) {
$name = $defs['name'];
}
$job = $entityManager->getEntity('ScheduledJob');
$job->set(array(
'job' => $jobName,
'status' => 'Active',
'scheduling' => $defs['scheduling'],
'isInternal' => true,
'name' => $jobName
'name' => $name
));
$entityManager->saveEntity($job);
}
@@ -168,5 +174,25 @@ class DataManager
$this->getContainer()->get('config')->save();
return true;
}
}
protected function populateConfigParameters()
{
$config = $this->getContainer()->get('config');
$pdo = $this->getContainer()->get('entityManager')->getPDO();
$query = "SHOW VARIABLES LIKE 'ft_min_word_len'";
$sth = $pdo->prepare($query);
$sth->execute();
$fullTextSearchMinLength = null;
if ($row = $sth->fetch(\PDO::FETCH_ASSOC)) {
if (isset($row['Value'])) {
$fullTextSearchMinLength = intval($row['Value']);
}
}
$config->set('fullTextSearchMinLength', $fullTextSearchMinLength);
$config->save();
}
}

View File

@@ -0,0 +1,36 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Exceptions;
class ServiceUnavailable extends \Exception
{
protected $code = 503;
}

View File

@@ -31,19 +31,35 @@ namespace Espo\Core\Export;
use \Espo\Core\Exceptions\Error;
use \Espo\Core\ORM\Entity;
class Csv extends \Espo\Core\Injectable
{
protected $dependencyList = [
'config',
'preferences'
'preferences',
'metadata'
];
public function loadAdditionalFields(Entity $entity, $fieldList)
{
foreach ($fieldList as $field) {
if ($this->getInjection('metadata')->get(['entityDefs', $entity->getEntityType(), 'fields', $field, 'type']) === 'linkMultiple') {
if (!$entity->has($field . 'Ids')) {
$entity->loadLinkMultipleField($field);
}
}
}
}
public function process($entityType, $params, $dataList)
{
if (!is_array($params['attributeList'])) {
throw new Error();
}
$dataList = $this->prepareDataList($dataList);
$attributeList = $params['attributeList'];
$delimiter = $this->getInjection('preferences')->get('exportDelimiter');
@@ -62,4 +78,21 @@ class Csv extends \Espo\Core\Injectable
return $csv;
}
protected function prepareDataList($dataList)
{
$prepareDataList = [];
foreach ($dataList as $row) {
$preparedRow = [];
foreach ($row as $item) {
if (is_array($item) || is_object($item)) {
$item = \Espo\Core\Utils\Json::encode($item);
}
$preparedRow[] = $item;
}
$prepareDataList[] = $preparedRow;
}
return $prepareDataList;
}
}

View File

@@ -62,22 +62,51 @@ class Xlsx extends \Espo\Core\Injectable
public function loadAdditionalFields(Entity $entity, $fieldList)
{
foreach ($entity->getRelationList() as $link) {
if ($entity->getRelationType($link) === 'belongsToParent') {
if (in_array($link, $fieldList)) {
$parent = $entity->get($link);
if ($parent instanceof Entity) {
$entity->set($link . 'Name', $parent->get('name'));
if (in_array($link, $fieldList)) {
if ($entity->getRelationType($link) === 'belongsToParent') {
if (!$entity->get($link . 'Name')) {
$entity->loadParentNameField($link);
}
}
} else if ($entity->getRelationType($link) === 'belongsTo' && $entity->getRelationParam($link, 'noJoin') && $entity->hasField($link . 'Name')) {
if (in_array($link, $fieldList)) {
$related = $entity->get($link);
if ($related instanceof Entity) {
$entity->set($link . 'Name', $related->get('name'));
} else if (
(
(
$entity->getRelationType($link) === 'belongsTo'
&&
$entity->getRelationParam($link, 'noJoin')
)
||
$entity->getRelationType($link) === 'hasOne'
)
&&
$entity->hasAttribute($link . 'Name')
) {
if (!$entity->get($link . 'Name') || !$entity->get($link . 'Id')) {
$entity->loadLinkField($link);
}
}
}
}
foreach ($fieldList as $field) {
if ($this->getMetadata()->get(['entityDefs', $entity->getEntityType(), 'fields', $field, 'type']) === 'linkMultiple') {
if (!$entity->has($field . 'Ids')) {
$entity->loadLinkMultipleField($field);
}
}
}
}
public function filterFieldList($entityType, $fieldList, $exportAllFields)
{
if ($exportAllFields) {
foreach ($fieldList as $i => $field) {
$type = $this->getMetadata()->get(['entityDefs', $entityType, 'fields', $field, 'type']);
if (in_array($type, ['linkMultiple', 'attachmentMultiple'])) {
unset($fieldList[$i]);
}
}
}
return array_values($fieldList);
}
public function addAdditionalAttributes($entityType, &$attributeList, $fieldList)
@@ -123,7 +152,7 @@ class Xlsx extends \Espo\Core\Injectable
throw new Error();
}
$phpExcel = new \PHPExcel();
$phpExcel = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $phpExcel->setActiveSheetIndex(0);
if (isset($params['exportName'])) {
@@ -155,10 +184,11 @@ class Xlsx extends \Espo\Core\Injectable
)
);
$now = new \DateTime();
$now->setTimezone(new \DateTimeZone($this->getInjection('config')->get('timeZone', 'UTC')));
$sheet->setCellValue('A1', $exportName);
$sheet->setCellValue('B1', \PHPExcel_Shared_Date::PHPToExcel(strtotime(date('Y-m-d H:i:s'))));
$sheet->setCellValue('B1', \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel(strtotime($now->format('Y-m-d H:i:s'))));
$sheet->getStyle('A1')->applyFromArray($titleStyle);
$sheet->getStyle('B1')->applyFromArray($dateStyle);
@@ -270,6 +300,8 @@ class Xlsx extends \Espo\Core\Injectable
}
} else if ($type == 'int') {
$sheet->setCellValue("$col$rowNumber", $row[$name] ?: 0);
} else if ($type == 'float') {
$sheet->setCellValue("$col$rowNumber", $row[$name] ?: 0);
} else if ($type == 'currency') {
if (array_key_exists($name.'Currency', $row) && array_key_exists($name, $row)) {
$sheet->setCellValue("$col$rowNumber", $row[$name] ? $row[$name] : '');
@@ -282,7 +314,7 @@ class Xlsx extends \Espo\Core\Injectable
}
} else if ($type == 'currencyConverted') {
if (array_key_exists($name, $row)) {
$currency = $this->getConfig()->get('baseCurrency');
$currency = $this->getConfig()->get('defaultCurrency');
$currencySymbol = $this->getMetadata()->get(['app', 'currency', 'symbolMap', $currency], '');
$sheet->getStyle("$col$rowNumber")
@@ -309,7 +341,7 @@ class Xlsx extends \Espo\Core\Injectable
}
} else if ($type == 'date') {
if (isset($row[$name])) {
$sheet->setCellValue("$col$rowNumber", \PHPExcel_Shared_Date::PHPToExcel(strtotime($row[$name])));
$sheet->setCellValue("$col$rowNumber", \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel(strtotime($row[$name])));
}
} else if ($type == 'datetime' || $type == 'datetimeOptional') {
$value = null;
@@ -334,14 +366,14 @@ class Xlsx extends \Espo\Core\Injectable
}
}
if ($value) {
$sheet->setCellValue("$col$rowNumber", \PHPExcel_Shared_Date::PHPToExcel(strtotime($value)));
$sheet->setCellValue("$col$rowNumber", \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel(strtotime($value)));
}
} else if ($type == 'image') {
if (isset($row[$name . 'Id']) && $row[$name . 'Id']) {
$attachment = $this->getEntityManager()->getEntity('Attachment', $row[$name . 'Id']);
if ($attachment) {
$objDrawing = new \PHPExcel_Worksheet_Drawing();
$objDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
$filePath = $this->getInjection('fileStorageManager')->getLocalFilePath($attachment);
if ($filePath && file_exists($filePath)) {
@@ -367,14 +399,97 @@ class Xlsx extends \Espo\Core\Injectable
}
$sheet->setCellValue("$col$rowNumber", $value);
}
} else if ($type == 'linkMultiple') {
if (array_key_exists($name . 'Ids', $row) && array_key_exists($name . 'Names', $row)) {
$nameList = [];
foreach ($row[$name . 'Ids'] as $relatedId) {
$relatedName = $relatedId;
if (property_exists($row[$name . 'Names'], $relatedId)) {
$relatedName = $row[$name . 'Names']->$relatedId;
}
$nameList[] = $relatedName;
}
$sheet->setCellValue("$col$rowNumber", implode(', ', $nameList));
}
} else if ($type == 'address') {
$value = '';
if (!empty($row[$name . 'Street'])) {
$value = $value .= $row[$name.'Street'];
}
if (!empty($row[$name.'City']) || !empty($row[$name.'State']) || !empty($row[$name.'PostalCode'])) {
if ($value) {
$value .= "\n";
}
if (!empty($row[$name.'City'])) {
$value .= $row[$name.'City'];
if (
!empty($row[$name.'State']) || !empty($row[$name.'PostalCode'])
) {
$value .= ', ';
}
}
if (!empty($row[$name.'State'])) {
$value .= $row[$name.'State'];
if (!empty($row[$name.'PostalCode'])) {
$value .= ' ';
}
}
if (!empty($row[$name.'PostalCode'])) {
$value .= $row[$name.'PostalCode'];
}
}
if (!empty($row[$name.'Country'])) {
if ($value) {
$value .= "\n";
}
$value .= $row[$name.'Country'];
}
$sheet->setCellValue("$col$rowNumber", $value);
} else if ($type == 'duration') {
if (!empty($row[$name])) {
$seconds = intval($row[$name]);
$days = intval(floor($seconds / 86400));
$seconds = $seconds - $days * 86400;
$hours = intval(floor($seconds / 3600));
$seconds = $seconds - $hours * 3600;
$minutes = intval(floor($seconds / 60));
$value = '';
if ($days) {
$value .= (string) $days . $this->getInjection('language')->translate('d', 'durationUnits');
if ($minutes || $hours) {
$value .= ' ';
}
}
if ($hours) {
$value .= (string) $hours . $this->getInjection('language')->translate('h', 'durationUnits');
if ($minutes) {
$value .= ' ';
}
}
if ($minutes) {
$value .= (string) $minutes . $this->getInjection('language')->translate('m', 'durationUnits');
}
$sheet->setCellValue("$col$rowNumber", $value);
}
} else {
if (array_key_exists($name, $row)) {
$sheet->setCellValue("$col$rowNumber", $row[$name]);
$sheet->setCellValueExplicit("$col$rowNumber", $row[$name], \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING);
}
}
$link = false;
$foreignLink = null;
$isForeign = false;
if (strpos($name, '_')) {
$isForeign = true;
list($foreignLink, $foreignField) = explode('_', $name);
}
if ($name == 'name') {
if (array_key_exists('id', $row)) {
$link = $this->getConfig()->getSiteUrl() . "/#".$entityType . "/view/" . $row['id'];
@@ -385,7 +500,13 @@ class Xlsx extends \Espo\Core\Injectable
}
} else if ($type == 'link') {
if (array_key_exists($name.'Id', $row)) {
$foreignEntity = $this->getMetadata()->get(['entityDefs', $entityType, 'links', $name, 'entity']);
$foreignEntity = null;
if (!$isForeign) {
$foreignEntity = $this->getMetadata()->get(['entityDefs', $entityType, 'links', $name, 'entity']);
} else {
$foreignEntity1 = $this->getMetadata()->get(['entityDefs', $entityType, 'links', $foreignLink, 'entity']);
$foreignEntity = $this->getMetadata()->get(['entityDefs', $foreignEntity1, 'links', $foreignField, 'entity']);
}
if ($foreignEntity) {
$link = $this->getConfig()->getSiteUrl() . "/#" . $foreignEntity. "/view/". $row[$name.'Id'];
}
@@ -417,12 +538,15 @@ class Xlsx extends \Espo\Core\Injectable
$sheet->getStyle("A2:A$rowNumber")
->getNumberFormat()
->setFormatCode(\PHPExcel_Style_NumberFormat::FORMAT_TEXT);
->setFormatCode(\PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_TEXT);
$startingRowNumber = 4;
foreach ($fieldList as $i => $name) {
$col = $azRange[$i];
if (!array_key_exists($name, $typesCache)) {
break;
}
$type = $typesCache[$name];
switch ($type) {
@@ -435,6 +559,11 @@ class Xlsx extends \Espo\Core\Injectable
->getNumberFormat()
->setFormatCode('0');
} break;
case 'float': {
$sheet->getStyle($col.$startingRowNumber.':'.$col.$rowNumber)
->getNumberFormat()
->setFormatCode(\PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED1);
} break;
case 'date': {
$sheet->getStyle($col.$startingRowNumber.':'.$col.$rowNumber)
->getNumberFormat()
@@ -468,7 +597,7 @@ class Xlsx extends \Espo\Core\Injectable
$sheet->getStyle($linkColumn.$startingRowNumber.':'.$linkColumn.$rowNumber)->applyFromArray($linkStyle);
}
$objWriter = \PHPExcel_IOFactory::createWriter($phpExcel, 'Excel2007');
$objWriter = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($phpExcel, 'Xlsx');
if (!$this->getInjection('fileManager')->isDir('data/cache/')) {
$this->getInjection('fileManager')->mkdir('data/cache/');

View File

@@ -36,10 +36,10 @@ class IncludesType extends \Espo\Core\Formula\Functions\Base
public function process(\StdClass $item)
{
if (!property_exists($item, 'value') || !is_array($item->value)) {
throw new Error('Value for \'Array\\Includses\' item is not array.');
throw new Error('Value for \'Array\\Includes\' item is not array.');
}
if (count($item->value) < 2) {
throw new Error('Bad arguments passed to \'Array\\Includses\'.');
throw new Error('Bad arguments passed to \'Array\\Includes\'.');
}
$list = $this->evaluate($item->value[0]);
$needle = $this->evaluate($item->value[1]);

View File

@@ -0,0 +1,89 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Formula\Functions\EntityGroup;
use \Espo\ORM\Entity;
use \Espo\Core\Exceptions\Error;
class CountRelatedType extends \Espo\Core\Formula\Functions\Base
{
protected function init()
{
$this->addDependency('entityManager');
$this->addDependency('selectManagerFactory');
}
public function process(\StdClass $item)
{
if (!property_exists($item, 'value')) {
throw new Error();
}
if (!is_array($item->value)) {
throw new Error();
}
if (count($item->value) < 1) {
throw new Error();
}
$link = $this->evaluate($item->value[0]);
if (empty($link)) {
throw new Error("No link passed to countRelated function.");
}
$filter = null;
if (count($item->value) > 1) {
$filter = $this->evaluate($item->value[1]);
}
$entity = $this->getEntity();
$entityManager = $this->getInjection('entityManager');
$foreignEntityType = $entity->getRelationParam($link, 'entity');
if (empty($foreignEntityType)) {
throw new Error();
}
$foreignSelectManager = $this->getInjection('selectManagerFactory')->create($foreignEntityType);
$selectParams = $foreignSelectManager->getEmptySelectParams();
if ($filter) {
$foreignSelectManager->applyFilter($filter, $selectParams);
}
return $entityManager->getRepository($entity->getEntityType())->countRelated($entity, $link, $selectParams);
}
}

View File

@@ -0,0 +1,119 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Formula\Functions\EntityGroup;
use \Espo\ORM\Entity;
use \Espo\Core\Exceptions\Error;
class SumRelatedType extends \Espo\Core\Formula\Functions\Base
{
protected function init()
{
$this->addDependency('entityManager');
$this->addDependency('selectManagerFactory');
}
public function process(\StdClass $item)
{
if (!property_exists($item, 'value')) {
throw new Error();
}
if (!is_array($item->value)) {
throw new Error();
}
if (count($item->value) < 2) {
throw new Error();
}
$link = $this->evaluate($item->value[0]);
if (empty($link)) {
throw new Error("No link passed to sumRelated function.");
}
$field = $this->evaluate($item->value[1]);
if (empty($field)) {
throw new Error("No field passed to sumRelated function.");
}
$filter = null;
if (count($item->value) > 2) {
$filter = $this->evaluate($item->value[2]);
}
$entity = $this->getEntity();
$entityManager = $this->getInjection('entityManager');
$foreignEntityType = $entity->getRelationParam($link, 'entity');
if (empty($foreignEntityType)) {
throw new Error();
}
$foreignSelectManager = $this->getInjection('selectManagerFactory')->create($foreignEntityType);
$foreignLink = $entity->getRelationParam($link, 'foreign');
if (empty($foreignLink)) {
throw new Error("No foreign link for link {$link}.");
}
$selectParams = $foreignSelectManager->getEmptySelectParams();
if ($filter) {
$foreignSelectManager->applyFilter($filter, $selectParams);
}
$selectParams['select'] = [[$foreignLink . '.id', 'foreignId'], 'SUM:' . $field];
$foreignSelectManager->addJoin($foreignLink, $selectParams);
$selectParams['groupBy'] = [$foreignLink . '.id'];
$entityManager->getRepository($foreignEntityType)->handleSelectParams($selectParams);
$sql = $entityManager->getQuery()->createSelectQuery($foreignEntityType, $selectParams);
$pdo = $entityManager->getPDO();
$sth = $pdo->prepare($sql);
$sth->execute();
$rowList = $sth->fetchAll(\PDO::FETCH_ASSOC);
if (empty($rowList)) {
return 0;
}
return $rowList[0]['SUM:' . $field];
}
}

View File

@@ -0,0 +1,53 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 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/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Formula\Functions\StringGroup;
use \Espo\Core\Exceptions\Error;
class ContainsType extends \Espo\Core\Formula\Functions\Base
{
public function process(\StdClass $item)
{
if (!property_exists($item, 'value') || !is_array($item->value)) {
throw new Error('Value for \'String\\Contains\' item is not an array.');
}
if (count($item->value) < 2) {
throw new Error('Bad arguments passed to \'String\\Contains\'.');
}
$string = $this->evaluate($item->value[0]);
$needle = $this->evaluate($item->value[1]);
if (!is_string($string)) {
return false;
}
return mb_strpos($string, $needle) !== false;
}
}

View File

@@ -1,3 +1,4 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
@@ -25,44 +26,33 @@
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
(function ($) {
var root = this;
namespace Espo\Core\Formula\Functions\StringGroup;
root.Espo = {};
use \Espo\Core\Exceptions\Error;
this.EspoTest = {
class LengthType extends \Espo\Core\Formula\Functions\Base
{
public function process(\StdClass $item)
{
if (!property_exists($item, 'value')) {
return '';
}
include: function (path, options) {
var thisObject = root;
if (options != undefined && 'self' in options) {
thisObject = options.self;
}
if (!is_array($item->value)) {
throw new Error();
}
var self = this;
if (count($item->value) < 1) {
throw new Error();
}
var ajaxOptions = {
url: path,
async: false,
cache: false,
type: 'GET',
dataType: 'text',
success: function (script) {
eval.call(thisObject, script);
},
error: function () {
console.error("Error occured while loading " + path);
}
};
$value = $this->evaluate($item->value[0]);
if (typeof options != 'undefined') {
_.each(options, function (value, key) {
ajaxOptions[key] = options[key];
});
}
if (!is_string($value)) {
$value = strval($value);
}
$.ajax(ajaxOptions);
},
};
}).call(this, $);
return mb_strlen($value);
}
}

View File

@@ -53,6 +53,6 @@ class LowerCaseType extends \Espo\Core\Formula\Functions\Base
$value = strval($value);
}
return strtolower($value);
return mb_strtolower($value);
}
}

View File

@@ -1,4 +1,4 @@
<?php
<?php
/************************************************************************
* This file is part of EspoCRM.
*
@@ -52,9 +52,9 @@ class SubstringType extends \Espo\Core\Formula\Functions\Base
if (count($item->value) > 2) {
$length = $this->evaluate($item->value[2]);
return substr($string, $start, $length);
return mb_substr($string, $start, $length);
} else {
return substr($string, $start);
return mb_substr($string, $start);
}
}
}

View File

@@ -53,6 +53,6 @@ class UpperCaseType extends \Espo\Core\Formula\Functions\Base
$value = strval($value);
}
return strtoupper($value);
return mb_strtoupper($value);
}
}

View File

@@ -176,6 +176,8 @@ class Parser
$this->processStrings($expression, $modifiedExpression, $splitterIndexList, true);
$expressionOutOfBraceList = [];
for ($i = 0; $i < strlen($modifiedExpression); $i++) {
if ($modifiedExpression[$i] === '(') {
$braceCounter++;
@@ -186,6 +188,11 @@ class Parser
if ($braceCounter === 0 && $i < strlen($modifiedExpression) - 1) {
$hasExcessBraces = false;
}
if ($braceCounter === 0) {
$expressionOutOfBraceList[] = true;
} else {
$expressionOutOfBraceList[] = false;
}
}
if ($braceCounter !== 0) {
throw new Error('Incorrect round brackets in expression ' . $expression . '.');
@@ -226,7 +233,13 @@ class Parser
foreach ($this->priorityList as $operationList) {
foreach ($operationList as $operator) {
$index = strpos($expression, $operator, 1);
$startFrom = 1;
while (true) {
$index = strpos($expression, $operator, $startFrom);
if ($index === false) break;
if ($expressionOutOfBraceList[$index]) break;
$startFrom = $index + 1;
}
if ($index !== false) {
$possibleRightOperator = null;
if (strlen($operator) === 1) {

View File

@@ -50,13 +50,19 @@ class Htmlizer
protected $entityManager;
public function __construct(FileManager $fileManager, DateTime $dateTime, NumberUtil $number, $acl = null, $entityManager = null)
protected $metadata;
protected $language;
public function __construct(FileManager $fileManager, DateTime $dateTime, NumberUtil $number, $acl = null, $entityManager = null, $metadata = null, $language = null)
{
$this->fileManager = $fileManager;
$this->dateTime = $dateTime;
$this->number = $number;
$this->acl = $acl;
$this->entityManager = $entityManager;
$this->metadata = $metadata;
$this->language = $language;
}
protected function getAcl()
@@ -94,10 +100,10 @@ class Htmlizer
$forbidenAttributeList = $this->getAcl()->getScopeForbiddenAttributeList($entity->getEntityType(), 'read');
}
foreach ($fieldList as $field) {
if (in_array($field, $forbidenAttributeList)) continue;
$type = $entity->getAttributeType($field);
if ($type == Entity::DATETIME) {
@@ -115,16 +121,16 @@ class Htmlizer
foreach ($list as $item) {
$v = $item;
if ($item instanceof \StdClass) {
$v = json_decode(json_encode($v), true);
$v = json_decode(json_encode($v, \JSON_PRESERVE_ZERO_FRACTION), true);
}
if (!is_array($v)) {
$v = [];
}
foreach ($v as $k => $w) {
$keyRaw = $k . '_RAW';
$v[$keyRaw] = $v[$k];
$v[$k] = $this->format($v[$k]);
if (is_array($v)) {
foreach ($v as $k => $w) {
$keyRaw = $k . '_RAW';
$v[$keyRaw] = $v[$k];
$v[$k] = $this->format($v[$k]);
}
}
$newList[] = $v;
}
$data[$field] = $newList;
@@ -133,7 +139,7 @@ class Htmlizer
if (!empty($data[$field])) {
$value = $data[$field];
if ($value instanceof \StdClass) {
$data[$field] = json_decode(json_encode($value), true);
$data[$field] = json_decode(json_encode($value, \JSON_PRESERVE_ZERO_FRACTION), true);
}
foreach ($data[$field] as $k => $w) {
$keyRaw = $k . '_RAW';
@@ -148,6 +154,14 @@ class Htmlizer
if (array_key_exists($field, $data)) {
$keyRaw = $field . '_RAW';
$data[$keyRaw] = $data[$field];
$fieldType = $this->getFieldType($entity->getEntityType(), $field);
if ($fieldType === 'enum') {
if ($this->language) {
$data[$field] = $this->language->translateOption($data[$field], $field, $entity->getEntityType());
}
}
$data[$field] = $this->format($data[$field]);
}
}
@@ -205,6 +219,14 @@ class Htmlizer
return number_format($number, $decimals, $decimalPoint, $thousandsSeparator);
}
return '';
},
'var' => function ($context, $options) {
if ($context && isset($context[0]) && isset($context[1])) {
if (isset($context[1][$context[0]])) {
return $context[1][$context[0]];
}
}
return;
}
],
'hbhelpers' => [
@@ -246,13 +268,20 @@ class Htmlizer
$data = $this->getDataFromEntity($entity, $skipLinks);
if (!array_key_exists('today', $data)) {
$data['today'] = $this->dateTime->getTodayString();
}
if (!array_key_exists('now', $data)) {
$data['now'] = $this->dateTime->getNowString();
}
foreach ($additionalData as $k => $value) {
$data[$k] = $value;
}
$html = $renderer($data);
$html = str_replace('?entryPoint=attachment&amp;', '?entryPoint=attachment&', $html);
if ($this->getEntityManager()) {
@@ -269,4 +298,9 @@ class Htmlizer
return $html;
}
protected function getFieldType($entityType, $field) {
if (!$this->metadata) return;
return $this->metadata->get(['entityDefs', $entityType, 'fields', $field, 'type']);
}
}

View File

@@ -154,31 +154,8 @@ class Importer
}
if ($duplicate = $this->findDuplicate($email)) {
if ($assignedUserId) {
$duplicate->addLinkMultipleId('users', $assignedUserId);
$duplicate->addLinkMultipleId('assignedUsers', $assignedUserId);
}
if (!empty($userIdList)) {
foreach ($userIdList as $uId) {
$duplicate->addLinkMultipleId('users', $uId);
}
}
if ($folderData) {
foreach ($folderData as $uId => $folderId) {
$email->setLinkMultipleColumn('users', 'folderId', $uId, $folderId);
}
}
$duplicate->set('isBeingImported', true);
$this->getEntityManager()->saveEntity($duplicate);
if (!empty($teamsIdList)) {
foreach ($teamsIdList as $teamId) {
$this->getEntityManager()->getRepository('Email')->relate($duplicate, 'teams', $teamId);
}
}
$duplicate = $this->getEntityManager()->getEntity('Email', $duplicate->id);
$this->processDuplicate($duplicate, $assignedUserId, $userIdList, $folderData, $teamsIdList);
return $duplicate;
}
@@ -228,6 +205,10 @@ class Importer
))->findOne();
if ($replied) {
$email->set('repliedId', $replied->id);
$repliedTeamIdList = $replied->getLinkMultipleIdList('teams');
foreach ($repliedTeamIdList as $repliedTeamId) {
$email->addLinkMultipleId('teams', $repliedTeamId);
}
}
}
@@ -299,6 +280,43 @@ class Importer
}
}
$this->getEntityManager()->getPdo()->query('LOCK TABLES `email` WRITE');
if ($duplicate = $this->findDuplicate($email)) {
$this->getEntityManager()->getPdo()->query('UNLOCK TABLES');
$duplicate = $this->getEntityManager()->getEntity('Email', $duplicate->id);
$this->processDuplicate($duplicate, $assignedUserId, $userIdList, $folderData, $teamsIdList);
return $duplicate;
}
if (!$email->get('messageId')) {
$email->setDummyMessageId();
}
$this->getEntityManager()->saveEntity($email, [
'skipAll' => true,
'keepNew' => true
]);
$this->getEntityManager()->getPdo()->query('UNLOCK TABLES');
if ($parentFound) {
$parentType = $email->get('parentType');
$parentId = $email->get('parentId');
$emailKeepParentTeamsEntityList = $this->getConfig()->get('emailKeepParentTeamsEntityList', []);
if ($parentId && in_array($parentType, $emailKeepParentTeamsEntityList)) {
if ($this->getEntityManager()->hasRepository($parentType)) {
$parent = $this->getEntityManager()->getEntity($parentType, $parentId);
if ($parent) {
$parentTeamIdList = $parent->getLinkMultipleIdList('teams');
foreach ($parentTeamIdList as $parentTeamId) {
$email->addLinkMultipleId('teams', $parentTeamId);
}
}
}
}
}
$this->getEntityManager()->saveEntity($email);
foreach ($inlineAttachmentList as $attachment) {
@@ -352,12 +370,41 @@ class Importer
protected function findDuplicate(Entity $email)
{
if ($email->get('messageId')) {
$duplicate = $this->getEntityManager()->getRepository('Email')->where(array(
$duplicate = $this->getEntityManager()->getRepository('Email')->select(['id'])->where(array(
'messageId' => $email->get('messageId')
))->findOne();
))->findOne(['skipAdditionalSelectParams' => true]);
if ($duplicate) {
return $duplicate;
}
}
}
protected function processDuplicate(Entity $duplicate, $assignedUserId, $userIdList, $folderData, $teamsIdList)
{
if ($assignedUserId) {
$duplicate->addLinkMultipleId('users', $assignedUserId);
$duplicate->addLinkMultipleId('assignedUsers', $assignedUserId);
}
if (!empty($userIdList)) {
foreach ($userIdList as $uId) {
$duplicate->addLinkMultipleId('users', $uId);
}
}
if ($folderData) {
foreach ($folderData as $uId => $folderId) {
$duplicate->setLinkMultipleColumn('users', 'folderId', $uId, $folderId);
}
}
$duplicate->set('isBeingImported', true);
$this->getEntityManager()->saveEntity($duplicate);
if (!empty($teamsIdList)) {
foreach ($teamsIdList as $teamId) {
$this->getEntityManager()->getRepository('Email')->relate($duplicate, 'teams', $teamId);
}
}
}
}

View File

@@ -179,9 +179,10 @@ class MailMimeParser
} else {
$email->set('isHtml', false);
$email->set('body', $bodyPlain);
$email->set('bodyPlain', $bodyPlain);
}
if (!$email->get('body') && $email->get('bodyPlain')) {
if (!$email->get('body') && $email->hasBodyPlain()) {
$email->set('body', $email->get('bodyPlain'));
}

View File

@@ -165,9 +165,10 @@ class PhpMimeMailParser
} else {
$email->set('isHtml', false);
$email->set('body', $bodyPlain);
$email->set('bodyPlain', $bodyPlain);
}
if (!$email->get('body') && $email->get('bodyPlain')) {
if (!$email->get('body') && $email->hasBodyPlain()) {
$email->set('body', $email->get('bodyPlain'));
}

View File

@@ -33,7 +33,7 @@ use \PhpMimeMailParser\Attachment;
class Parser extends \PhpMimeMailParser\Parser
{
public function getAttachments()
public function getAttachments($include_inline = true)
{
$attachments = [];
$dispositions = ['attachment', 'inline'];

View File

@@ -139,7 +139,7 @@ class ZendMail
$this->importPartDataToEmail($email, $zendMessage, $inlineIds, 'text/plain', $inlineAttachmentList);
}
if (!$email->get('body') && $email->get('bodyPlain')) {
if (!$email->get('body') && $email->hasBodyPlain()) {
$email->set('body', $email->get('bodyPlain'));
}
@@ -192,7 +192,7 @@ class ZendMail
$content = $this->getContentFromPart($part);
if ($type == 'text/plain') {
$bodyPlain = '';
if ($email->get('bodyPlain')) {
if ($email->hasBodyPlain()) {
$bodyPlain .= $email->get('bodyPlain') . "\n";
}
$bodyPlain .= $content;

View File

@@ -89,8 +89,12 @@ class Sender
$this->transport = new SmtpTransport();
$config = $this->config;
$localHostName = $config->get('smtpLocalHostName', gethostname());
$opts = array(
'name' => 'admin',
'name' => $localHostName,
'host' => $params['server'],
'port' => $params['port'],
'connection_config' => array()
@@ -132,8 +136,10 @@ class Sender
$config = $this->config;
$localHostName = $config->get('smtpLocalHostName', gethostname());
$opts = array(
'name' => 'admin',
'name' => $localHostName,
'host' => $config->get('smtpServer'),
'port' => $config->get('smtpPort'),
'connection_config' => array()
@@ -260,7 +266,7 @@ class Sender
$attachment = new MimePart(file_get_contents($fileName));
$attachment->disposition = Mime::DISPOSITION_ATTACHMENT;
$attachment->encoding = Mime::ENCODING_BASE64;
$attachment->filename = $a->get('name');
$attachment->filename ='=?utf-8?B?' . base64_encode($a->get('name')) . '?=';
if ($a->get('type')) {
$attachment->type = $a->get('type');
}
@@ -349,7 +355,7 @@ class Sender
try {
$messageId = $email->get('messageId');
if (empty($messageId) || !is_string($messageId) || strlen($messageId) < 4) {
if (empty($messageId) || !is_string($messageId) || strlen($messageId) < 4 || strpos($messageId, 'dummy:') === 0) {
$messageId = $this->generateMessageId($email);
$email->set('messageId', '<' . $messageId . '>');
} else {

View File

@@ -92,11 +92,27 @@ class Base implements Injectable
public function process(Entity $entity)
{
if (!$entity->get('assignedUserId')) return;
if (!$entity->isFieldChanged('assignedUserId')) return;
if ($entity->hasLinkMultipleField('assignedUsers')) {
$userIdList = $entity->getLinkMultipleIdList('assignedUsers');
$fetchedAssignedUserIdList = $entity->getFetched('assignedUsersIds');
if (!is_array($fetchedAssignedUserIdList)) {
$fetchedAssignedUserIdList = [];
}
$assignedUserId = $entity->get('assignedUserId');
foreach ($userIdList as $userId) {
if (in_array($userId, $fetchedAssignedUserIdList)) continue;
$this->processForUser($entity, $userId);
}
} else {
if (!$entity->get('assignedUserId')) return;
if (!$entity->isAttributeChanged('assignedUserId')) return;
$assignedUserId = $entity->get('assignedUserId');
$this->processForUser($entity, $assignedUserId);
}
}
protected function processForUser(Entity $entity, $assignedUserId)
{
if ($entity->hasAttribute('createdById') && $entity->hasAttribute('modifiedById')) {
if ($entity->isNew()) {
$isNotSelfAssignment = $assignedUserId !== $entity->get('createdById');

View File

@@ -41,6 +41,29 @@ class Entity extends \Espo\ORM\Entity
return $this->hasAttribute($field . 'Id');
}
public function loadParentNameField($field)
{
if (!$this->hasAttribute($field. 'Id') || !$this->hasAttribute($field . 'Type')) return;
$parentId = $this->get($field . 'Id');
$parentType = $this->get($field . 'Type');
if ($parentId && $parentType) {
if (!$this->entityManager->hasRepository($parentType)) return;
$repository = $this->entityManager->getRepository($parentType);
$select = ['id', 'name'];
$foreignEntity = $repository->select($select)->where(['id' => $parentId])->findOne();
if ($foreignEntity) {
$this->set($field . 'Name', $foreignEntity->get('name'));
} else {
$this->set($field . 'Name', null);
}
} else {
$this->set($field . 'Name', null);
}
}
public function loadLinkMultipleField($field, $columns = null)
{
if (!$this->hasRelation($field) || !$this->hasAttribute($field . 'Ids')) return;
@@ -50,31 +73,50 @@ class Entity extends \Espo\ORM\Entity
$defs['additionalColumns'] = $columns;
}
$idsAttribute = $field . 'Ids';
$foreignEntityType = $this->getRelationParam($field, 'entity');
if ($foreignEntityType && $this->entityManager) {
$foreignEntityDefs = $this->entityManager->getMetadata()->get($foreignEntityType);
if ($foreignEntityDefs && !empty($foreignEntityDefs['collection'])) {
$collectionDefs = $foreignEntityDefs['collection'];
if (!empty($foreignEntityDefs['collection']['orderBy'])) {
$orderBy = $foreignEntityDefs['collection']['orderBy'];
$order = 'ASC';
if (array_key_exists('order', $foreignEntityDefs['collection'])) {
$order = $foreignEntityDefs['collection']['order'];
}
if (array_key_exists($orderBy, $foreignEntityDefs['fields'])) {
$defs['orderBy'] = $orderBy;
$defs['order'] = $order;
if ($this->getAttributeParam($idsAttribute, 'orderBy')) {
$defs['orderBy'] = $this->getAttributeParam($idsAttribute, 'orderBy');
$defs['order'] = 'ASC';
if ($this->getAttributeParam($idsAttribute, 'orderDirection')) {
$defs['order'] = $this->getAttributeParam($idsAttribute, 'orderDirection');
}
} else {
if ($foreignEntityType && $this->entityManager) {
$foreignEntityDefs = $this->entityManager->getMetadata()->get($foreignEntityType);
if ($foreignEntityDefs && !empty($foreignEntityDefs['collection'])) {
$collectionDefs = $foreignEntityDefs['collection'];
if (!empty($foreignEntityDefs['collection']['orderBy'])) {
$orderBy = $foreignEntityDefs['collection']['orderBy'];
$order = 'ASC';
if (array_key_exists('order', $foreignEntityDefs['collection'])) {
$order = $foreignEntityDefs['collection']['order'];
}
if (array_key_exists($orderBy, $foreignEntityDefs['fields'])) {
$defs['orderBy'] = $orderBy;
$defs['order'] = $order;
}
}
}
}
}
$defs['select'] = ['id', 'name'];
$hasType = false;
if ($this->hasField($field . 'Types')) {
$hasType = true;
$defs['select'][] = 'type';
}
$collection = $this->get($field, $defs);
$ids = array();
$names = new \stdClass();
$types = new \stdClass();
$ids = [];
$names = (object) [];
$types = (object) [];
if (!empty($columns)) {
$columnsData = new \stdClass();
$columnsData = (object) [];
}
if ($collection) {
@@ -82,7 +124,9 @@ class Entity extends \Espo\ORM\Entity
$id = $e->id;
$ids[] = $id;
$names->$id = $e->get('name');
$types->$id = $e->get('type');
if ($hasType) {
$types->$id = $e->get('type');
}
if (!empty($columns)) {
$columnsData->$id = new \stdClass();
foreach ($columns as $column => $f) {
@@ -92,9 +136,15 @@ class Entity extends \Espo\ORM\Entity
}
}
$this->set($field . 'Ids', $ids);
$this->set($idsAttribute, $ids);
if (!$this->isNew() && !$this->hasFetched($idsAttribute)) {
$this->setFetched($idsAttribute, $ids);
}
$this->set($field . 'Names', $names);
$this->set($field . 'Types', $types);
if ($hasType) {
$this->set($field . 'Types', $types);
}
if (!empty($columns)) {
$this->set($field . 'Columns', $columnsData);
}
@@ -105,7 +155,13 @@ class Entity extends \Espo\ORM\Entity
if (!$this->hasRelation($field) || !$this->hasAttribute($field . 'Id')) return;
if ($this->getRelationType($field) !== 'hasOne' && $this->getRelationType($field) !== 'belongsTo') return;
$entity = $this->get($field);
$relatedEntityType = $this->getRelationParam($field, 'entity');
$select = ['id', 'name'];
$entity = $this->get($field, [
'select' => $select
]);
$entityId = null;
$entityName = null;
@@ -114,7 +170,13 @@ class Entity extends \Espo\ORM\Entity
$entityName = $entity->get('name');
}
$this->set($field . 'Id', $entityId);
$idAttribute = $field . 'Id';
if (!$this->isNew() && !$this->hasFetched($idAttribute)) {
$this->setFetched($idAttribute, $entityId);
}
$this->set($idAttribute, $entityId);
$this->set($field . 'Name', $entityName);
}

View File

@@ -40,7 +40,9 @@ use \Espo\Core\Interfaces\Injectable;
class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
{
protected $dependencies = array(
'metadata'
'metadata',
'config',
'fieldManagerUtil'
);
protected $injections = array();
@@ -51,6 +53,10 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
protected $processFieldsAfterSaveDisabled = false;
protected $processFieldsBeforeSaveDisabled = false;
protected $processFieldsAfterRemoveDisabled = false;
protected function addDependency($name)
{
$this->dependencies[] = $name;
@@ -83,6 +89,16 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
return $this->getInjection('metadata');
}
protected function getConfig()
{
return $this->getInjection('config');
}
protected function getFieldManagerUtil()
{
return $this->getInjection('fieldManagerUtil');
}
public function __construct($entityType, EntityManager $entityManager, EntityFactory $entityFactory)
{
parent::__construct($entityType, $entityManager, $entityFactory);
@@ -110,20 +126,17 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
return;
}
$defs = $metadata->get('entityDefs.' . $entityType);
$defs = $metadata->get(['entityDefs', $entityType]);
foreach ($defs['fields'] as $field => $d) {
if (isset($d['type']) && $d['type'] == 'currency') {
if (!empty($d['notStorable'])) {
continue;
}
if (empty($params['customJoin'])) {
$params['customJoin'] = '';
}
$alias = Util::toUnderScore($field) . "_currency_alias";
$params['customJoin'] .= "
LEFT JOIN currency AS `{$alias}` ON {$alias}.id = ".Util::toUnderScore($entityType).".".Util::toUnderScore($field)."_currency
";
if (!empty($d['notStorable'])) continue;
if (empty($params['leftJoins'])) $params['leftJoins'] = [];
$alias = $field . 'CurrencyRate';
$params['leftJoins'][] = ['Currency', $alias, [
$alias . '.id:' => $field . 'Currency'
]];
}
}
@@ -131,52 +144,30 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
protected function handleEmailAddressParams(&$params)
{
$entityType = $this->entityType;
$defs = $this->getEntityManager()->getMetadata()->get($entityType);
$defs = $this->getEntityManager()->getMetadata()->get($this->entityType);
if (!empty($defs['relations']) && array_key_exists('emailAddresses', $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'][] = 'emailAddresses';
$params['joinConditions']['emailAddresses'] = array(
if (empty($params['leftJoins'])) $params['leftJoins'] = [];
$params['leftJoins'][] = ['emailAddresses', null, [
'primary' => 1
);
]];
}
}
protected function handlePhoneNumberParams(&$params)
{
$entityType = $this->entityType;
$defs = $this->getEntityManager()->getMetadata()->get($entityType);
$defs = $this->getEntityManager()->getMetadata()->get($this->entityType);
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(
if (empty($params['leftJoins'])) $params['leftJoins'] = [];
$params['leftJoins'][] = ['phoneNumbers', null, [
'primary' => 1
);
]];
}
}
protected function beforeRemove(Entity $entity, array $options = array())
{
parent::beforeRemove($entity, $options);
if (!$this->hooksDisabled) {
if (!$this->hooksDisabled && empty($options['skipHooks'])) {
$this->getEntityManager()->getHookManager()->process($this->entityType, 'beforeRemove', $entity, $options);
}
@@ -192,14 +183,19 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
protected function afterRemove(Entity $entity, array $options = array())
{
parent::afterRemove($entity, $options);
if (!$this->hooksDisabled) {
if (!$this->processFieldsAfterRemoveDisabled) {
$this->processArrayFieldsRemove($entity);
}
if (!$this->hooksDisabled && empty($options['skipHooks'])) {
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterRemove', $entity, $options);
}
}
protected function afterMassRelate(Entity $entity, $relationName, array $params = array(), array $options = array())
{
if (!$this->hooksDisabled) {
if (!$this->hooksDisabled && empty($options['skipHooks'])) {
$hookData = array(
'relationName' => $relationName,
'relationParams' => $params
@@ -220,7 +216,7 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
if ($foreign instanceof Entity) {
$foreignEntity = $foreign;
if (!$this->hooksDisabled) {
if (!$this->hooksDisabled && empty($options['skipHooks'])) {
$hookData = array(
'relationName' => $relationName,
'relationData' => $data,
@@ -237,7 +233,7 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
if ($foreign instanceof Entity) {
$foreignEntity = $foreign;
if (!$this->hooksDisabled) {
if (!$this->hooksDisabled && empty($options['skipHooks'])) {
$hookData = array(
'relationName' => $relationName,
'foreignEntity' => $foreignEntity
@@ -251,9 +247,13 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
{
parent::beforeSave($entity, $options);
if (!$this->hooksDisabled) {
if (!$this->hooksDisabled && empty($options['skipHooks'])) {
$this->getEntityManager()->getHookManager()->process($this->entityType, 'beforeSave', $entity, $options);
}
if (!$this->processFieldsBeforeSaveDisabled) {
$this->processCurrencyFieldsBeforeSave($entity);
}
}
protected function afterSave(Entity $entity, array $options = array())
@@ -269,9 +269,11 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
$this->processPhoneNumberSave($entity);
$this->processSpecifiedRelationsSave($entity);
$this->processFileFieldsSave($entity);
$this->processArrayFieldsSave($entity);
$this->processWysiwygFieldsSave($entity);
}
if (!$this->hooksDisabled) {
if (!$this->hooksDisabled && empty($options['skipHooks'])) {
$this->getEntityManager()->getHookManager()->process($this->entityType, 'afterSave', $entity, $options);
}
}
@@ -285,35 +287,40 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
if (!$entity->has('id')) {
$entity->set('id', Util::generateId());
}
}
if ($entity->hasAttribute('createdAt')) {
if (empty($options['import']) || !$entity->has('createdAt')) {
$entity->set('createdAt', $nowString);
}
}
if ($entity->hasAttribute('modifiedAt')) {
$entity->set('modifiedAt', $nowString);
}
if ($entity->hasAttribute('createdById')) {
if (empty($options['skipCreatedBy']) && (empty($options['import']) || !$entity->has('createdById'))) {
if ($this->getEntityManager()->getUser()) {
$entity->set('createdById', $this->getEntityManager()->getUser()->id);
if (empty($options['skipAll'])) {
if ($entity->isNew()) {
if ($entity->hasAttribute('createdAt')) {
if (empty($options['import']) || !$entity->has('createdAt')) {
$entity->set('createdAt', $nowString);
}
}
}
} else {
if (empty($options['silent']) && empty($options['skipModifiedBy'])) {
if ($entity->hasAttribute('modifiedAt')) {
$entity->set('modifiedAt', $nowString);
}
if ($entity->hasAttribute('modifiedById')) {
if ($this->getEntityManager()->getUser()) {
$entity->set('modifiedById', $this->getEntityManager()->getUser()->id);
$entity->set('modifiedByName', $this->getEntityManager()->getUser()->get('name'));
if ($entity->hasAttribute('createdById')) {
if (empty($options['skipCreatedBy']) && (empty($options['import']) || !$entity->has('createdById'))) {
if ($this->getEntityManager()->getUser()) {
$entity->set('createdById', $this->getEntityManager()->getUser()->id);
}
}
}
} else {
if (empty($options['silent']) && empty($options['skipModifiedBy'])) {
if ($entity->hasAttribute('modifiedAt')) {
$entity->set('modifiedAt', $nowString);
}
if ($entity->hasAttribute('modifiedById')) {
if ($this->getEntityManager()->getUser()) {
$entity->set('modifiedById', $this->getEntityManager()->getUser()->id);
$entity->set('modifiedByName', $this->getEntityManager()->getUser()->get('name'));
}
}
}
}
}
$this->restoreData = $restoreData;
$result = parent::save($entity, $options);
@@ -321,6 +328,28 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
return $result;
}
protected function getFieldByTypeList($type)
{
return $this->getFieldManagerUtil()->getFieldByTypeList($this->entityType, $type);
}
protected function processCurrencyFieldsBeforeSave(Entity $entity)
{
foreach ($this->getFieldByTypeList('currency') as $field) {
$currencyAttribute = $field . 'Currency';
$defaultCurrency = $this->getConfig()->get('defaultCurrency');
if ($entity->isNew()) {
if ($entity->get($field) && !$entity->get($currencyAttribute)) {
$entity->set($currencyAttribute, $defaultCurrency);
}
} else {
if ($entity->isAttributeChanged($field) && $entity->has($currencyAttribute) && !$entity->get($currencyAttribute)) {
$entity->set($currencyAttribute, $defaultCurrency);
}
}
}
}
protected function processFileFieldsSave(Entity $entity)
{
foreach ($entity->getRelations() as $name => $defs) {
@@ -360,17 +389,68 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
}
}
protected function processArrayFieldsSave(Entity $entity)
{
foreach ($entity->getAttributes() as $attribute => $defs) {
if (!isset($defs['type']) || $defs['type'] !== Entity::JSON_ARRAY) continue;
if (!$entity->has($attribute)) continue;
if (!$entity->isAttributeChanged($attribute)) continue;
if (!$entity->getAttributeParam($attribute, 'storeArrayValues')) continue;
if ($entity->getAttributeParam($attribute, 'notStorable')) continue;
$this->getEntityManager()->getRepository('ArrayValue')->storeEntityAttribute($entity, $attribute);
}
}
protected function processWysiwygFieldsSave(Entity $entity)
{
if (!$entity->isNew()) return;
$fieldsDefs = $this->getMetadata()->get(['entityDefs', $entity->getEntityType(), 'fields'], []);
foreach ($fieldsDefs as $field => $defs) {
if (!empty($defs['type']) && $defs['type'] === 'wysiwyg') {
$content = $entity->get($field);
if (!$content) continue;
if (preg_match_all("/\?entryPoint=attachment&amp;id=([^&=\"']+)/", $content, $matches)) {
if (!empty($matches[1]) && is_array($matches[1])) {
foreach ($matches[1] as $id) {
$attachment = $this->getEntityManager()->getEntity('Attachment', $id);
if ($attachment) {
if (!$attachment->get('relatedId') && !$attachment->get('sourceId')) {
$attachment->set([
'relatedId' => $entity->id,
'relatedType' => $entity->getEntityType()
]);
$this->getEntityManager()->saveEntity($attachment);
}
}
}
}
}
}
}
}
protected function processArrayFieldsRemove(Entity $entity)
{
foreach ($entity->getAttributes() as $attribute => $defs) {
if (!isset($defs['type']) || $defs['type'] !== Entity::JSON_ARRAY) continue;
if (!$entity->getAttributeParam($attribute, 'storeArrayValues')) continue;
if ($entity->getAttributeParam($attribute, 'notStorable')) continue;
$this->getEntityManager()->getRepository('ArrayValue')->deleteEntityAttribute($entity, $attribute);
}
}
protected function processEmailAddressSave(Entity $entity)
{
if ($entity->hasRelation('emailAddresses') && $entity->hasAttribute('emailAddress')) {
$emailAddressRepository = $this->getEntityManager()->getRepository('EmailAddress')->storeEntityEmailAddress($entity);
$this->getEntityManager()->getRepository('EmailAddress')->storeEntityEmailAddress($entity);
}
}
protected function processPhoneNumberSave(Entity $entity)
{
if ($entity->hasRelation('phoneNumbers') && $entity->hasAttribute('phoneNumber')) {
$emailAddressRepository = $this->getEntityManager()->getRepository('PhoneNumber')->storeEntityPhoneNumber($entity);
$this->getEntityManager()->getRepository('PhoneNumber')->storeEntityPhoneNumber($entity);
}
}
@@ -420,17 +500,21 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
$data->$columnName = $foreignEntity->get($columnField);
}
$existingColumnsData->$foreignId = $data;
$entity->setFetched($columnsFieldsName, $existingColumnsData);
if (!$entity->isNew()) {
$entity->setFetched($columnsFieldsName, $existingColumnsData);
}
}
}
}
if ($entity->has($fieldName)) {
$entity->setFetched($fieldName, $existingIds);
}
if ($entity->has($columnsFieldsName) && !empty($columns)) {
$entity->setFetched($columnsFieldsName, $existingColumnsData);
if (!$entity->isNew()) {
if ($entity->has($fieldName)) {
$entity->setFetched($fieldName, $existingIds);
}
if ($entity->has($columnsFieldsName) && !empty($columns)) {
$entity->setFetched($columnsFieldsName, $existingColumnsData);
}
}
foreach ($existingIds as $id) {
@@ -495,13 +579,17 @@ class RDB extends \Espo\ORM\Repositories\RDB implements Injectable
$where[$foreignKey] = $entity->id;
$previousForeignEntity = $this->getEntityManager()->getRepository($foreignEntityType)->where($where)->findOne();
if ($previousForeignEntity) {
$entity->setFetched($idFieldName, $previousForeignEntity->id);
if (!$entity->isNew()) {
$entity->setFetched($idFieldName, $previousForeignEntity->id);
}
if ($previousForeignEntity->id !== $entity->get($idFieldName)) {
$previousForeignEntity->set($foreignKey, null);
$this->getEntityManager()->saveEntity($previousForeignEntity);
}
} else {
$entity->setFetched($idFieldName, null);
if (!$entity->isNew()) {
$entity->setFetched($idFieldName, null);
}
}
if ($entity->get($idFieldName)) {

View File

@@ -40,6 +40,13 @@ class Tcpdf extends \TCPDF
protected $footerPosition = 15;
protected $useGroupNumbers = false;
public function setUseGroupNumbers($value)
{
$this->useGroupNumbers = $value;
}
public function setFooterHtml($html)
{
$this->footerHtml = $html;
@@ -51,10 +58,26 @@ class Tcpdf extends \TCPDF
}
public function Footer() {
$breakMargin = $this->getBreakMargin();
$autoPageBreak = $this->AutoPageBreak;
$this->SetAutoPageBreak(false, 0);
$this->SetY((-1) * $this->footerPosition);
$html = str_replace('{pageNumber}', '{:pnp:}', $this->footerHtml);
$html = $this->footerHtml;
if ($this->useGroupNumbers) {
$html = str_replace('{pageNumber}', '{:png:}', $html);
$html = str_replace('{pageAbsoluteNumber}', '{:pnp:}', $html);
} else {
$html = str_replace('{pageNumber}', '{:pnp:}', $html);
$html = str_replace('{pageAbsoluteNumber}', '{:pnp:}', $html);
}
$this->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, '', 0, false, 'T');
$this->SetAutoPageBreak($autoPageBreak, $breakMargin);
}
protected function _putpages() {
@@ -91,6 +114,9 @@ class Tcpdf extends \TCPDF
++$pagegroupnum;
$pnga = TCPDF_STATIC::formatPageNumber($pagegroupnum);
$pngu = TCPDF_FONTS::UTF8ToUTF16BE($pnga, false, $this->isunicode, $this->CurrentFont);
$pnga = $pngu;
$png_num_chars = $this->GetNumChars($pnga);
// replace page numbers
$replace = array();

View File

@@ -41,6 +41,8 @@ class AclManager extends \Espo\Core\AclManager
private $portal = null;
protected $userAclClassName = '\\Espo\\Core\\Portal\\Acl';
public function getImplementation($scope)
{
if (empty($this->implementationHashMap[$scope])) {

View File

@@ -99,6 +99,6 @@ class Application extends \Espo\Core\Application
$this->getContainer()->get('clientManager')->display(null, 'html/portal.html', array(
'portalId' => $this->getPortal()->id
));
exit;
}
}

View File

@@ -41,7 +41,7 @@ class CategoryTree extends \Espo\Core\ORM\Repositories\RDB
$query = $this->getEntityManager()->getQuery();
$parentId = $entity->get('parentId');
$pathsTableName = $query->toDb($entity->getEntityType() . 'Path');
$pathsTableName = $query->toDb($query->sanitize($entity->getEntityType()) . 'Path');
if ($entity->isNew()) {
if ($parentId) {
@@ -62,7 +62,7 @@ class CategoryTree extends \Espo\Core\ORM\Repositories\RDB
}
$pdo->query($sql);
} else {
if ($entity->isFieldChanged('parentId')) {
if ($entity->isAttributeChanged('parentId')) {
$sql = "
DELETE a FROM `".$pathsTableName."` AS a
JOIN `".$pathsTableName."` AS d ON a.descendor_id = d.descendor_id
@@ -93,7 +93,7 @@ class CategoryTree extends \Espo\Core\ORM\Repositories\RDB
$pdo = $this->getEntityManager()->getPDO();
$query = $this->getEntityManager()->getQuery();
$pathsTableName = $query->toDb($entity->getEntityType() . 'Path');
$pathsTableName = $query->toDb($query->sanitize($entity->getEntityType()) . 'Path');
$sql = "DELETE FROM `".$pathsTableName."` WHERE descendor_id = ".$pdo->quote($entity->id)."";
$pdo->query($sql);

View File

@@ -61,10 +61,15 @@ class Event extends \Espo\Core\ORM\Repositories\RDB
$pdo->query($sql);
}
protected function afterSave(Entity $entity, array $options = array())
protected function afterSave(Entity $entity, array $options = [])
{
parent::afterSave($entity, $options);
$this->processReminderAfterSave($entity, $options);
parent::afterSave($entity, $options);
}
protected function processReminderAfterSave(Entity $entity, array $options = [])
{
if (
$entity->isNew() ||
$entity->isAttributeChanged('assignedUserId') ||

View File

@@ -32,6 +32,7 @@ namespace Espo\Core;
use \Espo\Core\Exceptions\Error;
use \Espo\Core\Utils\Util;
use \Espo\Core\InjectableFactory;
class SelectManagerFactory
{
@@ -43,7 +44,9 @@ class SelectManagerFactory
private $metadata;
public function __construct($entityManager, \Espo\Entities\User $user, Acl $acl, AclManager $aclManager, Utils\Metadata $metadata, Utils\Config $config)
private $injectableFactory;
public function __construct($entityManager, \Espo\Entities\User $user, Acl $acl, AclManager $aclManager, Utils\Metadata $metadata, Utils\Config $config, InjectableFactory $injectableFactory)
{
$this->entityManager = $entityManager;
$this->user = $user;
@@ -51,9 +54,10 @@ class SelectManagerFactory
$this->aclManager = $aclManager;
$this->metadata = $metadata;
$this->config = $config;
$this->injectableFactory = $injectableFactory;
}
public function create($entityType)
public function create($entityType, $user = null)
{
$normalizedName = Util::normilizeClassName($entityType);
@@ -70,7 +74,14 @@ class SelectManagerFactory
}
}
$selectManager = new $className($this->entityManager, $this->user, $this->acl, $this->aclManager, $this->metadata, $this->config);
if ($user) {
$acl = $this->aclManager->createUserAcl($user);
} else {
$acl = $this->acl;
$user = $this->user;
}
$selectManager = new $className($this->entityManager, $user, $acl, $this->aclManager, $this->metadata, $this->config, $this->injectableFactory);
$selectManager->setEntityType($entityType);
return $selectManager;

View File

@@ -36,6 +36,7 @@ use \Espo\Core\Acl;
use \Espo\Core\AclManager;
use \Espo\Core\Utils\Metadata;
use \Espo\Core\Utils\Config;
use \Espo\Core\InjectableFactory;
class Base
{
@@ -63,15 +64,19 @@ class Base
const MIN_LENGTH_FOR_CONTENT_SEARCH = 4;
public function __construct($entityManager, \Espo\Entities\User $user, Acl $acl, AclManager $aclManager, Metadata $metadata, Config $config)
const MIN_LENGTH_FOR_FULL_TEXT_SEARCH = 4;
protected $fullTextSearchDataCacheHash = [];
public function __construct($entityManager, \Espo\Entities\User $user, Acl $acl, AclManager $aclManager, Metadata $metadata, Config $config, InjectableFactory $injectableFactory)
{
$this->entityManager = $entityManager;
$this->user = $user;
$this->acl = $acl;
$this->aclManager = $aclManager;
$this->metadata = $metadata;
$this->config = $config;
$this->injectableFactory = $injectableFactory;
}
protected function getEntityManager()
@@ -104,6 +109,11 @@ class Base
return $this->aclManager;
}
protected function getInjectableFactory()
{
return $this->injectableFactory;
}
public function setEntityType($entityType)
{
$this->entityType = $entityType;
@@ -151,6 +161,9 @@ class Base
if ($desc) {
$list = array_reverse($list);
}
foreach ($list as $i => $listItem) {
$list[$i] = str_replace(',', '_COMMA_', $listItem);
}
$result['orderBy'] = 'LIST:' . $sortBy . ':' . implode(',', $list);
return;
}
@@ -186,7 +199,6 @@ class Base
{
$this->prepareResult($result);
$whereClause = array();
foreach ($where as $item) {
if (!isset($item['type'])) continue;
@@ -198,8 +210,8 @@ class Base
}
$this->applyBoolFilter($filter, $result);
}
} else if ($item['type'] == 'textFilter' && !empty($item['value'])) {
if (!empty($item['value'])) {
} else if ($item['type'] == 'textFilter') {
if (isset($item['value']) || $item['value'] !== '') {
$this->textFilter($item['value'], $result);
}
} else if ($item['type'] == 'primary' && !empty($item['value'])) {
@@ -207,10 +219,17 @@ class Base
}
}
$whereClause = $this->convertWhere($where, false, $result);
$result['whereClause'] = array_merge($result['whereClause'], $whereClause);
}
public function convertWhere(array $where, $ignoreAdditionaFilterTypes = false, &$result = null)
{
$whereClause = [];
$ignoreTypeList = array_merge(['bool', 'primary'], $this->additionalFilterTypeList);
$additionalFilters = array();
foreach ($where as $item) {
if (!isset($item['type'])) continue;
@@ -221,7 +240,7 @@ class Base
$whereClause[] = $part;
}
} else {
if (in_array($type, $this->additionalFilterTypeList)) {
if (!$ignoreAdditionaFilterTypes && in_array($type, $this->additionalFilterTypeList)) {
if (!empty($item['value'])) {
$methodName = 'apply' . ucfirst($type);
@@ -242,7 +261,7 @@ class Base
}
}
$result['whereClause'] = array_merge($result['whereClause'], $whereClause);
return $whereClause;
}
protected function applyLinkedWith($link, $idsValue, &$result)
@@ -375,8 +394,9 @@ class Base
protected function q($params, &$result)
{
if (!empty($params['q'])) {
$this->textFilter($params['q'], $result);
if (isset($params['q']) && $params['q'] !== '') {
$textFilter = $params['q'];
$this->textFilter($textFilter, $result);
}
}
@@ -389,7 +409,7 @@ class Base
public function manageTextFilter($textFilter, &$result)
{
$this->prepareResult($result);
$this->q(array('q' => $textFilter), $result);
$this->q(['q' => $textFilter], $result);
}
public function getEmptySelectParams()
@@ -472,9 +492,9 @@ class Base
{
if ($this->hasAssignedUsersField()) {
$this->setDistinct(true, $result);
$this->addLeftJoin('assignedUsers', $result);
$this->addLeftJoin(['assignedUsers', 'assignedUsersAccess'], $result);
$result['whereClause'][] = array(
'assignedUsers.id' => $this->getUser()->id
'assignedUsersAccess.id' => $this->getUser()->id
);
return;
}
@@ -720,7 +740,7 @@ class Base
$this->where($params['where'], $result);
}
if (!empty($params['textFilter'])) {
if (isset($params['textFilter']) && $params['textFilter'] !== '') {
$this->textFilter($params['textFilter'], $result);
}
@@ -952,7 +972,7 @@ class Base
protected function getWherePart($item, &$result = null)
{
$part = array();
$part = [];
$attribute = null;
if (!empty($item['field'])) { // for backward compatibility
@@ -984,165 +1004,199 @@ class Base
if (!array_key_exists('value', $item)) {
$item['value'] = null;
}
$value = $item['value'];
if (!empty($item['type'])) {
switch ($item['type']) {
$type = $item['type'];
switch ($type) {
case 'or':
case 'and':
case 'not':
if (is_array($item['value'])) {
$arr = array();
foreach ($item['value'] as $i) {
if (is_array($value)) {
$arr = [];
foreach ($value as $i) {
$a = $this->getWherePart($i, $result);
foreach ($a as $left => $right) {
if (!empty($right) || is_null($right) || $right === '') {
$arr[] = array($left => $right);
if (!empty($right) || is_null($right) || $right === '' || $right === 0 || $right === false) {
$arr[] = [$left => $right];
}
}
}
$part[strtoupper($item['type'])] = $arr;
$part[strtoupper($type)] = $arr;
}
break;
case 'like':
$part[$attribute . '*'] = $item['value'];
$part[$attribute . '*'] = $value;
break;
case 'notLike':
$part[$attribute . '!*'] = $item['value'];
$part[$attribute . '!*'] = $value;
break;
case 'equals':
case 'on':
$part[$attribute . '='] = $item['value'];
$part[$attribute . '='] = $value;
break;
case 'startsWith':
$part[$attribute . '*'] = $item['value'] . '%';
$part[$attribute . '*'] = $value . '%';
break;
case 'endsWith':
$part[$attribute . '*'] = '%' . $item['value'];
$part[$attribute . '*'] = '%' . $value;
break;
case 'contains':
$part[$attribute . '*'] = '%' . $item['value'] . '%';
$part[$attribute . '*'] = '%' . $value . '%';
break;
case 'notContains':
$part[$attribute . '!*'] = '%' . $item['value'] . '%';
$part[$attribute . '!*'] = '%' . $value . '%';
break;
case 'notEquals':
case 'notOn':
$part[$attribute . '!='] = $item['value'];
$part[$attribute . '!='] = $value;
break;
case 'greaterThan':
case 'after':
$part[$attribute . '>'] = $item['value'];
$part[$attribute . '>'] = $value;
break;
case 'lessThan':
case 'before':
$part[$attribute . '<'] = $item['value'];
$part[$attribute . '<'] = $value;
break;
case 'greaterThanOrEquals':
$part[$attribute . '>='] = $item['value'];
$part[$attribute . '>='] = $value;
break;
case 'lessThanOrEquals':
$part[$attribute . '<='] = $item['value'];
$part[$attribute . '<='] = $value;
break;
case 'in':
$part[$attribute . '='] = $item['value'];
$part[$attribute . '='] = $value;
break;
case 'notIn':
$part[$attribute . '!='] = $item['value'];
$part[$attribute . '!='] = $value;
break;
case 'isNull':
$part[$attribute . '='] = null;
break;
case 'isNotNull':
case 'ever':
$part[$attribute . '!='] = null;
break;
case 'isTrue':
$part[$attribute . '='] = true;
break;
case 'isFalse':
$part[$attribute . '='] = false;
break;
case 'today':
$part[$attribute . '='] = date('Y-m-d');
break;
case 'past':
$part[$attribute . '<'] = date('Y-m-d');
break;
case 'future':
$part[$attribute . '>='] = date('Y-m-d');
break;
case 'lastSevenDays':
$dt1 = new \DateTime();
$dt2 = clone $dt1;
$dt2->modify('-7 days');
$part['AND'] = array(
$part['AND'] = [
$attribute . '>=' => $dt2->format('Y-m-d'),
$attribute . '<=' => $dt1->format('Y-m-d'),
);
];
break;
case 'lastXDays':
$dt1 = new \DateTime();
$dt2 = clone $dt1;
$number = strval(intval($item['value']));
$number = strval(intval($value));
$dt2->modify('-'.$number.' days');
$part['AND'] = array(
$part['AND'] = [
$attribute . '>=' => $dt2->format('Y-m-d'),
$attribute . '<=' => $dt1->format('Y-m-d'),
);
];
break;
case 'nextXDays':
$dt1 = new \DateTime();
$dt2 = clone $dt1;
$number = strval(intval($item['value']));
$number = strval(intval($value));
$dt2->modify('+'.$number.' days');
$part['AND'] = array(
$part['AND'] = [
$attribute . '>=' => $dt1->format('Y-m-d'),
$attribute . '<=' => $dt2->format('Y-m-d'),
);
];
break;
case 'olderThanXDays':
$dt1 = new \DateTime();
$number = strval(intval($item['value']));
$number = strval(intval($value));
$dt1->modify('-'.$number.' days');
$part[$attribute . '<'] = $dt1->format('Y-m-d');
break;
case 'afterXDays':
$dt1 = new \DateTime();
$number = strval(intval($item['value']));
$number = strval(intval($value));
$dt1->modify('+'.$number.' days');
$part[$attribute . '>'] = $dt1->format('Y-m-d');
break;
case 'currentMonth':
$dt = new \DateTime();
$part['AND'] = array(
$part['AND'] = [
$attribute . '>=' => $dt->modify('first day of this month')->format('Y-m-d'),
$attribute . '<' => $dt->add(new \DateInterval('P1M'))->format('Y-m-d'),
);
];
break;
case 'lastMonth':
$dt = new \DateTime();
$part['AND'] = array(
$part['AND'] = [
$attribute . '>=' => $dt->modify('first day of last month')->format('Y-m-d'),
$attribute . '<' => $dt->add(new \DateInterval('P1M'))->format('Y-m-d'),
);
];
break;
case 'nextMonth':
$dt = new \DateTime();
$part['AND'] = array(
$part['AND'] = [
$attribute . '>=' => $dt->modify('first day of next month')->format('Y-m-d'),
$attribute . '<' => $dt->add(new \DateInterval('P1M'))->format('Y-m-d'),
);
];
break;
case 'currentQuarter':
$dt = new \DateTime();
$quarter = ceil($dt->format('m') / 3);
$dt->modify('first day of January this year');
$part['AND'] = array(
$part['AND'] = [
$attribute . '>=' => $dt->add(new \DateInterval('P'.(($quarter - 1) * 3).'M'))->format('Y-m-d'),
$attribute . '<' => $dt->add(new \DateInterval('P3M'))->format('Y-m-d'),
);
];
break;
case 'lastQuarter':
$dt = new \DateTime();
$quarter = ceil($dt->format('m') / 3);
@@ -1152,33 +1206,37 @@ class Base
$quarter = 4;
$dt->modify('-1 year');
}
$part['AND'] = array(
$part['AND'] = [
$attribute . '>=' => $dt->add(new \DateInterval('P'.(($quarter - 1) * 3).'M'))->format('Y-m-d'),
$attribute . '<' => $dt->add(new \DateInterval('P3M'))->format('Y-m-d'),
);
];
break;
case 'currentYear':
$dt = new \DateTime();
$part['AND'] = array(
$part['AND'] = [
$attribute . '>=' => $dt->modify('first day of January this year')->format('Y-m-d'),
$attribute . '<' => $dt->add(new \DateInterval('P1Y'))->format('Y-m-d'),
);
];
break;
case 'lastYear':
$dt = new \DateTime();
$part['AND'] = array(
$part['AND'] = [
$attribute . '>=' => $dt->modify('first day of January last year')->format('Y-m-d'),
$attribute . '<' => $dt->add(new \DateInterval('P1Y'))->format('Y-m-d'),
);
];
break;
case 'between':
if (is_array($item['value'])) {
$part['AND'] = array(
$attribute . '>=' => $item['value'][0],
$attribute . '<=' => $item['value'][1],
);
if (is_array($value)) {
$part['AND'] = [
$attribute . '>=' => $value[0],
$attribute . '<=' => $value[1],
];
}
break;
case 'columnLike':
case 'columnIn':
case 'columnIsNull':
@@ -1188,30 +1246,30 @@ class Base
$alias = $link . 'Filter' . strval(rand(10000, 99999));
$this->setDistinct(true, $result);
$this->addLeftJoin([$link, $alias], $result);
$value = $item['value'];
$columnKey = $alias . 'Middle.' . $column;
if ($item['type'] === 'columnIn') {
if ($type === 'columnIn') {
$part[$columnKey] = $value;
} else if ($item['type'] === 'columnNotIn') {
} else if ($type === 'columnNotIn') {
$part[$columnKey . '!='] = $value;
} else if ($item['type'] === 'columnIsNull') {
} else if ($type === 'columnIsNull') {
$part[$columnKey] = null;
} else if ($item['type'] === 'columnIsNotNull') {
} else if ($type === 'columnIsNotNull') {
$part[$columnKey . '!='] = null;
} else if ($item['type'] === 'columnLike') {
} else if ($type === 'columnLike') {
$part[$columnKey . '*'] = $value;
} else if ($item['type'] === 'columnStartsWith') {
} else if ($type === 'columnStartsWith') {
$part[$columnKey . '*'] = $value . '%';
} else if ($item['type'] === 'columnEndsWith') {
} else if ($type === 'columnEndsWith') {
$part[$columnKey . '*'] = '%' . $value;
} else if ($item['type'] === 'columnContains') {
} else if ($type === 'columnContains') {
$part[$columnKey . '*'] = '%' . $value . '%';
} else if ($item['type'] === 'columnEquals') {
} else if ($type === 'columnEquals') {
$part[$columnKey . '='] = $value;
} else if ($item['type'] === 'columnNotEquals') {
} else if ($type === 'columnNotEquals') {
$part[$columnKey . '!='] = $value;
}
break;
case 'isNotLinked':
if (!$result) break;
$alias = $attribute . 'IsNotLinkedFilter' . strval(rand(10000, 99999));
@@ -1219,6 +1277,7 @@ class Base
$this->setDistinct(true, $result);
$this->addLeftJoin([$attribute, $alias], $result);
break;
case 'isLinked':
if (!$result) break;
$alias = $attribute . 'IsLinkedFilter' . strval(rand(10000, 99999));
@@ -1226,6 +1285,7 @@ class Base
$this->setDistinct(true, $result);
$this->addLeftJoin([$attribute, $alias], $result);
break;
case 'linkedWith':
$seed = $this->getSeed();
$link = $attribute;
@@ -1233,9 +1293,7 @@ class Base
$alias = $link . 'Filter' . strval(rand(10000, 99999));
$value = $item['value'];
if (is_null($value)) break;
if (is_null($value) || !$value && !is_array($value)) break;
$relationType = $seed->getRelationType($link);
@@ -1264,13 +1322,12 @@ class Base
}
$this->setDistinct(true, $result);
break;
case 'notLinkedWith':
$seed = $this->getSeed();
$link = $attribute;
if (!$seed->hasRelation($link)) break;
$value = $item['value'];
if (is_null($value)) break;
$relationType = $seed->getRelationType($link);
@@ -1296,12 +1353,64 @@ class Base
$part[$key . '!='] = $value;
}
} else if ($relationType == 'hasOne') {
$this->addLeftJoin([$link, alias], $result);
$this->addLeftJoin([$link, $alias], $result);
$part[$alias . '.id!='] = $value;
} else {
break;
}
$this->setDistinct(true, $result);
break;
case 'arrayAnyOf':
case 'arrayNoneOf':
case 'arrayIsEmpty':
case 'arrayIsNotEmpty':
$arrayValueAlias = 'arrayFilter' . strval(rand(10000, 99999));
$arrayAttribute = $attribute;
$arrayEntityType = $this->getEntityType();
$idPart = 'id';
if (strpos($attribute, '.') > 0) {
list($arrayAttributeLink, $arrayAttribute) = explode('.', $attribute);
$seed = $this->getSeed();
$arrayEntityType = $seed->getRelationParam($arrayAttributeLink, 'entity');
$idPart = $arrayAttributeLink . '.id';
}
if ($type === 'arrayAnyOf') {
if (is_null($value) || !$value && !is_array($value)) break;
$this->addLeftJoin(['ArrayValue', $arrayValueAlias, [
$arrayValueAlias . '.entityId:' => $idPart,
$arrayValueAlias . '.entityType' => $arrayEntityType,
$arrayValueAlias . '.attribute' => $arrayAttribute
]], $result);
$part[$arrayValueAlias . '.value'] = $value;
} else if ($type === 'arrayNoneOf') {
if (is_null($value) || !$value && !is_array($value)) break;
$this->addLeftJoin(['ArrayValue', $arrayValueAlias, [
$arrayValueAlias . '.entityId:' => $idPart,
$arrayValueAlias . '.entityType' => $arrayEntityType,
$arrayValueAlias . '.attribute' => $arrayAttribute,
$arrayValueAlias . '.value=' => $value
]], $result);
$part[$arrayValueAlias . '.id'] = null;
} else if ($type === 'arrayIsEmpty') {
$this->addLeftJoin(['ArrayValue', $arrayValueAlias, [
$arrayValueAlias . '.entityId:' => $idPart,
$arrayValueAlias . '.entityType' => $arrayEntityType,
$arrayValueAlias . '.attribute' => $arrayAttribute
]], $result);
$part[$arrayValueAlias . '.id'] = null;
} else if ($type === 'arrayIsNotEmpty') {
$this->addLeftJoin(['ArrayValue', $arrayValueAlias, [
$arrayValueAlias . '.entityId:' => $idPart,
$arrayValueAlias . '.entityType' => $arrayEntityType,
$arrayValueAlias . '.attribute' => $arrayAttribute
]], $result);
$part[$arrayValueAlias . '.id!='] = null;
}
$this->setDistinct(true, $result);
}
}
@@ -1327,6 +1436,20 @@ class Base
$method = 'filter' . ucfirst($filterName);
if (method_exists($this, $method)) {
$this->$method($result);
} else {
$className = $this->getMetadata()->get(['entityDefs', $this->entityType, 'collection', 'filters', $filterName, 'className']);
if ($className) {
if (!class_exists($className)) {
$GLOBALS['log']->error("Could find class for filter {$filterName}.");
return;
}
$impl = $this->getInjectableFactory()->createByClassName($className);
if (!$impl) {
$GLOBALS['log']->error("Could not create filter {$filterName} implementation.");
return;
}
$impl->applyFilter($this->entityType, $filterName, $result, $this);
}
}
}
@@ -1474,35 +1597,252 @@ class Base
);
}
public function getFullTextSearchDataForTextFilter($textFilter, $isAuxiliaryUse = false)
{
if (array_key_exists($textFilter, $this->fullTextSearchDataCacheHash)) {
return $this->fullTextSearchDataCacheHash[$textFilter];
}
if ($this->getConfig()->get('fullTextSearchDisabled')) {
return null;
}
$result = null;
$fieldList = $this->getTextFilterFieldList();
if ($isAuxiliaryUse) {
$textFilter = str_replace('%', '', $textFilter);
}
$fullTextSearchColumnList = $this->getEntityManager()->getOrmMetadata()->get($this->getEntityType(), ['fullTextSearchColumnList']);
$useFullTextSearch = false;
if (
$this->getMetadata()->get(['entityDefs', $this->getEntityType(), 'collection', 'fullTextSearch'])
&&
!empty($fullTextSearchColumnList)
) {
$fullTextSearchMinLength = $this->getConfig()->get('fullTextSearchMinLength', self::MIN_LENGTH_FOR_FULL_TEXT_SEARCH);
if (!$fullTextSearchMinLength) {
$fullTextSearchMinLength = 0;
}
$textFilterWoWildcards = str_replace('*', '', $textFilter);
if (mb_strlen($textFilterWoWildcards) >= $fullTextSearchMinLength) {
$useFullTextSearch = true;
}
}
$fullTextSearchFieldList = [];
if ($useFullTextSearch) {
foreach ($fieldList as $field) {
$defs = $this->getMetadata()->get(['entityDefs', $this->getEntityType(), 'fields', $field], []);
if (empty($defs['type'])) continue;
$fieldType = $defs['type'];
if (!empty($defs['notStorable'])) continue;
if (!$this->getMetadata()->get(['fields', $fieldType, 'fullTextSearch'])) continue;
$fullTextSearchFieldList[] = $field;
}
if (!count($fullTextSearchFieldList)) {
$useFullTextSearch = false;
}
}
if (empty($fullTextSearchColumnList)) {
$useFullTextSearch = false;
}
if ($isAuxiliaryUse) {
if (mb_strpos($textFilter, '@') !== false) {
$useFullTextSearch = false;
}
}
if ($useFullTextSearch) {
$textFilter = str_replace(['(', ')'], '', $textFilter);
if (
$isAuxiliaryUse && mb_strpos($textFilter, '*') === false
||
mb_strpos($textFilter, ' ') === false
&&
mb_strpos($textFilter, '+') === false
&&
mb_strpos($textFilter, '-') === false
&&
mb_strpos($textFilter, '*') === false
) {
$function = 'MATCH_NATURAL_LANGUAGE';
} else {
$function = 'MATCH_BOOLEAN';
}
$textFilter = str_replace('"*', '"', $textFilter);
$textFilter = str_replace('*"', '"', $textFilter);
while (strpos($textFilter, '**')) {
$textFilter = str_replace('**', '*', $textFilter);
$textFilter = trim($textFilter);
}
while (mb_substr($textFilter, -2) === ' *') {
$textFilter = mb_substr($textFilter, 0, mb_strlen($textFilter) - 2);
$textFilter = trim($textFilter);
}
$fullTextSearchColumnSanitizedList = [];
$query = $this->getEntityManager()->getQuery();
foreach ($fullTextSearchColumnList as $i => $field) {
$fullTextSearchColumnSanitizedList[$i] = $query->sanitize($query->toDb($field));
}
$where = $function . ':' . implode(',', $fullTextSearchColumnSanitizedList) . ':' . $textFilter;
$result = [
'where' => $where,
'fieldList' => $fullTextSearchFieldList,
'columnList' => $fullTextSearchColumnList
];
}
$this->fullTextSearchDataCacheHash[$textFilter] = $result;
return $result;
}
protected function textFilter($textFilter, &$result)
{
$fieldDefs = $this->getSeed()->getAttributes();
$fieldList = $this->getTextFilterFieldList();
$d = array();
$group = [];
$textFilterContainsMinLength = $this->getConfig()->get('textFilterContainsMinLength', self::MIN_LENGTH_FOR_CONTENT_SEARCH);
$fullTextSearchData = null;
$forceFullTextSearch = false;
$useFullTextSearch = !empty($result['useFullTextSearch']);
if (mb_strpos($textFilter, 'ft:') === 0) {
$textFilter = mb_substr($textFilter, 3);
$useFullTextSearch = true;
$forceFullTextSearch = true;
}
$textFilterForFullTextSearch = $textFilter;
$skipWidlcards = false;
if (mb_strpos($textFilter, '*') !== false) {
$skipWidlcards = true;
$textFilter = str_replace('*', '%', $textFilter);
} else {
if (!$useFullTextSearch) {
$textFilterForFullTextSearch .= '*';
}
}
$textFilterForFullTextSearch = str_replace('%', '*', $textFilterForFullTextSearch);
$skipFullTextSearch = false;
if (!$forceFullTextSearch) {
if (mb_strpos($textFilterForFullTextSearch, '*') === 0) {
$skipFullTextSearch = true;
} else if (mb_strpos($textFilterForFullTextSearch, ' *') !== false) {
$skipFullTextSearch = true;
}
}
$fullTextSearchData = null;
if (!$skipFullTextSearch) {
$fullTextSearchData = $this->getFullTextSearchDataForTextFilter($textFilterForFullTextSearch, !$useFullTextSearch);
}
$fullTextGroup = [];
$fullTextSearchFieldList = [];
if ($fullTextSearchData) {
$fullTextGroup[] = $fullTextSearchData['where'];
$fullTextSearchFieldList = $fullTextSearchData['fieldList'];
}
foreach ($fieldList as $field) {
$expression = $textFilter . '%';
if (
strlen($textFilter) >= self::MIN_LENGTH_FOR_CONTENT_SEARCH
&&
(
!empty($fieldDefs[$field]['type']) && $fieldDefs[$field]['type'] == 'text'
||
!empty($this->textFilterUseContainsAttributeList[$field])
||
!empty($fieldDefs[$field]['type']) && $fieldDefs[$field]['type'] == 'varchar' &&
$this->getConfig()->get('textFilterUseContainsForVarchar')
)
) {
$expression = '%' . $textFilter . '%';
} else {
$expression = $textFilter . '%';
if ($useFullTextSearch) {
if (in_array($field, $fullTextSearchFieldList)) continue;
}
$d[$field . '*'] = $expression;
if ($forceFullTextSearch) continue;
$attributeType = null;
if (!empty($fieldDefs[$field]['type'])) {
$attributeType = $fieldDefs[$field]['type'];
}
if ($attributeType === 'int') {
if (is_numeric($textFilter)) {
$group[$field] = intval($textFilter);
}
continue;
}
if (!$skipWidlcards) {
if (
mb_strlen($textFilter) >= $textFilterContainsMinLength
&&
(
$attributeType == 'text'
||
in_array($field, $this->textFilterUseContainsAttributeList)
||
$attributeType == 'varchar' && $this->getConfig()->get('textFilterUseContainsForVarchar')
)
) {
$expression = '%' . $textFilter . '%';
} else {
$expression = $textFilter . '%';
}
} else {
$expression = $textFilter;
}
if ($fullTextSearchData) {
if (!$useFullTextSearch) {
if (in_array($field, $fullTextSearchFieldList)) {
if (!array_key_exists('OR', $fullTextGroup)) {
$fullTextGroup['OR'] = [];
}
$fullTextGroup['OR'][$field . '*'] = $expression;
continue;
}
}
}
$group[$field . '*'] = $expression;
}
$result['whereClause'][] = array(
'OR' => $d
);
if (!$forceFullTextSearch) {
$this->applyAdditionalToTextFilterGroup($textFilter, $group, $result);
}
if (!empty($fullTextGroup)) {
$group['AND'] = $fullTextGroup;
}
if (count($group) === 0) {
$result['whereClause'][] = [
'id' => null
];
}
$result['whereClause'][] = [
'OR' => $group
];
}
protected function applyAdditionalToTextFilterGroup($textFilter, &$group, &$result)
{
}
public function applyAccess(&$result)
@@ -1531,19 +1871,25 @@ class Base
protected function boolFilterOnlyMy(&$result)
{
if (!$this->checkIsPortal()) {
if ($this->hasAssignedUserField()) {
$result['whereClause'][] = array(
if ($this->hasAssignedUsersField()) {
$this->setDistinct(true, $result);
$this->addLeftJoin(['assignedUsers', 'assignedUsersAccess'], $result);
$result['whereClause'][] = [
'assignedUsersAccess.id' => $this->getUser()->id
];
} else if ($this->hasAssignedUserField()) {
$result['whereClause'][] = [
'assignedUserId' => $this->getUser()->id
);
];
} else {
$result['whereClause'][] = array(
$result['whereClause'][] = [
'createdById' => $this->getUser()->id
);
];
}
} else {
$result['whereClause'][] = array(
$result['whereClause'][] = [
'createdById' => $this->getUser()->id
);
];
}
}
@@ -1563,4 +1909,3 @@ class Base
$this->filterFollowed($result);
}
}

View File

@@ -9,7 +9,8 @@
"type": "text"
},
"website": {
"type": "url"
"type": "url",
"strip": true
},
"emailAddress": {
"type": "email"

View File

@@ -1,7 +1,8 @@
{
"fields": {
"name": {
"type": "personName"
"type": "personName",
"isPersonalData": true
},
"salutationName": {
"type": "enum",
@@ -24,15 +25,18 @@
"type": "text"
},
"emailAddress": {
"type": "email"
"type": "email",
"isPersonalData": true
},
"phoneNumber": {
"type": "phone",
"typeList": ["Mobile", "Office", "Home", "Fax", "Other"],
"defaultType": "Mobile"
"defaultType": "Mobile",
"isPersonalData": true
},
"address": {
"type": "address"
"type": "address",
"isPersonalData": true
},
"addressStreet": {
"type": "text",

View File

@@ -7,5 +7,6 @@
"aclPortalLevelList": ["all", "account", "contact", "own", "no"],
"customizable": true,
"importable": true,
"notifications": true
"notifications": true,
"hasPersonalData": true
}

View File

@@ -49,7 +49,7 @@ class Person extends \Espo\Services\Record
if (
($entity->get('emailAddress') || $entity->get('emailAddressData'))
&&
($entity->isNew() || $entity->isFieldChanged('emailAddress') || $entity->isFieldChanged('emailAddressData'))
($entity->isNew() || $entity->isAttributeChanged('emailAddress') || $entity->isAttributeChanged('emailAddressData'))
) {
if ($entity->get('emailAddress')) {
$list = [$entity->get('emailAddress')];

View File

@@ -1,6 +1,5 @@
{
"links": {
"meetings": "Meetings",
"calls": "Anrufe",
"tasks": "Aufgaben"
},

View File

@@ -5,7 +5,6 @@
"website": "Webseite"
},
"links": {
"meetings": "Meetings",
"calls": "Anrufe",
"tasks": "Aufgaben"
},

View File

@@ -4,7 +4,6 @@
"dateStart": "Startdatum",
"dateEnd": "Enddatum",
"duration": "Dauer",
"status": "Status",
"reminders": "Erinnerungen"
},
"links": {
@@ -20,7 +19,6 @@
"labels": {
"Create {entityType}": "{entityTypeTranslated} erstellen",
"Schedule {entityType}": "{entityTypeTranslated} planen",
"Log {entityType}": "Log {entityTypeTranslated}",
"Set Held": "Auf durchgeführt setzen",
"Set Not Held": "Auf nicht durchgeführt setzen"
},

View File

@@ -3,7 +3,6 @@
"address": "Adresse"
},
"links": {
"meetings": "Meetings",
"calls": "Anrufe",
"tasks": "Aufgaben"
},

View File

@@ -1,6 +1,6 @@
{
"links": {
"meetings": "Juntas",
"meetings": "Presentaciones",
"calls": "Llamadas",
"tasks": "Tareas"
},

View File

@@ -5,7 +5,7 @@
"website": "Sitio Web"
},
"links": {
"meetings": "Juntas",
"meetings": "Presentaciones",
"calls": "Llamadas",
"tasks": "Tareas"
},

View File

@@ -3,7 +3,7 @@
"address": "Dirección"
},
"links": {
"meetings": "Juntas",
"meetings": "Presentaciones",
"calls": "Llamadas",
"tasks": "Tareas"
},

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create {entityType}": "Napravi {entityTypeTranslated}"
}
}

View File

@@ -0,0 +1,10 @@
{
"links": {
"meetings": "Sastanci",
"calls": "Pozivi",
"tasks": "Zadaci"
},
"labels": {
"Create {entityType}": "Kreiraj {entityTypeTranslated}"
}
}

View File

@@ -0,0 +1,15 @@
{
"fields": {
"billingAddress": "Adresa za naplatu",
"shippingAddress": "Adresa za dostavu",
"website": "Sajt"
},
"links": {
"meetings": "Sastanci",
"calls": "Pozivi",
"tasks": "Zadaci"
},
"labels": {
"Create {entityType}": "Kreiraj {entityTypeTranslated}"
}
}

View File

@@ -0,0 +1,35 @@
{
"fields": {
"parent": "Nadređen",
"dateStart": "Početni datum",
"dateEnd": "Završni datum",
"duration": "Trajanje",
"reminders": "Podsjetnici"
},
"links": {
"parent": "Nadređen"
},
"options": {
"status": {
"Planned": "Planiran",
"Held": "Održan",
"Not Held": "Nije održan"
}
},
"labels": {
"Create {entityType}": "Kreiraj {entityTypeTranslated}",
"Schedule {entityType}": "Zakaži {entityTypeTranslated}",
"Log {entityType}": "Zabilježi {entitiTipeTranslated}",
"Set Held": "Postavi kao održano",
"Set Not Held": "Postavi kao nije održano"
},
"massActions": {
"setHeld": "Postavi kao održano",
"setNotHeld": "Postavi kao nije održano"
},
"presetFilters": {
"planned": "Planiran",
"held": "Održan",
"todays": "Današnji"
}
}

View File

@@ -0,0 +1,13 @@
{
"fields": {
"address": "Adresa"
},
"links": {
"meetings": "Sastanci",
"calls": "Pozivi",
"tasks": "Zadaci"
},
"labels": {
"Create {entityType}": "Kreiraj {entityTypeTranslated}"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create {entityType}": "{EntityTypeTranslated} létrehozása"
}
}

View File

@@ -0,0 +1,10 @@
{
"links": {
"meetings": "találkozók",
"calls": "felhívja",
"tasks": "feladatok"
},
"labels": {
"Create {entityType}": "{EntityTypeTranslated} létrehozása"
}
}

View File

@@ -0,0 +1,15 @@
{
"fields": {
"billingAddress": "számlázási cím",
"shippingAddress": "szállítási cím",
"website": "Weboldal"
},
"links": {
"meetings": "találkozók",
"calls": "felhívja",
"tasks": "feladatok"
},
"labels": {
"Create {entityType}": "{EntityTypeTranslated} létrehozása"
}
}

View File

@@ -0,0 +1,27 @@
{
"fields": {
"parent": "Szülő",
"dateStart": "Dátum kezdete",
"dateEnd": "Dátum vége",
"duration": "tartam",
"status": "Állapot",
"reminders": "Emlékeztetők"
},
"links": {
"parent": "Szülő"
},
"options": {
"status": {
"Planned": "Tervezett",
"Not Held": "Nem tartott"
}
},
"labels": {
"Create {entityType}": "{EntityTypeTranslated} létrehozása",
"Schedule {entityType}": "{EntityTypeTranslated} ütemezése"
},
"presetFilters": {
"planned": "Tervezett",
"todays": "A mai"
}
}

View File

@@ -0,0 +1,13 @@
{
"fields": {
"address": "Cím"
},
"links": {
"meetings": "találkozók",
"calls": "felhívja",
"tasks": "feladatok"
},
"labels": {
"Create {entityType}": "{EntityTypeTranslated} létrehozása"
}
}

View File

@@ -1,6 +1,6 @@
{
"links": {
"meetings": "Susirinkimai",
"meetings": "Susitikimai",
"calls": "Skambučiai",
"tasks": "Užduotys"
},

View File

@@ -2,10 +2,10 @@
"fields": {
"billingAddress": "Mokėtojo adresas",
"shippingAddress": "Siuntimo adresas",
"website": "Interntinė Svetainė"
"website": "Internetinė Svetainė"
},
"links": {
"meetings": "Susirinkimai",
"meetings": "Susitikimai",
"calls": "Skambučiai",
"tasks": "Užduotys"
},

View File

@@ -3,7 +3,7 @@
"address": "Adresas"
},
"links": {
"meetings": "Susirinkimai",
"meetings": "Susitikimai",
"calls": "Skambučiai",
"tasks": "Užduotys"
},

View File

@@ -1,5 +1,5 @@
{
"labels": {
"Create {entityType}": "Utwórz {entityTypeTranslated}"
}
}
"labels": {
"Create {entityType}": "Utwórz {entityTypeTranslated}"
}
}

View File

@@ -1,5 +1,10 @@
{
"labels": {
"Create {entityType}": "Utwórz {entityTypeTranslated}"
}
}
"links": {
"meetings": "Spotkania",
"calls": "Połączenia",
"tasks": "Zadania"
},
"labels": {
"Create {entityType}": "Utwórz {entityTypeTranslated}"
}
}

View File

@@ -1,5 +1,15 @@
{
"labels": {
"Create {entityType}": "Utwórz {entityTypeTranslated}"
}
}
"fields": {
"billingAddress": "Adres rozliczeniowy",
"shippingAddress": "Adres dostawy",
"website": "Strona internetowa"
},
"links": {
"meetings": "Spotkania",
"calls": "Połączenia",
"tasks": "Zadania"
},
"labels": {
"Create {entityType}": "Utwórz {entityTypeTranslated}"
}
}

View File

@@ -1,5 +1,20 @@
{
"labels": {
"Create {entityType}": "Utwórz {entityTypeTranslated}"
"fields": {
"dateStart": "Data rozpoczęcia",
"dateEnd": "Data zakończenia",
"duration": "Czas trwania",
"reminders": "Przypomnienia"
},
"options": {
"status": {
"Planned": "Planowane"
}
}
},
"labels": {
"Create {entityType}": "Utwórz {entityTypeTranslated}",
"Schedule {entityType}": "Zaplanuj {entityTypeTranslated} "
},
"presetFilters": {
"planned": "Planowane"
}
}

View File

@@ -1,5 +1,13 @@
{
"labels": {
"Create {entityType}": "Utwórz {entityTypeTranslated}"
}
}
"fields": {
"address": "Adres"
},
"links": {
"meetings": "Spotkania",
"calls": "Rozmowy",
"tasks": "Zadania"
},
"labels": {
"Create {entityType}": "Utwórz {entityTypeTranslated}"
}
}

View File

@@ -1,5 +1,5 @@
{
"labels": {
"Create {entityType}": "Creare {entityTypeTranslated}"
}
}
"labels": {
"Create {entityType}": "Creare {entityTypeTranslated}"
}
}

View File

@@ -1,5 +1,5 @@
{
"labels": {
"Create {entityType}": "Creare {entityTypeTranslated}"
}
}
"labels": {
"Create {entityType}": "Creare {entityTypeTranslated}"
}
}

View File

@@ -1,5 +1,5 @@
{
"labels": {
"Create {entityType}": "Creare {entityTypeTranslated}"
}
}
"labels": {
"Create {entityType}": "Creare {entityTypeTranslated}"
}
}

View File

@@ -1,5 +1,5 @@
{
"labels": {
"Create {entityType}": "Creare {entityTypeTranslated}"
}
}
"labels": {
"Create {entityType}": "Creare {entityTypeTranslated}"
}
}

View File

@@ -1,5 +1,5 @@
{
"labels": {
"Create {entityType}": "Creare {entityTypeTranslated}"
}
}
"labels": {
"Create {entityType}": "Creare {entityTypeTranslated}"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create {entityType}": "Vytvoriť {entityTypeTranslated}"
}
}

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