mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-06 17:47:01 +00:00
Compare commits
966 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ef2ed4144 | ||
|
|
befec82120 | ||
|
|
e88bd5898c | ||
|
|
a5bb5005f8 | ||
|
|
324f776ed5 | ||
|
|
1f04ba5083 | ||
|
|
1ad265611f | ||
|
|
04906c5307 | ||
|
|
fefadc58bd | ||
|
|
1628d3b566 | ||
|
|
b456d86b22 | ||
|
|
c3a1236ca9 | ||
|
|
d76a6fa0ec | ||
|
|
b008270fe6 | ||
|
|
2deb826266 | ||
|
|
66815e3192 | ||
|
|
9e34de69f0 | ||
|
|
6346fae044 | ||
|
|
5ab64077e8 | ||
|
|
ae8221e208 | ||
|
|
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 | ||
|
|
c351a8fc02 | ||
|
|
14c0f12fe9 | ||
|
|
ab87cff5bc | ||
|
|
a5280ec0ac | ||
|
|
6339690e58 | ||
|
|
c5ae2800b5 | ||
|
|
62501dc20d | ||
|
|
9e5810c8cf | ||
|
|
e6a0a94e17 | ||
|
|
777f9de3d9 | ||
|
|
c7b7848e69 | ||
|
|
791c172c7a | ||
|
|
3bef6d8e84 | ||
|
|
093d71e5ae | ||
|
|
a3be63c6f1 | ||
|
|
52fe2ca1c9 | ||
|
|
6513513108 | ||
|
|
442d2c030b | ||
|
|
391500a1c1 | ||
|
|
f239d2c478 | ||
|
|
67e83f5c9e | ||
|
|
101f8a29a3 | ||
|
|
b952f3dbfb | ||
|
|
23b125f552 | ||
|
|
93e17e8f8d | ||
|
|
9af562fda2 | ||
|
|
dfb846fb7e | ||
|
|
ecd6d5a558 | ||
|
|
0612cd2399 | ||
|
|
811ea3ad27 | ||
|
|
967571f030 | ||
|
|
ac2576b760 | ||
|
|
7f1bc0cf1d | ||
|
|
3ba9ea5085 | ||
|
|
08512304f1 | ||
|
|
c0da4e1777 | ||
|
|
14705e2100 | ||
|
|
0c99f35c02 | ||
|
|
a91da86ae4 | ||
|
|
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).
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.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. We appreciate if you prefer posting bug reports on weekdays rather than weekends.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
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: Freature requests are frozen til mid-June 2023. Please post on the forum instead. (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
|
||||
2
.idea/.gitignore
generated
vendored
2
.idea/.gitignore
generated
vendored
@@ -3,3 +3,5 @@
|
||||
!/codeStyles
|
||||
!/fileTemplates
|
||||
!/inspectionProfiles
|
||||
!misc.xml
|
||||
!jsonSchemas.xml
|
||||
|
||||
5
.idea/codeStyles/Project.xml
generated
5
.idea/codeStyles/Project.xml
generated
@@ -6,6 +6,11 @@
|
||||
<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" />
|
||||
|
||||
2
.idea/inspectionProfiles/Project_Default.xml
generated
2
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -14,6 +14,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>
|
||||
1351
.idea/jsonSchemas.xml
generated
Normal file
1351
.idea/jsonSchemas.xml
generated
Normal file
File diff suppressed because it is too large
Load Diff
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpEntryPointsManager">
|
||||
<pattern value="\Espo\Controllers\*" member="*Action*" />
|
||||
<pattern value="\Espo\Modules\*\Controllers\*" member="*Action*" />
|
||||
</component>
|
||||
</project>
|
||||
3
.vscode/.gitignore
vendored
Normal file
3
.vscode/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*
|
||||
!.gitignore
|
||||
!settings.json
|
||||
422
.vscode/settings.json
vendored
Normal file
422
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,422 @@
|
||||
{
|
||||
"json.schemas": [
|
||||
{
|
||||
"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/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/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"
|
||||
}
|
||||
]
|
||||
}
|
||||
13
Gruntfile.js
13
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.
|
||||
*/
|
||||
@@ -90,7 +90,7 @@ module.exports = grunt => {
|
||||
mkdir: {
|
||||
tmp: {
|
||||
options: {
|
||||
mode: 0755,
|
||||
mode: 0o755,
|
||||
create: [
|
||||
'build/tmp',
|
||||
],
|
||||
@@ -110,9 +110,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/*',
|
||||
@@ -236,7 +234,7 @@ module.exports = grunt => {
|
||||
options: {
|
||||
patterns: [
|
||||
{
|
||||
match: /\# \{\#dev\}(.*)\{\/dev\}/gs,
|
||||
match: /# \{#dev}(.*)\{\/dev}/gs,
|
||||
replacement: '',
|
||||
}
|
||||
]
|
||||
@@ -503,7 +501,8 @@ module.exports = grunt => {
|
||||
|
||||
grunt.registerTask('dev', [
|
||||
'composer-install-dev',
|
||||
'less',
|
||||
'npm-install',
|
||||
'internal',
|
||||
]);
|
||||
|
||||
grunt.registerTask('test', [
|
||||
|
||||
51
README.md
51
README.md
@@ -2,47 +2,72 @@
|
||||
|
||||
[](#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).
|
||||
|
||||
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/).
|
||||
|
||||
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,14 @@ class Binding implements BindingProcessor
|
||||
);
|
||||
}
|
||||
|
||||
private function bindCore(Binder $binder): void
|
||||
{
|
||||
$binder->bindImplementation(
|
||||
'Espo\\ORM\\PDO\\PDOProvider',
|
||||
'Espo\\ORM\\PDO\\DefaultPDOProvider'
|
||||
);
|
||||
}
|
||||
|
||||
private function bindMisc(Binder $binder): void
|
||||
{
|
||||
$binder->bindImplementation(
|
||||
@@ -246,7 +270,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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -33,22 +33,21 @@ 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,
|
||||
};
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\Query\Part\Condition as Cond;
|
||||
use Espo\ORM\Query\Part\Where\OrGroup;
|
||||
use Espo\ORM\Query\Part\WhereItem;
|
||||
|
||||
/**
|
||||
* @implements WhereBuilder<CoreEntity>
|
||||
*/
|
||||
class Company implements WhereBuilder
|
||||
{
|
||||
/**
|
||||
* @param CoreEntity $entity
|
||||
*/
|
||||
public function build(Entity $entity): ?WhereItem
|
||||
{
|
||||
assert($entity instanceof CoreEntity);
|
||||
|
||||
$orBuilder = OrGroup::createBuilder();
|
||||
|
||||
$toCheck = false;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -31,27 +31,24 @@ namespace Espo\Classes\DuplicateWhereBuilders;
|
||||
|
||||
use Espo\Core\ORM\Entity as CoreEntity;
|
||||
|
||||
use Espo\Core\{
|
||||
Duplicate\WhereBuilder,
|
||||
Field\EmailAddressGroup,
|
||||
};
|
||||
use Espo\Core\Duplicate\WhereBuilder;
|
||||
use Espo\Core\Field\EmailAddressGroup;
|
||||
|
||||
use Espo\ORM\{
|
||||
Query\Part\Condition as Cond,
|
||||
Query\Part\WhereItem,
|
||||
Query\Part\Where\OrGroup,
|
||||
Entity,
|
||||
};
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\Query\Part\Condition as Cond;
|
||||
use Espo\ORM\Query\Part\Where\OrGroup;
|
||||
use Espo\ORM\Query\Part\WhereItem;
|
||||
|
||||
/**
|
||||
* @implements WhereBuilder<CoreEntity>
|
||||
*/
|
||||
class Person implements WhereBuilder
|
||||
{
|
||||
/**
|
||||
* @param CoreEntity $entity
|
||||
*/
|
||||
public function build(Entity $entity): ?WhereItem
|
||||
{
|
||||
assert($entity instanceof CoreEntity);
|
||||
|
||||
$orBuilder = OrGroup::createBuilder();
|
||||
|
||||
$toCheck = false;
|
||||
|
||||
@@ -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,9 +182,9 @@ 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 */
|
||||
$value = $entity->get($field) ?? [];
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 ?
|
||||
|
||||
@@ -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 === []) {
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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>"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,30 +44,15 @@ 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;
|
||||
|
||||
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();
|
||||
@@ -98,7 +83,7 @@ class Admin
|
||||
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $params
|
||||
* @param array<string, mixed> $params
|
||||
* @param string $data
|
||||
* @return array{
|
||||
* id: string,
|
||||
@@ -160,7 +145,7 @@ class Admin
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int,array{id:string,type:string,message:string}>
|
||||
* @return array<int, array{id: string, type: string, message: string}>
|
||||
*/
|
||||
public function actionAdminNotificationList(): array
|
||||
{
|
||||
@@ -169,9 +154,9 @@ class Admin
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* php: array<string,array<string,mixed>>,
|
||||
* database: array<string,array<string,mixed>>,
|
||||
* permission: array<string,array<string,mixed>>,
|
||||
* php: array<string, array<string, mixed>>,
|
||||
* database: array<string, array<string, mixed>>,
|
||||
* permission: array<string, array<string, mixed>>,
|
||||
* }
|
||||
*/
|
||||
public function actionSystemRequirementList(): array
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -29,48 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
use Espo\Core\Exceptions\ForbiddenSilent;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Tools\EmailTemplate\Data;
|
||||
use Espo\Tools\EmailTemplate\Service;
|
||||
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Controllers\Record;
|
||||
|
||||
use stdClass;
|
||||
|
||||
class EmailTemplate extends Record
|
||||
{
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws NotFound
|
||||
* @throws ForbiddenSilent
|
||||
*/
|
||||
public function actionParse(Request $request): stdClass
|
||||
{
|
||||
$id = $request->getQueryParam('id');
|
||||
|
||||
if ($id === null) {
|
||||
throw new BadRequest("No `id`.");
|
||||
}
|
||||
|
||||
$data = Data::create()
|
||||
->withRelatedType($request->getQueryParam('relatedType'))
|
||||
->withRelatedId($request->getQueryParam('relatedId'))
|
||||
->withParentType($request->getQueryParam('parentType'))
|
||||
->withParentId($request->getQueryParam('parentId'))
|
||||
->withEmailAddress($request->getQueryParam('emailAddress'));
|
||||
|
||||
$result = $this->getEmailTemplateService()->process($id, $data);
|
||||
|
||||
return $result->getValueMap();
|
||||
|
||||
}
|
||||
|
||||
private function getEmailTemplateService(): Service
|
||||
{
|
||||
return $this->injectableFactory->create(Service::class);
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
@@ -31,5 +31,4 @@ namespace Espo\Controllers;
|
||||
|
||||
class EmailTemplateCategory extends \Espo\Core\Templates\Controllers\CategoryTree
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -29,33 +29,35 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\{
|
||||
Entities\User,
|
||||
Tools\EntityManager\EntityManager as EntityManagerTool,
|
||||
};
|
||||
use Espo\Core\Exceptions\Conflict;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Entities\User;
|
||||
use Espo\Tools\EntityManager\EntityManager as EntityManagerTool;
|
||||
|
||||
use Espo\Core\{
|
||||
Exceptions\Forbidden,
|
||||
Exceptions\BadRequest,
|
||||
Api\Request,
|
||||
};
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class EntityManager
|
||||
{
|
||||
private $user;
|
||||
|
||||
private $entityManagerTool;
|
||||
|
||||
public function __construct(User $user, EntityManagerTool $entityManagerTool)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->entityManagerTool = $entityManagerTool;
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
public function __construct(
|
||||
private User $user,
|
||||
private EntityManagerTool $entityManagerTool
|
||||
) {
|
||||
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
* @throws Conflict
|
||||
*/
|
||||
public function postActionCreateEntity(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -137,6 +139,10 @@ class EntityManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionUpdateEntity(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -160,6 +166,11 @@ class EntityManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionRemoveEntity(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -183,6 +194,11 @@ class EntityManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
* @throws Conflict
|
||||
*/
|
||||
public function postActionCreateLink(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
@@ -361,6 +377,10 @@ class EntityManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
*/
|
||||
public function postActionFormula(Request $request): bool
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
@@ -32,12 +32,10 @@ namespace Espo\Controllers;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
use Espo\Core\{
|
||||
Upgrades\ExtensionManager,
|
||||
Controllers\RecordBase,
|
||||
Api\Request,
|
||||
Api\Response,
|
||||
};
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use Espo\Core\Controllers\RecordBase;
|
||||
use Espo\Core\Upgrades\ExtensionManager;
|
||||
|
||||
use stdClass;
|
||||
|
||||
|
||||
@@ -29,36 +29,25 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\{
|
||||
Entities\User,
|
||||
Tools\FieldManager\FieldManager as FieldManagerTool,
|
||||
};
|
||||
|
||||
use Espo\Core\{
|
||||
Exceptions\Conflict,
|
||||
Exceptions\Error,
|
||||
Exceptions\Forbidden,
|
||||
Exceptions\BadRequest,
|
||||
Api\Request,
|
||||
DataManager};
|
||||
use Espo\Entities\User;
|
||||
use Espo\Tools\FieldManager\FieldManager as FieldManagerTool;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\DataManager;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Conflict;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class FieldManager
|
||||
{
|
||||
private $user;
|
||||
|
||||
private $dataManager;
|
||||
|
||||
private $fieldManagerTool;
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
public function __construct(User $user, DataManager $dataManager, FieldManagerTool $fieldManagerTool)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->dataManager = $dataManager;
|
||||
$this->fieldManagerTool = $fieldManagerTool;
|
||||
|
||||
public function __construct(
|
||||
private User $user,
|
||||
private DataManager $dataManager,
|
||||
private FieldManagerTool $fieldManagerTool
|
||||
) {
|
||||
$this->checkControllerAccess();
|
||||
}
|
||||
|
||||
@@ -73,7 +62,7 @@ class FieldManager
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
* @return array<string, mixed>
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
*/
|
||||
@@ -90,7 +79,7 @@ class FieldManager
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
* @return array<string, mixed>
|
||||
* @throws BadRequest
|
||||
* @throws Conflict
|
||||
* @throws Error
|
||||
@@ -123,7 +112,7 @@ class FieldManager
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
* @return array<string, mixed>
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
*/
|
||||
@@ -133,7 +122,7 @@ class FieldManager
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
* @return array<string, mixed>
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
*/
|
||||
@@ -176,6 +165,7 @@ class FieldManager
|
||||
|
||||
$result = $this->fieldManagerTool->delete($scope, $name);
|
||||
|
||||
$this->dataManager->clearCache();
|
||||
$this->dataManager->rebuildMetadata();
|
||||
|
||||
return $result;
|
||||
@@ -189,14 +179,20 @@ class FieldManager
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (empty($data->scope) || empty($data->name)) {
|
||||
$scope = $data->scope ?? null;
|
||||
$name = $data->name ?? null;
|
||||
|
||||
if (!$scope || !$name) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$this->fieldManagerTool->resetToDefault($data->scope, $data->name);
|
||||
if (!is_string($scope) || !is_string($name)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$this->dataManager->clearCache();
|
||||
$this->dataManager->rebuildMetadata();
|
||||
$this->fieldManagerTool->resetToDefault($scope, $name);
|
||||
|
||||
$this->dataManager->rebuild([$scope]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user