mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-06 11:07:00 +00:00
Compare commits
1133 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fa9f4bf91 | ||
|
|
6c4a139e66 | ||
|
|
d3a1db25c2 | ||
|
|
0fcd3cd780 | ||
|
|
61cb573eec | ||
|
|
5dd84bf9a1 | ||
|
|
5dad7c6bba | ||
|
|
3007d50299 | ||
|
|
11c0ac6987 | ||
|
|
2bb62883a4 | ||
|
|
5796d2fb85 | ||
|
|
dae318c9bb | ||
|
|
342764e9ff | ||
|
|
27b9e28e20 | ||
|
|
f8d5dd7fa6 | ||
|
|
7408f97fbd | ||
|
|
d1a9cf840f | ||
|
|
d593927b14 | ||
|
|
f62ebb8fe8 | ||
|
|
ede798dbe5 | ||
|
|
c3095b6a32 | ||
|
|
9eb5bfc9fe | ||
|
|
bf2c529884 | ||
|
|
7ce8150541 | ||
|
|
44de149923 | ||
|
|
8ecdc7b9d9 | ||
|
|
95c64359d2 | ||
|
|
44203e2178 | ||
|
|
d3d940d9c9 | ||
|
|
9d3efae141 | ||
|
|
e6eb3e7099 | ||
|
|
3ab2b37471 | ||
|
|
33e7f4e3ef | ||
|
|
6463eaa6f6 | ||
|
|
a066c0a187 | ||
|
|
176f65713f | ||
|
|
493afdf3d4 | ||
|
|
c85b6a37a6 | ||
|
|
81971d0eda | ||
|
|
8a6cc9ea35 | ||
|
|
4fd125ddfc | ||
|
|
1298a8382d | ||
|
|
bb9c352f55 | ||
|
|
045533d080 | ||
|
|
6a5ab5f738 | ||
|
|
c1b0e4fd17 | ||
|
|
e71928ffa7 | ||
|
|
de3f5de029 | ||
|
|
57ceee4d4c | ||
|
|
9a5cd7609b | ||
|
|
1382dca3e3 | ||
|
|
bc7a3e8839 | ||
|
|
c5d6f4c63f | ||
|
|
6776f813af | ||
|
|
6d18f2485d | ||
|
|
73753b364e | ||
|
|
68d6a14d04 | ||
|
|
c155d37790 | ||
|
|
6a6446d0b7 | ||
|
|
b0b4fe5570 | ||
|
|
6de8c3d1ca | ||
|
|
319f3f645a | ||
|
|
bedfbb0e6b | ||
|
|
148ffce6b7 | ||
|
|
85cb969780 | ||
|
|
c1a75ad051 | ||
|
|
7de49e9812 | ||
|
|
13c5d65f50 | ||
|
|
34ce9d68bf | ||
|
|
58dbadb869 | ||
|
|
0a9d901874 | ||
|
|
9ebad9aad8 | ||
|
|
e44b921143 | ||
|
|
6cb44e65a6 | ||
|
|
5398331956 | ||
|
|
de88ff0b6a | ||
|
|
1bbc92e460 | ||
|
|
e3ef9391ce | ||
|
|
b317f99196 | ||
|
|
512c45c9b5 | ||
|
|
5f4ae01c85 | ||
|
|
6c2bab44f6 | ||
|
|
b6f8a8bf9e | ||
|
|
ed3030606f | ||
|
|
274e46fa35 | ||
|
|
e95620c131 | ||
|
|
31cb11f0d1 | ||
|
|
fae905efb0 | ||
|
|
fcc1bada71 | ||
|
|
8a140b2303 | ||
|
|
9551590f92 | ||
|
|
0d8278aa0d | ||
|
|
c23a4e2085 | ||
|
|
fe77f2c14c | ||
|
|
5e06ad19ee | ||
|
|
8bce12aca3 | ||
|
|
d928ba7c3b | ||
|
|
25b0077adc | ||
|
|
ee0bcb7685 | ||
|
|
642141f574 | ||
|
|
90cdfb5e7e | ||
|
|
9967bc26d9 | ||
|
|
fef2d74ec2 | ||
|
|
9bbd262d05 | ||
|
|
555d8a1a24 | ||
|
|
f7f549fb05 | ||
|
|
d69c631a32 | ||
|
|
5e3a4c12d7 | ||
|
|
f75d0562ba | ||
|
|
ab745b3b03 | ||
|
|
f745d870f7 | ||
|
|
0ebae7734a | ||
|
|
b1b61963fc | ||
|
|
5282f01cda | ||
|
|
6fed836bee | ||
|
|
d39c8837fb | ||
|
|
870be0d1f0 | ||
|
|
a889163d23 | ||
|
|
1145d1c902 | ||
|
|
d641e5faaa | ||
|
|
57ca5ebf7b | ||
|
|
c2126e0680 | ||
|
|
45ba66c0ff | ||
|
|
a6af348a50 | ||
|
|
95fe5a47f5 | ||
|
|
29b3166da9 | ||
|
|
38ab3fbc44 | ||
|
|
b7ae677fb3 | ||
|
|
f54656dde1 | ||
|
|
fad1661b14 | ||
|
|
ed99c82137 | ||
|
|
c27a4fb609 | ||
|
|
216268f225 | ||
|
|
a5371d9a52 | ||
|
|
fdcf06efa9 | ||
|
|
755d48919f | ||
|
|
51bd72dc62 | ||
|
|
fe4a90ed97 | ||
|
|
7ee08a6713 | ||
|
|
0695fd87c0 | ||
|
|
ab8fe96919 | ||
|
|
a20c3f14ac | ||
|
|
62a0ca4fb5 | ||
|
|
2171f9c848 | ||
|
|
384aed2a91 | ||
|
|
2d9f20f2cc | ||
|
|
8430e24eae | ||
|
|
d13755ba5f | ||
|
|
d496892878 | ||
|
|
6d32879f21 | ||
|
|
40e7eeb118 | ||
|
|
02ef6b73af | ||
|
|
e831768d92 | ||
|
|
a0695b492e | ||
|
|
cddcebfe27 | ||
|
|
71ca25854f | ||
|
|
ad962d5bcd | ||
|
|
0083d99d37 | ||
|
|
5cd710e420 | ||
|
|
6da1bc083e | ||
|
|
47aaecf3ac | ||
|
|
a3f2fadd9e | ||
|
|
0cf851755b | ||
|
|
1361168d00 | ||
|
|
b888d3bcbc | ||
|
|
203dce371c | ||
|
|
1a81f4a8af | ||
|
|
9b788c3c2d | ||
|
|
17e487d011 | ||
|
|
b2b11fba32 | ||
|
|
4d4af995c8 | ||
|
|
0d04aedd00 | ||
|
|
53930866df | ||
|
|
9ce5c7c2fa | ||
|
|
dc30bd3991 | ||
|
|
70c90972dc | ||
|
|
9daa5b8583 | ||
|
|
5916cfd345 | ||
|
|
dec78c447d | ||
|
|
100359ad6f | ||
|
|
26e6f658fd | ||
|
|
15bf2bf772 | ||
|
|
4e72413829 | ||
|
|
0fb214434e | ||
|
|
2b4c62eab8 | ||
|
|
0ed5f41fa8 | ||
|
|
7e973667c8 | ||
|
|
8639fc5b39 | ||
|
|
f503a08813 | ||
|
|
634403cd6e | ||
|
|
6a539bcdcc | ||
|
|
c43830cd6a | ||
|
|
ca6c9dc312 | ||
|
|
c5194edcdd | ||
|
|
7905c1e254 | ||
|
|
fa0d46dba9 | ||
|
|
2bf8a96ec8 | ||
|
|
41a15cc254 | ||
|
|
2364ae67dd | ||
|
|
3c64db25b9 | ||
|
|
87b2703b1e | ||
|
|
d86a8e554b | ||
|
|
af809c66b1 | ||
|
|
702087f0b6 | ||
|
|
d91db9ef62 | ||
|
|
7af819a656 | ||
|
|
633e678590 | ||
|
|
a5f6d4e56a | ||
|
|
c71cf46cbe | ||
|
|
3dc0dbbbac | ||
|
|
eeba4fd8bf | ||
|
|
a797764534 | ||
|
|
9f4aca43ee | ||
|
|
849b992732 | ||
|
|
cdf0e079b2 | ||
|
|
be647848ae | ||
|
|
48369b203c | ||
|
|
dd60c26591 | ||
|
|
5e834689c4 | ||
|
|
141c848260 | ||
|
|
796a2fffda | ||
|
|
6ea6102ae6 | ||
|
|
bfeb504243 | ||
|
|
174a86b497 | ||
|
|
951902319e | ||
|
|
dcb08a1d47 | ||
|
|
6afe2beb5b | ||
|
|
906169fedc | ||
|
|
68f5e58b57 | ||
|
|
9755e8d08c | ||
|
|
b1872bb08a | ||
|
|
dd356cdfdc | ||
|
|
8231f1f839 | ||
|
|
d248515d76 | ||
|
|
113e075fb6 | ||
|
|
c6a2622744 | ||
|
|
cefec5e565 | ||
|
|
54ee4490c7 | ||
|
|
2ab21839cb | ||
|
|
cbdf954eac | ||
|
|
6504505297 | ||
|
|
fa5307dc87 | ||
|
|
80561c65fc | ||
|
|
3d3128b831 | ||
|
|
b228d5188d | ||
|
|
fdc8eeb650 | ||
|
|
8162f1f935 | ||
|
|
b456037a08 | ||
|
|
90f8eb20fc | ||
|
|
19cb848877 | ||
|
|
7ef4535892 | ||
|
|
5e5d38aef2 | ||
|
|
f2b8dd8109 | ||
|
|
8c706895b2 | ||
|
|
8c479396f1 | ||
|
|
fe83a35c0c | ||
|
|
902b5887fc | ||
|
|
9f9e2d7507 | ||
|
|
ed50b357ad | ||
|
|
65c45fa47d | ||
|
|
3d4ceb9efb | ||
|
|
a6940d38a7 | ||
|
|
204410d599 | ||
|
|
20f53eb50f | ||
|
|
887d0b208a | ||
|
|
69dc2cf5a5 | ||
|
|
a7353ee38a | ||
|
|
541b0579e4 | ||
|
|
ebb9ca1298 | ||
|
|
90aa40bfb5 | ||
|
|
6261d316f5 | ||
|
|
3bb439e4b1 | ||
|
|
d52d16ee19 | ||
|
|
9d3dc38a13 | ||
|
|
2888e1fadd | ||
|
|
fcc990ac24 | ||
|
|
5f9916202d | ||
|
|
53a95ccf51 | ||
|
|
5c4f7b62a6 | ||
|
|
8186e6ebf0 | ||
|
|
df2bd841ed | ||
|
|
048fde70e2 | ||
|
|
5d87c27f23 | ||
|
|
9d44f250ab | ||
|
|
31ace7d3f4 | ||
|
|
d893328343 | ||
|
|
1ae22f929d | ||
|
|
73121fadf7 | ||
|
|
4bba92cdac | ||
|
|
c3d6fa229c | ||
|
|
4b09a6e29a | ||
|
|
876b8cc984 | ||
|
|
cb188cc54d | ||
|
|
f3d4e85699 | ||
|
|
74992821f6 | ||
|
|
0299884306 | ||
|
|
b459ef5550 | ||
|
|
d526ce904a | ||
|
|
8b456270be | ||
|
|
21569e4025 | ||
|
|
621ada0c10 | ||
|
|
50055b6500 | ||
|
|
c81851d48d | ||
|
|
8904d577e5 | ||
|
|
34a7406167 | ||
|
|
ab1b769240 | ||
|
|
652ad7b344 | ||
|
|
48fdfd88fa | ||
|
|
1318f8d19d | ||
|
|
c5fe52ede2 | ||
|
|
ae51d341e6 | ||
|
|
96b08180d4 | ||
|
|
f0618e8465 | ||
|
|
c9dd7722c3 | ||
|
|
025cdf246a | ||
|
|
7fdd7cd280 | ||
|
|
4bb9c11e55 | ||
|
|
1b0dccab42 | ||
|
|
31c9a36bf4 | ||
|
|
534b7e7226 | ||
|
|
6b9d14a68b | ||
|
|
d41dfc86c7 | ||
|
|
b86e9c51f5 | ||
|
|
0088a53ab8 | ||
|
|
efdff66593 | ||
|
|
837f8b2796 | ||
|
|
82ff1772b2 | ||
|
|
36aa6739fc | ||
|
|
0c26d35287 | ||
|
|
753daebadf | ||
|
|
d21293ca13 | ||
|
|
1e8fd10a0a | ||
|
|
b9df4b36ab | ||
|
|
3832dec3e3 | ||
|
|
45ff49da16 | ||
|
|
dfc000c1e1 | ||
|
|
604b7abc89 | ||
|
|
a4676be9d7 | ||
|
|
19af4d8c96 | ||
|
|
272cff1cd9 | ||
|
|
d2f006892c | ||
|
|
05637fd7bf | ||
|
|
a9581907c7 | ||
|
|
4d9fff91d4 | ||
|
|
28b9cf683a | ||
|
|
20e1179085 | ||
|
|
c0ed4b7ed3 | ||
|
|
96fd21b381 | ||
|
|
49d4595049 | ||
|
|
eb98a1979d | ||
|
|
9416e3bc77 | ||
|
|
350b121328 | ||
|
|
47dfbce810 | ||
|
|
e2c51f9d00 | ||
|
|
d738188c8b | ||
|
|
0c8b3bc79e | ||
|
|
7f8a152909 | ||
|
|
50c208e4db | ||
|
|
92e9ef31a3 | ||
|
|
d6cce6a887 | ||
|
|
8f7a76f2fe | ||
|
|
6957de71ee | ||
|
|
ee9436d45f | ||
|
|
45c972f813 | ||
|
|
aa547c3934 | ||
|
|
894cd14802 | ||
|
|
950815890f | ||
|
|
3d28723a92 | ||
|
|
4b1519367f | ||
|
|
b515b58ed1 | ||
|
|
09cc9910a2 | ||
|
|
463cedc12c | ||
|
|
9d3abb7a0c | ||
|
|
fef056fbe9 | ||
|
|
acc8eaa4e2 | ||
|
|
d3f768975d | ||
|
|
385dfa697a | ||
|
|
560addae85 | ||
|
|
4924b5f883 | ||
|
|
49ed6eee31 | ||
|
|
f6a5f3cf06 | ||
|
|
704e274e6a | ||
|
|
6f71ad125d | ||
|
|
c891b3a02e | ||
|
|
417ce64c39 | ||
|
|
d3d0c33fe2 | ||
|
|
ae8f56381b | ||
|
|
5752ccdf98 | ||
|
|
7818f76e71 | ||
|
|
0a7d80cbad | ||
|
|
54a753ec7e | ||
|
|
d46f9ebd1f | ||
|
|
41453b0fb3 | ||
|
|
2cebfc8046 | ||
|
|
a20e7566c9 | ||
|
|
29b7bffadf | ||
|
|
2142598058 | ||
|
|
0ed319927a | ||
|
|
033f7a6a5f | ||
|
|
ac551b4448 | ||
|
|
2299906c23 | ||
|
|
607b7c6985 | ||
|
|
79c2378826 | ||
|
|
241b668073 | ||
|
|
e5ca8acdea | ||
|
|
9e8800a8ba | ||
|
|
b0d137b6bb | ||
|
|
5174b409fb | ||
|
|
0c0a4da7d3 | ||
|
|
aead8f6edd | ||
|
|
83f2899892 | ||
|
|
3f25833d3d | ||
|
|
26d2092ace | ||
|
|
c82c34f6a4 | ||
|
|
00dca8b099 | ||
|
|
5c9c1ee4ed | ||
|
|
4e9c4e62a2 | ||
|
|
3e5377c830 | ||
|
|
e3875812e7 | ||
|
|
ef16795ea7 | ||
|
|
9490623d54 | ||
|
|
f4f9086f79 | ||
|
|
22d057328a | ||
|
|
ef8c58e3b7 | ||
|
|
60c8502d27 | ||
|
|
e65583dba7 | ||
|
|
bebf02dccb | ||
|
|
219d8b2e41 | ||
|
|
d20c0d452b | ||
|
|
347c8bcef7 | ||
|
|
93176838e2 | ||
|
|
7dc6c4e5d0 | ||
|
|
430709b308 | ||
|
|
417cdf5901 | ||
|
|
ec0303ab09 | ||
|
|
b80fb7c817 | ||
|
|
962e48c77a | ||
|
|
4b1578237e | ||
|
|
247d8763f7 | ||
|
|
a3e2a32a7d | ||
|
|
237e39f495 | ||
|
|
a23b28bee9 | ||
|
|
d8d13d5ae2 | ||
|
|
0f6b35cbf6 | ||
|
|
969d06f934 | ||
|
|
ebcddd9477 | ||
|
|
0cbe196bd3 | ||
|
|
6087cad5ff | ||
|
|
511d3f8eae | ||
|
|
bbc8408c5a | ||
|
|
f0723940e4 | ||
|
|
34516008f5 | ||
|
|
000e3c0601 | ||
|
|
ec6416bfcb | ||
|
|
baa72e6f52 | ||
|
|
81f0b5ebe2 | ||
|
|
e833af4e9d | ||
|
|
1255dd0728 | ||
|
|
61ab5478bc | ||
|
|
c99eb08741 | ||
|
|
52f1329ca4 | ||
|
|
8f574b1275 | ||
|
|
5e171464c3 | ||
|
|
92bcb03cef | ||
|
|
ead45003e7 | ||
|
|
37a37e95c6 | ||
|
|
f68345d014 | ||
|
|
9605afbb05 | ||
|
|
7aa57ad36c | ||
|
|
82efcefac7 | ||
|
|
9b176299ab | ||
|
|
f70902255c | ||
|
|
cbe79473ef | ||
|
|
158df5f652 | ||
|
|
253f54cb20 | ||
|
|
90fa429fb9 | ||
|
|
d7063a914f | ||
|
|
0a6ba698ba | ||
|
|
b11bfb0e92 | ||
|
|
ece7d1f3b4 | ||
|
|
6d9a813d67 | ||
|
|
f6382c7774 | ||
|
|
2525c53029 | ||
|
|
ee9520811f | ||
|
|
212e8e34ab | ||
|
|
1fe53ac5c2 | ||
|
|
e1f7b64fe1 | ||
|
|
074d949d0b | ||
|
|
0c07c7454d | ||
|
|
82eb456565 | ||
|
|
285fc8ba8c | ||
|
|
91e971a9ac | ||
|
|
a12fcfd6b9 | ||
|
|
1d2ae3d282 | ||
|
|
2a42cc8542 | ||
|
|
e512f272a5 | ||
|
|
8a795dea4d | ||
|
|
bc1333c5c5 | ||
|
|
ab378f4a59 | ||
|
|
a0bb78bc58 | ||
|
|
8d7a64587c | ||
|
|
860dd74748 | ||
|
|
a8c4bb1a25 | ||
|
|
b4f73192ae | ||
|
|
bd48715737 | ||
|
|
9a31099821 | ||
|
|
1dba594fa4 | ||
|
|
e1f5f7b713 | ||
|
|
a5ed3f1d0c | ||
|
|
86ddf9d7cf | ||
|
|
6bd0a0ee1f | ||
|
|
05084c67db | ||
|
|
cbb51c92e9 | ||
|
|
ae7b42c3b0 | ||
|
|
3da75e9dd0 | ||
|
|
e7561911cc | ||
|
|
0d727e74c0 | ||
|
|
36dbe5556f | ||
|
|
8b8d08afaa | ||
|
|
dda95dd741 | ||
|
|
50cc43a742 | ||
|
|
d4ab9850f2 | ||
|
|
f561bb57f4 | ||
|
|
99d8681e46 | ||
|
|
ecd28f6c2d | ||
|
|
5a5f8845ca | ||
|
|
8ac34018ab | ||
|
|
95b1560c8a | ||
|
|
a7efea44d1 | ||
|
|
42d8d2256d | ||
|
|
6063a295a0 | ||
|
|
3c8bdeb539 | ||
|
|
08ecfe58d5 | ||
|
|
dd1bde9830 | ||
|
|
5861923f3b | ||
|
|
5aef00dfaa | ||
|
|
ea4790eb6f | ||
|
|
6de98fd652 | ||
|
|
2d180f5a07 | ||
|
|
0ec3991b15 | ||
|
|
d1a6a17c88 | ||
|
|
f1f1d1506d | ||
|
|
d8af0ee835 | ||
|
|
164f96e30a | ||
|
|
b444f8b0fb | ||
|
|
3bac29828c | ||
|
|
1c60d0b314 | ||
|
|
e7f4b555e9 | ||
|
|
5347d994ef | ||
|
|
bb20fe1929 | ||
|
|
b282110d40 | ||
|
|
87fd4e7f57 | ||
|
|
025b312a2e | ||
|
|
b08813f9b6 | ||
|
|
415199d814 | ||
|
|
6f7869784a | ||
|
|
ebe9784b23 | ||
|
|
645b891a1d | ||
|
|
34fbf2df6d | ||
|
|
9ad2cfc855 | ||
|
|
e4c7bd1baa | ||
|
|
1ee8037d2b | ||
|
|
275ee96750 | ||
|
|
8efff2f795 | ||
|
|
b66cb676a1 | ||
|
|
975b7b72c3 | ||
|
|
a520b9e57f | ||
|
|
65b9fabfd7 | ||
|
|
4be63cb75e | ||
|
|
910ed80ae2 | ||
|
|
8677a8354d | ||
|
|
d902417b21 | ||
|
|
338e2e9089 | ||
|
|
fa88ba1583 | ||
|
|
619c14ef65 | ||
|
|
3012967384 | ||
|
|
295aa8861b | ||
|
|
447d949537 | ||
|
|
c87fa9463e | ||
|
|
f7f424bad7 | ||
|
|
e0606e20d8 | ||
|
|
91a2216d27 | ||
|
|
d2643a3372 | ||
|
|
fa01e80386 | ||
|
|
31caa27d39 | ||
|
|
c78962f5f6 | ||
|
|
4a1bdae913 | ||
|
|
2dfd14f3c5 | ||
|
|
023400e84e | ||
|
|
05fd772d46 | ||
|
|
d409075b6c | ||
|
|
8267c48aad | ||
|
|
afbaf931eb | ||
|
|
12105fb25f | ||
|
|
0bd9dbdba2 | ||
|
|
f48fbc58b5 | ||
|
|
c287d0ff5a | ||
|
|
bac2240c0b | ||
|
|
300ed327df | ||
|
|
e14ca3ab77 | ||
|
|
2b5ba6049f | ||
|
|
caf6217b9a | ||
|
|
716976c078 | ||
|
|
00cf85abd4 | ||
|
|
8ef2ed4144 | ||
|
|
befec82120 | ||
|
|
eb7923f4bc | ||
|
|
d70687ff1e | ||
|
|
e7f0c461c6 | ||
|
|
0bbf3f5f0d | ||
|
|
321fd40355 | ||
|
|
add5bcbe6a | ||
|
|
f39e59ba5b | ||
|
|
a65bdbece5 | ||
|
|
184fa6fd9b | ||
|
|
897a14d07f | ||
|
|
36d09b923e | ||
|
|
0928c52100 | ||
|
|
daa1fcdcba | ||
|
|
6bea09f246 | ||
|
|
e88bd5898c | ||
|
|
a5bb5005f8 | ||
|
|
ec664163e5 | ||
|
|
b130076313 | ||
|
|
372a9c9640 | ||
|
|
958a1e6634 | ||
|
|
306a8728b4 | ||
|
|
e9527a6bbf | ||
|
|
d261a019bd | ||
|
|
6465277fb0 | ||
|
|
fc8be6d56f | ||
|
|
cc32089a51 | ||
|
|
56dd0aa594 | ||
|
|
71d8327b32 | ||
|
|
e322e036a4 | ||
|
|
4f2651dd2b | ||
|
|
f53553e301 | ||
|
|
324f776ed5 | ||
|
|
4c346bebff | ||
|
|
083a2c5235 | ||
|
|
1f04ba5083 | ||
|
|
1ad265611f | ||
|
|
7adfb6c1c0 | ||
|
|
190330c204 | ||
|
|
56f975c65e | ||
|
|
a79892028a | ||
|
|
3086b75616 | ||
|
|
9955da3521 | ||
|
|
0ba9130e96 | ||
|
|
0af14b93c5 | ||
|
|
191884d5af | ||
|
|
dd1aac89ce | ||
|
|
24203e8d07 | ||
|
|
e53f79be03 | ||
|
|
435dc2d818 | ||
|
|
39e446ecf2 | ||
|
|
5a013ddc88 | ||
|
|
14b595940f | ||
|
|
b6d4b96aa8 | ||
|
|
de4c5d641d | ||
|
|
f731419f86 | ||
|
|
0e2f00665c | ||
|
|
cae0f541b5 | ||
|
|
88dec452f6 | ||
|
|
28072ad24f | ||
|
|
857c252b14 | ||
|
|
04906c5307 | ||
|
|
19e9abb7c4 | ||
|
|
89fa2f0523 | ||
|
|
6686e78069 | ||
|
|
928ee586a0 | ||
|
|
08d661d275 | ||
|
|
f7709207d2 | ||
|
|
6174171cab | ||
|
|
6242e7c8b8 | ||
|
|
8a4fd72261 | ||
|
|
80588d0f5f | ||
|
|
377f977f79 | ||
|
|
68393c778b | ||
|
|
8b8458cf78 | ||
|
|
44e8dcf680 | ||
|
|
b83e6170a4 | ||
|
|
dde0e24e0e | ||
|
|
2d31c9bfb6 | ||
|
|
c0bdd74837 | ||
|
|
3ccf2f4a00 | ||
|
|
b9d81b7994 | ||
|
|
fe8af42814 | ||
|
|
03f2c33601 | ||
|
|
1613398492 | ||
|
|
87ad554531 | ||
|
|
d74363baea | ||
|
|
535baff2aa | ||
|
|
dcad84aeff | ||
|
|
df3e0bf956 | ||
|
|
4215ad6e88 | ||
|
|
5c6a4ae7b2 | ||
|
|
33cece0cd1 | ||
|
|
4b3b48c981 | ||
|
|
99eec81983 | ||
|
|
e1b5e2db33 | ||
|
|
cd76087c2f | ||
|
|
ff34df3e42 | ||
|
|
db43fd3a12 | ||
|
|
de42e7e4c1 | ||
|
|
5baeea2b5d | ||
|
|
6d7be12c60 | ||
|
|
98fb897785 | ||
|
|
7bdd9b25ce | ||
|
|
70b995e6f7 | ||
|
|
ecb6ec3adf | ||
|
|
431f7e6fd5 | ||
|
|
e0f8688cb9 | ||
|
|
6fcd6bc6e4 | ||
|
|
56d72946bc | ||
|
|
9099f84441 | ||
|
|
fefadc58bd | ||
|
|
1628d3b566 | ||
|
|
b456d86b22 | ||
|
|
c3a1236ca9 | ||
|
|
544e8e9d3f | ||
|
|
a032a41935 | ||
|
|
e43215cdf1 | ||
|
|
781aab0c1d | ||
|
|
197aade0d1 | ||
|
|
5de9f545b0 | ||
|
|
43cf24d8d6 | ||
|
|
b3858b977a | ||
|
|
1a38c79d94 | ||
|
|
7ea46bb370 | ||
|
|
2b8120811c | ||
|
|
3498ebb978 | ||
|
|
5f71c2c1b6 | ||
|
|
c68141d4bb | ||
|
|
70b6f456af | ||
|
|
0b86592d5c | ||
|
|
91ee5af643 | ||
|
|
9df03c1119 | ||
|
|
80fb01fd7d | ||
|
|
febbfa2126 | ||
|
|
c9a959d548 | ||
|
|
24473783e9 | ||
|
|
cd429f9556 | ||
|
|
c9b9023f38 | ||
|
|
c8adc8c654 | ||
|
|
08501ce207 | ||
|
|
1e3a9cc07d | ||
|
|
d9dc87f9ab | ||
|
|
31f8cf94da | ||
|
|
c9c5913845 | ||
|
|
95e3276394 | ||
|
|
8d06c82338 | ||
|
|
5da31f76f4 | ||
|
|
8c3933e60e | ||
|
|
c67ea8309a | ||
|
|
d76a6fa0ec | ||
|
|
b7c3b32b49 | ||
|
|
f6f32fbaa0 | ||
|
|
06f807bb4d | ||
|
|
20975628b2 | ||
|
|
c6b7337317 | ||
|
|
4e040700ab | ||
|
|
b008270fe6 | ||
|
|
2deb826266 | ||
|
|
66815e3192 | ||
|
|
673fcfc9fe | ||
|
|
9e34de69f0 | ||
|
|
ed1ac27f75 | ||
|
|
d202d53ce2 | ||
|
|
8485e7b436 | ||
|
|
e85c110697 | ||
|
|
a9c0aefa58 | ||
|
|
3a5c840ce8 | ||
|
|
bbf7f8a98b | ||
|
|
24dee6aa62 | ||
|
|
c33452fd0b | ||
|
|
ad099dff27 | ||
|
|
d31e90fb42 | ||
|
|
c150ee66af | ||
|
|
dac6d74fd1 | ||
|
|
598a87c349 | ||
|
|
34ec6cfc8d | ||
|
|
39865b4c09 | ||
|
|
116a605053 | ||
|
|
a1da459343 | ||
|
|
6346fae044 | ||
|
|
12440e7ab6 | ||
|
|
39af37f20c | ||
|
|
0b9abdd70d | ||
|
|
29c9b0fc78 | ||
|
|
aee977ac36 | ||
|
|
8b03a82480 | ||
|
|
95f9946476 | ||
|
|
5ab64077e8 | ||
|
|
ae8221e208 | ||
|
|
a18866a900 | ||
|
|
ab65f99a44 | ||
|
|
2a4158a130 | ||
|
|
0befa49f1a | ||
|
|
d4aa9745ca | ||
|
|
260a5c89ef | ||
|
|
b19aec81b4 | ||
|
|
9eea792fb1 | ||
|
|
d05a084509 | ||
|
|
1722d3b69f | ||
|
|
53a6384515 | ||
|
|
5e492d3e3f | ||
|
|
1daac4cfad | ||
|
|
646939bcf8 | ||
|
|
84062f331f | ||
|
|
0a1cd5cb74 | ||
|
|
f63b7e04d6 | ||
|
|
c287137283 | ||
|
|
d3d8a5dc25 | ||
|
|
bf5468d4f4 | ||
|
|
7b93cf028a | ||
|
|
3012008b85 | ||
|
|
145312af2c | ||
|
|
0414ee6aa0 | ||
|
|
bf716b7953 | ||
|
|
d4657ff85d | ||
|
|
5023a58cc1 | ||
|
|
9ea75f1abf | ||
|
|
50a91836e8 | ||
|
|
12d05f7a6b | ||
|
|
bff4002cad | ||
|
|
29388a8a8d | ||
|
|
7f29a66ad3 | ||
|
|
e7067447b6 | ||
|
|
b807f32669 | ||
|
|
db596c886e | ||
|
|
0e37635373 | ||
|
|
58ac7de123 | ||
|
|
ab8421dbae | ||
|
|
915b8f288b | ||
|
|
52b7a59085 | ||
|
|
e75119645b | ||
|
|
a39cd8f114 | ||
|
|
4e8f771ef7 | ||
|
|
e0ce18407d | ||
|
|
fcdcf78629 | ||
|
|
821e346e7d | ||
|
|
0276fcf5ce | ||
|
|
7c729aa23f | ||
|
|
14d08204f1 | ||
|
|
2747fe2716 | ||
|
|
ff6957f577 | ||
|
|
39c0da248b | ||
|
|
4a29c14051 | ||
|
|
4f8dcf0447 | ||
|
|
081998c79f | ||
|
|
23f0f0bc6d | ||
|
|
4f7f40a245 | ||
|
|
624be85604 | ||
|
|
452eca267d | ||
|
|
0711781a1e | ||
|
|
65d3c25a9e | ||
|
|
3a94e1fb98 | ||
|
|
c621b84a4c | ||
|
|
df69375644 | ||
|
|
53ecb36705 | ||
|
|
2c5ba1b826 | ||
|
|
90ddfe3b43 | ||
|
|
a58d4be849 | ||
|
|
6f7b5e9973 | ||
|
|
a727cee3a6 | ||
|
|
562da819a6 | ||
|
|
7cc980d525 | ||
|
|
4af973015f | ||
|
|
210fac225d | ||
|
|
875377e0d2 | ||
|
|
eacd62f7fb | ||
|
|
4faaa2d082 | ||
|
|
8dda1321b5 | ||
|
|
bb59cda131 | ||
|
|
ed12c6f6bd | ||
|
|
324ded28de | ||
|
|
1262fdbf29 | ||
|
|
901c0ba24e | ||
|
|
8213f704ce | ||
|
|
17af6bf515 | ||
|
|
0d9f1a225f | ||
|
|
8518a44935 | ||
|
|
458fb47f43 | ||
|
|
f4db21af2c | ||
|
|
9d426f7feb | ||
|
|
52ae61b1a5 | ||
|
|
c3c76fab71 | ||
|
|
61db883330 | ||
|
|
447c236953 | ||
|
|
8bbfb743f0 | ||
|
|
3e18f488c6 | ||
|
|
ad6d001e9f | ||
|
|
faa11d603e | ||
|
|
ae2eff925b | ||
|
|
f180a8ff84 | ||
|
|
e6ad56d6d0 | ||
|
|
37f1948f9f | ||
|
|
1adea79d23 | ||
|
|
dd640c2fbe | ||
|
|
6c49e93cbf | ||
|
|
247858d295 | ||
|
|
797679ce7a | ||
|
|
ae17acce20 | ||
|
|
5974098482 | ||
|
|
0ae0a7e1f9 | ||
|
|
fb1e4acd60 | ||
|
|
e6407bf292 | ||
|
|
2ee1728776 | ||
|
|
5cab488a81 | ||
|
|
c623dfac75 | ||
|
|
3e94e18b73 | ||
|
|
1d00350fa1 | ||
|
|
9056ad493b | ||
|
|
b5a9007619 | ||
|
|
9221cbc361 | ||
|
|
9a6cfd4228 | ||
|
|
81ac053818 | ||
|
|
693bb804b6 | ||
|
|
6ec70d7792 | ||
|
|
0c6ddb725b | ||
|
|
fe7689297c | ||
|
|
95809454b8 | ||
|
|
9bc932d54f | ||
|
|
d57d5d1d4a | ||
|
|
b929aa07ec | ||
|
|
0c0e118ea2 | ||
|
|
d522eab8f5 | ||
|
|
21d5ea9fe6 | ||
|
|
9bb1cb3efc | ||
|
|
c681c3ba54 | ||
|
|
7960eb87cc | ||
|
|
f565f4cf04 | ||
|
|
5775ddcf6a | ||
|
|
a220bce2a4 | ||
|
|
184573946f | ||
|
|
e0a00f4d41 | ||
|
|
4fe1a035c6 | ||
|
|
5148f5e341 | ||
|
|
19fa50b6a7 | ||
|
|
19949f4217 | ||
|
|
bef906e421 | ||
|
|
0c68ecef37 | ||
|
|
4c5cd11ffb | ||
|
|
b4a5d28f53 | ||
|
|
06ffc8c6f6 | ||
|
|
eb32f23d38 | ||
|
|
5d61b049b5 | ||
|
|
2b667ffa03 | ||
|
|
fdb24513b5 | ||
|
|
a822535537 | ||
|
|
83b60e49c6 | ||
|
|
86c8fe9a83 | ||
|
|
d460805c8b | ||
|
|
a9d73a8501 | ||
|
|
a3cf76be92 | ||
|
|
23c9893362 | ||
|
|
7efbe56763 | ||
|
|
9759ab523c | ||
|
|
21f8ff0168 | ||
|
|
f865bd9282 | ||
|
|
8e0770b15d | ||
|
|
0b696f8388 | ||
|
|
6b6c166eca | ||
|
|
598422a822 | ||
|
|
15b3a89520 | ||
|
|
7d06d0f6a4 | ||
|
|
b975799231 | ||
|
|
96a8194775 | ||
|
|
600150c363 | ||
|
|
8a1242c312 | ||
|
|
b44b8721c5 | ||
|
|
6149f1a476 | ||
|
|
f4eb69c831 | ||
|
|
0e94a9708a | ||
|
|
97cc94d3d9 | ||
|
|
ec848524a6 | ||
|
|
ec20edde5e | ||
|
|
d6093e7764 | ||
|
|
b71bc36061 | ||
|
|
359fc94d99 | ||
|
|
5e59cbea8a | ||
|
|
843a7c1f1e | ||
|
|
aa5427d976 | ||
|
|
04218e0291 | ||
|
|
9a7c4da780 | ||
|
|
da777f2e40 | ||
|
|
7fc92a6a03 | ||
|
|
f93958ffea | ||
|
|
1f71856d59 | ||
|
|
097f5141d3 | ||
|
|
9547c45109 | ||
|
|
753158ae7a | ||
|
|
f50752df6f | ||
|
|
1525401105 | ||
|
|
d62d4265a8 | ||
|
|
4aae685c6e | ||
|
|
18cd794fe1 | ||
|
|
b20a4e768e | ||
|
|
c7c6cfe27f | ||
|
|
87077c7644 | ||
|
|
fd02e83cea | ||
|
|
8da8285c56 | ||
|
|
5c7f67a711 | ||
|
|
26634de090 | ||
|
|
1f2c89517e | ||
|
|
472a4a63d7 | ||
|
|
634315f9e4 | ||
|
|
064ccd31fc | ||
|
|
0c694447d6 | ||
|
|
3ae84a0e5b | ||
|
|
234de9b812 | ||
|
|
257e3621ea | ||
|
|
65e31f15a2 | ||
|
|
982201a1fa | ||
|
|
bb9c2f5e92 | ||
|
|
9dc04b2357 | ||
|
|
98d457dae6 | ||
|
|
d0f7798d55 | ||
|
|
5ee7b4ffad | ||
|
|
7b15b13e8b | ||
|
|
2b10be3464 | ||
|
|
4911d7caa1 | ||
|
|
a23886143a | ||
|
|
16e0ee4576 | ||
|
|
33dccd4ef7 | ||
|
|
7d03ae498b | ||
|
|
fda1dedbe4 | ||
|
|
07c2a2e49b | ||
|
|
4964056343 | ||
|
|
98e15c8f87 | ||
|
|
6c602610d4 | ||
|
|
08efd3f979 | ||
|
|
49a9cf9248 | ||
|
|
d56877c591 | ||
|
|
6fe123b3f9 | ||
|
|
427d2dcf52 | ||
|
|
755f3de523 | ||
|
|
fc72d847da | ||
|
|
6a963f39d4 | ||
|
|
5161fbb1d4 | ||
|
|
fe32d8d47b | ||
|
|
fffa608816 | ||
|
|
fb79de7903 | ||
|
|
007cf8c2aa | ||
|
|
67c86c9521 | ||
|
|
780d83f049 | ||
|
|
1e420ed6f7 | ||
|
|
e5a382b2ec | ||
|
|
b326142952 | ||
|
|
6870c47132 | ||
|
|
5251fcd4ec | ||
|
|
f9c6147396 | ||
|
|
937b2adf57 | ||
|
|
b4e4c875b9 | ||
|
|
1d52afb45a | ||
|
|
37165fc735 | ||
|
|
bed891289f | ||
|
|
3a007518e5 | ||
|
|
c2b856c3da | ||
|
|
5f944554cf | ||
|
|
db34791130 | ||
|
|
8b73912c3d | ||
|
|
1ac2f489ab | ||
|
|
4309d79c56 | ||
|
|
a802f740c5 | ||
|
|
9eb4fd7cf9 | ||
|
|
4dd5784838 | ||
|
|
87911fc3b6 | ||
|
|
d2a1737a9e | ||
|
|
352eefdb29 | ||
|
|
e3a2042990 | ||
|
|
a492a3bbb6 | ||
|
|
fac84830d3 | ||
|
|
3d743d306b | ||
|
|
6de9e82709 | ||
|
|
773f929b01 | ||
|
|
3a6a185548 | ||
|
|
32d1863411 | ||
|
|
23dd15e979 | ||
|
|
f3da3e0fb3 | ||
|
|
396d74df63 | ||
|
|
7293893fc7 | ||
|
|
9b796e7832 | ||
|
|
a8dab3a3b1 | ||
|
|
e432e14a95 | ||
|
|
ee865662b2 | ||
|
|
a24313c789 | ||
|
|
02fd5c430f | ||
|
|
4e0e223766 | ||
|
|
2df5017e94 | ||
|
|
6deb9b4ab7 | ||
|
|
0a57e538d5 | ||
|
|
e8dae0cfd1 | ||
|
|
e9c55bbd43 | ||
|
|
7a98325eae | ||
|
|
b0a811c51d | ||
|
|
da013d8aae | ||
|
|
a1d920f003 | ||
|
|
07443e54de | ||
|
|
717a678c9a | ||
|
|
ffaf999587 | ||
|
|
37fba10ba7 | ||
|
|
0a9de8cf56 | ||
|
|
a02be88c4a | ||
|
|
e8dc05ad99 | ||
|
|
6338a73eaa | ||
|
|
73533080f6 | ||
|
|
1c7a6d9825 | ||
|
|
c553bc8d0a | ||
|
|
9ff967249b | ||
|
|
3011cdf22c | ||
|
|
4f2ade5f7f | ||
|
|
b882aad4ab | ||
|
|
0d6f98319d | ||
|
|
8541c12441 | ||
|
|
57d9dbc33e | ||
|
|
81d92870e9 | ||
|
|
a86795ea48 | ||
|
|
cb6a320eb5 | ||
|
|
c9ab718666 | ||
|
|
46cace5ed2 | ||
|
|
2a967261b3 | ||
|
|
66ecf7794e | ||
|
|
7365007511 | ||
|
|
88870ccac8 | ||
|
|
12e40352fe | ||
|
|
2b0bde8c0b | ||
|
|
931e8b934c | ||
|
|
a07cb5ef38 | ||
|
|
66a6f70a30 | ||
|
|
d7a629c5a3 | ||
|
|
2010d16d4d |
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a bug report
|
||||
about: Create a bug report. Not to be used for help requests or server configuration issues. Only for issues related to open source EspoCRM. Issues related to extensions should not to be posted here.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
@@ -11,7 +11,7 @@ assignees: ''
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
Explicit steps to reproduce the behavior:
|
||||
1. ...
|
||||
2. ...
|
||||
3. ...
|
||||
|
||||
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,4 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: EspoCRM forum
|
||||
url: https://forum.espocrm.com/
|
||||
about: Please use our forum to ask questions not related to product development
|
||||
about: "Use our forum for help requests and questions not related to product development. We don't provide support on GitHub."
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for EspoCRM
|
||||
about: Suggest an idea for EspoCRM.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
1
.idea/.gitignore
generated
vendored
1
.idea/.gitignore
generated
vendored
@@ -4,3 +4,4 @@
|
||||
!/fileTemplates
|
||||
!/inspectionProfiles
|
||||
!misc.xml
|
||||
!jsonSchemas.xml
|
||||
|
||||
3
.idea/codeStyles/Project.xml
generated
3
.idea/codeStyles/Project.xml
generated
@@ -1,5 +1,8 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JSCodeStyleSettings version="0">
|
||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||
</JSCodeStyleSettings>
|
||||
<PHPCodeStyleSettings>
|
||||
<option name="GROUP_USE_WRAP" value="2" />
|
||||
<option name="VARIABLE_NAMING_STYLE" value="CAMEL_CASE" />
|
||||
|
||||
1
.idea/inspectionProfiles/Project_Default.xml
generated
1
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -2,6 +2,7 @@
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="DuplicatedCode" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ES6ConvertLetToConst" enabled="true" level="WEAK WARNING" enabled_by_default="true" editorAttributes="INFO_ATTRIBUTES" />
|
||||
<inspection_tool class="ES6ConvertVarToLetConst" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="JSIgnoredPromiseFromCall" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PhpDocMissingThrowsInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
|
||||
1411
.idea/jsonSchemas.xml
generated
Normal file
1411
.idea/jsonSchemas.xml
generated
Normal file
File diff suppressed because it is too large
Load Diff
3
.vscode/.gitignore
vendored
Normal file
3
.vscode/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*
|
||||
!.gitignore
|
||||
!settings.json
|
||||
440
.vscode/settings.json
vendored
Normal file
440
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,440 @@
|
||||
{
|
||||
"json.schemas": [
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/autoload.json"
|
||||
],
|
||||
"url": "./schema/autoload.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/routes.json"
|
||||
],
|
||||
"url": "./schema/routes.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/module.json"
|
||||
],
|
||||
"url": "./schema/routes.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/layouts/*/detail.json",
|
||||
"*/Resources/layouts/*/detailSmall.json",
|
||||
"*/Resources/layouts/*/detailConvert.json"
|
||||
],
|
||||
"url": "./schema/layouts/detail.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/layouts/*/list.json",
|
||||
"*/Resources/layouts/*/listSmall.json",
|
||||
"*/Resources/layouts/*/listFor*.json"
|
||||
],
|
||||
"url": "./schema/layouts/list.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/aclDefs/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/aclDefs.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/authenticationMethods/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/authenticationMethods.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/clientDefs/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/clientDefs.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/dashlets/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/dashlets.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata//*.json"
|
||||
],
|
||||
"url": "./schema/metadata/.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/entityAcl/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/entityAcl.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/entityDefs/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/entityDefs.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/fields/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/fields.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/integrations/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/integrations.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/notificationDefs/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/notificationDefs.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/pdfDefs/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/pdfDefs.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/recordDefs/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/recordDefs.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/scopes/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/scopes.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/selectDefs/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/selectDefs.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/metadata/streamDefs/*.json"
|
||||
],
|
||||
"url": "./schema/metadata/streamDefs.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/acl.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/acl.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/aclPortal.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/aclPortal.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/actions.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/actions.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/addressFormats.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/addressFormats.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/adminPanel.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/adminPanel.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/api.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/api.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/appParams.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/appParams.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/authentication.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/authentication.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/authentication2FAMethods.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/authentication2FAMethods.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/cleanup.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/cleanup.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/client.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/client.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/clientRoutes.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/clientRoutes.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/complexExpression.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/complexExpression.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/config.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/config.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/consoleCommands.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/consoleCommands.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/containerServices.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/containerServices.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/currency.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/currency.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/currencyConversion.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/currencyConversion.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/databasePlatforms.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/databasePlatforms.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/dateTime.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/dateTime.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/defaultDashboardLayouts.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/defaultDashboardLayouts.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/defaultDashboardOptions.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/defaultDashboardOptions.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/entityManagerParams.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/entityManagerParams.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/entityTemplateList.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/entityTemplateList.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/entityTemplates.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/entityTemplates.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/export.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/export.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/fieldProcessing.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/fieldProcessing.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/file.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/file.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/fileStorage.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/fileStorage.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/formula.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/formula.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/hook.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/hook.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/image.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/image.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/jsLibs.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/jsLibs.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/language.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/language.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/linkManager.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/linkManager.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/entityManager.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/entityManager.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/massActions.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/massActions.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/metadata.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/metadata.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/orm.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/orm.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/pdfEngines.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/pdfEngines.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/popupNotifications.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/popupNotifications.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/portalContainerServices.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/portalContainerServices.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/rebuild.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/rebuild.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/recordId.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/recordId.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/regExpPatterns.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/regExpPatterns.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/relationships.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/relationships.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/scheduledJobs.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/scheduledJobs.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/select.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/select.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/smsProviders.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/smsProviders.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/templateHelpers.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/templateHelpers.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/templates.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/templates.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/webSocket.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/webSocket.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
88
Gruntfile.js
88
Gruntfile.js
@@ -33,16 +33,32 @@ const fs = require('fs');
|
||||
const cp = require('child_process');
|
||||
const path = require('path');
|
||||
const buildUtils = require('./js/build-utils');
|
||||
const {TemplateBundler, Bundler} = require('espo-frontend-build-tools');
|
||||
const LayoutTypeBundler = require('./js/layout-template-bundler');
|
||||
|
||||
const bundleConfig = require('./frontend/bundle-config.json');
|
||||
const libs = require('./frontend/libs.json');
|
||||
|
||||
module.exports = grunt => {
|
||||
|
||||
const pkg = grunt.file.readJSON('package.json');
|
||||
const bundleConfig = require('./frontend/bundle-config.json');
|
||||
const libs = require('./frontend/libs.json');
|
||||
|
||||
const originalLibDir = 'client/lib/original';
|
||||
|
||||
let bundleJsFileList = buildUtils.getPreparedBundleLibList(libs).concat(originalLibDir + '/espo.js');
|
||||
let libsBundleFileList = [
|
||||
'client/src/namespace.js',
|
||||
'client/src/loader.js',
|
||||
...buildUtils.getPreparedBundleLibList(libs),
|
||||
];
|
||||
|
||||
let bundleFileMap = {'client/lib/espo.js': libsBundleFileList};
|
||||
|
||||
for (let name in bundleConfig.chunks) {
|
||||
let namePart = 'espo-' + name;
|
||||
|
||||
bundleFileMap[`client/lib/${namePart}.js`] = originalLibDir + `/${namePart}.js`
|
||||
}
|
||||
|
||||
let copyJsFileList = buildUtils.getCopyLibDataList(libs);
|
||||
|
||||
let minifyLibFileList = copyJsFileList
|
||||
@@ -90,7 +106,7 @@ module.exports = grunt => {
|
||||
mkdir: {
|
||||
tmp: {
|
||||
options: {
|
||||
mode: 0755,
|
||||
mode: 0o755,
|
||||
create: [
|
||||
'build/tmp',
|
||||
],
|
||||
@@ -110,9 +126,7 @@ module.exports = grunt => {
|
||||
beforeFinal: {
|
||||
src: [
|
||||
'build/tmp/custom/Espo/Custom/*',
|
||||
'build/tmp/custom/Espo/Modules/*',
|
||||
'!build/tmp/custom/Espo/Custom/.htaccess',
|
||||
'!build/tmp/custom/Espo/Modules/.htaccess',
|
||||
'build/tmp/install/config.php',
|
||||
'build/tmp/vendor/*/*/.git',
|
||||
'build/tmp/custom/Espo/Custom/*',
|
||||
@@ -120,6 +134,10 @@ module.exports = grunt => {
|
||||
'!build/tmp/client/custom/modules',
|
||||
'build/tmp/client/custom/modules/*',
|
||||
'!build/tmp/client/custom/modules/dummy.txt',
|
||||
'build/tmp/client/lib/original/espo.js',
|
||||
'build/tmp/client/lib/original/espo-*.js',
|
||||
'!build/tmp/client/lib/original/espo-funnel-chart.js',
|
||||
'build/tmp/client/lib/transpiled',
|
||||
]
|
||||
},
|
||||
},
|
||||
@@ -134,19 +152,19 @@ module.exports = grunt => {
|
||||
|
||||
uglify: {
|
||||
options: {
|
||||
mangle: true,
|
||||
sourceMap: true,
|
||||
output: {
|
||||
comments: /^!/,
|
||||
},
|
||||
beautify: false,
|
||||
mangle: true,
|
||||
compress: true
|
||||
},
|
||||
bundle: {
|
||||
options: {
|
||||
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
|
||||
},
|
||||
files: {
|
||||
'client/lib/espo.min.js': bundleJsFileList,
|
||||
},
|
||||
files: bundleFileMap,
|
||||
},
|
||||
lib: {
|
||||
files: minifyLibFileList,
|
||||
@@ -164,7 +182,6 @@ module.exports = grunt => {
|
||||
'src/**',
|
||||
'res/**',
|
||||
'fonts/**',
|
||||
'cfg/**',
|
||||
'modules/**',
|
||||
'img/**',
|
||||
'css/**',
|
||||
@@ -236,7 +253,7 @@ module.exports = grunt => {
|
||||
options: {
|
||||
patterns: [
|
||||
{
|
||||
match: /\# \{\#dev\}(.*)\{\/dev\}/gs,
|
||||
match: /# \{#dev}(.*)\{\/dev}/gs,
|
||||
replacement: '',
|
||||
}
|
||||
]
|
||||
@@ -251,16 +268,43 @@ module.exports = grunt => {
|
||||
},
|
||||
});
|
||||
|
||||
grunt.registerTask('espo-bundle', () => {
|
||||
const Bundler = require('./js/bundler');
|
||||
|
||||
let contents = (new Bundler()).bundle(bundleConfig.jsFiles);
|
||||
|
||||
const writeOriginalLib = (name, contents) => {
|
||||
if (!fs.existsSync(originalLibDir)) {
|
||||
fs.mkdirSync(originalLibDir);
|
||||
}
|
||||
|
||||
fs.writeFileSync(originalLibDir + '/espo.js', contents, 'utf8');
|
||||
let file = originalLibDir + `/${name}.js`;
|
||||
|
||||
fs.writeFileSync(file, contents, 'utf8');
|
||||
};
|
||||
|
||||
grunt.registerTask('bundle', () => {
|
||||
let bundler = new Bundler(bundleConfig, libs);
|
||||
|
||||
let result = bundler.bundle();
|
||||
|
||||
for (let name in result) {
|
||||
let contents = result[name];
|
||||
|
||||
let key = 'espo-' + name;
|
||||
|
||||
if (name === 'main') {
|
||||
contents += '\n' + (new LayoutTypeBundler()).bundle();
|
||||
}
|
||||
|
||||
writeOriginalLib(key, contents);
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('bundle-templates', () => {
|
||||
let templateBundler = new TemplateBundler({
|
||||
dirs: [
|
||||
'client/res/templates',
|
||||
'client/modules/crm/res/templates',
|
||||
],
|
||||
});
|
||||
|
||||
templateBundler.process();
|
||||
});
|
||||
|
||||
grunt.registerTask('prepare-lib-original', () => {
|
||||
@@ -272,6 +316,10 @@ module.exports = grunt => {
|
||||
cp.execSync("node js/scripts/prepare-lib");
|
||||
});
|
||||
|
||||
grunt.registerTask('transpile', () => {
|
||||
cp.execSync("node js/transpile");
|
||||
});
|
||||
|
||||
grunt.registerTask('chmod-folders', () => {
|
||||
cp.execSync(
|
||||
"find . -type d -exec chmod 755 {} +",
|
||||
@@ -445,8 +493,10 @@ module.exports = grunt => {
|
||||
grunt.registerTask('internal', [
|
||||
'less',
|
||||
'cssmin',
|
||||
'espo-bundle',
|
||||
'prepare-lib-original',
|
||||
'transpile',
|
||||
'bundle',
|
||||
'bundle-templates',
|
||||
'uglify:bundle',
|
||||
'copy:frontendLib',
|
||||
'prepare-lib',
|
||||
|
||||
34
README.md
34
README.md
@@ -22,41 +22,53 @@ You can try the CRM on the online [demo](https://www.espocrm.com/demo/).
|
||||
|
||||
* PHP 8.0 and later;
|
||||
* MySQL 5.7 (and later), or MariaDB 10.2 (and later).
|
||||
* PostgreSQL 15 (and later) (yet experimental, officially supported soon)
|
||||
|
||||
For more information about server configuration see [this article](https://docs.espocrm.com/administration/server-configuration/).
|
||||
|
||||
### Documentation
|
||||
|
||||
The documentation for administrators, users and developers is available [here](https://docs.espocrm.com).
|
||||
See the [documentation](https://docs.espocrm.com) for administrators, users and developers.
|
||||
|
||||
### Bug reporting
|
||||
|
||||
Create an issue [here](https://github.com/espocrm/espocrm/issues) or post on our [forum](https://forum.espocrm.com/forum/bug-reports).
|
||||
We'd appreciate if you prefer posting issues on weekdays rather than weekends.
|
||||
Create a [GitHub issue](https://github.com/espocrm/espocrm/issues/new/choose) or post on our [forum](https://forum.espocrm.com/forum/bug-reports).
|
||||
|
||||
### Installing the stable version
|
||||
### Installing stable version
|
||||
|
||||
See the [instructions](https://docs.espocrm.com/administration/installation/) on installation.
|
||||
See installation instructions:
|
||||
|
||||
* [Manual installation](https://docs.espocrm.com/administration/installation/)
|
||||
* [Installation by script](https://docs.espocrm.com/administration/installation-by-script/)
|
||||
* [Installation with Docker](https://docs.espocrm.com/administration/docker/installation/)
|
||||
* [Installation with Traefik](https://docs.espocrm.com/administration/docker/traefik/)
|
||||
|
||||
### Development
|
||||
|
||||
* [Getting started](https://docs.espocrm.com/development/how-to-start)
|
||||
* [Running tests](https://docs.espocrm.com/development/tests)
|
||||
* [Making translation](https://docs.espocrm.com/development/translation)
|
||||
See the [developer documentation](https://docs.espocrm.com/development/).
|
||||
|
||||
We highly recommend using IDE for development. The backend codebase follows SOLID principles, utilizes interfaces, static typing and generics. We recommend to start learning EspoCRM from the Dependency Injection article in the documentation.
|
||||
|
||||
### Contributing
|
||||
|
||||
Before we can merge your pull request, you need to accept our CLA [here](https://github.com/espocrm/cla). It's very simple to do.
|
||||
|
||||
Contribute translations to [POEditor](https://poeditor.com/join/project/gLDKZtUF4i). Changes
|
||||
are usually merged to the GitHub repository before minor releases.
|
||||
|
||||
Branches:
|
||||
|
||||
* *fix* – upcoming maintenance release; minor fixes should be pushed to this branch;
|
||||
* *master* – develop branch; new features should be pushed to this branch;
|
||||
* *stable* – last stable release.
|
||||
|
||||
### Language
|
||||
|
||||
If you want to improve existing translation or add a language that is not available yet, you can contribute on our [POEditor](https://poeditor.com/join/project/gLDKZtUF4i) project. See instructions [here](https://www.espocrm.com/blog/how-to-use-poeditor-to-translate-espocrm/). It may be reasonable to let us know about your intention to join the POEditor project by posting on our forum or via the contact form on our website.
|
||||
|
||||
Changes on POEditor are usually merged to the GitHub repository before minor releases.
|
||||
|
||||
### Community & Support
|
||||
|
||||
If you have a question regarding some features, need help or customizations, want to get in touch with other EspoCRM users, or add a feature request, please use our [community forum](https://forum.espocrm.com/). We believe that using the forum to ask for help and share experience allows everyone in the community to contribute and use this knowledge later.
|
||||
|
||||
### License
|
||||
|
||||
EspoCRM is published under the GNU GPLv3 [license](https://raw.githubusercontent.com/espocrm/espocrm/master/LICENSE.txt).
|
||||
|
||||
@@ -240,6 +240,11 @@ class Binding implements BindingProcessor
|
||||
'Espo\\ORM\\PDO\\PDOProvider',
|
||||
'Espo\\ORM\\PDO\\DefaultPDOProvider'
|
||||
);
|
||||
|
||||
$binder->bindImplementation(
|
||||
'Espo\\Core\\Utils\\Database\\ConfigDataProvider',
|
||||
'Espo\\Core\\Utils\\Database\\DefaultConfigDataProvider'
|
||||
);
|
||||
}
|
||||
|
||||
private function bindMisc(Binder $binder): void
|
||||
@@ -282,6 +287,16 @@ class Binding implements BindingProcessor
|
||||
'Espo\\Core\\Mail\\Importer\\DuplicateFinder',
|
||||
'Espo\\Core\\Mail\\Importer\\DefaultDuplicateFinder'
|
||||
);
|
||||
|
||||
$binder->bindImplementation(
|
||||
'Espo\\Tools\\Api\\Cors\\Helper',
|
||||
'Espo\\Tools\\Api\\Cors\\DefaultHelper'
|
||||
);
|
||||
|
||||
$binder->bindImplementation(
|
||||
'Espo\\Core\\Record\\ActionHistory\\ActionLogger',
|
||||
'Espo\\Core\\Record\\ActionHistory\\DefaultActionLogger'
|
||||
);
|
||||
}
|
||||
|
||||
private function bindAcl(Binder $binder): void
|
||||
|
||||
@@ -48,17 +48,12 @@ class AccessChecker implements AccessEntityCREDChecker
|
||||
{
|
||||
use DefaultAccessCheckerDependency;
|
||||
|
||||
private AclManager $aclManager;
|
||||
private EntityManager $entityManager;
|
||||
|
||||
public function __construct(
|
||||
DefaultAccessChecker $defaultAccessChecker,
|
||||
AclManager $aclManager,
|
||||
EntityManager $entityManager
|
||||
private AclManager $aclManager,
|
||||
private EntityManager $entityManager
|
||||
) {
|
||||
$this->defaultAccessChecker = $defaultAccessChecker;
|
||||
$this->aclManager = $aclManager;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool
|
||||
@@ -126,8 +121,8 @@ class AccessChecker implements AccessEntityCREDChecker
|
||||
{
|
||||
if ($note->getTargetType() === Note::TARGET_TEAMS) {
|
||||
$intersect = array_intersect(
|
||||
$note->getLinkMultipleIdList('teams') ?? [],
|
||||
$user->getLinkMultipleIdList('teams') ?? []
|
||||
$note->getLinkMultipleIdList('teams'),
|
||||
$user->getLinkMultipleIdList('teams')
|
||||
);
|
||||
|
||||
if (count($intersect)) {
|
||||
@@ -150,6 +145,10 @@ class AccessChecker implements AccessEntityCREDChecker
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($note->getTargetType() === Note::TARGET_ALL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$note->getParentId() || !$note->getParentType()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ class AccessChecker implements AccessEntityCREDChecker
|
||||
}
|
||||
|
||||
if ($entity->getTargetType() === Note::TARGET_TEAMS) {
|
||||
$targetTeamIdList = $entity->getLinkMultipleIdList('teams') ?? [];
|
||||
$targetTeamIdList = $entity->getLinkMultipleIdList('teams');
|
||||
|
||||
foreach ($user->getTeamIdList() as $teamId) {
|
||||
if (in_array($teamId, $targetTeamIdList)) {
|
||||
@@ -138,7 +138,7 @@ class AccessChecker implements AccessEntityCREDChecker
|
||||
}
|
||||
|
||||
if ($entity->getTargetType() === Note::TARGET_USERS) {
|
||||
return in_array($user->getId(), $entity->getLinkMultipleIdList('users') ?? []);
|
||||
return in_array($user->getId(), $entity->getLinkMultipleIdList('users'));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -51,8 +51,8 @@ class OwnershipChecker implements OwnershipOwnChecker, OwnershipTeamChecker
|
||||
assert($entity instanceof CoreEntity);
|
||||
|
||||
$intersect = array_intersect(
|
||||
$user->getLinkMultipleIdList('teams') ?? [],
|
||||
$entity->getLinkMultipleIdList('teams') ?? []
|
||||
$user->getLinkMultipleIdList('teams'),
|
||||
$entity->getLinkMultipleIdList('teams')
|
||||
);
|
||||
|
||||
if (count($intersect)) {
|
||||
|
||||
@@ -131,8 +131,8 @@ class AccessChecker implements AccessEntityCREDChecker
|
||||
|
||||
if ($note->getTargetType() === Note::TARGET_PORTALS) {
|
||||
$intersect = array_intersect(
|
||||
$note->getLinkMultipleIdList('portals') ?? [],
|
||||
$user->getLinkMultipleIdList('portals') ?? []
|
||||
$note->getLinkMultipleIdList('portals'),
|
||||
$user->getLinkMultipleIdList('portals')
|
||||
);
|
||||
|
||||
if (count($intersect)) {
|
||||
|
||||
@@ -118,7 +118,7 @@ class AccessChecker implements AccessEntityCREDChecker
|
||||
}
|
||||
|
||||
if ($entity->getTargetType() === Note::TARGET_PORTALS) {
|
||||
return in_array($user->getPortalId(), $entity->getLinkMultipleIdList('portals') ?? []);
|
||||
return in_array($user->getPortalId(), $entity->getLinkMultipleIdList('portals'));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -29,10 +29,8 @@
|
||||
|
||||
namespace Espo\Classes\AddressFormatters;
|
||||
|
||||
use Espo\Core\{
|
||||
Field\Address,
|
||||
Field\Address\AddressFormatter,
|
||||
};
|
||||
use Espo\Core\Field\Address;
|
||||
use Espo\Core\Field\Address\AddressFormatter;
|
||||
|
||||
class Formatter1 implements AddressFormatter
|
||||
{
|
||||
|
||||
@@ -29,10 +29,8 @@
|
||||
|
||||
namespace Espo\Classes\AddressFormatters;
|
||||
|
||||
use Espo\Core\{
|
||||
Field\Address,
|
||||
Field\Address\AddressFormatter,
|
||||
};
|
||||
use Espo\Core\Field\Address;
|
||||
use Espo\Core\Field\Address\AddressFormatter;
|
||||
|
||||
class Formatter2 implements AddressFormatter
|
||||
{
|
||||
|
||||
@@ -29,10 +29,8 @@
|
||||
|
||||
namespace Espo\Classes\AddressFormatters;
|
||||
|
||||
use Espo\Core\{
|
||||
Field\Address,
|
||||
Field\Address\AddressFormatter,
|
||||
};
|
||||
use Espo\Core\Field\Address;
|
||||
use Espo\Core\Field\Address\AddressFormatter;
|
||||
|
||||
class Formatter3 implements AddressFormatter
|
||||
{
|
||||
|
||||
@@ -29,10 +29,8 @@
|
||||
|
||||
namespace Espo\Classes\AddressFormatters;
|
||||
|
||||
use Espo\Core\{
|
||||
Field\Address,
|
||||
Field\Address\AddressFormatter,
|
||||
};
|
||||
use Espo\Core\Field\Address;
|
||||
use Espo\Core\Field\Address\AddressFormatter;
|
||||
|
||||
class Formatter4 implements AddressFormatter
|
||||
{
|
||||
|
||||
@@ -29,23 +29,14 @@
|
||||
|
||||
namespace Espo\Classes\AppInfo;
|
||||
|
||||
use Espo\Core\{
|
||||
Container as ContainerService,
|
||||
Utils\Metadata,
|
||||
Console\Command\Params,
|
||||
};
|
||||
use Espo\Core\Console\Command\Params;
|
||||
use Espo\Core\Container as ContainerService;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
|
||||
class Container
|
||||
{
|
||||
private $container;
|
||||
|
||||
private $metadata;
|
||||
|
||||
public function __construct(ContainerService $container, Metadata $metadata)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
public function __construct(private ContainerService $container, private Metadata $metadata)
|
||||
{}
|
||||
|
||||
public function process(Params $params): string
|
||||
{
|
||||
|
||||
@@ -29,85 +29,5 @@
|
||||
|
||||
namespace Espo\Classes\DuplicateWhereBuilders;
|
||||
|
||||
use Espo\Core\Duplicate\WhereBuilder;
|
||||
use Espo\Core\Field\EmailAddressGroup;
|
||||
use Espo\Core\ORM\Entity as CoreEntity;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\Query\Part\Condition as Cond;
|
||||
use Espo\ORM\Query\Part\Where\OrGroup;
|
||||
use Espo\ORM\Query\Part\WhereItem;
|
||||
|
||||
/**
|
||||
* @implements WhereBuilder<CoreEntity>
|
||||
*/
|
||||
class Company implements WhereBuilder
|
||||
{
|
||||
/**
|
||||
* @param CoreEntity $entity
|
||||
*/
|
||||
public function build(Entity $entity): ?WhereItem
|
||||
{
|
||||
$orBuilder = OrGroup::createBuilder();
|
||||
|
||||
$toCheck = false;
|
||||
|
||||
if ($entity->get('name')) {
|
||||
$orBuilder->add(
|
||||
Cond::equal(
|
||||
Cond::column('name'),
|
||||
$entity->get('name')
|
||||
),
|
||||
);
|
||||
|
||||
$toCheck = true;
|
||||
}
|
||||
|
||||
if (
|
||||
($entity->get('emailAddress') || $entity->get('emailAddressData')) &&
|
||||
(
|
||||
$entity->isNew() ||
|
||||
$entity->isAttributeChanged('emailAddress') ||
|
||||
$entity->isAttributeChanged('emailAddressData')
|
||||
)
|
||||
) {
|
||||
foreach ($this->getEmailAddressList($entity) as $emailAddress) {
|
||||
$orBuilder->add(
|
||||
Cond::equal(
|
||||
Cond::column('emailAddress'),
|
||||
$emailAddress
|
||||
)
|
||||
);
|
||||
|
||||
$toCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$toCheck) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $orBuilder->build();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getEmailAddressList(CoreEntity $entity): array
|
||||
{
|
||||
if ($entity->get('emailAddressData')) {
|
||||
/** @var EmailAddressGroup $eaGroup */
|
||||
$eaGroup = $entity->getValueObject('emailAddress');
|
||||
|
||||
return $eaGroup->getAddressList();
|
||||
}
|
||||
|
||||
if ($entity->get('emailAddress')) {
|
||||
return [
|
||||
$entity->get('emailAddress')
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
class Company extends General
|
||||
{}
|
||||
|
||||
262
application/Espo/Classes/DuplicateWhereBuilders/General.php
Normal file
262
application/Espo/Classes/DuplicateWhereBuilders/General.php
Normal file
@@ -0,0 +1,262 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://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\Classes\DuplicateWhereBuilders;
|
||||
|
||||
use Espo\Core\Duplicate\WhereBuilder;
|
||||
use Espo\Core\Field\EmailAddressGroup;
|
||||
use Espo\Core\Field\PhoneNumberGroup;
|
||||
use Espo\Core\ORM\Entity as CoreEntity;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\ORM\Defs;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\Query\Part\Condition as Cond;
|
||||
use Espo\ORM\Query\Part\Where\OrGroup;
|
||||
use Espo\ORM\Query\Part\Where\OrGroupBuilder;
|
||||
use Espo\ORM\Query\Part\WhereItem;
|
||||
use Espo\ORM\Type\AttributeType;
|
||||
|
||||
/**
|
||||
* @implements WhereBuilder<CoreEntity>
|
||||
*/
|
||||
class General implements WhereBuilder
|
||||
{
|
||||
public function __construct(
|
||||
private Metadata $metadata,
|
||||
private Defs $ormDefs
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param CoreEntity $entity
|
||||
*/
|
||||
public function build(Entity $entity): ?WhereItem
|
||||
{
|
||||
/** @var string[] $fieldList */
|
||||
$fieldList = $this->metadata->get(['scopes', $entity->getEntityType(), 'duplicateCheckFieldList']) ?? [];
|
||||
|
||||
$orBuilder = OrGroup::createBuilder();
|
||||
|
||||
$toCheck = false;
|
||||
|
||||
foreach ($fieldList as $field) {
|
||||
$toCheckItem = $this->applyField($field, $entity, $orBuilder);
|
||||
|
||||
if ($toCheckItem) {
|
||||
$toCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$toCheck) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $orBuilder->build();
|
||||
}
|
||||
|
||||
private function applyField(
|
||||
string $field,
|
||||
CoreEntity $entity,
|
||||
OrGroupBuilder $orBuilder
|
||||
): bool {
|
||||
|
||||
$type = $this->ormDefs
|
||||
->getEntity($entity->getEntityType())
|
||||
->tryGetField($field)
|
||||
?->getType();
|
||||
|
||||
if ($type === 'personName') {
|
||||
return $this->applyFieldPersonName($field, $entity, $orBuilder);
|
||||
}
|
||||
|
||||
if ($type === 'email') {
|
||||
return $this->applyFieldEmail($field, $entity, $orBuilder);
|
||||
}
|
||||
|
||||
if ($type === 'phone') {
|
||||
return $this->applyFieldPhone($field, $entity, $orBuilder);
|
||||
}
|
||||
|
||||
if ($entity->getAttributeType($field) === AttributeType::VARCHAR) {
|
||||
return $this->applyFieldVarchar($field, $entity, $orBuilder);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function applyFieldPersonName(
|
||||
string $field,
|
||||
CoreEntity $entity,
|
||||
OrGroupBuilder $orBuilder
|
||||
): bool {
|
||||
|
||||
$first = 'first' . ucfirst($field);
|
||||
$last = 'last' . ucfirst($field);
|
||||
|
||||
if (!$entity->get($first) && !$entity->get($last)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$orBuilder->add(
|
||||
Cond::and(
|
||||
Cond::equal(
|
||||
Cond::column($first),
|
||||
$entity->get($first)
|
||||
),
|
||||
Cond::equal(
|
||||
Cond::column($last),
|
||||
$entity->get($last)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function applyFieldEmail(
|
||||
string $field,
|
||||
CoreEntity $entity,
|
||||
OrGroupBuilder $orBuilder
|
||||
): bool {
|
||||
|
||||
$toCheck = false;
|
||||
|
||||
if (
|
||||
($entity->get($field) || $entity->get($field . 'Data')) &&
|
||||
(
|
||||
$entity->isNew() ||
|
||||
$entity->isAttributeChanged($field) ||
|
||||
$entity->isAttributeChanged($field . 'Data')
|
||||
)
|
||||
) {
|
||||
foreach ($this->getEmailAddressList($entity) as $emailAddress) {
|
||||
$orBuilder->add(
|
||||
Cond::equal(
|
||||
Cond::column($field),
|
||||
$emailAddress
|
||||
)
|
||||
);
|
||||
|
||||
$toCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $toCheck;
|
||||
}
|
||||
|
||||
private function applyFieldPhone(
|
||||
string $field,
|
||||
CoreEntity $entity,
|
||||
OrGroupBuilder $orBuilder
|
||||
): bool {
|
||||
|
||||
$toCheck = false;
|
||||
|
||||
if (
|
||||
($entity->get($field) || $entity->get($field . 'Data')) &&
|
||||
(
|
||||
$entity->isNew() ||
|
||||
$entity->isAttributeChanged($field) ||
|
||||
$entity->isAttributeChanged($field . 'Data')
|
||||
)
|
||||
) {
|
||||
foreach ($this->getPhoneNumberList($entity) as $phoneNumber) {
|
||||
$orBuilder->add(
|
||||
Cond::equal(
|
||||
Cond::column($field),
|
||||
$phoneNumber
|
||||
)
|
||||
);
|
||||
|
||||
$toCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $toCheck;
|
||||
}
|
||||
|
||||
private function applyFieldVarchar(
|
||||
string $field,
|
||||
CoreEntity $entity,
|
||||
OrGroupBuilder $orBuilder
|
||||
): bool {
|
||||
|
||||
if (!$entity->get($field)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$orBuilder->add(
|
||||
Cond::equal(
|
||||
Cond::column($field),
|
||||
$entity->get($field)
|
||||
),
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getEmailAddressList(CoreEntity $entity): array
|
||||
{
|
||||
if ($entity->get('emailAddressData')) {
|
||||
/** @var EmailAddressGroup $eaGroup */
|
||||
$eaGroup = $entity->getValueObject('emailAddress');
|
||||
|
||||
return $eaGroup->getAddressList();
|
||||
}
|
||||
|
||||
if ($entity->get('emailAddress')) {
|
||||
return [
|
||||
$entity->get('emailAddress')
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getPhoneNumberList(CoreEntity $entity): array
|
||||
{
|
||||
if ($entity->get('phoneNumberData')) {
|
||||
/** @var PhoneNumberGroup $eaGroup */
|
||||
$eaGroup = $entity->getValueObject('phoneNumber');
|
||||
|
||||
return $eaGroup->getNumberList();
|
||||
}
|
||||
|
||||
if ($entity->get('phoneNumber')) {
|
||||
return [$entity->get('phoneNumber')];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -29,92 +29,5 @@
|
||||
|
||||
namespace Espo\Classes\DuplicateWhereBuilders;
|
||||
|
||||
use Espo\Core\ORM\Entity as CoreEntity;
|
||||
|
||||
use Espo\Core\Duplicate\WhereBuilder;
|
||||
use Espo\Core\Field\EmailAddressGroup;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\Query\Part\Condition as Cond;
|
||||
use Espo\ORM\Query\Part\Where\OrGroup;
|
||||
use Espo\ORM\Query\Part\WhereItem;
|
||||
|
||||
/**
|
||||
* @implements WhereBuilder<CoreEntity>
|
||||
*/
|
||||
class Person implements WhereBuilder
|
||||
{
|
||||
/**
|
||||
* @param CoreEntity $entity
|
||||
*/
|
||||
public function build(Entity $entity): ?WhereItem
|
||||
{
|
||||
$orBuilder = OrGroup::createBuilder();
|
||||
|
||||
$toCheck = false;
|
||||
|
||||
if ($entity->get('firstName') || $entity->get('lastName')) {
|
||||
$orBuilder->add(
|
||||
Cond::and(
|
||||
Cond::equal(
|
||||
Cond::column('firstName'),
|
||||
$entity->get('firstName')
|
||||
),
|
||||
Cond::equal(
|
||||
Cond::column('lastName'),
|
||||
$entity->get('lastName')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$toCheck = true;
|
||||
}
|
||||
|
||||
if (
|
||||
($entity->get('emailAddress') || $entity->get('emailAddressData')) &&
|
||||
(
|
||||
$entity->isNew() ||
|
||||
$entity->isAttributeChanged('emailAddress') ||
|
||||
$entity->isAttributeChanged('emailAddressData')
|
||||
)
|
||||
) {
|
||||
foreach ($this->getEmailAddressList($entity) as $emailAddress) {
|
||||
$orBuilder->add(
|
||||
Cond::equal(
|
||||
Cond::column('emailAddress'),
|
||||
$emailAddress
|
||||
)
|
||||
);
|
||||
|
||||
$toCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$toCheck) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $orBuilder->build();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getEmailAddressList(CoreEntity $entity): array
|
||||
{
|
||||
if ($entity->get('emailAddressData')) {
|
||||
/** @var EmailAddressGroup $eaGroup */
|
||||
$eaGroup = $entity->getValueObject('emailAddress');
|
||||
|
||||
return $eaGroup->getAddressList();
|
||||
}
|
||||
|
||||
if ($entity->get('emailAddress')) {
|
||||
return [
|
||||
$entity->get('emailAddress')
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
class Person extends General
|
||||
{}
|
||||
|
||||
199
application/Espo/Classes/FieldConverters/RelationshipRole.php
Normal file
199
application/Espo/Classes/FieldConverters/RelationshipRole.php
Normal file
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://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\Classes\FieldConverters;
|
||||
|
||||
use Espo\Core\Utils\Database\Orm\Defs\AttributeDefs;
|
||||
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
|
||||
use Espo\Core\Utils\Database\Orm\FieldConverter;
|
||||
use Espo\ORM\Defs\FieldDefs;
|
||||
use Espo\ORM\Type\AttributeType;
|
||||
use RuntimeException;
|
||||
|
||||
class RelationshipRole implements FieldConverter
|
||||
{
|
||||
public function convert(FieldDefs $fieldDefs, string $entityType): EntityDefs
|
||||
{
|
||||
$name = $fieldDefs->getName();
|
||||
|
||||
$attributeDefs = AttributeDefs::create($name)
|
||||
->withType(AttributeType::VARCHAR)
|
||||
->withNotStorable();
|
||||
|
||||
$attributeDefs = $this->addWhere($attributeDefs, $fieldDefs, $entityType);
|
||||
|
||||
return EntityDefs::create()
|
||||
->withAttribute($attributeDefs);
|
||||
}
|
||||
|
||||
private function addWhere(AttributeDefs $attributeDefs, FieldDefs $fieldDefs, string $entityType): AttributeDefs
|
||||
{
|
||||
$data = $fieldDefs->getParam('converterData');
|
||||
|
||||
if (!is_array($data)) {
|
||||
throw new RuntimeException("No `converterData` in field defs.");
|
||||
}
|
||||
|
||||
/** @var ?string $column */
|
||||
$column = $data['column'] ?? null;
|
||||
/** @var ?string $link */
|
||||
$link = $data['link'] ?? null;
|
||||
/** @var ?string $relationName */
|
||||
$relationName = $data['relationName'] ?? null;
|
||||
/** @var ?string $nearKey */
|
||||
$nearKey = $data['nearKey'] ?? null;
|
||||
|
||||
if (!$column || !$link || !$relationName || !$nearKey) {
|
||||
throw new RuntimeException("Bad `converterData`.");
|
||||
}
|
||||
|
||||
$midTable = ucfirst($relationName);
|
||||
|
||||
return $attributeDefs->withParamsMerged([
|
||||
'where' => [
|
||||
'=' => [
|
||||
'whereClause' => [
|
||||
'id=s' => [
|
||||
'from' => $midTable,
|
||||
'select' => [$nearKey],
|
||||
'whereClause' => [
|
||||
'deleted' => false,
|
||||
$column => '{value}',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'<>' => [
|
||||
'whereClause' => [
|
||||
'id!=s' => [
|
||||
'from' => $midTable,
|
||||
'select' => [$nearKey],
|
||||
'whereClause' => [
|
||||
'deleted' => false,
|
||||
$column => '{value}',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'IN' => [
|
||||
'whereClause' => [
|
||||
'id=s' => [
|
||||
'from' => $midTable,
|
||||
'select' => [$nearKey],
|
||||
'whereClause' => [
|
||||
'deleted' => false,
|
||||
$column => '{value}',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'NOT IN' => [
|
||||
'whereClause' => [
|
||||
'id!=s' => [
|
||||
'from' => $midTable,
|
||||
'select' => [$nearKey],
|
||||
'whereClause' => [
|
||||
'deleted' => false,
|
||||
$column => '{value}',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'LIKE' => [
|
||||
'whereClause' => [
|
||||
'id=s' => [
|
||||
'from' => $midTable,
|
||||
'select' => [$nearKey],
|
||||
'whereClause' => [
|
||||
'deleted' => false,
|
||||
"$column*" => '{value}',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'NOT LIKE' => [
|
||||
'whereClause' => [
|
||||
'id!=s' => [
|
||||
'from' => $midTable,
|
||||
'select' => [$nearKey],
|
||||
'whereClause' => [
|
||||
'deleted' => false,
|
||||
"$column*" => '{value}',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'IS NULL' => [
|
||||
'whereClause' => [
|
||||
'NOT' => [
|
||||
'EXISTS' => [
|
||||
'from' => $entityType,
|
||||
'fromAlias' => 'sq',
|
||||
'select' => ['id'],
|
||||
'leftJoins' => [
|
||||
[
|
||||
$link,
|
||||
'm',
|
||||
null,
|
||||
['onlyMiddle' => true]
|
||||
]
|
||||
],
|
||||
'whereClause' => [
|
||||
"m.$column!=" => null,
|
||||
'sq.id:' => lcfirst($entityType) . '.id',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'IS NOT NULL' => [
|
||||
'whereClause' => [
|
||||
'EXISTS' => [
|
||||
'from' => $entityType,
|
||||
'fromAlias' => 'sq',
|
||||
'select' => ['id'],
|
||||
'leftJoins' => [
|
||||
[
|
||||
$link,
|
||||
'm',
|
||||
null,
|
||||
['onlyMiddle' => true]
|
||||
]
|
||||
],
|
||||
'whereClause' => [
|
||||
"m.$column!=" => null,
|
||||
'sq.id:' => lcfirst($entityType) . '.id',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -30,31 +30,27 @@
|
||||
namespace Espo\Classes\FieldProcessing\Email;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
FieldProcessing\Loader,
|
||||
FieldProcessing\Loader\Params,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
use Espo\Core\FieldProcessing\Loader;
|
||||
use Espo\Core\FieldProcessing\Loader\Params;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
use Espo\Repositories\Email as EmailRepository;
|
||||
use Espo\Entities\Email;
|
||||
|
||||
/**
|
||||
* @implements Loader<\Espo\Entities\Email>
|
||||
* @implements Loader<Email>
|
||||
*/
|
||||
class AddressDataLoader implements Loader
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
public function __construct(private EntityManager $entityManager)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @param Email $entity
|
||||
*/
|
||||
public function process(Entity $entity, Params $params): void
|
||||
{
|
||||
/** @var EmailRepository $repository */
|
||||
$repository = $this->entityManager->getRepository('Email');
|
||||
$repository = $this->entityManager->getRepository(Email::ENTITY_TYPE);
|
||||
|
||||
$repository->loadFromField($entity);
|
||||
$repository->loadToField($entity);
|
||||
|
||||
@@ -29,27 +29,21 @@
|
||||
|
||||
namespace Espo\Classes\FieldProcessing\Import;
|
||||
|
||||
use Espo\Entities\Import;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
FieldProcessing\Loader,
|
||||
FieldProcessing\Loader\Params,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
use Espo\Core\FieldProcessing\Loader;
|
||||
use Espo\Core\FieldProcessing\Loader\Params;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
|
||||
use Espo\Repositories\Import as ImportRepository;
|
||||
|
||||
/**
|
||||
* @implements Loader<\Espo\Entities\Import>
|
||||
* @implements Loader<Import>
|
||||
*/
|
||||
class CountsLoader implements Loader
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
public function __construct(private EntityManager $entityManager)
|
||||
{}
|
||||
|
||||
public function process(Entity $entity, Params $params): void
|
||||
{
|
||||
|
||||
@@ -30,16 +30,12 @@
|
||||
namespace Espo\Classes\FieldProcessing\Note;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
FieldProcessing\Loader,
|
||||
FieldProcessing\Loader\Params,
|
||||
};
|
||||
|
||||
use Espo\Core\FieldProcessing\Loader;
|
||||
use Espo\Core\FieldProcessing\Loader\Params;
|
||||
use Espo\Entities\Note;
|
||||
|
||||
/**
|
||||
* @implements Loader<\Espo\Entities\Note>
|
||||
* @implements Loader<Note>
|
||||
*/
|
||||
class AttachmentsLoader implements Loader
|
||||
{
|
||||
|
||||
@@ -33,19 +33,16 @@ use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Repositories\Portal as PortalRepository;
|
||||
use Espo\Entities\Portal;
|
||||
|
||||
use Espo\Core\{
|
||||
FieldProcessing\Loader,
|
||||
FieldProcessing\Loader\Params,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
use Espo\Core\FieldProcessing\Loader;
|
||||
use Espo\Core\FieldProcessing\Loader\Params;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* @implements Loader<\Espo\Entities\Portal>
|
||||
* @implements Loader<Portal>
|
||||
*/
|
||||
class UrlLoader implements Loader
|
||||
{
|
||||
private $entityManager;
|
||||
private EntityManager $entityManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ class ArrayType
|
||||
{
|
||||
private const DEFAULT_MAX_ITEM_LENGTH = 100;
|
||||
|
||||
public function __construct(private Metadata $metadata, private Defs $defs)
|
||||
public function __construct(protected Metadata $metadata, private Defs $defs)
|
||||
{}
|
||||
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
@@ -128,6 +128,14 @@ class ArrayType
|
||||
|
||||
/** @var ?string $path */
|
||||
$path = $fieldDefs->getParam('optionsPath');
|
||||
/** @var ?string $path */
|
||||
$ref = $fieldDefs->getParam('optionsReference');
|
||||
|
||||
if (!$path && $ref && str_contains($ref, '.')) {
|
||||
[$refEntityType, $refField] = explode('.', $ref);
|
||||
|
||||
$path = "entityDefs.{$refEntityType}.fields.{$refField}.options";
|
||||
}
|
||||
|
||||
/** @var string[]|null|false $optionList */
|
||||
$optionList = $path ?
|
||||
@@ -178,11 +186,11 @@ class ArrayType
|
||||
{
|
||||
$maxLength = $validationValue ?? self::DEFAULT_MAX_ITEM_LENGTH;
|
||||
|
||||
/** @var string[] $value */
|
||||
/** @var mixed[] $value */
|
||||
$value = $entity->get($field) ?? [];
|
||||
|
||||
foreach ($value as $item) {
|
||||
if (mb_strlen($item) > $maxLength) {
|
||||
if (is_string($item) && mb_strlen($item) > $maxLength) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,14 @@ class CurrencyType extends FloatType
|
||||
$currency = $entity->get($attribute);
|
||||
$currencyList = $this->config->get('currencyList') ?? [$this->config->get('defaultCurrency')];
|
||||
|
||||
if (
|
||||
$currency === null &&
|
||||
!$entity->has($field) &&
|
||||
$entity->isNew()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
$currency === null &&
|
||||
$entity->has($field) &&
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://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\Classes\FieldValidators\Email\Addresses;
|
||||
|
||||
use Espo\Core\FieldValidation\Validator;
|
||||
use Espo\Core\FieldValidation\Validator\Data;
|
||||
use Espo\Core\FieldValidation\Validator\Failure;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Entities\Email;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* @implements Validator<Email>
|
||||
*/
|
||||
class MaxCount implements Validator
|
||||
{
|
||||
private const MAX_COUNT = 100;
|
||||
|
||||
public function __construct(private Config $config) {}
|
||||
|
||||
/**
|
||||
* @param Email $entity
|
||||
*/
|
||||
public function validate(Entity $entity, string $field, Data $data): ?Failure
|
||||
{
|
||||
if ($field === 'to') {
|
||||
$addresses = $entity->getToAddressList();
|
||||
}
|
||||
else if ($field === 'cc') {
|
||||
$addresses = $entity->getCcAddressList();
|
||||
}
|
||||
else if ($field === 'bcc') {
|
||||
$addresses = $entity->getBccAddressList();
|
||||
}
|
||||
else {
|
||||
throw new LogicException();
|
||||
}
|
||||
|
||||
$maxCount = $this->config->get('emailRecipientAddressMaxCount') ?? self::MAX_COUNT;
|
||||
|
||||
if (count($addresses) > $maxCount) {
|
||||
return Failure::create();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
@@ -26,7 +27,45 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('models/email', ['model'], function (Dep) {
|
||||
namespace Espo\Classes\FieldValidators\Email\Addresses;
|
||||
|
||||
return Dep.extend({});
|
||||
});
|
||||
use Espo\Core\FieldValidation\Validator;
|
||||
use Espo\Core\FieldValidation\Validator\Data;
|
||||
use Espo\Core\FieldValidation\Validator\Failure;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Entities\Email;
|
||||
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* @implements Validator<Email>
|
||||
*/
|
||||
class Valid implements Validator
|
||||
{
|
||||
/**
|
||||
* @param Email $entity
|
||||
*/
|
||||
public function validate(Entity $entity, string $field, Data $data): ?Failure
|
||||
{
|
||||
if ($field === 'to') {
|
||||
$addresses = $entity->getToAddressList();
|
||||
}
|
||||
else if ($field === 'cc') {
|
||||
$addresses = $entity->getCcAddressList();
|
||||
}
|
||||
else if ($field === 'bcc') {
|
||||
$addresses = $entity->getBccAddressList();
|
||||
}
|
||||
else {
|
||||
throw new LogicException();
|
||||
}
|
||||
|
||||
foreach ($addresses as $address) {
|
||||
if (!filter_var($address, FILTER_VALIDATE_EMAIL)) {
|
||||
return Failure::create();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -29,13 +29,17 @@
|
||||
|
||||
namespace Espo\Classes\FieldValidators\Email;
|
||||
|
||||
use Espo\Entities\Email;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class EmailAddresses
|
||||
{
|
||||
/**
|
||||
* @param Email $entity
|
||||
*/
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
if ($entity->get('status') === 'Draft') {
|
||||
if ($entity->getStatus() === Email::STATUS_DRAFT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ use Espo\ORM\Entity;
|
||||
class EnumType
|
||||
{
|
||||
private Metadata $metadata;
|
||||
|
||||
private Defs $defs;
|
||||
|
||||
private const DEFAULT_MAX_LENGTH = 255;
|
||||
@@ -65,6 +64,14 @@ class EnumType
|
||||
|
||||
/** @var ?string $path */
|
||||
$path = $fieldDefs->getParam('optionsPath');
|
||||
/** @var ?string $path */
|
||||
$ref = $fieldDefs->getParam('optionsReference');
|
||||
|
||||
if (!$path && $ref && str_contains($ref, '.')) {
|
||||
[$refEntityType, $refField] = explode('.', $ref);
|
||||
|
||||
$path = "entityDefs.{$refEntityType}.fields.{$refField}.options";
|
||||
}
|
||||
|
||||
/** @var string[]|null|false $optionList */
|
||||
$optionList = $path ?
|
||||
@@ -88,7 +95,7 @@ class EnumType
|
||||
$value = $entity->get($field);
|
||||
|
||||
// For bc.
|
||||
// @todo Remove in v8.0.
|
||||
// @todo Remove in v9.0.
|
||||
if ($value === '') {
|
||||
$value = null;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use stdClass;
|
||||
|
||||
class IntType
|
||||
{
|
||||
@@ -40,6 +41,7 @@ class IntType
|
||||
|
||||
/**
|
||||
* @param mixed $validationValue
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function checkMax(Entity $entity, string $field, $validationValue): bool
|
||||
{
|
||||
@@ -56,6 +58,7 @@ class IntType
|
||||
|
||||
/**
|
||||
* @param mixed $validationValue
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function checkMin(Entity $entity, string $field, $validationValue): bool
|
||||
{
|
||||
@@ -70,6 +73,26 @@ class IntType
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
public function rawCheckValid(stdClass $data, string $field): bool
|
||||
{
|
||||
if (!isset($data->$field)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$value = $data->$field;
|
||||
|
||||
if ($value === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_numeric($value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isNotEmpty(Entity $entity, string $field): bool
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== null;
|
||||
|
||||
@@ -117,7 +117,7 @@ class LinkMultipleType
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var ?array<string,string> $columnsMap */
|
||||
/** @var ?array<string, string> $columnsMap */
|
||||
$columnsMap = $fieldDefs->getParam('columns');
|
||||
|
||||
if ($columnsMap === null || $columnsMap === []) {
|
||||
@@ -258,7 +258,7 @@ class LinkMultipleType
|
||||
);
|
||||
|
||||
// For bc.
|
||||
// @todo Remove in v8.0.
|
||||
// @todo Remove in v9.0.
|
||||
if ($value === '') {
|
||||
$value = null;
|
||||
}
|
||||
|
||||
@@ -30,19 +30,12 @@
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\FieldUtil,
|
||||
};
|
||||
use Espo\Core\Utils\FieldUtil;
|
||||
|
||||
class PersonNameType
|
||||
{
|
||||
private $fieldUtil;
|
||||
|
||||
public function __construct(FieldUtil $fieldUtil)
|
||||
{
|
||||
$this->fieldUtil = $fieldUtil;
|
||||
}
|
||||
public function __construct(private FieldUtil $fieldUtil)
|
||||
{}
|
||||
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
|
||||
55
application/Espo/Classes/FieldValidators/UrlMultipleType.php
Normal file
55
application/Espo/Classes/FieldValidators/UrlMultipleType.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://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\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class UrlMultipleType extends ArrayType
|
||||
{
|
||||
private const MAX_ITEM_LENGTH = 255;
|
||||
|
||||
public function checkNoEmptyString(Entity $entity, string $field, ?bool $validationValue): bool
|
||||
{
|
||||
return parent::checkNoEmptyString($entity, $field, true);
|
||||
}
|
||||
|
||||
public function checkMaxItemLength(Entity $entity, string $field, ?int $validationValue): bool
|
||||
{
|
||||
return parent::checkMaxItemLength($entity, $field, self::MAX_ITEM_LENGTH);
|
||||
}
|
||||
|
||||
public function checkPattern(Entity $entity, string $field, ?string $validationValue): bool
|
||||
{
|
||||
/** @var string $pattern */
|
||||
$pattern = $this->metadata->get(['app', 'regExpPatterns', 'uriOptionalProtocol', 'pattern']);
|
||||
|
||||
return parent::checkPattern($entity, $field, $pattern);
|
||||
}
|
||||
}
|
||||
@@ -29,31 +29,28 @@
|
||||
|
||||
namespace Espo\Classes\JobPreparators;
|
||||
|
||||
use Espo\Core\Utils\DateTime;
|
||||
use Espo\Core\Job\Job\Status;
|
||||
use Espo\Core\Job\Preparator;
|
||||
use Espo\Core\Job\Preparator\Data;
|
||||
|
||||
use Espo\Entities\EmailAccount;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
use Espo\Entities\Job as JobEntity;
|
||||
use Espo\Entities\EmailAccount;
|
||||
use Espo\Core\Job\Preparator\CollectionHelper;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
class CheckEmailAccounts implements Preparator
|
||||
{
|
||||
private EntityManager $entityManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
/**
|
||||
* @param CollectionHelper<EmailAccount> $helper
|
||||
*/
|
||||
public function __construct(
|
||||
private EntityManager $entityManager,
|
||||
private CollectionHelper $helper
|
||||
) {}
|
||||
|
||||
public function prepare(Data $data, DateTimeImmutable $executeTime): void
|
||||
{
|
||||
$collection = $this->entityManager
|
||||
->getRDBRepository(EmailAccount::ENTITY_TYPE)
|
||||
->getRDBRepositoryByClass(EmailAccount::class)
|
||||
->join('assignedUser', 'assignedUserAdditional')
|
||||
->where([
|
||||
'status' => EmailAccount::STATUS_ACTIVE,
|
||||
@@ -62,49 +59,6 @@ class CheckEmailAccounts implements Preparator
|
||||
])
|
||||
->find();
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
$running = $this->entityManager
|
||||
->getRDBRepository(JobEntity::ENTITY_TYPE)
|
||||
->where([
|
||||
'scheduledJobId' => $data->getId(),
|
||||
'status' => [
|
||||
Status::RUNNING,
|
||||
Status::READY,
|
||||
],
|
||||
'targetType' => EmailAccount::ENTITY_TYPE,
|
||||
'targetId' => $entity->getId(),
|
||||
])
|
||||
->findOne();
|
||||
|
||||
if ($running) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$countPending = $this->entityManager
|
||||
->getRDBRepository(JobEntity::ENTITY_TYPE)
|
||||
->where([
|
||||
'scheduledJobId' => $data->getId(),
|
||||
'status' => Status::PENDING,
|
||||
'targetType' => EmailAccount::ENTITY_TYPE,
|
||||
'targetId' => $entity->getId(),
|
||||
])
|
||||
->count();
|
||||
|
||||
if ($countPending > 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$jobEntity = $this->entityManager->getNewEntity(JobEntity::ENTITY_TYPE);
|
||||
|
||||
$jobEntity->set([
|
||||
'name' => $data->getName(),
|
||||
'scheduledJobId' => $data->getId(),
|
||||
'executeTime' => $executeTime->format(DateTime::SYSTEM_DATE_TIME_FORMAT),
|
||||
'targetType' => EmailAccount::ENTITY_TYPE,
|
||||
'targetId' => $entity->getId(),
|
||||
]);
|
||||
|
||||
$this->entityManager->saveEntity($jobEntity);
|
||||
}
|
||||
$this->helper->prepare($collection, $data, $executeTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,80 +29,34 @@
|
||||
|
||||
namespace Espo\Classes\JobPreparators;
|
||||
|
||||
use Espo\Core\Utils\DateTime;
|
||||
use Espo\Core\Job\Job\Status;
|
||||
use Espo\Core\Job\Preparator;
|
||||
use Espo\Core\Job\Preparator\Data;
|
||||
|
||||
use Espo\Entities\InboundEmail;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
use Espo\Entities\Job as JobEntity;
|
||||
use Espo\Entities\InboundEmail;
|
||||
use Espo\Core\Job\Preparator\CollectionHelper;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
class CheckInboundEmails implements Preparator
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
/**
|
||||
* @param CollectionHelper<InboundEmail> $helper
|
||||
*/
|
||||
public function __construct(
|
||||
private EntityManager $entityManager,
|
||||
private CollectionHelper $helper
|
||||
) {}
|
||||
|
||||
public function prepare(Data $data, DateTimeImmutable $executeTime): void
|
||||
{
|
||||
$collection = $this->entityManager
|
||||
->getRDBRepository(InboundEmail::ENTITY_TYPE)
|
||||
->getRDBRepositoryByClass(InboundEmail::class)
|
||||
->where([
|
||||
'status' => InboundEmail::STATUS_ACTIVE,
|
||||
'useImap' => true,
|
||||
])
|
||||
->find();
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
$running = $this->entityManager
|
||||
->getRDBRepository(JobEntity::ENTITY_TYPE)
|
||||
->where([
|
||||
'scheduledJobId' => $data->getId(),
|
||||
'status' => [
|
||||
Status::RUNNING,
|
||||
Status::READY,
|
||||
],
|
||||
'targetType' => InboundEmail::ENTITY_TYPE,
|
||||
'targetId' => $entity->getId(),
|
||||
])
|
||||
->findOne();
|
||||
|
||||
if ($running) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$countPending = $this->entityManager
|
||||
->getRDBRepository(JobEntity::ENTITY_TYPE)
|
||||
->where([
|
||||
'scheduledJobId' => $data->getId(),
|
||||
'status' => Status::PENDING,
|
||||
'targetType' => InboundEmail::ENTITY_TYPE,
|
||||
'targetId' => $entity->getId(),
|
||||
])
|
||||
->count();
|
||||
|
||||
if ($countPending > 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$jobEntity = $this->entityManager->getNewEntity(JobEntity::ENTITY_TYPE);
|
||||
|
||||
$jobEntity->set([
|
||||
'name' => $data->getName(),
|
||||
'scheduledJobId' => $data->getId(),
|
||||
'executeTime' => $executeTime->format(DateTime::SYSTEM_DATE_TIME_FORMAT),
|
||||
'targetType' => InboundEmail::ENTITY_TYPE,
|
||||
'targetId' => $entity->getId(),
|
||||
]);
|
||||
|
||||
$this->entityManager->saveEntity($jobEntity);
|
||||
}
|
||||
$this->helper->prepare($collection, $data, $executeTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,8 +609,6 @@ class Cleanup implements JobDataLess
|
||||
|
||||
$repository->deleteFromDb($entity->getId());
|
||||
|
||||
$query = $this->entityManager->getQueryComposer();
|
||||
|
||||
foreach ($entity->getRelationList() as $relation) {
|
||||
if ($entity->getRelationType($relation) !== Entity::MANY_MANY) {
|
||||
continue;
|
||||
@@ -763,6 +761,15 @@ class Cleanup implements JobDataLess
|
||||
'deleted' => true,
|
||||
];
|
||||
|
||||
if (
|
||||
!$this->entityManager
|
||||
->getDefs()
|
||||
->getEntity($scope)
|
||||
->hasAttribute('deleted')
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->metadata->get(['entityDefs', $scope, 'fields', 'modifiedAt'])) {
|
||||
$whereClause['modifiedAt<'] = $datetime->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT);
|
||||
}
|
||||
|
||||
@@ -29,19 +29,13 @@
|
||||
|
||||
namespace Espo\Classes\Jobs;
|
||||
|
||||
use Espo\Core\{
|
||||
Job\JobDataLess,
|
||||
Webhook\Queue,
|
||||
};
|
||||
use Espo\Core\Job\JobDataLess;
|
||||
use Espo\Core\Webhook\Queue;
|
||||
|
||||
class ProcessWebhookQueue implements JobDataLess
|
||||
{
|
||||
private $queue;
|
||||
|
||||
public function __construct(Queue $queue)
|
||||
{
|
||||
$this->queue = $queue;
|
||||
}
|
||||
public function __construct(private Queue $queue)
|
||||
{}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
|
||||
@@ -29,20 +29,14 @@
|
||||
|
||||
namespace Espo\Classes\Select\ActionHistoryRecord\AccessControlFilters;
|
||||
|
||||
use Espo\{
|
||||
Core\Select\AccessControl\Filter,
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
Entities\User,
|
||||
};
|
||||
use Espo\Core\Select\AccessControl\Filter;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class OnlyOwn implements Filter
|
||||
{
|
||||
private $user;
|
||||
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
public function __construct(private User $user)
|
||||
{}
|
||||
|
||||
public function apply(QueryBuilder $queryBuilder): void
|
||||
{
|
||||
|
||||
@@ -29,22 +29,16 @@
|
||||
|
||||
namespace Espo\Classes\Select\ActionHistoryRecord\BoolFilters;
|
||||
|
||||
use Espo\{
|
||||
Core\Select\Bool\Filter,
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereClause,
|
||||
ORM\Query\Part\Where\OrGroupBuilder,
|
||||
Entities\User,
|
||||
};
|
||||
use Espo\Core\Select\Bool\Filter;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\Part\Where\OrGroupBuilder;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class OnlyMy implements Filter
|
||||
{
|
||||
private $user;
|
||||
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
public function __construct(private User $user)
|
||||
{}
|
||||
|
||||
public function apply(QueryBuilder $queryBuilder, OrGroupBuilder $orGroupBuilder): void
|
||||
{
|
||||
|
||||
@@ -29,27 +29,15 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\AccessControlFilters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\AccessControl\Filter,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
Classes\Select\Email\Helpers\JoinHelper,
|
||||
Entities\User,
|
||||
};
|
||||
use Espo\Core\Select\AccessControl\Filter;
|
||||
use Espo\Classes\Select\Email\Helpers\JoinHelper;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class PortalOnlyAccount implements Filter
|
||||
{
|
||||
private $user;
|
||||
|
||||
private $joinHelper;
|
||||
|
||||
public function __construct(User $user, JoinHelper $joinHelper)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->joinHelper = $joinHelper;
|
||||
}
|
||||
public function __construct(private User $user, private JoinHelper $joinHelper)
|
||||
{}
|
||||
|
||||
public function apply(QueryBuilder $queryBuilder): void
|
||||
{
|
||||
|
||||
@@ -29,27 +29,15 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\AccessControlFilters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\AccessControl\Filter,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
Classes\Select\Email\Helpers\JoinHelper,
|
||||
Entities\User,
|
||||
};
|
||||
use Espo\Core\Select\AccessControl\Filter;
|
||||
use Espo\Classes\Select\Email\Helpers\JoinHelper;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class PortalOnlyContact implements Filter
|
||||
{
|
||||
private $user;
|
||||
|
||||
private $joinHelper;
|
||||
|
||||
public function __construct(User $user, JoinHelper $joinHelper)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->joinHelper = $joinHelper;
|
||||
}
|
||||
public function __construct(private User $user, private JoinHelper $joinHelper)
|
||||
{}
|
||||
|
||||
public function apply(QueryBuilder $queryBuilder): void
|
||||
{
|
||||
|
||||
@@ -29,26 +29,17 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\BoolFilters;
|
||||
|
||||
use Espo\{
|
||||
Core\Select\Bool\Filter,
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereClause,
|
||||
ORM\Query\Part\Where\OrGroupBuilder,
|
||||
Classes\Select\Email\Helpers\JoinHelper,
|
||||
Entities\User,
|
||||
};
|
||||
use Espo\Classes\Select\Email\Helpers\JoinHelper;
|
||||
use Espo\Core\Select\Bool\Filter;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\Part\Where\OrGroupBuilder;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class OnlyMy implements Filter
|
||||
{
|
||||
private $user;
|
||||
|
||||
private $joinHelper;
|
||||
|
||||
public function __construct(User $user, JoinHelper $joinHelper)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->joinHelper = $joinHelper;
|
||||
}
|
||||
public function __construct(private User $user, private JoinHelper $joinHelper)
|
||||
{}
|
||||
|
||||
public function apply(QueryBuilder $queryBuilder, OrGroupBuilder $orGroupBuilder): void
|
||||
{
|
||||
|
||||
@@ -29,32 +29,20 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\Where\ItemConverters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\Where\ItemConverter,
|
||||
Select\Where\Item,
|
||||
Select\Helpers\RandomStringGenerator,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereItem as WhereClauseItem,
|
||||
ORM\Query\Part\WhereClause,
|
||||
Classes\Select\Email\Helpers\EmailAddressHelper,
|
||||
};
|
||||
use Espo\Core\Select\Helpers\RandomStringGenerator;
|
||||
use Espo\Core\Select\Where\Item;
|
||||
use Espo\Core\Select\Where\ItemConverter;
|
||||
use Espo\Classes\Select\Email\Helpers\EmailAddressHelper;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\Part\WhereItem as WhereClauseItem;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class EmailAddressEquals implements ItemConverter
|
||||
{
|
||||
private $emailAddressHelper;
|
||||
|
||||
private $randomStringGenerator;
|
||||
|
||||
public function __construct(
|
||||
EmailAddressHelper $emailAddressHelper,
|
||||
RandomStringGenerator $randomStringGenerator
|
||||
) {
|
||||
$this->emailAddressHelper = $emailAddressHelper;
|
||||
$this->randomStringGenerator = $randomStringGenerator;
|
||||
}
|
||||
private EmailAddressHelper $emailAddressHelper,
|
||||
private RandomStringGenerator $randomStringGenerator
|
||||
) {}
|
||||
|
||||
public function convert(QueryBuilder $queryBuilder, Item $item): WhereClauseItem
|
||||
{
|
||||
|
||||
@@ -29,38 +29,18 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\Where\ItemConverters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\Where\ItemConverter,
|
||||
Select\Where\Item,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereItem as WhereClauseItem,
|
||||
ORM\Query\Part\WhereClause,
|
||||
ORM\EntityManager,
|
||||
Classes\Select\Email\Helpers\EmailAddressHelper,
|
||||
};
|
||||
use Espo\Core\Select\Where\Item;
|
||||
use Espo\Core\Select\Where\ItemConverter;
|
||||
use Espo\Classes\Select\Email\Helpers\EmailAddressHelper;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\Part\WhereItem as WhereClauseItem;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class FromEquals implements ItemConverter
|
||||
{
|
||||
/**
|
||||
* @var EntityManager
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* @var EmailAddressHelper
|
||||
*/
|
||||
protected $emailAddressHelper;
|
||||
|
||||
public function __construct(
|
||||
EntityManager $entityManager,
|
||||
EmailAddressHelper $emailAddressHelper
|
||||
) {
|
||||
$this->entityManager = $entityManager;
|
||||
$this->emailAddressHelper = $emailAddressHelper;
|
||||
}
|
||||
private EmailAddressHelper $emailAddressHelper
|
||||
) {}
|
||||
|
||||
public function convert(QueryBuilder $queryBuilder, Item $item): WhereClauseItem
|
||||
{
|
||||
|
||||
@@ -29,30 +29,18 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\Where\ItemConverters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\Where\ItemConverter,
|
||||
Select\Where\Item,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereItem as WhereClauseItem,
|
||||
ORM\Query\Part\WhereClause,
|
||||
Entities\User,
|
||||
Classes\Select\Email\Helpers\JoinHelper,
|
||||
};
|
||||
use Espo\Core\Select\Where\Item;
|
||||
use Espo\Core\Select\Where\ItemConverter;
|
||||
use Espo\Classes\Select\Email\Helpers\JoinHelper;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\Part\WhereItem as WhereClauseItem;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class IsImportantIsFalse implements ItemConverter
|
||||
{
|
||||
private $user;
|
||||
|
||||
private $joinHelper;
|
||||
|
||||
public function __construct(User $user, JoinHelper $joinHelper)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->joinHelper = $joinHelper;
|
||||
}
|
||||
public function __construct(private User $user, private JoinHelper $joinHelper)
|
||||
{}
|
||||
|
||||
public function convert(QueryBuilder $queryBuilder, Item $item): WhereClauseItem
|
||||
{
|
||||
|
||||
@@ -29,30 +29,18 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\Where\ItemConverters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\Where\ItemConverter,
|
||||
Select\Where\Item,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereItem as WhereClauseItem,
|
||||
ORM\Query\Part\WhereClause,
|
||||
Entities\User,
|
||||
Classes\Select\Email\Helpers\JoinHelper,
|
||||
};
|
||||
use Espo\Core\Select\Where\Item;
|
||||
use Espo\Core\Select\Where\ItemConverter;
|
||||
use Espo\Classes\Select\Email\Helpers\JoinHelper;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\Part\WhereItem as WhereClauseItem;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class IsImportantIsTrue implements ItemConverter
|
||||
{
|
||||
private $user;
|
||||
|
||||
private $joinHelper;
|
||||
|
||||
public function __construct(User $user, JoinHelper $joinHelper)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->joinHelper = $joinHelper;
|
||||
}
|
||||
public function __construct(private User $user, private JoinHelper $joinHelper)
|
||||
{}
|
||||
|
||||
public function convert(QueryBuilder $queryBuilder, Item $item): WhereClauseItem
|
||||
{
|
||||
|
||||
@@ -29,30 +29,18 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\Where\ItemConverters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\Where\ItemConverter,
|
||||
Select\Where\Item,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereItem as WhereClauseItem,
|
||||
ORM\Query\Part\WhereClause,
|
||||
Entities\User,
|
||||
Classes\Select\Email\Helpers\JoinHelper,
|
||||
};
|
||||
use Espo\Core\Select\Where\Item;
|
||||
use Espo\Core\Select\Where\ItemConverter;
|
||||
use Espo\Classes\Select\Email\Helpers\JoinHelper;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\Part\WhereItem as WhereClauseItem;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class IsNotReadIsFalse implements ItemConverter
|
||||
{
|
||||
private $user;
|
||||
|
||||
private $joinHelper;
|
||||
|
||||
public function __construct(User $user, JoinHelper $joinHelper)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->joinHelper = $joinHelper;
|
||||
}
|
||||
public function __construct(private User $user, private JoinHelper $joinHelper)
|
||||
{}
|
||||
|
||||
public function convert(QueryBuilder $queryBuilder, Item $item): WhereClauseItem
|
||||
{
|
||||
|
||||
@@ -29,30 +29,18 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\Where\ItemConverters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\Where\ItemConverter,
|
||||
Select\Where\Item,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereItem as WhereClauseItem,
|
||||
ORM\Query\Part\WhereClause,
|
||||
Entities\User,
|
||||
Classes\Select\Email\Helpers\JoinHelper,
|
||||
};
|
||||
use Espo\Core\Select\Where\Item;
|
||||
use Espo\Core\Select\Where\ItemConverter;
|
||||
use Espo\Classes\Select\Email\Helpers\JoinHelper;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\Part\WhereItem as WhereClauseItem;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class IsNotReadIsTrue implements ItemConverter
|
||||
{
|
||||
private $user;
|
||||
|
||||
private $joinHelper;
|
||||
|
||||
public function __construct(User $user, JoinHelper $joinHelper)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->joinHelper = $joinHelper;
|
||||
}
|
||||
public function __construct(private User $user, private JoinHelper $joinHelper)
|
||||
{}
|
||||
|
||||
public function convert(QueryBuilder $queryBuilder, Item $item): WhereClauseItem
|
||||
{
|
||||
|
||||
@@ -29,16 +29,11 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\Where\ItemConverters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\Where\ItemConverter,
|
||||
Select\Where\Item,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereItem as WhereClauseItem,
|
||||
ORM\Query\Part\WhereClause,
|
||||
};
|
||||
use Espo\Core\Select\Where\Item;
|
||||
use Espo\Core\Select\Where\ItemConverter;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\Part\WhereItem as WhereClauseItem;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class IsNotRepliedIsFalse implements ItemConverter
|
||||
{
|
||||
|
||||
@@ -29,16 +29,11 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\Where\ItemConverters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\Where\ItemConverter,
|
||||
Select\Where\Item,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereItem as WhereClauseItem,
|
||||
ORM\Query\Part\WhereClause,
|
||||
};
|
||||
use Espo\Core\Select\Where\Item;
|
||||
use Espo\Core\Select\Where\ItemConverter;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\Part\WhereItem as WhereClauseItem;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class IsNotRepliedIsTrue implements ItemConverter
|
||||
{
|
||||
|
||||
@@ -29,32 +29,20 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\Where\ItemConverters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\Where\ItemConverter,
|
||||
Select\Where\Item,
|
||||
Select\Helpers\RandomStringGenerator,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereItem as WhereClauseItem,
|
||||
ORM\Query\Part\WhereClause,
|
||||
Classes\Select\Email\Helpers\EmailAddressHelper,
|
||||
};
|
||||
use Espo\Core\Select\Helpers\RandomStringGenerator;
|
||||
use Espo\Core\Select\Where\Item;
|
||||
use Espo\Core\Select\Where\ItemConverter;
|
||||
use Espo\Classes\Select\Email\Helpers\EmailAddressHelper;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\Part\WhereItem as WhereClauseItem;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class ToEquals implements ItemConverter
|
||||
{
|
||||
private $emailAddressHelper;
|
||||
|
||||
private $randomStringGenerator;
|
||||
|
||||
public function __construct(
|
||||
EmailAddressHelper $emailAddressHelper,
|
||||
RandomStringGenerator $randomStringGenerator
|
||||
) {
|
||||
$this->emailAddressHelper = $emailAddressHelper;
|
||||
$this->randomStringGenerator = $randomStringGenerator;
|
||||
}
|
||||
private EmailAddressHelper $emailAddressHelper,
|
||||
private RandomStringGenerator $randomStringGenerator
|
||||
) {}
|
||||
|
||||
public function convert(QueryBuilder $queryBuilder, Item $item): WhereClauseItem
|
||||
{
|
||||
|
||||
@@ -29,20 +29,14 @@
|
||||
|
||||
namespace Espo\Classes\Select\EmailAccount\AccessControlFilters;
|
||||
|
||||
use Espo\{
|
||||
Core\Select\AccessControl\Filter,
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
Entities\User,
|
||||
};
|
||||
use Espo\Core\Select\AccessControl\Filter;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class Mandatory implements Filter
|
||||
{
|
||||
private $user;
|
||||
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
public function __construct(private User $user)
|
||||
{}
|
||||
|
||||
public function apply(QueryBuilder $queryBuilder): void
|
||||
{
|
||||
|
||||
@@ -29,13 +29,11 @@
|
||||
|
||||
namespace Espo\Classes\Select\EmailFilter\AccessControlFilters;
|
||||
|
||||
use Espo\{
|
||||
Core\Select\AccessControl\Filter,
|
||||
Entities\EmailAccount,
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\EntityManager,
|
||||
Entities\User,
|
||||
};
|
||||
use Espo\Core\Select\AccessControl\Filter;
|
||||
use Espo\Entities\EmailAccount;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class OnlyOwn implements Filter
|
||||
{
|
||||
|
||||
@@ -29,26 +29,18 @@
|
||||
|
||||
namespace Espo\Classes\Select\EmailFilter\BoolFilters;
|
||||
|
||||
use Espo\{
|
||||
Core\Select\Bool\Filter,
|
||||
Entities\EmailAccount,
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereClause,
|
||||
ORM\Query\Part\Where\OrGroupBuilder,
|
||||
ORM\EntityManager,
|
||||
Entities\User,
|
||||
};
|
||||
use Espo\Core\Select\Bool\Filter;
|
||||
use Espo\Entities\EmailAccount;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\ORM\Query\Part\Where\OrGroupBuilder;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class OnlyMy implements Filter
|
||||
{
|
||||
private User $user;
|
||||
private EntityManager $entityManager;
|
||||
|
||||
public function __construct(User $user, EntityManager $entityManager)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
public function __construct(private User $user, private EntityManager $entityManager)
|
||||
{}
|
||||
|
||||
public function apply(QueryBuilder $queryBuilder, OrGroupBuilder $orGroupBuilder): void
|
||||
{
|
||||
|
||||
@@ -30,19 +30,13 @@
|
||||
namespace Espo\Classes\Select\EmailFolder\AccessControlFilters;
|
||||
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
|
||||
use Espo\Core\Select\AccessControl\Filter;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
class Mandatory implements Filter
|
||||
{
|
||||
private $user;
|
||||
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
public function __construct(private User $user)
|
||||
{}
|
||||
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://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\Classes\Select\Event\PrimaryFilters;
|
||||
|
||||
use Espo\Core\Select\Primary\Filter;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
|
||||
class Held implements Filter
|
||||
{
|
||||
public function __construct(
|
||||
private string $entityType,
|
||||
private Metadata $metadata
|
||||
) {}
|
||||
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
$statusList = $this->metadata->get(['scopes', $this->entityType, 'completedStatusList']) ?? [];
|
||||
|
||||
$queryBuilder->where(['status' => $statusList]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://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\Classes\Select\Event\PrimaryFilters;
|
||||
|
||||
use Espo\Core\Select\Primary\Filter;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
|
||||
class Planned implements Filter
|
||||
{
|
||||
public function __construct(
|
||||
private string $entityType,
|
||||
private Metadata $metadata
|
||||
) {}
|
||||
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
$statusList = $this->metadata->get(['scopes', $this->entityType, 'activityStatusList']) ?? [];
|
||||
|
||||
$queryBuilder->where(['status' => $statusList]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://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\Classes\Select\Event\PrimaryFilters;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Select\Primary\Filter;
|
||||
use Espo\Core\Select\Helpers\UserTimeZoneProvider;
|
||||
use Espo\Core\Select\Where\ConverterFactory;
|
||||
use Espo\Core\Select\Where\Item;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
use Espo\Entities\User;
|
||||
use LogicException;
|
||||
|
||||
class Todays implements Filter
|
||||
{
|
||||
public function __construct(
|
||||
private User $user,
|
||||
private UserTimeZoneProvider $userTimeZoneProvider,
|
||||
private ConverterFactory $converterFactory,
|
||||
private string $entityType
|
||||
) {}
|
||||
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
$item = Item::fromRaw([
|
||||
'type' => Item\Type::TODAY,
|
||||
'attribute' => 'dateStart',
|
||||
'timeZone' => $this->userTimeZoneProvider->get(),
|
||||
'dateTime' => true,
|
||||
]);
|
||||
|
||||
try {
|
||||
$whereItem = $this->converterFactory
|
||||
->create($this->entityType, $this->user)
|
||||
->convert($queryBuilder, $item);
|
||||
}
|
||||
catch (Error $e) {
|
||||
throw new LogicException($e->getMessage());
|
||||
}
|
||||
|
||||
$queryBuilder->where($whereItem);
|
||||
}
|
||||
}
|
||||
@@ -37,12 +37,8 @@ use Espo\Entities\User;
|
||||
|
||||
class Mandatory implements Filter
|
||||
{
|
||||
private $user;
|
||||
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
public function __construct(private User $user)
|
||||
{}
|
||||
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
|
||||
@@ -29,33 +29,21 @@
|
||||
|
||||
namespace Espo\Classes\Select\Template\AccessControlFilters;
|
||||
|
||||
use Espo\ORM\{
|
||||
Query\SelectBuilder,
|
||||
Defs,
|
||||
};
|
||||
|
||||
use Espo\Core\{
|
||||
Select\AccessControl\Filter,
|
||||
AclManager,
|
||||
Acl\Exceptions\NotImplemented,
|
||||
};
|
||||
use Espo\ORM\Defs;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
use Espo\Core\Acl\Exceptions\NotImplemented;
|
||||
use Espo\Core\AclManager;
|
||||
use Espo\Core\Select\AccessControl\Filter;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
class Mandatory implements Filter
|
||||
{
|
||||
private $user;
|
||||
|
||||
private $defs;
|
||||
|
||||
private $aclManager;
|
||||
|
||||
public function __construct(User $user, Defs $defs, AclManager $aclManager)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->defs = $defs;
|
||||
$this->aclManager = $aclManager;
|
||||
}
|
||||
public function __construct(
|
||||
private User $user,
|
||||
private Defs $defs,
|
||||
private AclManager $aclManager
|
||||
) {}
|
||||
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
|
||||
@@ -30,26 +30,16 @@
|
||||
namespace Espo\Classes\Select\User\AccessControlFilters;
|
||||
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\AccessControl\Filter,
|
||||
AclManager,
|
||||
Acl\Table,
|
||||
};
|
||||
use Espo\Core\Acl\Table;
|
||||
use Espo\Core\AclManager;
|
||||
use Espo\Core\Select\AccessControl\Filter;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
class OnlyOwn implements Filter
|
||||
{
|
||||
private $user;
|
||||
|
||||
private $aclManager;
|
||||
|
||||
public function __construct(User $user, AclManager $aclManager)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->aclManager = $aclManager;
|
||||
}
|
||||
public function __construct(private User $user, private AclManager $aclManager)
|
||||
{}
|
||||
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
@@ -57,7 +47,7 @@ class OnlyOwn implements Filter
|
||||
$queryBuilder->where([
|
||||
'OR' => [
|
||||
'id' => $this->user->getId(),
|
||||
'type' => 'portal',
|
||||
'type' => User::TYPE_PORTAL,
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
use Espo\Core\Container;
|
||||
use Espo\Core\DataManager;
|
||||
use Espo\Core\Api\Request;
|
||||
@@ -44,6 +44,9 @@ use Espo\Entities\User;
|
||||
|
||||
class Admin
|
||||
{
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
public function __construct(
|
||||
private Container $container,
|
||||
private Config $config,
|
||||
@@ -53,12 +56,14 @@ class Admin
|
||||
private ScheduledJob $scheduledJob,
|
||||
private DataManager $dataManager
|
||||
) {
|
||||
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionRebuild(): bool
|
||||
{
|
||||
$this->dataManager->rebuild();
|
||||
@@ -66,6 +71,9 @@ class Admin
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionClearCache(): bool
|
||||
{
|
||||
$this->dataManager->clearCache();
|
||||
@@ -81,24 +89,28 @@ class Admin
|
||||
return $this->scheduledJob->getAvailableList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $params
|
||||
* @param string $data
|
||||
* @return array{
|
||||
* @return object{
|
||||
* id: string,
|
||||
* version: string,
|
||||
* }
|
||||
* @throws Forbidden
|
||||
* @throws Error
|
||||
* @todo Use Request.
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function postActionUploadUpgradePackage($params, $data): array
|
||||
public function postActionUploadUpgradePackage(Request $request): object
|
||||
{
|
||||
if ($this->config->get('restrictedMode')) {
|
||||
if (!$this->user->isSuperAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
if (
|
||||
$this->config->get('restrictedMode') &&
|
||||
!$this->user->isSuperAdmin()
|
||||
) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$data = $request->getBodyContents();
|
||||
|
||||
if (!$data) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$upgradeManager = new UpgradeManager($this->container);
|
||||
@@ -106,7 +118,7 @@ class Admin
|
||||
$upgradeId = $upgradeManager->upload($data);
|
||||
$manifest = $upgradeManager->getManifest();
|
||||
|
||||
return [
|
||||
return (object) [
|
||||
'id' => $upgradeId,
|
||||
'version' => $manifest['version'],
|
||||
];
|
||||
@@ -120,10 +132,11 @@ class Admin
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if ($this->config->get('restrictedMode')) {
|
||||
if (!$this->user->isSuperAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
if (
|
||||
$this->config->get('restrictedMode') &&
|
||||
!$this->user->isSuperAdmin()
|
||||
) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$upgradeManager = new UpgradeManager($this->container);
|
||||
@@ -134,33 +147,37 @@ class Admin
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* message: string,
|
||||
* command: string,
|
||||
* @return object{
|
||||
* message: string,
|
||||
* command: string,
|
||||
* }
|
||||
*/
|
||||
public function actionCronMessage(): array
|
||||
public function getActionCronMessage(): object
|
||||
{
|
||||
return $this->scheduledJob->getSetupMessage();
|
||||
return (object) $this->scheduledJob->getSetupMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int,array{id:string,type:string,message:string}>
|
||||
* @return array<int, array{
|
||||
* id: string,
|
||||
* type: string,
|
||||
* message: string,
|
||||
* }>
|
||||
*/
|
||||
public function actionAdminNotificationList(): array
|
||||
public function getActionAdminNotificationList(): array
|
||||
{
|
||||
return $this->adminNotificationManager->getNotificationList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* php: array<string,array<string,mixed>>,
|
||||
* database: array<string,array<string,mixed>>,
|
||||
* permission: array<string,array<string,mixed>>,
|
||||
* @return object{
|
||||
* php: array<string, array<string, mixed>>,
|
||||
* database: array<string, array<string, mixed>>,
|
||||
* permission: array<string, array<string, mixed>>,
|
||||
* }
|
||||
*/
|
||||
public function actionSystemRequirementList(): array
|
||||
public function getActionSystemRequirementList(): object
|
||||
{
|
||||
return $this->systemRequirements->getAllRequiredList();
|
||||
return (object) $this->systemRequirements->getAllRequiredList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,9 +78,15 @@ class EmailFolder extends RecordBase
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getActionListAll(): stdClass
|
||||
/**
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function getActionListAll(Request $request): stdClass
|
||||
{
|
||||
$list = $this->getEmailFolderService()->listAll();
|
||||
$userId = $request->getQueryParam('userId');
|
||||
|
||||
$list = $this->getEmailFolderService()->listAll($userId);
|
||||
|
||||
return (object) ['list' => $list];
|
||||
}
|
||||
|
||||
@@ -29,26 +29,43 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Exceptions\Conflict;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Entities\User;
|
||||
use Espo\Tools\EntityManager\EntityManager as EntityManagerTool;
|
||||
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Tools\ExportCustom\ExportCustom;
|
||||
use Espo\Tools\ExportCustom\Params as ExportCustomParams;
|
||||
use Espo\Tools\ExportCustom\Service as ExportCustomService;
|
||||
use Espo\Tools\LinkManager\LinkManager;
|
||||
use stdClass;
|
||||
|
||||
use const FILTER_SANITIZE_STRING;
|
||||
|
||||
class EntityManager
|
||||
{
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
public function __construct(
|
||||
private User $user,
|
||||
private EntityManagerTool $entityManagerTool
|
||||
private EntityManagerTool $entityManagerTool,
|
||||
private LinkManager $linkManager,
|
||||
private InjectableFactory $injectableFactory
|
||||
) {
|
||||
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
* @throws Conflict
|
||||
*/
|
||||
public function postActionCreateEntity(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -62,8 +79,8 @@ class EntityManager
|
||||
$name = $data['name'];
|
||||
$type = $data['type'];
|
||||
|
||||
$name = filter_var($name, \FILTER_SANITIZE_STRING);
|
||||
$type = filter_var($type, \FILTER_SANITIZE_STRING);
|
||||
$name = filter_var($name, FILTER_SANITIZE_STRING);
|
||||
$type = filter_var($type, FILTER_SANITIZE_STRING);
|
||||
|
||||
if (!is_string($name) || !is_string($type)) {
|
||||
throw new BadRequest();
|
||||
@@ -130,6 +147,10 @@ class EntityManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionUpdateEntity(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -142,7 +163,7 @@ class EntityManager
|
||||
|
||||
$name = $data['name'];
|
||||
|
||||
$name = filter_var($name, \FILTER_SANITIZE_STRING);
|
||||
$name = filter_var($name, FILTER_SANITIZE_STRING);
|
||||
|
||||
if (!is_string($name)) {
|
||||
throw new BadRequest();
|
||||
@@ -153,6 +174,11 @@ class EntityManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionRemoveEntity(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -165,7 +191,7 @@ class EntityManager
|
||||
|
||||
$name = $data['name'];
|
||||
|
||||
$name = filter_var($name, \FILTER_SANITIZE_STRING);
|
||||
$name = filter_var($name, FILTER_SANITIZE_STRING);
|
||||
|
||||
if (!is_string($name)) {
|
||||
throw new BadRequest();
|
||||
@@ -176,6 +202,11 @@ class EntityManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
* @throws Conflict
|
||||
*/
|
||||
public function postActionCreateLink(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -203,11 +234,11 @@ class EntityManager
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$params[$item] = filter_var($data[$item], \FILTER_SANITIZE_STRING);
|
||||
$params[$item] = filter_var($data[$item], FILTER_SANITIZE_STRING);
|
||||
}
|
||||
|
||||
foreach ($additionalParamList as $item) {
|
||||
$params[$item] = filter_var($data[$item] ?? null, \FILTER_SANITIZE_STRING);
|
||||
$params[$item] = filter_var($data[$item] ?? null, FILTER_SANITIZE_STRING);
|
||||
}
|
||||
|
||||
$params['labelForeign'] = $params['labelForeign'] ?? $params['linkForeign'];
|
||||
@@ -236,6 +267,14 @@ class EntityManager
|
||||
$params['foreignLinkEntityTypeList'] = $data['foreignLinkEntityTypeList'];
|
||||
}
|
||||
|
||||
if (array_key_exists('layout', $data)) {
|
||||
$params['layout'] = $data['layout'];
|
||||
}
|
||||
|
||||
if (array_key_exists('layoutForeign', $data)) {
|
||||
$params['layoutForeign'] = $data['layoutForeign'];
|
||||
}
|
||||
|
||||
/** @var array{
|
||||
* linkType: string,
|
||||
* entity: string,
|
||||
@@ -249,14 +288,20 @@ class EntityManager
|
||||
* linkMultipleFieldForeign?: bool,
|
||||
* audited?: bool,
|
||||
* auditedForeign?: bool,
|
||||
* layout?: string,
|
||||
* layoutForeign?: string,
|
||||
* } $params
|
||||
*/
|
||||
|
||||
$this->entityManagerTool->createLink($params);
|
||||
$this->linkManager->create($params);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionUpdateLink(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -276,7 +321,7 @@ class EntityManager
|
||||
|
||||
foreach ($paramList as $item) {
|
||||
if (array_key_exists($item, $data)) {
|
||||
$params[$item] = filter_var($data[$item], \FILTER_SANITIZE_STRING);
|
||||
$params[$item] = filter_var($data[$item], FILTER_SANITIZE_STRING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,6 +348,14 @@ class EntityManager
|
||||
$params['foreignLinkEntityTypeList'] = $data['foreignLinkEntityTypeList'];
|
||||
}
|
||||
|
||||
if (array_key_exists('layout', $data)) {
|
||||
$params['layout'] = $data['layout'];
|
||||
}
|
||||
|
||||
if (array_key_exists('auditedForeign', $data)) {
|
||||
$params['layoutForeign'] = $data['layoutForeign'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array{
|
||||
* entity: string,
|
||||
@@ -317,14 +370,20 @@ class EntityManager
|
||||
* auditedForeign?: bool,
|
||||
* parentEntityTypeList?: string[],
|
||||
* foreignLinkEntityTypeList?: string[],
|
||||
* layout?: string,
|
||||
* layoutForeign?: string,
|
||||
* } $params
|
||||
*/
|
||||
|
||||
$this->entityManagerTool->updateLink($params);
|
||||
$this->linkManager->update($params);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionRemoveLink(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -339,7 +398,7 @@ class EntityManager
|
||||
$params = [];
|
||||
|
||||
foreach ($paramList as $item) {
|
||||
$params[$item] = filter_var($data[$item], \FILTER_SANITIZE_STRING);
|
||||
$params[$item] = filter_var($data[$item], FILTER_SANITIZE_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,11 +408,15 @@ class EntityManager
|
||||
* } $params
|
||||
*/
|
||||
|
||||
$this->entityManagerTool->deleteLink($params);
|
||||
$this->linkManager->delete($params);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionFormula(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -373,6 +436,29 @@ class EntityManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function postActionResetFormulaToDefault(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$scope = $data->scope ?? null;
|
||||
$type = $data->type ?? null;
|
||||
|
||||
if (!$scope || !$type) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$this->entityManagerTool->resetFormulaToDefault($scope, $type);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionResetToDefault(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -385,4 +471,45 @@ class EntityManager
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function postActionExportCustom(Request $request): stdClass
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$name = $data->name ?? null;
|
||||
$version = $data->version ?? null;
|
||||
$author = $data->author ?? null;
|
||||
$module = $data->module ?? null;
|
||||
$description = $data->description ?? null;
|
||||
|
||||
if (
|
||||
!is_string($name) ||
|
||||
!is_string($version) ||
|
||||
!is_string($author) ||
|
||||
!is_string($module) ||
|
||||
!is_string($description) && !is_null($description)
|
||||
) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$params = new ExportCustomParams(
|
||||
name: $name,
|
||||
module: $module,
|
||||
version: $version,
|
||||
author: $author,
|
||||
description: $description
|
||||
);
|
||||
|
||||
$export = $this->injectableFactory->create(ExportCustom::class);
|
||||
$service = $this->injectableFactory->create(ExportCustomService::class);
|
||||
|
||||
$service->storeToConfig($params);
|
||||
|
||||
$result = $export->process($params);
|
||||
|
||||
return (object) ['id' => $result->getAttachmentId()];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ class FieldManager
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
* @return array<string, mixed>
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
*/
|
||||
|
||||
@@ -43,7 +43,7 @@ class I18n
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getActionRead(Request $request): array
|
||||
{
|
||||
|
||||
@@ -29,34 +29,26 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\{
|
||||
Exceptions\Forbidden,
|
||||
Exceptions\BadRequest,
|
||||
Api\Request,
|
||||
DataManager,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
Tools\LabelManager\LabelManager as LabelManagerTool,
|
||||
Entities\User,
|
||||
};
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\DataManager;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Entities\User;
|
||||
use Espo\Tools\LabelManager\LabelManager as LabelManagerTool;
|
||||
|
||||
use stdClass;
|
||||
|
||||
class LabelManager
|
||||
{
|
||||
private $user;
|
||||
|
||||
private $dataManager;
|
||||
|
||||
private $labelManagerTool;
|
||||
|
||||
public function __construct(User $user, DataManager $dataManager, LabelManagerTool $labelManagerTool)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->dataManager = $dataManager;
|
||||
$this->labelManagerTool = $labelManagerTool;
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
public function __construct(
|
||||
private User $user,
|
||||
private DataManager $dataManager,
|
||||
private LabelManagerTool $labelManagerTool
|
||||
) {
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
@@ -29,25 +29,16 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\{
|
||||
Api\Request,
|
||||
Record\SearchParamsFetcher,
|
||||
};
|
||||
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Record\SearchParamsFetcher;
|
||||
use Espo\Tools\ActionHistory\Service as Service;
|
||||
|
||||
use stdClass;
|
||||
|
||||
class LastViewed
|
||||
{
|
||||
private SearchParamsFetcher $searchParamsFetcher;
|
||||
private Service $service;
|
||||
|
||||
public function __construct(SearchParamsFetcher $searchParamsFetcher, Service $service)
|
||||
{
|
||||
$this->searchParamsFetcher = $searchParamsFetcher;
|
||||
$this->service = $service;
|
||||
}
|
||||
public function __construct(private SearchParamsFetcher $searchParamsFetcher, private Service $service)
|
||||
{}
|
||||
|
||||
public function getActionIndex(Request $request): stdClass
|
||||
{
|
||||
|
||||
@@ -29,25 +29,26 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Exceptions\Conflict;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Tools\Layout\CustomLayoutService;
|
||||
use Espo\Tools\Layout\LayoutDefs;
|
||||
use Espo\Tools\Layout\Service as Service;
|
||||
use Espo\Entities\User;
|
||||
use stdClass;
|
||||
|
||||
class Layout
|
||||
{
|
||||
private User $user;
|
||||
private Service $service;
|
||||
|
||||
public function __construct(User $user, Service $service)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->service = $service;
|
||||
}
|
||||
public function __construct(
|
||||
private User $user,
|
||||
private Service $service,
|
||||
private InjectableFactory $injectableFactory
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
@@ -103,7 +104,7 @@ class Layout
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @return array<int, mixed>|stdClass|null
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
* @throws NotFound
|
||||
@@ -125,7 +126,7 @@ class Layout
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @return array<int, mixed>|stdClass|null
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
@@ -147,4 +148,75 @@ class Layout
|
||||
|
||||
return $this->service->getOriginal($scope, $name, $setId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
* @throws Conflict
|
||||
*/
|
||||
public function postActionCreate(Request $request): bool
|
||||
{
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$body = $request->getParsedBody();
|
||||
|
||||
$scope = $body->scope ?? null;
|
||||
$name = $body->name ?? null;
|
||||
$type = $body->type ?? null;
|
||||
$label = $body->label ?? null;
|
||||
|
||||
if (
|
||||
!is_string($scope) ||
|
||||
!is_string($name) ||
|
||||
!is_string($type) ||
|
||||
!is_string($label) ||
|
||||
!$scope ||
|
||||
!$name ||
|
||||
!$type ||
|
||||
!$label
|
||||
) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$defs = new LayoutDefs($scope, $name, $type, $label);
|
||||
|
||||
$service = $this->injectableFactory->create(CustomLayoutService::class);
|
||||
|
||||
$service->create($defs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function postActionDelete(Request $request): bool
|
||||
{
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$body = $request->getParsedBody();
|
||||
|
||||
$scope = $body->scope ?? null;
|
||||
$name = $body->name ?? null;
|
||||
|
||||
if (
|
||||
!is_string($scope) ||
|
||||
!is_string($name) ||
|
||||
!$scope ||
|
||||
!$name
|
||||
) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$service = $this->injectableFactory->create(CustomLayoutService::class);
|
||||
|
||||
$service->delete($scope, $name);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,15 +31,14 @@ namespace Espo\Controllers;
|
||||
|
||||
use Espo\Tools\Notification\RecordService as Service;
|
||||
|
||||
use Espo\Core\{
|
||||
Controllers\RecordBase,
|
||||
Api\Request,
|
||||
Api\Response,
|
||||
Exceptions\BadRequest,
|
||||
Exceptions\Error,
|
||||
Exceptions\Forbidden,
|
||||
Select\SearchParams,
|
||||
Select\Where\Item as WhereItem};
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use Espo\Core\Controllers\RecordBase;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Select\SearchParams;
|
||||
use Espo\Core\Select\Where\Item as WhereItem;
|
||||
|
||||
use stdClass;
|
||||
|
||||
|
||||
@@ -29,10 +29,8 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\{
|
||||
Controllers\Record,
|
||||
Acl\Table,
|
||||
};
|
||||
use Espo\Core\Acl\Table;
|
||||
use Espo\Core\Controllers\Record;
|
||||
|
||||
class Portal extends Record
|
||||
{
|
||||
|
||||
@@ -31,39 +31,38 @@ namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Core\Utils\TemplateFileManager;
|
||||
use Espo\Core\ApplicationState;
|
||||
|
||||
use Espo\Core\{
|
||||
Api\Request,
|
||||
};
|
||||
use Espo\Core\Api\Request;
|
||||
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
* @todo Move to a service class.
|
||||
*/
|
||||
class TemplateManager
|
||||
{
|
||||
private $metadata;
|
||||
|
||||
private $templateFileManager;
|
||||
|
||||
private $applicationState;
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
public function __construct(
|
||||
Metadata $metadata,
|
||||
TemplateFileManager $templateFileManager,
|
||||
ApplicationState $applicationState
|
||||
private Metadata $metadata,
|
||||
private TemplateFileManager $templateFileManager,
|
||||
private ApplicationState $applicationState,
|
||||
private Config $config
|
||||
) {
|
||||
$this->metadata = $metadata;
|
||||
$this->templateFileManager = $templateFileManager;
|
||||
$this->applicationState = $applicationState;
|
||||
|
||||
if (!$this->applicationState->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function getActionGetTemplate(Request $request): stdClass
|
||||
{
|
||||
$name = $request->getQueryParam('name');
|
||||
@@ -75,7 +74,6 @@ class TemplateManager
|
||||
$scope = $request->getQueryParam('scope');
|
||||
|
||||
$module = $this->metadata->get(['app', 'templates', $name, 'module']);
|
||||
|
||||
$hasSubject = !$this->metadata->get(['app', 'templates', $name, 'noSubject']);
|
||||
|
||||
$templateFileManager = $this->templateFileManager;
|
||||
@@ -91,6 +89,10 @@ class TemplateManager
|
||||
return $returnData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
*/
|
||||
public function postActionSaveTemplate(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -98,9 +100,18 @@ class TemplateManager
|
||||
$scope = null;
|
||||
|
||||
if (empty($data->name)) {
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
if (
|
||||
$data->name === 'passwordChangeLink' &&
|
||||
$this->config->get('restrictedMode') &&
|
||||
!$this->applicationState->getUser()->isSuperAdmin()
|
||||
) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
if (!empty($data->scope)) {
|
||||
$scope = $data->scope;
|
||||
}
|
||||
@@ -118,6 +129,9 @@ class TemplateManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function postActionResetTemplate(Request $request): stdClass
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -133,7 +147,6 @@ class TemplateManager
|
||||
}
|
||||
|
||||
$module = $this->metadata->get(['app', 'templates', $data->name, 'module']);
|
||||
|
||||
$hasSubject = !$this->metadata->get(['app', 'templates', $data->name, 'noSubject']);
|
||||
|
||||
$templateFileManager = $this->templateFileManager;
|
||||
|
||||
@@ -29,11 +29,9 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\{
|
||||
Controllers\RecordBase,
|
||||
Api\Request,
|
||||
Api\Response,
|
||||
};
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use Espo\Core\Controllers\RecordBase;
|
||||
|
||||
use stdClass;
|
||||
|
||||
|
||||
@@ -29,41 +29,27 @@
|
||||
|
||||
namespace Espo\Core\Acl\AccessChecker;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\ClassFinder,
|
||||
Utils\Metadata,
|
||||
InjectableFactory,
|
||||
Acl\Exceptions\NotImplemented,
|
||||
Acl\DefaultAccessChecker,
|
||||
Acl\AccessChecker,
|
||||
AclManager,
|
||||
Binding\BindingContainer,
|
||||
Binding\Binder,
|
||||
Binding\BindingData,
|
||||
};
|
||||
use Espo\Core\Acl\AccessChecker;
|
||||
use Espo\Core\Acl\DefaultAccessChecker;
|
||||
use Espo\Core\Acl\Exceptions\NotImplemented;
|
||||
use Espo\Core\AclManager;
|
||||
use Espo\Core\Binding\Binder;
|
||||
use Espo\Core\Binding\BindingContainer;
|
||||
use Espo\Core\Binding\BindingData;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\Utils\ClassFinder;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
|
||||
class AccessCheckerFactory
|
||||
{
|
||||
/**
|
||||
* @var class-string<AccessChecker>
|
||||
*/
|
||||
/** @var class-string<AccessChecker> */
|
||||
private string $defaultClassName = DefaultAccessChecker::class;
|
||||
|
||||
private ClassFinder $classFinder;
|
||||
|
||||
private Metadata $metadata;
|
||||
|
||||
private InjectableFactory $injectableFactory;
|
||||
|
||||
public function __construct(
|
||||
ClassFinder $classFinder,
|
||||
Metadata $metadata,
|
||||
InjectableFactory $injectableFactory
|
||||
) {
|
||||
$this->classFinder = $classFinder;
|
||||
$this->metadata = $metadata;
|
||||
$this->injectableFactory = $injectableFactory;
|
||||
}
|
||||
private ClassFinder $classFinder,
|
||||
private Metadata $metadata,
|
||||
private InjectableFactory $injectableFactory
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Create an access checker.
|
||||
@@ -112,7 +98,6 @@ class AccessCheckerFactory
|
||||
$bindingData = new BindingData();
|
||||
|
||||
$binder = new Binder($bindingData);
|
||||
|
||||
$binder->bindInstance(AclManager::class, $aclManager);
|
||||
|
||||
return new BindingContainer($bindingData);
|
||||
|
||||
@@ -29,10 +29,8 @@
|
||||
|
||||
namespace Espo\Core\Acl\AccessChecker;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\ScopeData,
|
||||
Acl\Table,
|
||||
};
|
||||
use Espo\Core\Acl\ScopeData;
|
||||
use Espo\Core\Acl\Table;
|
||||
|
||||
/**
|
||||
* Checks scope access.
|
||||
@@ -40,8 +38,7 @@ use Espo\Core\{
|
||||
class ScopeChecker
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
public function check(ScopeData $data, ?string $action = null, ?ScopeCheckerData $checkerData = null): bool
|
||||
{
|
||||
|
||||
@@ -29,20 +29,17 @@
|
||||
|
||||
namespace Espo\Core\Acl\AccessChecker;
|
||||
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* Scope checker data.
|
||||
*/
|
||||
class ScopeCheckerData
|
||||
{
|
||||
private $isOwnChecker;
|
||||
|
||||
private $inTeamChecker;
|
||||
|
||||
public function __construct(callable $isOwnChecker, callable $inTeamChecker)
|
||||
{
|
||||
$this->isOwnChecker = $isOwnChecker;
|
||||
$this->inTeamChecker = $inTeamChecker;
|
||||
}
|
||||
public function __construct(
|
||||
private Closure $isOwnChecker,
|
||||
private Closure $inTeamChecker
|
||||
) {}
|
||||
|
||||
public function isOwn(): bool
|
||||
{
|
||||
|
||||
@@ -36,9 +36,8 @@ use Closure;
|
||||
*/
|
||||
class ScopeCheckerDataBuilder
|
||||
{
|
||||
private $isOwnChecker;
|
||||
|
||||
private $inTeamChecker;
|
||||
private Closure $isOwnChecker;
|
||||
private Closure $inTeamChecker;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
@@ -29,37 +29,28 @@
|
||||
|
||||
namespace Espo\Core\Acl\AssignmentChecker;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Metadata,
|
||||
InjectableFactory,
|
||||
Acl\AssignmentChecker,
|
||||
Acl\DefaultAssignmentChecker,
|
||||
Acl\Exceptions\NotImplemented,
|
||||
};
|
||||
use Espo\Core\Acl\AssignmentChecker;
|
||||
use Espo\Core\Acl\DefaultAssignmentChecker;
|
||||
use Espo\Core\Acl\Exceptions\NotImplemented;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\ORM\Entity as CoreEntity;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class AssignmentCheckerFactory
|
||||
{
|
||||
/**
|
||||
* @var class-string<AssignmentChecker<\Espo\Core\ORM\Entity>>
|
||||
*/
|
||||
/** @var class-string<AssignmentChecker<CoreEntity>> */
|
||||
private string $defaultClassName = DefaultAssignmentChecker::class;
|
||||
|
||||
private Metadata $metadata;
|
||||
|
||||
private InjectableFactory $injectableFactory;
|
||||
|
||||
public function __construct(
|
||||
Metadata $metadata,
|
||||
InjectableFactory $injectableFactory
|
||||
) {
|
||||
$this->metadata = $metadata;
|
||||
$this->injectableFactory = $injectableFactory;
|
||||
}
|
||||
private Metadata $metadata,
|
||||
private InjectableFactory $injectableFactory
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Create an access checker.
|
||||
*
|
||||
* @return AssignmentChecker<\Espo\ORM\Entity>
|
||||
* @return AssignmentChecker<Entity>
|
||||
* @throws NotImplemented
|
||||
*/
|
||||
public function create(string $scope): AssignmentChecker
|
||||
@@ -70,12 +61,12 @@ class AssignmentCheckerFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string<AssignmentChecker<\Espo\ORM\Entity>>
|
||||
* @return class-string<AssignmentChecker<Entity>>
|
||||
* @throws NotImplemented
|
||||
*/
|
||||
private function getClassName(string $scope): string
|
||||
{
|
||||
/** @var ?class-string<AssignmentChecker<\Espo\ORM\Entity>> $className */
|
||||
/** @var ?class-string<AssignmentChecker<Entity>> $className */
|
||||
$className = $this->metadata->get(['aclDefs', $scope, 'assignmentCheckerClassName']);
|
||||
|
||||
if ($className) {
|
||||
@@ -86,7 +77,7 @@ class AssignmentCheckerFactory
|
||||
throw new NotImplemented();
|
||||
}
|
||||
|
||||
/** @var class-string<AssignmentChecker<\Espo\ORM\Entity>> */
|
||||
/** @var class-string<AssignmentChecker<Entity>> */
|
||||
return $this->defaultClassName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,24 +30,16 @@
|
||||
namespace Espo\Core\Acl\AssignmentChecker;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\Acl\AssignmentChecker;
|
||||
|
||||
class AssignmentCheckerManager
|
||||
{
|
||||
/**
|
||||
* @var array<string,AssignmentChecker<Entity>>
|
||||
*/
|
||||
/** @var array<string, AssignmentChecker<Entity>> */
|
||||
private $checkerCache = [];
|
||||
|
||||
private AssignmentCheckerFactory $factory;
|
||||
|
||||
public function __construct(AssignmentCheckerFactory $factory)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
}
|
||||
public function __construct(private AssignmentCheckerFactory $factory)
|
||||
{}
|
||||
|
||||
public function check(User $user, Entity $entity): bool
|
||||
{
|
||||
|
||||
@@ -32,16 +32,12 @@ namespace Espo\Core\Acl;
|
||||
use Espo\Core\Interfaces\Injectable;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\{
|
||||
ORM\EntityManager,
|
||||
Acl\AccessChecker\ScopeCheckerData,
|
||||
Acl\AccessChecker\ScopeChecker,
|
||||
AclManager,
|
||||
Utils\Config,
|
||||
};
|
||||
use Espo\Core\Acl\AccessChecker\ScopeChecker;
|
||||
use Espo\Core\Acl\AccessChecker\ScopeCheckerData;
|
||||
use Espo\Core\AclManager;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
use Espo\Core\Utils\Config;
|
||||
|
||||
/**
|
||||
* @deprecated As of v6.0. Use AccessChecker interfaces instead.
|
||||
|
||||
@@ -39,14 +39,8 @@ use Espo\ORM\EntityManager;
|
||||
*/
|
||||
class Clearer
|
||||
{
|
||||
private FileManager $fileManager;
|
||||
private EntityManager $entityManager;
|
||||
|
||||
public function __construct(FileManager $fileManager, EntityManager $entityManager)
|
||||
{
|
||||
$this->fileManager = $fileManager;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
public function __construct(private FileManager $fileManager, private EntityManager $entityManager)
|
||||
{}
|
||||
|
||||
public function clearForAllInternalUsers(): void
|
||||
{
|
||||
|
||||
@@ -27,9 +27,8 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Tools\EntityManager\Hooks;
|
||||
namespace Espo\Core\Acl\Exceptions;
|
||||
|
||||
class PersonType extends BasePlusType
|
||||
{
|
||||
use RuntimeException;
|
||||
|
||||
}
|
||||
class NotAvailable extends RuntimeException {}
|
||||
@@ -29,18 +29,14 @@
|
||||
|
||||
namespace Espo\Core\Acl\Map;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\Table,
|
||||
Utils\FieldUtil,
|
||||
};
|
||||
use Espo\Core\Acl\Table;
|
||||
use Espo\Core\Utils\FieldUtil;
|
||||
|
||||
use stdClass;
|
||||
|
||||
class DataBuilder
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
/** @var string[] */
|
||||
private $actionList = [
|
||||
Table::ACTION_READ,
|
||||
Table::ACTION_STREAM,
|
||||
@@ -48,32 +44,19 @@ class DataBuilder
|
||||
Table::ACTION_DELETE,
|
||||
Table::ACTION_CREATE,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
/** @var string[] */
|
||||
private $fieldActionList = [
|
||||
Table::ACTION_READ,
|
||||
Table::ACTION_EDIT,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
/** @var string[] */
|
||||
private $fieldLevelList = [
|
||||
Table::LEVEL_YES,
|
||||
Table::LEVEL_NO,
|
||||
];
|
||||
|
||||
private MetadataProvider $metadataProvider;
|
||||
|
||||
private FieldUtil $fieldUtil;
|
||||
|
||||
public function __construct(MetadataProvider $metadataProvider, FieldUtil $fieldUtil)
|
||||
{
|
||||
$this->metadataProvider = $metadataProvider;
|
||||
$this->fieldUtil = $fieldUtil;
|
||||
}
|
||||
public function __construct(private MetadataProvider $metadataProvider, private FieldUtil $fieldUtil)
|
||||
{}
|
||||
|
||||
public function build(Table $table): stdClass
|
||||
{
|
||||
|
||||
@@ -33,12 +33,8 @@ use Espo\Entities\User;
|
||||
|
||||
class DefaultCacheKeyProvider implements CacheKeyProvider
|
||||
{
|
||||
private $user;
|
||||
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
public function __construct(private User $user)
|
||||
{}
|
||||
|
||||
public function get(): string
|
||||
{
|
||||
|
||||
@@ -29,14 +29,10 @@
|
||||
|
||||
namespace Espo\Core\Acl\Map;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\Table,
|
||||
Utils\Config,
|
||||
Utils\DataCache,
|
||||
Utils\ObjectUtil,
|
||||
};
|
||||
use Espo\Core\Acl\Table;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Core\Utils\DataCache;
|
||||
use Espo\Core\Utils\ObjectUtil;
|
||||
|
||||
use stdClass;
|
||||
use RuntimeException;
|
||||
@@ -47,50 +43,24 @@ use RuntimeException;
|
||||
class Map
|
||||
{
|
||||
private stdClass $data;
|
||||
|
||||
private string $cacheKey;
|
||||
|
||||
/**
|
||||
* @var array<string,string[]>
|
||||
*/
|
||||
/** @var array<string, string[]> */
|
||||
private $forbiddenFieldsCache = [];
|
||||
|
||||
/**
|
||||
* @var array<string,string[]>
|
||||
*/
|
||||
/** @var array<string, string[]> */
|
||||
private $forbiddenAttributesCache;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
/** @var string[] */
|
||||
private $fieldLevelList = [
|
||||
Table::LEVEL_YES,
|
||||
Table::LEVEL_NO,
|
||||
];
|
||||
|
||||
private User $user;
|
||||
|
||||
private Table $table;
|
||||
|
||||
private Config $config;
|
||||
|
||||
private DataCache $dataCache;
|
||||
|
||||
private DataBuilder $dataBuilder;
|
||||
|
||||
public function __construct(
|
||||
User $user,
|
||||
Table $table,
|
||||
DataBuilder $dataBuilder,
|
||||
Config $config,
|
||||
DataCache $dataCache,
|
||||
private DataBuilder $dataBuilder,
|
||||
private Config $config,
|
||||
private DataCache $dataCache,
|
||||
CacheKeyProvider $cacheKeyProvider
|
||||
) {
|
||||
$this->user = $user;
|
||||
$this->table = $table;
|
||||
$this->dataBuilder = $dataBuilder;
|
||||
$this->config = $config;
|
||||
$this->dataCache = $dataCache;
|
||||
|
||||
$this->cacheKey = $cacheKeyProvider->get();
|
||||
|
||||
|
||||
@@ -31,23 +31,16 @@ namespace Espo\Core\Acl\Map;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\{
|
||||
InjectableFactory,
|
||||
Acl\Table,
|
||||
Acl\Map\Map,
|
||||
Binding\BindingContainer,
|
||||
Binding\Binder,
|
||||
Binding\BindingData,
|
||||
};
|
||||
use Espo\Core\Acl\Table;
|
||||
use Espo\Core\Binding\Binder;
|
||||
use Espo\Core\Binding\BindingContainer;
|
||||
use Espo\Core\Binding\BindingData;
|
||||
use Espo\Core\InjectableFactory;
|
||||
|
||||
class MapFactory
|
||||
{
|
||||
private $injectableFactory;
|
||||
|
||||
public function __construct(InjectableFactory $injectableFactory)
|
||||
{
|
||||
$this->injectableFactory = $injectableFactory;
|
||||
}
|
||||
public function __construct(private InjectableFactory $injectableFactory)
|
||||
{}
|
||||
|
||||
public function create(User $user, Table $table): Map
|
||||
{
|
||||
@@ -61,7 +54,6 @@ class MapFactory
|
||||
$bindingData = new BindingData();
|
||||
|
||||
$binder = new Binder($bindingData);
|
||||
|
||||
$binder
|
||||
->bindInstance(User::class, $user)
|
||||
->bindInstance(Table::class, $table)
|
||||
|
||||
@@ -35,12 +35,8 @@ class MetadataProvider
|
||||
{
|
||||
protected string $type = 'acl';
|
||||
|
||||
private Metadata $metadata;
|
||||
|
||||
public function __construct(Metadata $metadata)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
public function __construct(private Metadata $metadata)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
@@ -66,7 +62,7 @@ class MetadataProvider
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int,string>
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function getPermissionList(): array
|
||||
{
|
||||
@@ -74,7 +70,7 @@ class MetadataProvider
|
||||
|
||||
return array_map(
|
||||
function (string $item): string {
|
||||
if (substr($item, -10) === 'Permission') {
|
||||
if (str_ends_with($item, 'Permission')) {
|
||||
return substr($item, 0, -10);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,36 +29,25 @@
|
||||
|
||||
namespace Espo\Core\Acl\OwnershipChecker;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Metadata,
|
||||
InjectableFactory,
|
||||
Acl\Exceptions\NotImplemented,
|
||||
Acl\DefaultOwnershipChecker,
|
||||
Acl\OwnershipChecker,
|
||||
AclManager,
|
||||
Binding\BindingContainer,
|
||||
Binding\Binder,
|
||||
Binding\BindingData,
|
||||
};
|
||||
use Espo\Core\Acl\DefaultOwnershipChecker;
|
||||
use Espo\Core\Acl\Exceptions\NotImplemented;
|
||||
use Espo\Core\Acl\OwnershipChecker;
|
||||
use Espo\Core\AclManager;
|
||||
use Espo\Core\Binding\Binder;
|
||||
use Espo\Core\Binding\BindingContainer;
|
||||
use Espo\Core\Binding\BindingData;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
|
||||
class OwnershipCheckerFactory
|
||||
{
|
||||
/**
|
||||
* @var class-string<OwnershipChecker>
|
||||
*/
|
||||
/** @var class-string<OwnershipChecker> */
|
||||
private string $defaultClassName = DefaultOwnershipChecker::class;
|
||||
|
||||
private Metadata $metadata;
|
||||
|
||||
private InjectableFactory $injectableFactory;
|
||||
|
||||
public function __construct(
|
||||
Metadata $metadata,
|
||||
InjectableFactory $injectableFactory
|
||||
) {
|
||||
$this->metadata = $metadata;
|
||||
$this->injectableFactory = $injectableFactory;
|
||||
}
|
||||
private Metadata $metadata,
|
||||
private InjectableFactory $injectableFactory
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Create an ownership checker.
|
||||
|
||||
@@ -40,7 +40,7 @@ class ScopeData
|
||||
{
|
||||
/** @var stdClass|bool */
|
||||
private $raw;
|
||||
/** @var array<string,string> */
|
||||
/** @var array<string, string> */
|
||||
private $actionData = [];
|
||||
private bool $isBoolean = false;
|
||||
|
||||
|
||||
@@ -30,28 +30,16 @@
|
||||
namespace Espo\Core\Acl\Table;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\{
|
||||
InjectableFactory,
|
||||
Acl\Table,
|
||||
Acl\Table\DefaultTable,
|
||||
Acl\Table\CacheKeyProvider,
|
||||
Acl\Table\DefaultCacheKeyProvider,
|
||||
Acl\Table\RoleListProvider,
|
||||
Acl\Table\DefaultRoleListProvider,
|
||||
Binding\BindingContainer,
|
||||
Binding\Binder,
|
||||
Binding\BindingData,
|
||||
};
|
||||
use Espo\Core\Acl\Table;
|
||||
use Espo\Core\Binding\Binder;
|
||||
use Espo\Core\Binding\BindingContainer;
|
||||
use Espo\Core\Binding\BindingData;
|
||||
use Espo\Core\InjectableFactory;
|
||||
|
||||
class DefaultTableFactory implements TableFactory
|
||||
{
|
||||
private $injectableFactory;
|
||||
|
||||
public function __construct(InjectableFactory $injectableFactory)
|
||||
{
|
||||
$this->injectableFactory = $injectableFactory;
|
||||
}
|
||||
public function __construct(private InjectableFactory $injectableFactory)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Create a table.
|
||||
|
||||
@@ -30,24 +30,18 @@
|
||||
namespace Espo\Core\AclPortal;
|
||||
|
||||
use Espo\Core\Interfaces\Injectable;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\AclManager;
|
||||
|
||||
use Espo\Core\{
|
||||
ORM\EntityManager,
|
||||
Portal\AclManager as PortalAclManager,
|
||||
Utils\Config,
|
||||
Acl\AccessChecker,
|
||||
Acl\ScopeData,
|
||||
Portal\Acl\Table,
|
||||
Portal\Acl\AccessChecker\ScopeChecker,
|
||||
Portal\Acl\AccessChecker\ScopeCheckerData,
|
||||
Portal\Acl\DefaultAccessChecker,
|
||||
};
|
||||
use Espo\Core\Acl\AccessChecker;
|
||||
use Espo\Core\Acl\ScopeData;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
use Espo\Core\Portal\Acl\AccessChecker\ScopeChecker;
|
||||
use Espo\Core\Portal\Acl\AccessChecker\ScopeCheckerData;
|
||||
use Espo\Core\Portal\Acl\DefaultAccessChecker;
|
||||
use Espo\Core\Portal\Acl\Table;
|
||||
use Espo\Core\Portal\AclManager as PortalAclManager;
|
||||
use Espo\Core\Utils\Config;
|
||||
|
||||
/**
|
||||
* @deprecated Use AccessChecker interfaces instead.
|
||||
|
||||
@@ -30,30 +30,32 @@
|
||||
namespace Espo\Core\Action\Actions;
|
||||
|
||||
use Espo\Core\Acl;
|
||||
use Espo\Core\Acl\Table;
|
||||
use Espo\Core\Action\Action;
|
||||
use Espo\Core\Action\Data;
|
||||
use Espo\Core\Action\Params;
|
||||
use Espo\Core\Currency\ConfigDataProvider as CurrencyConfigDataProvider;
|
||||
use Espo\Core\Currency\Converter as CurrencyConverter;
|
||||
use Espo\Core\ORM\Entity as CoreEntity;
|
||||
use Espo\Core\Currency\Rates as CurrencyRates;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Field\Currency;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
use Espo\Core\Utils\FieldUtil;
|
||||
use Espo\Core\ORM\Repository\Option\SaveOption;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Entities\User;
|
||||
use Espo\Tools\Currency\Conversion\EntityConverterFactory;
|
||||
use RuntimeException;
|
||||
|
||||
class ConvertCurrency implements Action
|
||||
{
|
||||
public function __construct(
|
||||
private EntityConverterFactory $converterFactory,
|
||||
private Acl $acl,
|
||||
private EntityManager $entityManager,
|
||||
private FieldUtil $fieldUtil,
|
||||
private Metadata $metadata,
|
||||
private CurrencyConfigDataProvider $configDataProvider,
|
||||
private CurrencyConverter $currencyConverter
|
||||
private User $user
|
||||
) {}
|
||||
|
||||
public function process(Params $params, Data $data): void
|
||||
@@ -65,22 +67,16 @@ class ConvertCurrency implements Action
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$fieldList = $this->getFieldList($entityType, $data);
|
||||
|
||||
if (empty($fieldList)) {
|
||||
throw new Forbidden("No fields to convert.");
|
||||
}
|
||||
$this->checkFieldAccess($entityType);
|
||||
|
||||
$baseCurrency = $this->configDataProvider->getBaseCurrency();
|
||||
|
||||
$targetCurrency = $data->get('targetCurrency');
|
||||
|
||||
if (!$targetCurrency) {
|
||||
throw new BadRequest("No target currency.");
|
||||
}
|
||||
|
||||
$rates =
|
||||
$this->getRatesFromData($data) ??
|
||||
$rates = $this->getRatesFromData($data) ??
|
||||
$this->configDataProvider->getCurrencyRates();
|
||||
|
||||
if ($targetCurrency !== $baseCurrency && !$rates->hasRate($targetCurrency)) {
|
||||
@@ -94,56 +90,21 @@ class ConvertCurrency implements Action
|
||||
}
|
||||
|
||||
if (!$this->acl->checkEntityEdit($entity)) {
|
||||
throw new Forbidden();
|
||||
throw new Forbidden("No 'edit' access.");
|
||||
}
|
||||
|
||||
$this->convertEntity($entity, $fieldList, $targetCurrency, $rates);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $fieldList
|
||||
*/
|
||||
protected function convertEntity(
|
||||
Entity $entity,
|
||||
array $fieldList,
|
||||
string $targetCurrency,
|
||||
CurrencyRates $rates
|
||||
): void {
|
||||
|
||||
$entityDefs = $this->entityManager
|
||||
->getDefs()
|
||||
->getEntity($entity->getEntityType());
|
||||
|
||||
foreach ($fieldList as $field) {
|
||||
$disabled = $entityDefs->getField($field)->getParam('conversionDisabled');
|
||||
|
||||
if ($disabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$amount = $entity->get($field);
|
||||
$code = $entity->get($field . 'Currency');
|
||||
|
||||
if ($amount === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($targetCurrency === $code) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = new Currency($amount, $code);
|
||||
|
||||
$convertedValue = $this->currencyConverter->convertWithRates($value, $targetCurrency, $rates);
|
||||
|
||||
$entity->set($field, $convertedValue->getAmount());
|
||||
$entity->set($field . 'Currency', $convertedValue->getCode());
|
||||
if (!$entity instanceof CoreEntity) {
|
||||
throw new RuntimeException("Only Core-Entity allowed.");
|
||||
}
|
||||
|
||||
$this->entityManager->saveEntity($entity);
|
||||
$converter = $this->converterFactory->create($entityType);
|
||||
|
||||
$converter->convert($entity, $targetCurrency, $rates);
|
||||
|
||||
$this->entityManager->saveEntity($entity, [SaveOption::MODIFIED_BY_ID => $this->user->getId()]);
|
||||
}
|
||||
|
||||
protected function getRatesFromData(Data $data): ?CurrencyRates
|
||||
private function getRatesFromData(Data $data): ?CurrencyRates
|
||||
{
|
||||
if ($data->get('rates') === null) {
|
||||
return null;
|
||||
@@ -152,37 +113,27 @@ class ConvertCurrency implements Action
|
||||
$baseCurrency = $this->configDataProvider->getBaseCurrency();
|
||||
|
||||
$ratesArray = get_object_vars($data->get('rates'));
|
||||
|
||||
$ratesArray[$baseCurrency] = 1.0;
|
||||
|
||||
return CurrencyRates::fromAssoc($ratesArray, $baseCurrency);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* @throws Forbidden
|
||||
*/
|
||||
protected function getFieldList(string $entityType, Data $data): array
|
||||
private function checkFieldAccess(string $entityType): void
|
||||
{
|
||||
$forbiddenFieldList = $this->acl->getScopeForbiddenFieldList($entityType, 'edit');
|
||||
/** @var string[] $requiredFieldList */
|
||||
$requiredFieldList = $this->metadata->get(['scopes', $entityType, 'currencyConversionAccessRequiredFieldList']);
|
||||
|
||||
$resultList = [];
|
||||
|
||||
$fieldList = $data->get('fieldList') ?? $this->fieldUtil->getEntityTypeFieldList($entityType);
|
||||
|
||||
foreach ($fieldList as $field) {
|
||||
$type = $this->metadata->get(['entityDefs', $entityType, 'fields', $field, 'type']);
|
||||
|
||||
if ($type !== 'currency') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($field, $forbiddenFieldList)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$resultList[] = $field;
|
||||
if ($requiredFieldList === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $resultList;
|
||||
foreach ($requiredFieldList as $field) {
|
||||
if (!$this->acl->checkField($entityType, $field, Table::ACTION_EDIT)) {
|
||||
throw new Forbidden("No edit access to field `$field`.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,12 +35,11 @@ use Espo\Core\Action\Params;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
use Espo\Core\Record\ActionHistory\Action;
|
||||
use Espo\Core\Record\ServiceContainer;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Core\Utils\ObjectUtil;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Entities\EmailAddress;
|
||||
use Espo\Entities\PhoneNumber;
|
||||
|
||||
@@ -83,6 +82,8 @@ class Merger
|
||||
|
||||
$entity->set($clonedData);
|
||||
|
||||
$this->unsetNotActualAttributes($entity);
|
||||
|
||||
if (!$service->checkAssignment($entity)) {
|
||||
throw new Forbidden("Assignment permission failure.");
|
||||
}
|
||||
@@ -136,7 +137,7 @@ class Merger
|
||||
foreach ($sourceEntityList as $sourceEntity) {
|
||||
$this->entityManager->removeEntity($sourceEntity);
|
||||
|
||||
$service->processActionHistoryRecord('delete', $sourceEntity);
|
||||
$service->processActionHistoryRecord(Action::DELETE, $sourceEntity);
|
||||
}
|
||||
|
||||
if ($hasPhoneNumber) {
|
||||
@@ -151,7 +152,7 @@ class Merger
|
||||
|
||||
$this->entityManager->saveEntity($entity);
|
||||
|
||||
$service->processActionHistoryRecord('update', $entity);
|
||||
$service->processActionHistoryRecord(Action::UPDATE, $entity);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -365,4 +366,20 @@ class Merger
|
||||
|
||||
$data->emailAddressData = $emailAddressData;
|
||||
}
|
||||
|
||||
private function unsetNotActualAttributes(Entity $entity): void
|
||||
{
|
||||
$fieldDefsList = $this->entityManager
|
||||
->getDefs()
|
||||
->getEntity($entity->getEntityType())
|
||||
->getFieldList();
|
||||
|
||||
foreach ($fieldDefsList as $fieldDefs) {
|
||||
$field = $fieldDefs->getName();
|
||||
|
||||
if ($fieldDefs->getType() === 'link' && $entity->isAttributeChanged($field . 'Id')) {
|
||||
$entity->clear($field . 'Name');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user