mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-09 06:27:01 +00:00
Compare commits
1731 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 | ||
|
|
506e96e333 | ||
|
|
76a9177c46 | ||
|
|
a8baac3f92 | ||
|
|
8d9d073c16 | ||
|
|
177ecdb70b | ||
|
|
89ce80d5b2 | ||
|
|
7f07175bee | ||
|
|
8bca35934c | ||
|
|
65bef1df65 | ||
|
|
922a2e835c | ||
|
|
048c83def8 | ||
|
|
cf4a8c6c11 | ||
|
|
7259142117 | ||
|
|
746398c5ca | ||
|
|
6a61772e43 | ||
|
|
2412fb5151 | ||
|
|
5e5a229366 | ||
|
|
5d27a7a828 | ||
|
|
82cc4a7f03 | ||
|
|
d2033c53fc | ||
|
|
86043a5ce5 | ||
|
|
1fae4ac84b | ||
|
|
6301ba491c | ||
|
|
defe9965d4 | ||
|
|
937ad48841 | ||
|
|
781030df60 | ||
|
|
9b009962a5 | ||
|
|
255b6637ff | ||
|
|
28d1c052d2 | ||
|
|
828d8da741 | ||
|
|
54688795e2 | ||
|
|
6414a13c6f | ||
|
|
c48f17449b | ||
|
|
cbf65feb09 | ||
|
|
f1a3021c1c | ||
|
|
b70327874e | ||
|
|
9345ada934 | ||
|
|
92c66a3b9a | ||
|
|
c78f84650c | ||
|
|
cf1692a8a4 | ||
|
|
94321b3500 | ||
|
|
2010d16d4d | ||
|
|
c1a1e1094a | ||
|
|
c2fefd6227 | ||
|
|
99946c8da5 | ||
|
|
86c2478721 | ||
|
|
5331332103 | ||
|
|
0e380e1c10 | ||
|
|
c54dbdc169 | ||
|
|
f88261a40a | ||
|
|
7ec8d1f69c | ||
|
|
77ce0a3b4e | ||
|
|
134bde3370 | ||
|
|
811c841420 | ||
|
|
48751813fb | ||
|
|
79c182d173 | ||
|
|
87a612a1bc | ||
|
|
388da3db70 | ||
|
|
60fdeafd77 | ||
|
|
2057534f19 | ||
|
|
b85f60b855 | ||
|
|
b4d02130fb | ||
|
|
9a9d924b19 | ||
|
|
1fb06f60e0 | ||
|
|
9d65855868 | ||
|
|
8cf2e270a5 | ||
|
|
07ebd43ac6 | ||
|
|
b1447a2922 | ||
|
|
66b85bf4e9 | ||
|
|
e9b58926b4 | ||
|
|
75724b28b2 | ||
|
|
79f0730257 | ||
|
|
13abed67f2 | ||
|
|
84b98c1cfe | ||
|
|
bc557706ca | ||
|
|
2ef0f5f80e | ||
|
|
33db2270d6 | ||
|
|
6810ee37ac | ||
|
|
9e25804f89 | ||
|
|
42d30a3f8e | ||
|
|
524f94cd54 | ||
|
|
739230c4b9 | ||
|
|
caeadc2f28 | ||
|
|
fd330f991c | ||
|
|
e09bf8fa31 | ||
|
|
2ea60e66ba | ||
|
|
f184e34838 | ||
|
|
d721e9b448 | ||
|
|
e1241eddb7 | ||
|
|
c693654e80 | ||
|
|
9d0f3dadad | ||
|
|
2c4033f363 | ||
|
|
3c62414c8d | ||
|
|
9dddd0b92f | ||
|
|
2284a3e2e5 | ||
|
|
60d83b138a | ||
|
|
c94d41a79c | ||
|
|
fc78cd28a6 | ||
|
|
b0e01a1fcb | ||
|
|
41222f8e9e | ||
|
|
64baaa5253 | ||
|
|
35a0f14d28 | ||
|
|
9bb2197717 | ||
|
|
1607240f5d | ||
|
|
8be1af0671 | ||
|
|
58ac0800f9 | ||
|
|
2acac3d0b0 | ||
|
|
5e44fc2d40 | ||
|
|
2b08f83ac2 | ||
|
|
cc1bfce3dd | ||
|
|
08647b3ed6 | ||
|
|
b97f4ee124 | ||
|
|
d4e73f500f | ||
|
|
5e13e6cf99 | ||
|
|
3fd06a89f1 | ||
|
|
6678500d1b | ||
|
|
1a6f236dc7 | ||
|
|
f57a95349a | ||
|
|
b3496268e0 | ||
|
|
fa38ece181 | ||
|
|
5866f02eca | ||
|
|
6edce56ca7 | ||
|
|
3dc239acc5 | ||
|
|
385c70845a | ||
|
|
4f65a46434 | ||
|
|
a9c4689500 | ||
|
|
75b544a995 | ||
|
|
451d5e5659 | ||
|
|
134f5862dd | ||
|
|
b59279ab16 | ||
|
|
0621c8aefc | ||
|
|
3229ba1043 | ||
|
|
06868b8b57 | ||
|
|
fce1d49407 | ||
|
|
8c2cf02891 | ||
|
|
ccdafc67b5 | ||
|
|
b6a470c52e | ||
|
|
76c63bede4 | ||
|
|
837e96c061 | ||
|
|
2bebe4b045 | ||
|
|
9ee1b41b52 | ||
|
|
f18a3043eb | ||
|
|
01d5f1a07f | ||
|
|
06b31d537f | ||
|
|
989a04dddf | ||
|
|
055e968660 | ||
|
|
585512773d | ||
|
|
71f4abeb97 | ||
|
|
4f973e057e | ||
|
|
416bf152f0 | ||
|
|
3f473617c0 | ||
|
|
56766e2246 | ||
|
|
a92e44bd6c | ||
|
|
369f3ba9a5 | ||
|
|
2d62c902cb | ||
|
|
5985b6d93f | ||
|
|
587bda5c73 | ||
|
|
230a9aced0 | ||
|
|
023b0ea892 | ||
|
|
2578b397e7 | ||
|
|
0659b30588 | ||
|
|
0afd5e1d73 | ||
|
|
f824d8eaf5 | ||
|
|
abab4e2061 | ||
|
|
36c6883743 | ||
|
|
9c44f79b4d | ||
|
|
cd3c7b1407 | ||
|
|
6afd616e42 | ||
|
|
7aabbc5d28 | ||
|
|
9589b0b70a | ||
|
|
8822104227 | ||
|
|
e34e6b5d9a | ||
|
|
6341492965 | ||
|
|
aeece9acda | ||
|
|
f5823d04dd | ||
|
|
28df6738e2 | ||
|
|
0e371ebe04 | ||
|
|
6fe4034237 | ||
|
|
48c3ea5f13 | ||
|
|
da5b1cf005 | ||
|
|
2655f0d9c5 | ||
|
|
e11e3d6168 | ||
|
|
90806c0e82 | ||
|
|
ca9f25636b | ||
|
|
abcc290a7c | ||
|
|
091b64dd3d | ||
|
|
8fd8434d68 | ||
|
|
9ef5c0bc1b | ||
|
|
8adfb80558 | ||
|
|
5ccbf49773 | ||
|
|
e2cde84447 | ||
|
|
26e7f3dfd2 | ||
|
|
6a75b28f8c | ||
|
|
e8b6db20a2 | ||
|
|
9e37739197 | ||
|
|
f0b49cd467 | ||
|
|
aae918886f | ||
|
|
cbf0a82c52 | ||
|
|
fb7683e35b | ||
|
|
105bb8a80f | ||
|
|
eab0596c33 | ||
|
|
7e84278cef | ||
|
|
f2a27c024f | ||
|
|
1b76097311 | ||
|
|
ae23f58bf5 | ||
|
|
f3bf7d93c1 | ||
|
|
656ff76a8d | ||
|
|
c72bcc365a | ||
|
|
f58687ad6b | ||
|
|
aefe547ef8 | ||
|
|
3619696b12 | ||
|
|
40d0ad5d08 | ||
|
|
c9d3a3f967 | ||
|
|
0b1f7d1548 | ||
|
|
59cee9a2ee | ||
|
|
e7373ab817 | ||
|
|
9570a28066 | ||
|
|
b3f7242bae | ||
|
|
823d371e9d | ||
|
|
2399d21829 | ||
|
|
01d5091aa3 | ||
|
|
ed867d1b95 | ||
|
|
3392c843e6 | ||
|
|
1e29280a1d | ||
|
|
aeecd1f3a6 | ||
|
|
5ecce30720 | ||
|
|
c02f87d1c0 | ||
|
|
929dce6b2e | ||
|
|
c82d35af27 | ||
|
|
a0a0b22d2f | ||
|
|
db3af5749c | ||
|
|
f1e13f4b95 | ||
|
|
9f43a0ff89 | ||
|
|
17bc8a6137 | ||
|
|
66b06b8baa | ||
|
|
1d6745396d | ||
|
|
4f53038578 | ||
|
|
79f5a7a94b | ||
|
|
77a433445b | ||
|
|
be54198265 | ||
|
|
7da892ba98 | ||
|
|
7b2526430a | ||
|
|
e416dac56f | ||
|
|
d11f0f4f1b | ||
|
|
f72fbed6e1 | ||
|
|
56fe4e2ef7 | ||
|
|
684a995e17 | ||
|
|
2f03572df8 | ||
|
|
5bb0222abd | ||
|
|
82cf211822 | ||
|
|
29fd164023 | ||
|
|
c52fedcf07 | ||
|
|
68b12ff848 | ||
|
|
a351af06a1 | ||
|
|
72c502b492 | ||
|
|
1047d243a2 | ||
|
|
5ab129bd9b | ||
|
|
6e5e940b30 | ||
|
|
fa577a4fa9 | ||
|
|
64f2c59134 | ||
|
|
a82408a06f | ||
|
|
b80d8830ba | ||
|
|
edcdf3c8be | ||
|
|
ae27f360ca | ||
|
|
474759ab6e | ||
|
|
02ea7cc041 | ||
|
|
0a67950913 | ||
|
|
4ef66b1601 | ||
|
|
33220d607a | ||
|
|
ac9f80312d | ||
|
|
0db2ee0a8d | ||
|
|
7d4ab54505 | ||
|
|
a06bfde766 | ||
|
|
46f333fced | ||
|
|
f9294c652d | ||
|
|
a22dc4b2fb | ||
|
|
b293086482 | ||
|
|
93139cb3ef | ||
|
|
1db70eeaa8 | ||
|
|
8ccda3fd2d | ||
|
|
60eb9008f7 | ||
|
|
635fa8b893 | ||
|
|
183603e09a | ||
|
|
3399b2cc01 | ||
|
|
9d4d441ec2 | ||
|
|
51bda2f5d2 | ||
|
|
92e62c7760 | ||
|
|
7bb204a432 | ||
|
|
39939191e5 | ||
|
|
aa43f29615 | ||
|
|
f109131d38 | ||
|
|
a6fb0bbded | ||
|
|
9b808908b6 | ||
|
|
0691a3cdda | ||
|
|
7208a4f88c | ||
|
|
7d37006450 | ||
|
|
73f1e425ca | ||
|
|
2336ae74da | ||
|
|
4419d0827a | ||
|
|
0d1bc90848 | ||
|
|
7665010bff | ||
|
|
5ba16b4c27 | ||
|
|
cbf6b0cc6b | ||
|
|
c51a51e110 | ||
|
|
b59ff42ac2 | ||
|
|
b635018949 | ||
|
|
fcb2a0b7a5 | ||
|
|
2048f3fa10 | ||
|
|
0fe7fb032f | ||
|
|
bb24b576e0 | ||
|
|
2a7a12f58c | ||
|
|
5ccb081af5 | ||
|
|
bf1ed3c287 | ||
|
|
ddcb5ccbf9 | ||
|
|
5b8dc4e629 | ||
|
|
1032b73b85 | ||
|
|
e7b914ff4b | ||
|
|
30e94f25e6 | ||
|
|
7fa7fe63f8 | ||
|
|
716a5b86ff | ||
|
|
a29ce1a873 | ||
|
|
ace2dc802a | ||
|
|
1018bfd4d4 | ||
|
|
cc828661da | ||
|
|
4c265dbae1 | ||
|
|
2615869691 | ||
|
|
fbbb7c99c0 | ||
|
|
da7fc9d6a0 | ||
|
|
9b63470e9a | ||
|
|
5879a57cd1 | ||
|
|
702b3f4e2b | ||
|
|
75749efacb | ||
|
|
854f6c6390 | ||
|
|
717c21e91b | ||
|
|
07f1100ccc | ||
|
|
3157bb4fcf | ||
|
|
a3a35be818 | ||
|
|
1c1042cd75 | ||
|
|
8f8eb4807d | ||
|
|
f97bb82d9e | ||
|
|
62b325c24b | ||
|
|
4051b83b30 | ||
|
|
75444b3e0b | ||
|
|
961a7bd0bf | ||
|
|
f4b09c0135 | ||
|
|
d09f83e267 | ||
|
|
b874cc283f | ||
|
|
b5873c9c1d | ||
|
|
89bde00e3b | ||
|
|
242de1824f | ||
|
|
02d277d045 | ||
|
|
76d31a3885 | ||
|
|
c6a8e36849 | ||
|
|
d88e47b508 | ||
|
|
46bd520b52 | ||
|
|
d9c0f7d055 | ||
|
|
4a9bd1b54c | ||
|
|
1626e4b6bf | ||
|
|
c1cfa0483a | ||
|
|
c7d5bc8169 | ||
|
|
37e091ddda | ||
|
|
a7c33afd93 | ||
|
|
f7678abad1 | ||
|
|
b181624064 | ||
|
|
8a6c63e12c | ||
|
|
aba1881a5c | ||
|
|
3350ffc0b7 | ||
|
|
c498d463e7 | ||
|
|
93c1f4ef8a | ||
|
|
54bf67e8bd | ||
|
|
59e852a285 | ||
|
|
dcbe24746e | ||
|
|
deb3ee0653 | ||
|
|
698db9ebd6 | ||
|
|
214cf538ad | ||
|
|
f578fd4af9 | ||
|
|
57c011ee94 | ||
|
|
e4285d1d2a | ||
|
|
5f4643d725 | ||
|
|
fcc13ef10c | ||
|
|
826c1734a2 | ||
|
|
849ddadb8c | ||
|
|
3e4bd12a76 | ||
|
|
e6aae5f4ed | ||
|
|
d8bd2f451f | ||
|
|
9c47341fc1 | ||
|
|
bbea0c0215 | ||
|
|
4e4e29e0f1 | ||
|
|
4658eb800e | ||
|
|
16a313f659 | ||
|
|
c2fcd8d86c | ||
|
|
8666a3977a | ||
|
|
fa06a437e5 | ||
|
|
0dcea2ad5b | ||
|
|
5a3142b252 | ||
|
|
4598b58fbb | ||
|
|
7ff9d85a11 | ||
|
|
89b912ee73 | ||
|
|
a4f75f1423 | ||
|
|
03a69cb364 | ||
|
|
e7fa98dc09 | ||
|
|
5eb49d6c3d | ||
|
|
1d84aad483 | ||
|
|
af847a8fe7 | ||
|
|
89d775a8a8 | ||
|
|
f09fe03f60 | ||
|
|
08a6a2c66b | ||
|
|
0a4a3938fb | ||
|
|
0bc05b4a6d | ||
|
|
b7ad2dd760 | ||
|
|
363842aff2 | ||
|
|
ac889dea91 | ||
|
|
89e31795cc | ||
|
|
9953ea8419 | ||
|
|
1ae1f07de2 | ||
|
|
b8386f3ea3 | ||
|
|
846b57842f | ||
|
|
6fcd0e155d | ||
|
|
3e945b7fd8 | ||
|
|
3fa7ddf9f8 | ||
|
|
5b8ccb4513 | ||
|
|
99464c5210 | ||
|
|
64c9fbf4f8 | ||
|
|
029d09e689 | ||
|
|
be27fc45ee | ||
|
|
0eefc5d75d | ||
|
|
876817ffe9 | ||
|
|
f6b3e33e7e | ||
|
|
24301b22a9 | ||
|
|
31be2f81ff | ||
|
|
bc435b0729 | ||
|
|
4cd0961f80 | ||
|
|
70edfbb88b | ||
|
|
9066a2bf97 | ||
|
|
b39bffa1f2 | ||
|
|
c49db089f5 | ||
|
|
2a110851df | ||
|
|
3e60103516 | ||
|
|
481b870565 | ||
|
|
9564d0807a | ||
|
|
785746c801 | ||
|
|
a89ac23625 | ||
|
|
adc2cb5a66 | ||
|
|
4b5787c0d0 | ||
|
|
dcbd2bfa42 | ||
|
|
147fcb02b6 | ||
|
|
1762096532 | ||
|
|
d21857075e | ||
|
|
a81759b0f1 | ||
|
|
99fb897b63 | ||
|
|
f6e7da57f7 | ||
|
|
aa001b4a7f | ||
|
|
fe3ab8b8a0 | ||
|
|
37c3cfc539 | ||
|
|
5cace584f1 | ||
|
|
da45d958b7 | ||
|
|
b6e7f5113f | ||
|
|
aaf095e32b | ||
|
|
282f701b77 | ||
|
|
ea8ba18d2e | ||
|
|
d08e969915 | ||
|
|
5567cc6938 | ||
|
|
720188822d | ||
|
|
48e0e53ab1 | ||
|
|
03c123d63e | ||
|
|
7d4ded2480 | ||
|
|
5d48dd090c | ||
|
|
785bc0ed6e | ||
|
|
1ce3825338 | ||
|
|
1fba05dd04 | ||
|
|
2c9b16a2d5 | ||
|
|
314b5bcd87 | ||
|
|
433af312cf | ||
|
|
30b18cf945 | ||
|
|
81b9991e6d | ||
|
|
84f3830eca | ||
|
|
cb878c70b5 | ||
|
|
8224eec990 | ||
|
|
d655ee92a2 | ||
|
|
a8d868e812 | ||
|
|
e5c400214a | ||
|
|
5be5275eda | ||
|
|
e61535ee92 | ||
|
|
e0abe23260 | ||
|
|
8d65a3256b | ||
|
|
d82c297b79 | ||
|
|
f7ed15c507 | ||
|
|
37b583d431 | ||
|
|
c3286c7c4a | ||
|
|
740c751d1b | ||
|
|
7e66f14e16 | ||
|
|
c3d0559260 | ||
|
|
27762e61a6 | ||
|
|
cdbeab8e47 | ||
|
|
15f337a319 | ||
|
|
dd0deeb967 | ||
|
|
80cce0b1ba | ||
|
|
b477c3420b | ||
|
|
72a1d73848 | ||
|
|
7d36e685b8 | ||
|
|
0559e21baf | ||
|
|
22e68e8fdf | ||
|
|
ad89d65a48 | ||
|
|
0a92ed8f39 | ||
|
|
48fa62105f | ||
|
|
7e354d560f | ||
|
|
bd1fdaf9d9 | ||
|
|
d5d19f2974 | ||
|
|
6e3c765ba3 | ||
|
|
ab87cff5bc | ||
|
|
a5280ec0ac | ||
|
|
6339690e58 | ||
|
|
c5ae2800b5 | ||
|
|
62501dc20d | ||
|
|
c7b7848e69 | ||
|
|
a3be63c6f1 | ||
|
|
52fe2ca1c9 | ||
|
|
6513513108 | ||
|
|
442d2c030b | ||
|
|
391500a1c1 | ||
|
|
f239d2c478 | ||
|
|
101f8a29a3 | ||
|
|
dfb846fb7e | ||
|
|
ecd6d5a558 | ||
|
|
048d54a7af | ||
|
|
5645066d68 | ||
|
|
923ecc883a | ||
|
|
59a95fa3bc | ||
|
|
4789c3c2ad | ||
|
|
c149aa8560 | ||
|
|
e9f5d99e9b | ||
|
|
4309dfb57a | ||
|
|
4ad0a22a6a | ||
|
|
2daff0eabb | ||
|
|
cde59bce55 | ||
|
|
80b9d0dc7b | ||
|
|
bfdaa4721d | ||
|
|
60db5cdc6c | ||
|
|
1a5a9060a6 | ||
|
|
ddf9dfba47 | ||
|
|
f93060a5ca | ||
|
|
7e5b491313 | ||
|
|
b083a11099 | ||
|
|
63f67e0f66 | ||
|
|
141c6430c4 | ||
|
|
b872e6960a | ||
|
|
8ba47b11ec | ||
|
|
883351eaf3 | ||
|
|
7976e6d5b5 | ||
|
|
8fcda8c621 | ||
|
|
c1b2870c91 | ||
|
|
2b4f6239f7 | ||
|
|
bae0144393 | ||
|
|
af21cc4400 | ||
|
|
f50d7717a9 | ||
|
|
03a79ddefe | ||
|
|
353246281c | ||
|
|
747d8220e1 | ||
|
|
b6a1648486 | ||
|
|
e0e168945c | ||
|
|
385d7af1b6 | ||
|
|
14811a7c1a | ||
|
|
c828242359 | ||
|
|
c4610c4e24 | ||
|
|
583ba47e78 | ||
|
|
a9e8d5b2b2 | ||
|
|
3c4e33f0c5 | ||
|
|
a0d39be19c | ||
|
|
83ef7b32b5 | ||
|
|
f365a38858 | ||
|
|
e6f081c7d1 | ||
|
|
f463421a33 | ||
|
|
49bb6771f6 | ||
|
|
28d8fcd31e | ||
|
|
008935f054 | ||
|
|
7ed90d7bbf | ||
|
|
7fdcb41547 | ||
|
|
7eca082d9f | ||
|
|
ab81d0fae6 | ||
|
|
3f84551b50 | ||
|
|
0e56c727ff | ||
|
|
c911c0f6e5 | ||
|
|
9e424f16d7 | ||
|
|
dcf1698dad | ||
|
|
8b92df3f6a | ||
|
|
c343a4600f | ||
|
|
d196a574fd | ||
|
|
72b2a456b9 | ||
|
|
d9d42fd664 | ||
|
|
a131308e1a | ||
|
|
aff948f0a6 | ||
|
|
0657d78eb5 | ||
|
|
4807beca0b | ||
|
|
8a26478019 | ||
|
|
3a9851c89b | ||
|
|
2824d8cd84 | ||
|
|
e041238d03 | ||
|
|
df36d33b98 | ||
|
|
f34ca2fe6b |
22
.github/CONTRIBUTING.md
vendored
22
.github/CONTRIBUTING.md
vendored
@@ -1,17 +1,25 @@
|
||||
## Pull Requests
|
||||
|
||||
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.
|
||||
Before we can merge your pull request, you need to accept our CLA [here](https://github.com/espocrm/cla).
|
||||
|
||||
See [Code Style Guidelines](https://github.com/espocrm/espocrm/wiki/Code-Style-Guidelines).
|
||||
It's desirable that one PR solves one specific problem. Do not include code style changes to PRs
|
||||
(unless the main purpose of the PR is a code style fix).
|
||||
|
||||
If you would like to contribute something that is not a small fix, it's reasonable to create an issue first
|
||||
(a bug report or feature request).
|
||||
|
||||
Branches:
|
||||
|
||||
* *hotfix/** – upcoming maintenance release; fixes should be pushed to this branch;
|
||||
* *master* – develop branch; new features should be pushed to this branch;
|
||||
* *stable* – last stable release.
|
||||
* *master* – the develop branch; new features should be pushed to here;
|
||||
* *fix* – the upcoming maintenance release; small fixes should be pushed to here.
|
||||
|
||||
## Issues
|
||||
|
||||
When reporting a possible bug please provide detail steps so that we will be able to reproduce the issue. Please try not to use phrases like "very big bug", "huge issue", etc. No need to use exclamation marks as well.
|
||||
We'd appreciate if you prefer posting issues on weekdays rather than weekends.
|
||||
|
||||
Note that we don't provide developer help or any kind of support on Github. Please use our [forum](https://forum.espocrm.com) for this.
|
||||
When reporting a possible bug, please provide detail steps so that we will be able
|
||||
to reproduce the issue. Please try not to use phrases like "very big bug",
|
||||
"huge issue", etc. No need to use exclamation marks as well.
|
||||
|
||||
Note that we don't provide developer help or any kind of support on GitHub.
|
||||
For this, please use our [forum](https://forum.espocrm.com).
|
||||
|
||||
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: ''
|
||||
|
||||
2
.github/SECURITY.md
vendored
2
.github/SECURITY.md
vendored
@@ -2,7 +2,7 @@
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
If you believe you have discovered a vulnerability in EspoCRM please contacts us via [this](https://www.espocrm.com/contacts/) or [this](https://www.espocrm.com/support/) forms.
|
||||
If you believe you have discovered a vulnerability in EspoCRM, please contacts us via [this](https://www.espocrm.com/contacts/) or [this](https://www.espocrm.com/support/) forms. Or create a private vulnerability report on GitHub.
|
||||
|
||||
## Supported versions
|
||||
|
||||
|
||||
63
.github/workflows/test-integration-pg.yml
vendored
Normal file
63
.github/workflows/test-integration-pg.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
name: Test Integration on PostgreSQL
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 11 * * *'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test on PHP ${{ matrix.php-versions }}
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
TEST_DATABASE_HOST: '127.0.0.1'
|
||||
TEST_DATABASE_PLATFORM: 'Postgresql'
|
||||
TEST_DATABASE_CHARSET: 'utf8'
|
||||
TEST_DATABASE_PORT: '8888'
|
||||
TEST_DATABASE_NAME: integration_test
|
||||
TEST_DATABASE_USER: postgres
|
||||
TEST_DATABASE_PASSWORD: password
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15.2
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: password
|
||||
POSTGRES_DB: integration_test
|
||||
ports:
|
||||
- '8888:5432'
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['8.2']
|
||||
branches: ['master']
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ matrix.branches }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
- name: Setup PHP with Composer
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
tools: composer:v2
|
||||
ini-values: memory_limit=1024M
|
||||
|
||||
- name: NPM install
|
||||
run: npm install
|
||||
|
||||
- name: Build
|
||||
run: grunt test
|
||||
|
||||
- name: Integration testing
|
||||
run: vendor/bin/phpunit --testsuite integration-pg
|
||||
1
.idea/.gitignore
generated
vendored
1
.idea/.gitignore
generated
vendored
@@ -4,3 +4,4 @@
|
||||
!/fileTemplates
|
||||
!/inspectionProfiles
|
||||
!misc.xml
|
||||
!jsonSchemas.xml
|
||||
|
||||
8
.idea/codeStyles/Project.xml
generated
8
.idea/codeStyles/Project.xml
generated
@@ -1,11 +1,19 @@
|
||||
<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" />
|
||||
<option name="KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE" value="true" />
|
||||
<option name="FORCE_EMPTY_METHODS_IN_ONE_LINE" value="true" />
|
||||
</PHPCodeStyleSettings>
|
||||
<codeStyleSettings language="JSON">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="PHP">
|
||||
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
|
||||
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
|
||||
|
||||
3
.idea/inspectionProfiles/Project_Default.xml
generated
3
.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" />
|
||||
@@ -14,6 +15,8 @@
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PhpSwitchStatementWitSingleBranchInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PsalmAdvanceCallableParamsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="TrivialIfJS" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
95
Gruntfile.js
95
Gruntfile.js
@@ -21,10 +21,10 @@
|
||||
|
||||
/**
|
||||
* * `grunt` - full build;
|
||||
* * `grunt dev` - build only items needed for development (takes less time);
|
||||
* * `grunt dev` - build for development;
|
||||
* * `grunt offline` - build but skip *composer install*;
|
||||
* * `grunt internal` - build only libs and css;
|
||||
* * `grunt release` - full build plus upgrade packages`;
|
||||
* * `grunt release` - full build zipped with upgrade packages`;
|
||||
* * `grunt test` - build for tests running;
|
||||
* * `grunt run-tests` - build and run unit and integration tests.
|
||||
*/
|
||||
@@ -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',
|
||||
@@ -503,7 +553,8 @@ module.exports = grunt => {
|
||||
|
||||
grunt.registerTask('dev', [
|
||||
'composer-install-dev',
|
||||
'less',
|
||||
'npm-install',
|
||||
'internal',
|
||||
]);
|
||||
|
||||
grunt.registerTask('test', [
|
||||
|
||||
52
README.md
52
README.md
@@ -2,47 +2,73 @@
|
||||
|
||||
[](#espocrm)
|
||||
|
||||
[EspoCRM is an Open Source CRM](https://www.espocrm.com) (Customer Relationship Management) software that allows you to see, enter and evaluate all your company relationships regardless of the type. People, companies or opportunities – all in an easy and intuitive interface.
|
||||
[EspoCRM is an Open Source CRM](https://www.espocrm.com) (Customer Relationship Management)
|
||||
software that allows you to see, enter and evaluate all your company relationships regardless
|
||||
of the type. People, companies or opportunities – all in an easy and intuitive interface.
|
||||
|
||||
It's a web application with a frontend designed as a single page application and REST API backend written in PHP.
|
||||
It's a web application with a frontend designed as a single page application and REST API
|
||||
backend written in PHP.
|
||||
|
||||
[Download](https://www.espocrm.com/download/) the latest release from our website.
|
||||
[Download](https://www.espocrm.com/download/) the latest release from our website. Release notes
|
||||
and release packages are available at [Releases](https://github.com/espocrm/espocrm/releases) on GitHub.
|
||||
|
||||

|
||||
|
||||
### Demo
|
||||
|
||||
You can try the CRM on the online [demo](https://www.espocrm.com/demo/).
|
||||
|
||||
### Requirements
|
||||
|
||||
* PHP 8.0 and later;
|
||||
* MySQL 5.7 (and later), or MariaDB 10.1 (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](http://forum.espocrm.com/forum/bug-reports).
|
||||
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/) about 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.
|
||||
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.
|
||||
|
||||
Branches:
|
||||
|
||||
* *fix* – upcoming maintenance release; fixes should be pushed to this branch;
|
||||
* *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).
|
||||
|
||||
@@ -44,6 +44,7 @@ class Binding implements BindingProcessor
|
||||
public function process(Binder $binder): void
|
||||
{
|
||||
$this->bindServices($binder);
|
||||
$this->bindCore($binder);
|
||||
$this->bindMisc($binder);
|
||||
$this->bindAcl($binder);
|
||||
$this->bindWebSocket($binder);
|
||||
@@ -63,7 +64,12 @@ class Binding implements BindingProcessor
|
||||
);
|
||||
|
||||
$binder->bindService(
|
||||
'Espo\\Core\\Container\\Container',
|
||||
'Espo\\Core\\Container',
|
||||
'container'
|
||||
);
|
||||
|
||||
$binder->bindService(
|
||||
'Psr\\Container\\ContainerInterface',
|
||||
'container'
|
||||
);
|
||||
|
||||
@@ -72,6 +78,16 @@ class Binding implements BindingProcessor
|
||||
'module'
|
||||
);
|
||||
|
||||
$binder->bindService(
|
||||
'Espo\\Core\\Utils\\Config',
|
||||
'config'
|
||||
);
|
||||
|
||||
$binder->bindService(
|
||||
'Espo\\Core\\Utils\\File\\Manager',
|
||||
'fileManager'
|
||||
);
|
||||
|
||||
$binder->bindService(
|
||||
'Espo\\ORM\\EntityManager',
|
||||
'entityManager'
|
||||
@@ -208,8 +224,8 @@ class Binding implements BindingProcessor
|
||||
);
|
||||
|
||||
$binder->bindService(
|
||||
'Espo\\Core\\Acl',
|
||||
'acl'
|
||||
'Espo\\Core\\Utils\\ClientManager',
|
||||
'clientManager'
|
||||
);
|
||||
|
||||
$binder->bindService(
|
||||
@@ -218,6 +234,19 @@ class Binding implements BindingProcessor
|
||||
);
|
||||
}
|
||||
|
||||
private function bindCore(Binder $binder): void
|
||||
{
|
||||
$binder->bindImplementation(
|
||||
'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
|
||||
{
|
||||
$binder->bindImplementation(
|
||||
@@ -246,7 +275,7 @@ class Binding implements BindingProcessor
|
||||
->for('Espo\\Core\\Authentication\\Oidc\\Login')
|
||||
->bindImplementation(
|
||||
'Espo\\Core\\Authentication\\Oidc\\UserProvider',
|
||||
'Espo\\Core\\Authentication\\Oidc\\DefaultUserProvider'
|
||||
'Espo\\Core\\Authentication\\Oidc\\UserProvider\\DefaultUserProvider'
|
||||
);
|
||||
|
||||
$binder->bindImplementation(
|
||||
@@ -258,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
|
||||
{
|
||||
|
||||
102
application/Espo/Classes/ConsoleCommands/CreateAdminUser.php
Normal file
102
application/Espo/Classes/ConsoleCommands/CreateAdminUser.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?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\ConsoleCommands;
|
||||
|
||||
use Espo\Core\Console\Command;
|
||||
use Espo\Core\Console\Command\Params;
|
||||
use Espo\Core\Console\IO;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class CreateAdminUser implements Command
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManager $entityManager,
|
||||
private Config $config
|
||||
) {}
|
||||
|
||||
public function run(Params $params, IO $io): void
|
||||
{
|
||||
$userName = $params->getArgument(0);
|
||||
|
||||
if (!$userName) {
|
||||
$io->writeLine("A username must be specified as the first argument.");
|
||||
$io->setExitStatus(1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var ?string $regExp */
|
||||
$regExp = $this->config->get('userNameRegularExpression');
|
||||
|
||||
if (!$regExp) {
|
||||
throw new RuntimeException("No `userNameRegularExpression` in config.");
|
||||
}
|
||||
|
||||
if (
|
||||
str_contains($userName, ' ') ||
|
||||
preg_replace("/{$regExp}/", '_', $userName) !== $userName
|
||||
) {
|
||||
$io->writeLine("Not allowed username.");
|
||||
$io->setExitStatus(1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$repository = $this->entityManager->getRDBRepositoryByClass(User::class);
|
||||
|
||||
$existingUser = $repository
|
||||
->where(['userName' => $userName])
|
||||
->findOne();
|
||||
|
||||
if ($existingUser) {
|
||||
$io->writeLine("A user with the same username already exists.");
|
||||
$io->setExitStatus(1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$user = $repository->getNew();
|
||||
|
||||
$user->set('userName', $userName);
|
||||
$user->set('type', User::TYPE_ADMIN);
|
||||
$user->set('name', $userName);
|
||||
|
||||
$repository->save($user);
|
||||
|
||||
$message = "The user '{$userName}' has been created. " .
|
||||
"Set password with the command: `bin/command set-password {$userName}`.";
|
||||
|
||||
$io->writeLine($message);
|
||||
}
|
||||
}
|
||||
@@ -32,26 +32,16 @@ namespace Espo\Classes\ConsoleCommands;
|
||||
use Espo\Tools\Import\Service;
|
||||
|
||||
use Espo\Core\Utils\File\Manager as FileManager;
|
||||
|
||||
use Espo\Core\{
|
||||
Console\Command,
|
||||
Console\Command\Params,
|
||||
Console\IO,
|
||||
};
|
||||
use Espo\Core\Console\Command;
|
||||
use Espo\Core\Console\Command\Params;
|
||||
use Espo\Core\Console\IO;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class Import implements Command
|
||||
{
|
||||
private Service $service;
|
||||
|
||||
private FileManager $fileManager;
|
||||
|
||||
public function __construct(Service $service, FileManager $fileManager)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->fileManager = $fileManager;
|
||||
}
|
||||
public function __construct(private Service $service, private FileManager $fileManager)
|
||||
{}
|
||||
|
||||
public function run(Params $params, IO $io) : void
|
||||
{
|
||||
|
||||
@@ -63,7 +63,7 @@ class PopulateNumbers implements Command
|
||||
$field = $params->getArgument(1);
|
||||
|
||||
$orderBy = $params->getOption('orderBy') ?? 'createdAt';
|
||||
$order = $params->getOption('order') ?? Order::ASC;
|
||||
$order = strtoupper($params->getOption('order') ?? Order::ASC);
|
||||
|
||||
if (!$entityType) {
|
||||
throw new ArgumentNotSpecified("No entity type argument.");
|
||||
@@ -73,6 +73,10 @@ class PopulateNumbers implements Command
|
||||
throw new ArgumentNotSpecified("No field argument.");
|
||||
}
|
||||
|
||||
if ($order !== Order::ASC && $order !== Order::DESC) {
|
||||
throw new InvalidArgument("Bad order option.");
|
||||
}
|
||||
|
||||
$fieldType = $this->entityManager
|
||||
->getDefs()
|
||||
->getEntity($entityType)
|
||||
|
||||
@@ -29,86 +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\{
|
||||
Query\Part\Condition as Cond,
|
||||
Query\Part\WhereItem,
|
||||
Query\Part\Where\OrGroup,
|
||||
Entity,
|
||||
};
|
||||
|
||||
/**
|
||||
* @implements WhereBuilder<CoreEntity>
|
||||
*/
|
||||
class Company implements WhereBuilder
|
||||
{
|
||||
public function build(Entity $entity): ?WhereItem
|
||||
{
|
||||
assert($entity instanceof CoreEntity);
|
||||
|
||||
$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 [];
|
||||
}
|
||||
}
|
||||
54
application/Espo/Classes/DuplicateWhereBuilders/Name.php
Normal file
54
application/Espo/Classes/DuplicateWhereBuilders/Name.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?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\ORM\Entity;
|
||||
use Espo\ORM\Query\Part\Condition as Cond;
|
||||
use Espo\ORM\Query\Part\WhereItem;
|
||||
|
||||
/**
|
||||
* @implements WhereBuilder<Entity>
|
||||
*/
|
||||
class Name implements WhereBuilder
|
||||
{
|
||||
public function build(Entity $entity): ?WhereItem
|
||||
{
|
||||
if ($entity->get('name')) {
|
||||
return Cond::equal(
|
||||
Cond::column('name'),
|
||||
$entity->get('name')
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -29,95 +29,5 @@
|
||||
|
||||
namespace Espo\Classes\DuplicateWhereBuilders;
|
||||
|
||||
use Espo\Core\ORM\Entity as CoreEntity;
|
||||
|
||||
use Espo\Core\{
|
||||
Duplicate\WhereBuilder,
|
||||
Field\EmailAddressGroup,
|
||||
};
|
||||
|
||||
use Espo\ORM\{
|
||||
Query\Part\Condition as Cond,
|
||||
Query\Part\WhereItem,
|
||||
Query\Part\Where\OrGroup,
|
||||
Entity,
|
||||
};
|
||||
|
||||
/**
|
||||
* @implements WhereBuilder<CoreEntity>
|
||||
*/
|
||||
class Person implements WhereBuilder
|
||||
{
|
||||
public function build(Entity $entity): ?WhereItem
|
||||
{
|
||||
assert($entity instanceof CoreEntity);
|
||||
|
||||
$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)
|
||||
{
|
||||
|
||||
@@ -38,17 +38,10 @@ use stdClass;
|
||||
|
||||
class ArrayType
|
||||
{
|
||||
private Metadata $metadata;
|
||||
private const DEFAULT_MAX_ITEM_LENGTH = 100;
|
||||
|
||||
private Defs $defs;
|
||||
|
||||
private const DEFAULT_MAX_LENGTH = 100;
|
||||
|
||||
public function __construct(Metadata $metadata, Defs $defs)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
$this->defs = $defs;
|
||||
}
|
||||
public function __construct(protected Metadata $metadata, private Defs $defs)
|
||||
{}
|
||||
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
@@ -135,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 ?
|
||||
@@ -181,15 +182,15 @@ class ArrayType
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkMaxLength(Entity $entity, string $field, ?int $validationValue): bool
|
||||
public function checkMaxItemLength(Entity $entity, string $field, ?int $validationValue): bool
|
||||
{
|
||||
$maxLength = $validationValue ?? self::DEFAULT_MAX_LENGTH;
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?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\AuthenticationProvider;
|
||||
|
||||
use Espo\Core\FieldValidation\Validator;
|
||||
use Espo\Core\FieldValidation\Validator\Data;
|
||||
use Espo\Core\FieldValidation\Validator\Failure;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Entities\AuthenticationProvider;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
/**
|
||||
* @implements Validator<AuthenticationProvider>
|
||||
*/
|
||||
class MethodValid implements Validator
|
||||
{
|
||||
public function __construct(private Metadata $metadata) {}
|
||||
|
||||
public function validate(Entity $entity, string $field, Data $data): ?Failure
|
||||
{
|
||||
$value = $entity->get($field);
|
||||
|
||||
if (!$value) {
|
||||
return Failure::create();
|
||||
}
|
||||
|
||||
$isAvailable = $this->metadata->get(['authenticationMethods', $value, 'provider', 'isAvailable']);
|
||||
|
||||
if (!$isAvailable) {
|
||||
return Failure::create();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -29,11 +29,15 @@
|
||||
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\Core\Field\Currency;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\ORM\BaseEntity;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class CurrencyType extends FloatType
|
||||
{
|
||||
private const DEFAULT_PRECISION = 13;
|
||||
|
||||
public function __construct(private Config $config) {}
|
||||
|
||||
protected function isNotEmpty(Entity $entity, string $field): bool
|
||||
@@ -44,6 +48,62 @@ class CurrencyType extends FloatType
|
||||
$entity->get($field . 'Currency') !== '';
|
||||
}
|
||||
|
||||
public function checkValid(Entity $entity, string $field): bool
|
||||
{
|
||||
if (!$this->isNotEmpty($entity, $field)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($entity->getAttributeType($field) !== Entity::VARCHAR) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var string $value */
|
||||
$value = $entity->get($field);
|
||||
|
||||
if (preg_match('/-?[0-9]+\\.?[0-9]*/', $value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkInPermittedRange(Entity $entity, string $field): bool
|
||||
{
|
||||
if (!$this->isNotEmpty($entity, $field)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($entity->getAttributeType($field) !== Entity::VARCHAR) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$entity instanceof BaseEntity) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var int $precision */
|
||||
$precision = $entity->getAttributeParam($field, 'precision') ?? self::DEFAULT_PRECISION;
|
||||
|
||||
$value = $entity->get($field);
|
||||
|
||||
$currency = Currency::create($value, 'USD');
|
||||
|
||||
if ($currency->isNegative()) {
|
||||
$currency = $currency->multiply(-1);
|
||||
}
|
||||
|
||||
$pad = str_pad('', $precision, '9');
|
||||
|
||||
$limit = Currency::create($pad, 'USD');
|
||||
|
||||
if ($currency->compare($limit) === 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkValidCurrency(Entity $entity, string $field): bool
|
||||
{
|
||||
$attribute = $field . 'Currency';
|
||||
@@ -55,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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?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\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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ class Cleanup implements JobDataLess
|
||||
->from($scope)
|
||||
->withDeleted()
|
||||
->where([
|
||||
'deleted' => 1,
|
||||
'deleted' => true,
|
||||
'modifiedAt<' => $datetime->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT),
|
||||
'modifiedAt>' => $datetimeFrom->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT),
|
||||
])
|
||||
@@ -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;
|
||||
@@ -760,9 +758,18 @@ class Cleanup implements JobDataLess
|
||||
$service = $this->recordServiceContainer->get($scope);
|
||||
|
||||
$whereClause = [
|
||||
'deleted' => 1,
|
||||
'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
|
||||
{
|
||||
|
||||
@@ -41,29 +41,20 @@ use Espo\Entities\EmailFolder;
|
||||
use Espo\Entities\GroupEmailFolder;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\Tools\Email\Folder;
|
||||
use Espo\Tools\Email\InboxService as EmailService;
|
||||
use Exception;
|
||||
|
||||
class MoveToFolder implements MassAction
|
||||
{
|
||||
private const FOLDER_INBOX = 'inbox';
|
||||
|
||||
private QueryBuilder $queryBuilder;
|
||||
private EntityManager $entityManager;
|
||||
private EmailService $service;
|
||||
private User $user;
|
||||
private const FOLDER_INBOX = Folder::INBOX;
|
||||
|
||||
public function __construct(
|
||||
QueryBuilder $queryBuilder,
|
||||
EntityManager $entityManager,
|
||||
EmailService $service,
|
||||
User $user
|
||||
) {
|
||||
$this->queryBuilder = $queryBuilder;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->service = $service;
|
||||
$this->user = $user;
|
||||
}
|
||||
private QueryBuilder $queryBuilder,
|
||||
private EntityManager $entityManager,
|
||||
private EmailService $service,
|
||||
private User $user
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
@@ -77,7 +68,7 @@ class MoveToFolder implements MassAction
|
||||
throw new BadRequest("No folder ID.");
|
||||
}
|
||||
|
||||
if ($folderId !== self::FOLDER_INBOX && strpos($folderId, 'group:') !== 0) {
|
||||
if ($folderId !== self::FOLDER_INBOX && !str_starts_with($folderId, 'group:')) {
|
||||
$folder = $this->entityManager
|
||||
->getRDBRepositoryByClass(EmailFolder::class)
|
||||
->where([
|
||||
@@ -91,7 +82,7 @@ class MoveToFolder implements MassAction
|
||||
}
|
||||
}
|
||||
|
||||
if ($folderId && strpos($folderId, 'group:') === 0) {
|
||||
if ($folderId && str_starts_with($folderId, 'group:')) {
|
||||
$folder = $this->entityManager
|
||||
->getRDBRepositoryByClass(GroupEmailFolder::class)
|
||||
->where(['id' => substr($folderId, 6)])
|
||||
@@ -117,7 +108,7 @@ class MoveToFolder implements MassAction
|
||||
try {
|
||||
$this->service->moveToFolder($email->getId(), $folderId, $this->user->getId());
|
||||
}
|
||||
catch (Exception $e) {
|
||||
catch (Exception) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,48 +29,36 @@
|
||||
|
||||
namespace Espo\Classes\MassAction\User;
|
||||
|
||||
use Espo\Core\{
|
||||
ApplicationUser,
|
||||
MassAction\Actions\MassDelete as MassDeleteOriginal,
|
||||
MassAction\QueryBuilder,
|
||||
MassAction\Params,
|
||||
MassAction\Result,
|
||||
MassAction\Data,
|
||||
MassAction\MassAction,
|
||||
Acl,
|
||||
ORM\EntityManager,
|
||||
Exceptions\Forbidden,
|
||||
};
|
||||
use Espo\Core\Acl;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\MassAction\Actions\MassDelete as MassDeleteOriginal;
|
||||
use Espo\Core\MassAction\Data;
|
||||
use Espo\Core\MassAction\MassAction;
|
||||
use Espo\Core\MassAction\Params;
|
||||
use Espo\Core\MassAction\QueryBuilder;
|
||||
use Espo\Core\MassAction\Result;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
|
||||
use Espo\{
|
||||
Entities\User,
|
||||
ORM\Entity,
|
||||
};
|
||||
use Espo\Core\Utils\SystemUser;
|
||||
use Espo\Entities\User;
|
||||
|
||||
/**
|
||||
* Extended to forbid removal of own and system users.
|
||||
*/
|
||||
class MassDelete implements MassAction
|
||||
{
|
||||
private MassDeleteOriginal $massDeleteOriginal;
|
||||
private QueryBuilder $queryBuilder;
|
||||
private EntityManager $entityManager;
|
||||
private Acl $acl;
|
||||
private User $user;
|
||||
|
||||
public function __construct(
|
||||
MassDeleteOriginal $massDeleteOriginal,
|
||||
QueryBuilder $queryBuilder,
|
||||
EntityManager $entityManager,
|
||||
Acl $acl,
|
||||
User $user
|
||||
) {
|
||||
$this->massDeleteOriginal = $massDeleteOriginal;
|
||||
$this->queryBuilder = $queryBuilder;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->acl = $acl;
|
||||
$this->user = $user;
|
||||
}
|
||||
private MassDeleteOriginal $massDeleteOriginal,
|
||||
private QueryBuilder $queryBuilder,
|
||||
private EntityManager $entityManager,
|
||||
private Acl $acl,
|
||||
private User $user
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function process(Params $params, Data $data): Result
|
||||
{
|
||||
@@ -93,7 +81,7 @@ class MassDelete implements MassAction
|
||||
->getRDBRepository(User::ENTITY_TYPE)
|
||||
->clone($query)
|
||||
->sth()
|
||||
->select(['id'])
|
||||
->select(['id', 'userName'])
|
||||
->find();
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
@@ -106,9 +94,9 @@ class MassDelete implements MassAction
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
protected function checkEntity(Entity $entity): void
|
||||
private function checkEntity(User $entity): void
|
||||
{
|
||||
if ($entity->getId() === ApplicationUser::SYSTEM_USER_ID) {
|
||||
if ($entity->getUserName() === SystemUser::NAME) {
|
||||
throw new Forbidden("Can't delete 'system' user.");
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
namespace Espo\Classes\MassAction\User;
|
||||
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\MassAction\Actions\MassUpdate as MassUpdateOriginal;
|
||||
use Espo\Core\MassAction\QueryBuilder;
|
||||
use Espo\Core\MassAction\Params;
|
||||
@@ -42,24 +43,15 @@ use Espo\Core\Acl\Table;
|
||||
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
use Espo\Core\Utils\SystemUser;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
use Espo\Tools\MassUpdate\Data as MassUpdateData;
|
||||
|
||||
class MassUpdate implements MassAction
|
||||
{
|
||||
private MassUpdateOriginal $massUpdateOriginal;
|
||||
private QueryBuilder $queryBuilder;
|
||||
private EntityManager $entityManager;
|
||||
private Acl $acl;
|
||||
private User $user;
|
||||
private FileManager $fileManager;
|
||||
private DataManager $dataManager;
|
||||
|
||||
private const PERMISSION = 'massUpdatePermission';
|
||||
private const SYSTEM_USER_ID = 'system';
|
||||
|
||||
/** @var string[] */
|
||||
private array $notAllowedAttributeList = [
|
||||
@@ -72,25 +64,18 @@ class MassUpdate implements MassAction
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
MassUpdateOriginal $massUpdateOriginal,
|
||||
QueryBuilder $queryBuilder,
|
||||
EntityManager $entityManager,
|
||||
Acl $acl,
|
||||
User $user,
|
||||
FileManager $fileManager,
|
||||
DataManager $dataManager
|
||||
) {
|
||||
$this->massUpdateOriginal = $massUpdateOriginal;
|
||||
$this->queryBuilder = $queryBuilder;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->acl = $acl;
|
||||
$this->user = $user;
|
||||
$this->fileManager = $fileManager;
|
||||
$this->dataManager = $dataManager;
|
||||
}
|
||||
private MassUpdateOriginal $massUpdateOriginal,
|
||||
private QueryBuilder $queryBuilder,
|
||||
private EntityManager $entityManager,
|
||||
private Acl $acl,
|
||||
private User $user,
|
||||
private FileManager $fileManager,
|
||||
private DataManager $dataManager
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function process(Params $params, Data $data): Result
|
||||
{
|
||||
@@ -118,7 +103,7 @@ class MassUpdate implements MassAction
|
||||
->getRDBRepository(User::ENTITY_TYPE)
|
||||
->clone($query)
|
||||
->sth()
|
||||
->select(['id'])
|
||||
->select(['id', 'userName'])
|
||||
->find();
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
@@ -147,9 +132,9 @@ class MassUpdate implements MassAction
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
private function checkEntity(Entity $entity, MassUpdateData $data): void
|
||||
private function checkEntity(User $entity, MassUpdateData $data): void
|
||||
{
|
||||
if ($entity->getId() === self::SYSTEM_USER_ID) {
|
||||
if ($entity->getUserName() === SystemUser::NAME) {
|
||||
throw new Forbidden("Can't update 'system' user.");
|
||||
}
|
||||
|
||||
|
||||
@@ -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,34 +29,23 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\AccessControlFilters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\AccessControl\Filter,
|
||||
};
|
||||
use Espo\Core\Select\AccessControl\Filter;
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
Classes\Select\Email\Helpers\JoinHelper,
|
||||
Entities\User,
|
||||
};
|
||||
use Espo\Classes\Select\Email\Helpers\JoinHelper;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class OnlyOwn 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
|
||||
{
|
||||
$this->joinHelper->joinEmailUser($queryBuilder, $this->user->getId());
|
||||
|
||||
$queryBuilder->where([
|
||||
'emailUser.userId' => $this->user->getId(),
|
||||
]);
|
||||
$queryBuilder->where(['emailUser.userId' => $this->user->getId()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,39 +29,47 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\AccessControlFilters;
|
||||
|
||||
use Espo\Core\{
|
||||
Select\AccessControl\Filter,
|
||||
};
|
||||
use Espo\Core\Select\AccessControl\Filter;
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
Classes\Select\Email\Helpers\JoinHelper,
|
||||
Entities\User,
|
||||
};
|
||||
use Espo\Entities\Email;
|
||||
use Espo\Entities\Team;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\Part\Condition as Cond;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class OnlyTeam 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)
|
||||
{}
|
||||
|
||||
public function apply(QueryBuilder $queryBuilder): void
|
||||
{
|
||||
$this->joinHelper->joinEmailUser($queryBuilder, $this->user->getId());
|
||||
|
||||
$queryBuilder->distinct();
|
||||
$queryBuilder->leftJoin('teams', 'teamsAccess');
|
||||
$queryBuilder->where([
|
||||
'OR' => [
|
||||
'teamsAccessMiddle.teamId' => $this->user->getLinkMultipleIdList('teams'),
|
||||
$subQuery = QueryBuilder::create()
|
||||
->select('id')
|
||||
->from(Email::ENTITY_TYPE)
|
||||
->leftJoin(Team::RELATIONSHIP_ENTITY_TEAM, 'entityTeam', [
|
||||
'entityTeam.entityId:' => 'id',
|
||||
'entityTeam.entityType' => Email::ENTITY_TYPE,
|
||||
'entityTeam.deleted' => false,
|
||||
])
|
||||
->leftJoin(Email::RELATIONSHIP_EMAIL_USER, 'emailUser', [
|
||||
'emailUser.emailId:' => 'id',
|
||||
'emailUser.deleted' => false,
|
||||
'emailUser.userId' => $this->user->getId(),
|
||||
]
|
||||
]);
|
||||
])
|
||||
->where([
|
||||
'OR' => [
|
||||
'entityTeam.teamId' => $this->user->getTeamIdList(),
|
||||
'emailUser.userId' => $this->user->getId(),
|
||||
]
|
||||
])
|
||||
->build();
|
||||
|
||||
$queryBuilder->where(
|
||||
Cond::in(
|
||||
Cond::column('id'),
|
||||
$subQuery
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -30,45 +30,53 @@
|
||||
namespace Espo\Classes\Select\Email\AdditionalAppliers;
|
||||
|
||||
use Espo\Core\Select\Applier\AdditionalApplier;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
use Espo\Core\Select\SearchParams;
|
||||
|
||||
use Espo\Classes\Select\Email\Helpers\JoinHelper;
|
||||
|
||||
use Espo\Entities\Email;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
use Espo\Tools\Email\Folder;
|
||||
|
||||
class Main implements AdditionalApplier
|
||||
{
|
||||
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(SelectBuilder $queryBuilder, SearchParams $searchParams): void
|
||||
{
|
||||
$folder = $this->retrieveFolder($searchParams);
|
||||
|
||||
if ($folder === 'drafts') {
|
||||
$queryBuilder->useIndex('createdById');
|
||||
}
|
||||
else if ($folder === 'important') {
|
||||
// skip
|
||||
}
|
||||
else if ($this->checkApplyDateSentIndex($queryBuilder, $searchParams)) {
|
||||
$queryBuilder->useIndex('dateSent');
|
||||
}
|
||||
$this->applyIndexes($folder, $queryBuilder, $searchParams);
|
||||
|
||||
if ($folder !== 'drafts') {
|
||||
if ($folder !== Folder::DRAFTS) {
|
||||
$this->joinEmailUser($queryBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
protected function joinEmailUser(SelectBuilder $queryBuilder): void
|
||||
private function applyIndexes(?string $folder, SelectBuilder $queryBuilder, SearchParams $searchParams): void
|
||||
{
|
||||
if ($searchParams->getTextFilter()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($folder === Folder::IMPORTANT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($folder === Folder::DRAFTS) {
|
||||
$queryBuilder->useIndex('createdById');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->checkApplyDateSentIndex($queryBuilder, $searchParams)) {
|
||||
$queryBuilder->useIndex('dateSent');
|
||||
}
|
||||
}
|
||||
|
||||
private function joinEmailUser(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
$this->joinHelper->joinEmailUser($queryBuilder, $this->user->getId());
|
||||
|
||||
@@ -77,10 +85,10 @@ class Main implements AdditionalApplier
|
||||
}
|
||||
|
||||
$itemList = [
|
||||
'isRead',
|
||||
'isImportant',
|
||||
'inTrash',
|
||||
'folderId',
|
||||
Email::USERS_COLUMN_IS_READ,
|
||||
Email::USERS_COLUMN_IS_IMPORTANT,
|
||||
Email::USERS_COLUMN_IN_TRASH,
|
||||
Email::USERS_COLUMN_FOLDER_ID,
|
||||
];
|
||||
|
||||
foreach ($itemList as $item) {
|
||||
@@ -88,7 +96,7 @@ class Main implements AdditionalApplier
|
||||
}
|
||||
}
|
||||
|
||||
protected function retrieveFolder(SearchParams $searchParams): ?string
|
||||
private function retrieveFolder(SearchParams $searchParams): ?string
|
||||
{
|
||||
if (!$searchParams->getWhere()) {
|
||||
return null;
|
||||
@@ -103,7 +111,7 @@ class Main implements AdditionalApplier
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function checkApplyDateSentIndex(SelectBuilder $queryBuilder, SearchParams $searchParams): bool
|
||||
private function checkApplyDateSentIndex(SelectBuilder $queryBuilder, SearchParams $searchParams): bool
|
||||
{
|
||||
if ($searchParams->getTextFilter()) {
|
||||
return false;
|
||||
|
||||
@@ -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,9 +29,8 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email\Helpers;
|
||||
|
||||
use Espo\{
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
};
|
||||
use Espo\Entities\Email;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class JoinHelper
|
||||
{
|
||||
@@ -41,14 +40,10 @@ class JoinHelper
|
||||
return;
|
||||
}
|
||||
|
||||
$queryBuilder->leftJoin(
|
||||
'EmailUser',
|
||||
'emailUser',
|
||||
[
|
||||
'emailUser.emailId:' => 'id',
|
||||
'emailUser.deleted' => false,
|
||||
'emailUser.userId' => $userId,
|
||||
]
|
||||
);
|
||||
$queryBuilder->leftJoin(Email::RELATIONSHIP_EMAIL_USER, 'emailUser', [
|
||||
'emailUser.emailId:' => 'id',
|
||||
'emailUser.deleted' => false,
|
||||
'emailUser.userId' => $userId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
namespace Espo\Classes\Select\Email;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Select\Text\Filter;
|
||||
use Espo\Core\Select\Text\Filter\Data;
|
||||
use Espo\Core\Select\Text\DefaultFilter;
|
||||
@@ -44,22 +45,15 @@ use Espo\Entities\EmailAddress;
|
||||
|
||||
class TextFilter implements Filter
|
||||
{
|
||||
private $defaultFilter;
|
||||
|
||||
private $config;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(
|
||||
DefaultFilter $defaultFilter,
|
||||
ConfigProvider $config,
|
||||
EntityManager $entityManager
|
||||
) {
|
||||
$this->defaultFilter = $defaultFilter;
|
||||
$this->config = $config;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
private DefaultFilter $defaultFilter,
|
||||
private ConfigProvider $config,
|
||||
private EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws Error
|
||||
*/
|
||||
public function apply(QueryBuilder $queryBuilder, Data $data): void
|
||||
{
|
||||
$filter = $data->getFilter();
|
||||
@@ -67,7 +61,7 @@ class TextFilter implements Filter
|
||||
|
||||
if (
|
||||
mb_strlen($filter) < $this->config->getMinLengthForContentSearch() ||
|
||||
strpos($filter, '@') === false ||
|
||||
!str_contains($filter, '@') ||
|
||||
$data->forceFullTextSearch()
|
||||
) {
|
||||
$this->defaultFilter->apply($queryBuilder, $data);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -39,46 +39,29 @@ use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\Entities\User;
|
||||
use Espo\Classes\Select\Email\Helpers\JoinHelper;
|
||||
use Espo\Tools\Email\Folder;
|
||||
|
||||
class InFolder implements ItemConverter
|
||||
{
|
||||
private User $user;
|
||||
private EntityManager $entityManager;
|
||||
private JoinHelper $joinHelper;
|
||||
|
||||
public function __construct(User $user, EntityManager $entityManager, JoinHelper $joinHelper)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->joinHelper = $joinHelper;
|
||||
}
|
||||
public function __construct(
|
||||
private User $user,
|
||||
private EntityManager $entityManager,
|
||||
private JoinHelper $joinHelper
|
||||
) {}
|
||||
|
||||
public function convert(QueryBuilder $queryBuilder, Item $item): WhereClauseItem
|
||||
{
|
||||
$folderId = $item->getValue();
|
||||
|
||||
switch ($folderId) {
|
||||
case 'all':
|
||||
return WhereClause::fromRaw([]);
|
||||
|
||||
case 'inbox':
|
||||
return $this->convertInbox($queryBuilder);
|
||||
|
||||
case 'important':
|
||||
return $this->convertImportant($queryBuilder);
|
||||
|
||||
case 'sent':
|
||||
return $this->convertSent($queryBuilder);
|
||||
|
||||
case 'trash':
|
||||
return $this->convertTrash($queryBuilder);
|
||||
|
||||
case 'drafts':
|
||||
return $this->convertDraft($queryBuilder);
|
||||
|
||||
default:
|
||||
return $this->convertFolderId($queryBuilder, $folderId);
|
||||
}
|
||||
return match ($folderId) {
|
||||
Folder::ALL => WhereClause::fromRaw([]),
|
||||
Folder::INBOX => $this->convertInbox($queryBuilder),
|
||||
Folder::IMPORTANT => $this->convertImportant($queryBuilder),
|
||||
Folder::SENT => $this->convertSent($queryBuilder),
|
||||
Folder::TRASH => $this->convertTrash($queryBuilder),
|
||||
Folder::DRAFTS => $this->convertDraft($queryBuilder),
|
||||
default => $this->convertFolderId($queryBuilder, $folderId),
|
||||
};
|
||||
}
|
||||
|
||||
protected function convertInbox(QueryBuilder $queryBuilder): WhereClauseItem
|
||||
@@ -171,7 +154,7 @@ class InFolder implements ItemConverter
|
||||
{
|
||||
$this->joinEmailUser($queryBuilder);
|
||||
|
||||
if (substr($folderId, 0, 6) === 'group:') {
|
||||
if (str_starts_with($folderId, 'group:')) {
|
||||
$groupFolderId = substr($folderId, 6);
|
||||
|
||||
if ($groupFolderId === '') {
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -30,22 +30,14 @@
|
||||
namespace Espo\Classes\Select\Team\AccessControlFilters;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\Select\AccessControl\Filter;
|
||||
|
||||
use Espo\ORM\Query\{
|
||||
SelectBuilder,
|
||||
Part\Condition as Cond,
|
||||
};
|
||||
use Espo\ORM\Query\Part\Condition as Cond;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
|
||||
class OnlyTeam 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,40 +30,31 @@
|
||||
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 Mandatory 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
|
||||
{
|
||||
if (!$this->user->isAdmin()) {
|
||||
$queryBuilder->where([
|
||||
'isActive' => true,
|
||||
'type!=' => 'api',
|
||||
'type!=' => User::TYPE_API,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($this->aclManager->getPermissionLevel($this->user, 'portalPermission') !== Table::LEVEL_YES) {
|
||||
$queryBuilder->where([
|
||||
'OR' => [
|
||||
'type!=' => 'portal',
|
||||
'type!=' => User::TYPE_PORTAL,
|
||||
'id' => $this->user->getId(),
|
||||
]
|
||||
]);
|
||||
@@ -71,12 +62,12 @@ class Mandatory implements Filter
|
||||
|
||||
if (!$this->user->isSuperAdmin()) {
|
||||
$queryBuilder->where([
|
||||
'type!=' => 'super-admin'
|
||||
'type!=' => User::TYPE_SUPER_ADMIN,
|
||||
]);
|
||||
}
|
||||
|
||||
$queryBuilder->where([
|
||||
'type!=' => 'system'
|
||||
'type!=' => User::TYPE_SYSTEM,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
@@ -31,25 +31,18 @@ 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 OnlyTeam 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
|
||||
{
|
||||
@@ -59,7 +52,7 @@ class OnlyTeam implements Filter
|
||||
];
|
||||
|
||||
if ($this->aclManager->getPermissionLevel($this->user, 'portalPermission') === Table::LEVEL_YES) {
|
||||
$orGroup['type'] = 'portal';
|
||||
$orGroup['type'] = User::TYPE_PORTAL;
|
||||
}
|
||||
|
||||
$queryBuilder
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
namespace Espo\Classes\Select\User\PrimaryFilters;
|
||||
|
||||
use Espo\Core\Select\Primary\Filter;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
|
||||
class Internal implements Filter
|
||||
@@ -37,7 +38,11 @@ class Internal implements Filter
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
$queryBuilder->where([
|
||||
'type!=' => ['portal', 'api', 'system'],
|
||||
'type!=' => [
|
||||
User::TYPE_PORTAL,
|
||||
User::TYPE_API,
|
||||
User::TYPE_SYSTEM,
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,16 +29,12 @@
|
||||
|
||||
namespace Espo\Classes\Select\User\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\Entities\User;
|
||||
use Espo\ORM\Query\Part\WhereClause;
|
||||
use Espo\ORM\Query\Part\WhereItem as WhereClauseItem;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
|
||||
class IsOfType implements ItemConverter
|
||||
{
|
||||
@@ -46,23 +42,21 @@ class IsOfType implements ItemConverter
|
||||
{
|
||||
$type = $item->getValue();
|
||||
|
||||
switch ($type) {
|
||||
case 'internal':
|
||||
return WhereClause::fromRaw([
|
||||
'type!=' => ['portal', 'api', 'system'],
|
||||
]);
|
||||
|
||||
case 'api':
|
||||
return WhereClause::fromRaw([
|
||||
'type' => 'api',
|
||||
]);
|
||||
|
||||
case 'portal':
|
||||
return WhereClause::fromRaw([
|
||||
'type' => 'portal',
|
||||
]);
|
||||
}
|
||||
|
||||
return WhereClause::fromRaw(['id' => null]);
|
||||
return match ($type) {
|
||||
'internal' => WhereClause::fromRaw([
|
||||
'type!=' => [
|
||||
User::TYPE_PORTAL,
|
||||
User::TYPE_API,
|
||||
User::TYPE_SYSTEM,
|
||||
],
|
||||
]),
|
||||
User::TYPE_PORTAL => WhereClause::fromRaw([
|
||||
'type' => User::TYPE_PORTAL,
|
||||
]),
|
||||
User::TYPE_API => WhereClause::fromRaw([
|
||||
'type' => User::TYPE_API,
|
||||
]),
|
||||
default => WhereClause::fromRaw(['id' => null]),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,8 +51,10 @@ class TableTag implements Helper
|
||||
|
||||
$content = $function !== null ? $function() : '';
|
||||
|
||||
$style = "border: {$border}; border-spacing: 0; border-collapse: collapse;";
|
||||
|
||||
return Result::createSafeString(
|
||||
"<table border=\"{$border}\" cellpadding=\"{$cellpadding}\" {$attributesPart}>" .
|
||||
"<table style=\"{$style}\" border=\"{$border}\" cellpadding=\"{$cellpadding}\" {$attributesPart}>" .
|
||||
$content .
|
||||
"</table>"
|
||||
);
|
||||
|
||||
@@ -56,7 +56,7 @@ class TdTag implements Helper
|
||||
$content = $function !== null ? $function() : '';
|
||||
|
||||
return Result::createSafeString(
|
||||
"<td>" . $content . "</td>"
|
||||
"<td {$attributesPart}>{$content}</td>"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,36 +44,26 @@ use Espo\Entities\User;
|
||||
|
||||
class Admin
|
||||
{
|
||||
private Container $container;
|
||||
private Config $config;
|
||||
private User $user;
|
||||
private AdminNotificationManager $adminNotificationManager;
|
||||
private SystemRequirements $systemRequirements;
|
||||
private ScheduledJob $scheduledJob;
|
||||
private DataManager $dataManager;
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
public function __construct(
|
||||
Container $container,
|
||||
Config $config,
|
||||
User $user,
|
||||
AdminNotificationManager $adminNotificationManager,
|
||||
SystemRequirements $systemRequirements,
|
||||
ScheduledJob $scheduledJob,
|
||||
DataManager $dataManager
|
||||
private Container $container,
|
||||
private Config $config,
|
||||
private User $user,
|
||||
private AdminNotificationManager $adminNotificationManager,
|
||||
private SystemRequirements $systemRequirements,
|
||||
private ScheduledJob $scheduledJob,
|
||||
private DataManager $dataManager
|
||||
) {
|
||||
$this->container = $container;
|
||||
$this->config = $config;
|
||||
$this->user = $user;
|
||||
$this->adminNotificationManager = $adminNotificationManager;
|
||||
$this->systemRequirements = $systemRequirements;
|
||||
$this->scheduledJob = $scheduledJob;
|
||||
$this->dataManager = $dataManager;
|
||||
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionRebuild(): bool
|
||||
{
|
||||
$this->dataManager->rebuild();
|
||||
@@ -81,6 +71,9 @@ class Admin
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionClearCache(): bool
|
||||
{
|
||||
$this->dataManager->clearCache();
|
||||
@@ -96,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);
|
||||
@@ -121,7 +118,7 @@ class Admin
|
||||
$upgradeId = $upgradeManager->upload($data);
|
||||
$manifest = $upgradeManager->getManifest();
|
||||
|
||||
return [
|
||||
return (object) [
|
||||
'id' => $upgradeId,
|
||||
'version' => $manifest['version'],
|
||||
];
|
||||
@@ -135,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);
|
||||
@@ -149,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,17 +29,11 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use Espo\Core\Controllers\RecordBase;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Tools\Attachment\FieldData;
|
||||
use Espo\Tools\Attachment\Service;
|
||||
use Espo\Tools\Attachment\UploadUrlService;
|
||||
use Espo\Tools\Attachment\UploadService;
|
||||
|
||||
use stdClass;
|
||||
|
||||
class Attachment extends RecordBase
|
||||
@@ -52,125 +46,4 @@ class Attachment extends RecordBase
|
||||
|
||||
return parent::getActionList($request, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionGetAttachmentFromImageUrl(Request $request): stdClass
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$url = $data->url ?? null;
|
||||
$field = $data->field ?? null;
|
||||
$parentType = $data->parentType ?? null;
|
||||
$relatedType = $data->relatedType ?? null;
|
||||
|
||||
if (!$url || !$field) {
|
||||
throw new BadRequest("No `url` or `field`.");
|
||||
}
|
||||
|
||||
try {
|
||||
$fieldData = new FieldData(
|
||||
$field,
|
||||
$parentType,
|
||||
$relatedType
|
||||
);
|
||||
}
|
||||
catch (Error $e) {
|
||||
throw new BadRequest($e->getMessage());
|
||||
}
|
||||
|
||||
return $this->injectableFactory
|
||||
->create(UploadUrlService::class)
|
||||
->uploadImage($url, $fieldData)
|
||||
->getValueMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function postActionGetCopiedAttachment(Request $request): stdClass
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$id = $data->id ?? null;
|
||||
$field = $data->field ?? null;
|
||||
$parentType = $data->parentType ?? null;
|
||||
$relatedType = $data->relatedType ?? null;
|
||||
|
||||
if (!$id || !$field) {
|
||||
throw new BadRequest("No `id` or `field`.");
|
||||
}
|
||||
|
||||
try {
|
||||
$fieldData = new FieldData(
|
||||
$field,
|
||||
$parentType,
|
||||
$relatedType
|
||||
);
|
||||
}
|
||||
catch (Error $e) {
|
||||
throw new BadRequest($e->getMessage());
|
||||
}
|
||||
|
||||
return $this->getAttachmentService()
|
||||
->copy($id, $fieldData)
|
||||
->getValueMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function getActionFile(Request $request, Response $response): void
|
||||
{
|
||||
$id = $request->getRouteParam('id');
|
||||
|
||||
if (!$id) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$fileData = $this->getAttachmentService()->getFileData($id);
|
||||
|
||||
if ($fileData->getType()) {
|
||||
$response->setHeader('Content-Type', $fileData->getType());
|
||||
}
|
||||
|
||||
$response
|
||||
->setHeader('Content-Disposition', 'attachment; filename="' . $fileData->getName() . '"')
|
||||
->setHeader('Content-Length', (string) $fileData->getSize())
|
||||
->setBody($fileData->getStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
* @throws Error
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function postActionChunk(Request $request, Response $response): void
|
||||
{
|
||||
$id = $request->getRouteParam('id');
|
||||
$body = $request->getBodyContents();
|
||||
|
||||
if (!$id || !$body) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$this->injectableFactory
|
||||
->create(UploadService::class)
|
||||
->uploadChunk($id, $body);
|
||||
|
||||
$response->writeBody('true');
|
||||
}
|
||||
|
||||
private function getAttachmentService(): Service
|
||||
{
|
||||
return $this->injectableFactory->create(Service::class);
|
||||
}
|
||||
}
|
||||
|
||||
44
application/Espo/Controllers/AuthenticationProvider.php
Normal file
44
application/Espo/Controllers/AuthenticationProvider.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?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\Controllers;
|
||||
|
||||
use Espo\Core\Controllers\RecordBase;
|
||||
|
||||
class AuthenticationProvider extends RecordBase
|
||||
{
|
||||
protected function checkAccess(): bool
|
||||
{
|
||||
if (!$this->user->isAdmin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -32,26 +32,17 @@ namespace Espo\Controllers;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
use Espo\Core\{
|
||||
Api\Request,
|
||||
Api\Response,
|
||||
Acl,
|
||||
};
|
||||
use Espo\Core\Acl;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
|
||||
use Espo\Tools\DataPrivacy\Erasor;
|
||||
|
||||
class DataPrivacy
|
||||
{
|
||||
private $erasor;
|
||||
|
||||
private $acl;
|
||||
|
||||
public function __construct(Erasor $erasor, Acl $acl)
|
||||
public function __construct(private Erasor $erasor, private Acl $acl)
|
||||
{
|
||||
$this->erasor = $erasor;
|
||||
$this->acl = $acl;
|
||||
|
||||
if ($this->acl->get('dataPrivacyPermission') === 'no') {
|
||||
if ($this->acl->getPermissionLevel('dataPrivacyPermission') === Acl\Table::LEVEL_NO) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,356 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Acl\Table;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
|
||||
use Espo\Core\Controllers\Record;
|
||||
use Espo\Core\Api\Request;
|
||||
|
||||
use Espo\Core\Mail\SmtpParams;
|
||||
use Espo\Entities\Email as EmailEntity;
|
||||
use Espo\Tools\Attachment\FieldData;
|
||||
use Espo\Tools\Email\SendService;
|
||||
use Espo\Tools\Email\InboxService as InboxService;
|
||||
|
||||
use Espo\Tools\Email\Service;
|
||||
use Espo\Tools\Email\TestSendData;
|
||||
use Espo\Tools\EmailTemplate\InsertField\Service as InsertFieldService;
|
||||
use stdClass;
|
||||
|
||||
class Email extends Record
|
||||
{
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function postActionGetCopiedAttachments(Request $request): stdClass
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$id = $data->id ?? null;
|
||||
$field = $data->field ?? null;
|
||||
$parentType = $data->parentType ?? null;
|
||||
$relatedType = $data->relatedType ?? null;
|
||||
|
||||
if (!$id || !$field) {
|
||||
throw new BadRequest("No `id` or `field`.");
|
||||
}
|
||||
|
||||
try {
|
||||
$fieldData = new FieldData(
|
||||
$field,
|
||||
$parentType,
|
||||
$relatedType
|
||||
);
|
||||
}
|
||||
catch (Error $e) {
|
||||
throw new BadRequest($e->getMessage());
|
||||
}
|
||||
|
||||
$list = $this->injectableFactory
|
||||
->create(Service::class)
|
||||
->copyAttachments($id, $fieldData);
|
||||
|
||||
$ids = array_map(
|
||||
fn ($item) => $item->getId(),
|
||||
$list
|
||||
);
|
||||
|
||||
$names = (object) [];
|
||||
|
||||
foreach ($list as $item) {
|
||||
$names->{$item->getId()} = $item->getName();
|
||||
}
|
||||
|
||||
return (object) [
|
||||
'ids' => $ids,
|
||||
'names' => $names,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
* @throws Error
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function postActionSendTestEmail(Request $request): bool
|
||||
{
|
||||
if (!$this->acl->checkScope(EmailEntity::ENTITY_TYPE)) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$type = $data->type ?? null;
|
||||
$id = $data->id ?? null;
|
||||
$server = $data->server ?? null;
|
||||
$port = $data->port ?? null;
|
||||
$username = $data->username ?? null;
|
||||
$password = $data->password ?? null;
|
||||
$auth = $data->auth ?? null;
|
||||
$authMechanism = $data->authMechanism ?? null;
|
||||
$security = $data->security ?? null;
|
||||
$userId = $data->userId ?? null;
|
||||
$fromAddress = $data->fromAddress ?? null;
|
||||
$fromName = $data->fromName ?? null;
|
||||
$emailAddress = $data->emailAddress ?? null;
|
||||
|
||||
if (!is_string($server)) {
|
||||
throw new BadRequest("`server`");
|
||||
}
|
||||
|
||||
|
||||
if (!is_int($port)) {
|
||||
throw new BadRequest("`port`.");
|
||||
}
|
||||
|
||||
if (!is_string($emailAddress)) {
|
||||
throw new BadRequest("`emailAddress`.");
|
||||
}
|
||||
|
||||
$smtpParams = SmtpParams
|
||||
::create($server, $port)
|
||||
->withSecurity($security)
|
||||
->withFromName($fromName)
|
||||
->withFromAddress($fromAddress)
|
||||
->withAuth($auth);
|
||||
|
||||
if ($auth) {
|
||||
$smtpParams = $smtpParams
|
||||
->withUsername($username)
|
||||
->withPassword($password)
|
||||
->withAuthMechanism($authMechanism);
|
||||
}
|
||||
|
||||
$data = new TestSendData($emailAddress, $type, $id, $userId);
|
||||
|
||||
$this->getSendService()->sendTestEmail($smtpParams, $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function postActionMarkAsRead(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!empty($data->ids)) {
|
||||
$idList = $data->ids;
|
||||
}
|
||||
else {
|
||||
if (!empty($data->id)) {
|
||||
$idList = [$data->id];
|
||||
}
|
||||
else {
|
||||
throw new BadRequest();
|
||||
}
|
||||
}
|
||||
|
||||
$this->getInboxService()->markAsReadIdList($idList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function postActionMarkAsNotRead(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!empty($data->ids)) {
|
||||
$idList = $data->ids;
|
||||
}
|
||||
else {
|
||||
if (!empty($data->id)) {
|
||||
$idList = [$data->id];
|
||||
}
|
||||
else {
|
||||
throw new BadRequest();
|
||||
}
|
||||
}
|
||||
|
||||
$this->getInboxService()->markAsNotReadIdList($idList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function postActionMarkAllAsRead(): bool
|
||||
{
|
||||
$this->getInboxService()->markAllAsRead();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function postActionMarkAsImportant(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!empty($data->ids)) {
|
||||
$idList = $data->ids;
|
||||
}
|
||||
else {
|
||||
if (!empty($data->id)) {
|
||||
$idList = [$data->id];
|
||||
}
|
||||
else {
|
||||
throw new BadRequest();
|
||||
}
|
||||
}
|
||||
|
||||
$this->getInboxService()->markAsImportantIdList($idList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function postActionMarkAsNotImportant(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!empty($data->ids)) {
|
||||
$idList = $data->ids;
|
||||
}
|
||||
else {
|
||||
if (!empty($data->id)) {
|
||||
$idList = [$data->id];
|
||||
}
|
||||
else {
|
||||
throw new BadRequest();
|
||||
}
|
||||
}
|
||||
|
||||
$this->getInboxService()->markAsNotImportantIdList($idList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function postActionMoveToTrash(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!empty($data->ids)) {
|
||||
$idList = $data->ids;
|
||||
}
|
||||
else {
|
||||
if (!empty($data->id)) {
|
||||
$idList = [$data->id];
|
||||
}
|
||||
else {
|
||||
throw new BadRequest();
|
||||
}
|
||||
}
|
||||
|
||||
$this->getInboxService()->moveToTrashIdList($idList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function postActionRetrieveFromTrash(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!empty($data->ids)) {
|
||||
$idList = $data->ids;
|
||||
}
|
||||
else {
|
||||
if (!empty($data->id)) {
|
||||
$idList = [$data->id];
|
||||
}
|
||||
else {
|
||||
throw new BadRequest();
|
||||
}
|
||||
}
|
||||
|
||||
$this->getInboxService()->retrieveFromTrashIdList($idList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getActionGetFoldersNotReadCounts(): stdClass
|
||||
{
|
||||
return (object) $this->getInboxService()->getFoldersNotReadCounts();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function postActionMoveToFolder(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!empty($data->ids)) {
|
||||
$idList = $data->ids;
|
||||
}
|
||||
else if (!empty($data->id)) {
|
||||
$idList = [$data->id];
|
||||
}
|
||||
else {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
if (empty($data->folderId)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
if (count($idList) === 1) {
|
||||
$this->getInboxService()->moveToFolder($idList[0], $data->folderId);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
$this->getInboxService()->moveToFolderIdList($idList, $data->folderId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
public function getActionGetInsertFieldData(Request $request): stdClass
|
||||
{
|
||||
if (!$this->acl->checkScope(EmailEntity::ENTITY_TYPE, Table::ACTION_CREATE)) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
return $this->injectableFactory
|
||||
->create(InsertFieldService::class)
|
||||
->getData(
|
||||
$request->getQueryParam('parentType'),
|
||||
$request->getQueryParam('parentId'),
|
||||
$request->getQueryParam('to')
|
||||
);
|
||||
}
|
||||
|
||||
private function getInboxService(): InboxService
|
||||
{
|
||||
return $this->injectableFactory->create(InboxService::class);
|
||||
}
|
||||
|
||||
private function getSendService(): SendService
|
||||
{
|
||||
return $this->injectableFactory->create(SendService::class);
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
@@ -29,52 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
use Espo\Tools\Email\AddressService as Service;
|
||||
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Controllers\RecordBase;
|
||||
|
||||
class EmailAddress extends RecordBase
|
||||
{
|
||||
private const ADDRESS_MAX_SIZE = 50;
|
||||
|
||||
/**
|
||||
* @return array<int,array<string,mixed>>
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function actionSearchInAddressBook(Request $request): array
|
||||
{
|
||||
if (!$this->acl->checkScope('Email')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
if (!$this->acl->checkScope('Email', 'create')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$q = $request->getQueryParam('q');
|
||||
|
||||
if ($q === null) {
|
||||
throw new BadRequest("No `q` parameter.");
|
||||
}
|
||||
|
||||
$maxSize = intval($request->getQueryParam('maxSize'));
|
||||
|
||||
if (!$maxSize || $maxSize > self::ADDRESS_MAX_SIZE) {
|
||||
$maxSize = (int) $this->config->get('recordsPerPage');
|
||||
}
|
||||
|
||||
$onlyActual = $request->getQueryParam('onlyActual') === 'true';
|
||||
|
||||
return $this->getEmailAddressService()->searchInAddressBook($q, $maxSize, $onlyActual);
|
||||
}
|
||||
|
||||
private function getEmailAddressService(): Service
|
||||
{
|
||||
return $this->injectableFactory->create(Service::class);
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
@@ -31,5 +31,4 @@ namespace Espo\Controllers;
|
||||
|
||||
class EmailFilter extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user