mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-09 15:07:01 +00:00
Compare commits
1475 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef260784ac | ||
|
|
bc7be925e2 | ||
|
|
9091e49650 | ||
|
|
5a8dd95565 | ||
|
|
23df87a8c3 | ||
|
|
3781d10cb6 | ||
|
|
f1d505330c | ||
|
|
fc9fbd25fe | ||
|
|
b3e5003e0c | ||
|
|
be9fd29023 | ||
|
|
22bb9cfe09 | ||
|
|
02238b4000 | ||
|
|
2f9bf085fa | ||
|
|
11010f274f | ||
|
|
9f2c57c3f1 | ||
|
|
41d815103c | ||
|
|
967c48f6d7 | ||
|
|
c4d0d0fba7 | ||
|
|
9a720e9c82 | ||
|
|
c41522ab67 | ||
|
|
501a4b3415 | ||
|
|
7af59ac7ec | ||
|
|
c16a4707b5 | ||
|
|
0a86ea65ed | ||
|
|
273ab1fe54 | ||
|
|
1b9622e6dd | ||
|
|
7209184636 | ||
|
|
b4c0b264b9 | ||
|
|
2e13e758b8 | ||
|
|
5359eb85e1 | ||
|
|
e42e758150 | ||
|
|
340fd9a324 | ||
|
|
1e277e5681 | ||
|
|
2534176b8d | ||
|
|
4f1c547f77 | ||
|
|
4698b2a0e7 | ||
|
|
cb76c9762c | ||
|
|
496890357a | ||
|
|
fc7dba6c91 | ||
|
|
67efbdc6e9 | ||
|
|
d660137e7e | ||
|
|
15ae14d4a1 | ||
|
|
111524b6c6 | ||
|
|
ce806c5aa8 | ||
|
|
b244f613ee | ||
|
|
ad5cb35260 | ||
|
|
c0ca2174b6 | ||
|
|
c3c1398a2d | ||
|
|
1fbdd2edf4 | ||
|
|
a64a66912f | ||
|
|
61bbb23e7a | ||
|
|
e8d62ecc22 | ||
|
|
7db64e9375 | ||
|
|
0a320cb3b3 | ||
|
|
50d38d127c | ||
|
|
1ad42423bf | ||
|
|
273c9b2f18 | ||
|
|
90260bbed5 | ||
|
|
833804c7b4 | ||
|
|
206f4bc2bb | ||
|
|
5280bdab86 | ||
|
|
ce0113cd6c | ||
|
|
24885853fd | ||
|
|
1f4ce20c8b | ||
|
|
5629682a9a | ||
|
|
826e335611 | ||
|
|
06c0a425cd | ||
|
|
dc9b4bbb20 | ||
|
|
4e951bcb98 | ||
|
|
428cafeb7d | ||
|
|
e145e461fa | ||
|
|
7bfd268793 | ||
|
|
2bc2d4ed26 | ||
|
|
185d006a61 | ||
|
|
42068c8a95 | ||
|
|
cb4e86886a | ||
|
|
02f6b1850c | ||
|
|
a667380d7a | ||
|
|
21be67f025 | ||
|
|
7d3fbcc7d0 | ||
|
|
cbbfc2227c | ||
|
|
9add3fa538 | ||
|
|
ef13bffcb9 | ||
|
|
a40c9d2b11 | ||
|
|
ddaa4c056d | ||
|
|
8f0b34c2de | ||
|
|
5ff145ff12 | ||
|
|
6e8a3fa05d | ||
|
|
2d3816e3ae | ||
|
|
4c9441a690 | ||
|
|
035523b426 | ||
|
|
93179a21b2 | ||
|
|
53534cf3d5 | ||
|
|
8bb6c4012a | ||
|
|
57960111f7 | ||
|
|
165e6322fc | ||
|
|
2afc157c24 | ||
|
|
9822bb94a1 | ||
|
|
bf72c8a4cc | ||
|
|
f6c8281c9e | ||
|
|
dcc2b2cb31 | ||
|
|
e9d3127932 | ||
|
|
c5d6b7d053 | ||
|
|
9bb0950c12 | ||
|
|
b2d6bd58e6 | ||
|
|
4fdcdec802 | ||
|
|
0873b17894 | ||
|
|
48957d33b6 | ||
|
|
48675f1875 | ||
|
|
ef4377c77b | ||
|
|
4394e0fca1 | ||
|
|
fc7b15042c | ||
|
|
bbaa119617 | ||
|
|
88f4797f0b | ||
|
|
fa35e32578 | ||
|
|
c40cbc6cc2 | ||
|
|
8fcd6c2ff9 | ||
|
|
30c6a713d6 | ||
|
|
029a18ff1a | ||
|
|
45049ae176 | ||
|
|
01f59521af | ||
|
|
0f3cd9dd24 | ||
|
|
ba4619df21 | ||
|
|
f7aa5aaf0b | ||
|
|
d3f0553c65 | ||
|
|
601d7729bc | ||
|
|
ac464b4036 | ||
|
|
5f220bc364 | ||
|
|
962ea50c44 | ||
|
|
742fda24c6 | ||
|
|
e0c10f3564 | ||
|
|
5a94143fd7 | ||
|
|
c5ba226fa0 | ||
|
|
be8dff3de7 | ||
|
|
0582fd680d | ||
|
|
c93a5e5299 | ||
|
|
c5229f1100 | ||
|
|
d78023f388 | ||
|
|
f15b63fd66 | ||
|
|
0ff236edbc | ||
|
|
9d23f3bdd0 | ||
|
|
dd74aac117 | ||
|
|
d49b713ccd | ||
|
|
d6431cbcc4 | ||
|
|
392748db57 | ||
|
|
70cc8fb9e3 | ||
|
|
bbabe672d8 | ||
|
|
447732bf9c | ||
|
|
29f60b5199 | ||
|
|
94fa7b17ff | ||
|
|
b5ec93e571 | ||
|
|
132e762c7e | ||
|
|
8ef94890a9 | ||
|
|
b6c9ef990f | ||
|
|
b19ce60e74 | ||
|
|
632e1ecb5c | ||
|
|
fa3ec522ca | ||
|
|
4615cea8a6 | ||
|
|
3c5dc1672a | ||
|
|
768c68df49 | ||
|
|
c44731bd97 | ||
|
|
9450cf9447 | ||
|
|
1cfb60d65b | ||
|
|
64519d6310 | ||
|
|
3d9b5852f8 | ||
|
|
dc6109c530 | ||
|
|
7fe1e27667 | ||
|
|
e24209438c | ||
|
|
ee2a3c9bea | ||
|
|
5861aa11c1 | ||
|
|
0041c11aae | ||
|
|
ed8def4ece | ||
|
|
7f08cc9cf0 | ||
|
|
981e477bd0 | ||
|
|
01bf39764a | ||
|
|
b4a2ad646b | ||
|
|
79d557542b | ||
|
|
26d411c94d | ||
|
|
8d3ae2ef00 | ||
|
|
f28854b7f2 | ||
|
|
5a24771d3c | ||
|
|
84830d6aef | ||
|
|
134cd53f45 | ||
|
|
717b9db4af | ||
|
|
87c313c933 | ||
|
|
928320c1bd | ||
|
|
bba4ad55da | ||
|
|
23604fba25 | ||
|
|
112c51d6e3 | ||
|
|
9339a15d18 | ||
|
|
a4b65ba0c7 | ||
|
|
00dfe2599e | ||
|
|
dcf6ec5612 | ||
|
|
0acd47fba0 | ||
|
|
4e718ff879 | ||
|
|
1205462620 | ||
|
|
75344a4ed2 | ||
|
|
6dae15155a | ||
|
|
338922099d | ||
|
|
0c840de187 | ||
|
|
16755831bc | ||
|
|
4c64b7e456 | ||
|
|
28a56c0bd7 | ||
|
|
894f99aa66 | ||
|
|
450d785a58 | ||
|
|
a26be8e7f0 | ||
|
|
d2f982fccb | ||
|
|
4b38f81384 | ||
|
|
20bc336036 | ||
|
|
cec4585538 | ||
|
|
8b4635ffaa | ||
|
|
3dc53c5436 | ||
|
|
7265b3c4b6 | ||
|
|
49033dec1a | ||
|
|
9b632f582f | ||
|
|
a989c8a6d1 | ||
|
|
e5c0427e68 | ||
|
|
c5811749cb | ||
|
|
5e925865a7 | ||
|
|
175f837f3d | ||
|
|
b28d3816c0 | ||
|
|
3ad66acb20 | ||
|
|
958b44af15 | ||
|
|
99b20f6724 | ||
|
|
4eec64e811 | ||
|
|
052548fda7 | ||
|
|
98e7218cf5 | ||
|
|
374c3786df | ||
|
|
a9a3f4381a | ||
|
|
b845ad6d3c | ||
|
|
7c8d3caba6 | ||
|
|
fcddc472e1 | ||
|
|
1c18348475 | ||
|
|
c6c74bd7b9 | ||
|
|
0775edd29e | ||
|
|
52017e5281 | ||
|
|
af3aecc3f8 | ||
|
|
eaf6b511d0 | ||
|
|
e13d0248ae | ||
|
|
e3d563a556 | ||
|
|
e2078bba84 | ||
|
|
017af8a383 | ||
|
|
0739e9f655 | ||
|
|
6f2904eb9a | ||
|
|
4003977ce3 | ||
|
|
d058bb7c3b | ||
|
|
139dfc5b81 | ||
|
|
152a5b5a7b | ||
|
|
ad54fa2ace | ||
|
|
d2e15f52c3 | ||
|
|
f670f382cd | ||
|
|
1ebedaf791 | ||
|
|
2879f426e0 | ||
|
|
d7c2cd8d2a | ||
|
|
78814dedd3 | ||
|
|
4865cf2202 | ||
|
|
239c533137 | ||
|
|
55bf893228 | ||
|
|
349cb32c5f | ||
|
|
1545305d43 | ||
|
|
0f84c6eaaa | ||
|
|
df94b38019 | ||
|
|
e8451f9648 | ||
|
|
b42ed51c5e | ||
|
|
9ed9ccbe4a | ||
|
|
b4d0343992 | ||
|
|
4b0604a183 | ||
|
|
8d50ae1f46 | ||
|
|
6ed4b60ebb | ||
|
|
86e0c502ae | ||
|
|
c1936cf46b | ||
|
|
973910b837 | ||
|
|
590918ac6d | ||
|
|
b9e1efbe00 | ||
|
|
2ca6870c6a | ||
|
|
ca3bedeeb4 | ||
|
|
f85d56ac4d | ||
|
|
9a522f7922 | ||
|
|
f453077796 | ||
|
|
387029c5a6 | ||
|
|
f3b74696c0 | ||
|
|
f946adb6d1 | ||
|
|
dc3174747b | ||
|
|
837ad89502 | ||
|
|
58ffd93961 | ||
|
|
579c392a09 | ||
|
|
81fd1f522f | ||
|
|
e30dcac465 | ||
|
|
ee54cf2ebb | ||
|
|
f47ead51ca | ||
|
|
ab425e0492 | ||
|
|
95134b9ab8 | ||
|
|
7ccac9aa79 | ||
|
|
69f221a424 | ||
|
|
3c6eabaef8 | ||
|
|
76361d1ca9 | ||
|
|
de69cf7ceb | ||
|
|
3fd894df50 | ||
|
|
ddbed22a6f | ||
|
|
f51140f361 | ||
|
|
1876667db1 | ||
|
|
2587c2e372 | ||
|
|
4f6dfe3132 | ||
|
|
58dbd7868a | ||
|
|
3d1245bee6 | ||
|
|
2df012fb97 | ||
|
|
83d5f74e19 | ||
|
|
4dfac05fcb | ||
|
|
3548e3e8cd | ||
|
|
862ebe7d48 | ||
|
|
a56acf553c | ||
|
|
0658f5b7fa | ||
|
|
972e154a75 | ||
|
|
70b0bedf9b | ||
|
|
d843f719c8 | ||
|
|
edf8d8a463 | ||
|
|
8c3e61c6a0 | ||
|
|
6de1d45246 | ||
|
|
5488870267 | ||
|
|
a3845187b3 | ||
|
|
2955a61a5c | ||
|
|
0f11730181 | ||
|
|
75255d80cd | ||
|
|
2d88f5966c | ||
|
|
2984b755d5 | ||
|
|
7362db833b | ||
|
|
7b9bbd5be4 | ||
|
|
11d4687794 | ||
|
|
ef7c94f4e0 | ||
|
|
676e516f73 | ||
|
|
d83d3982cd | ||
|
|
a24bf2d1d7 | ||
|
|
db46faef29 | ||
|
|
64e7c1081b | ||
|
|
56bfd6a069 | ||
|
|
18ac071c5d | ||
|
|
b44790c15f | ||
|
|
e04f0eb98b | ||
|
|
2278a1217b | ||
|
|
183205b8d4 | ||
|
|
435bb7b65b | ||
|
|
52159093dd | ||
|
|
c7056efe69 | ||
|
|
1b69ffe9e0 | ||
|
|
04203312bf | ||
|
|
57bb2a3978 | ||
|
|
c32cea8f8a | ||
|
|
6ba62abd88 | ||
|
|
a31bf4e48e | ||
|
|
fab113db25 | ||
|
|
2858fd4fa8 | ||
|
|
49f12ac82f | ||
|
|
bf943cc706 | ||
|
|
09d8c550b5 | ||
|
|
dadcee8fe2 | ||
|
|
9dacaf7ddf | ||
|
|
622cf46858 | ||
|
|
0c6f8bb52d | ||
|
|
cccf05db39 | ||
|
|
f4ca5290ce | ||
|
|
2380b6aa76 | ||
|
|
215ccb70bc | ||
|
|
3d5376889f | ||
|
|
6053e3be64 | ||
|
|
51f6d27edf | ||
|
|
e46a2089dd | ||
|
|
d5dd918fde | ||
|
|
bf855c8b4c | ||
|
|
4d273b34f7 | ||
|
|
eb82a8afda | ||
|
|
73c4204ee9 | ||
|
|
8fbbd0e714 | ||
|
|
438daf82b4 | ||
|
|
7066098957 | ||
|
|
4e2b1cf4ce | ||
|
|
8e36b55e40 | ||
|
|
e8df572503 | ||
|
|
3e9556e1ef | ||
|
|
ceef3e690d | ||
|
|
3e6bc02256 | ||
|
|
6cc1d7f721 | ||
|
|
53dba06764 | ||
|
|
e514a34e60 | ||
|
|
3efe76dc71 | ||
|
|
571e7e3333 | ||
|
|
6b4d955d7c | ||
|
|
da0b4ca25d | ||
|
|
3b093f5da3 | ||
|
|
570c02ae55 | ||
|
|
81ff4f2c8a | ||
|
|
34b0402bc1 | ||
|
|
469b75624d | ||
|
|
59e239118c | ||
|
|
10957b5fdf | ||
|
|
bc9f66008d | ||
|
|
76b798d6e2 | ||
|
|
7717a15fc2 | ||
|
|
e0ef0a38a5 | ||
|
|
b21eea1568 | ||
|
|
ac73f8d6b6 | ||
|
|
7d95969f03 | ||
|
|
f67b06be88 | ||
|
|
fa5effe1a9 | ||
|
|
1f4dcb5a38 | ||
|
|
949149ea4d | ||
|
|
8ff262456b | ||
|
|
03cf443b14 | ||
|
|
2681fdabec | ||
|
|
678c9779ce | ||
|
|
1728f5d9f0 | ||
|
|
b71312b8eb | ||
|
|
ebe27c499e | ||
|
|
fbc164df8c | ||
|
|
d419da1cac | ||
|
|
67e6e29994 | ||
|
|
3059e60096 | ||
|
|
8a4a0f6bdc | ||
|
|
a1ea97950e | ||
|
|
2d58361620 | ||
|
|
a98262338a | ||
|
|
47cd8b71f7 | ||
|
|
36d6a72317 | ||
|
|
1da5f7e223 | ||
|
|
29398de678 | ||
|
|
d95d562843 | ||
|
|
cb51839eb9 | ||
|
|
ec31075fae | ||
|
|
b30a845a65 | ||
|
|
9667c2fc5a | ||
|
|
7df4084d45 | ||
|
|
d91c9f45c3 | ||
|
|
840b3940cd | ||
|
|
8a1e875020 | ||
|
|
8c43d3f378 | ||
|
|
d67ebbe683 | ||
|
|
16d9845027 | ||
|
|
5591b49c8d | ||
|
|
e67d140af0 | ||
|
|
d8252fc769 | ||
|
|
dfb50ab7ee | ||
|
|
fcc2271e83 | ||
|
|
ae25a48d4e | ||
|
|
b703c6a0ae | ||
|
|
c8ae67aba8 | ||
|
|
9e68c32f96 | ||
|
|
5887480b29 | ||
|
|
edabd603b3 | ||
|
|
1131af8283 | ||
|
|
59e69ac1cc | ||
|
|
25281d0c6f | ||
|
|
0ab3da1512 | ||
|
|
80d4799073 | ||
|
|
71353042c3 | ||
|
|
b5c3fb16cb | ||
|
|
3e3159f03b | ||
|
|
97a2044f5e | ||
|
|
fd1093180f | ||
|
|
68f3d6c056 | ||
|
|
6002e73a59 | ||
|
|
1e0fd60d4e | ||
|
|
f0d5cda1c5 | ||
|
|
04f8630d96 | ||
|
|
440db9ba7e | ||
|
|
44fca49e3f | ||
|
|
061220263c | ||
|
|
428f8a68bf | ||
|
|
03f3e4595e | ||
|
|
21fe26d042 | ||
|
|
38f79e9244 | ||
|
|
2ff4ec81ac | ||
|
|
3d24f63fd7 | ||
|
|
e8c66db876 | ||
|
|
f38811ae9d | ||
|
|
74693c5f6e | ||
|
|
3f2560655e | ||
|
|
bac596ff5b | ||
|
|
b7561b6cfc | ||
|
|
afb41ebc05 | ||
|
|
4961f4859e | ||
|
|
0b18e1ae88 | ||
|
|
217fcaaddc | ||
|
|
f77c23f781 | ||
|
|
639c7bb876 | ||
|
|
b9a5498279 | ||
|
|
3a8e98bb82 | ||
|
|
f2e5e66383 | ||
|
|
2a52d3c52e | ||
|
|
7332d0aa37 | ||
|
|
1e7f248d28 | ||
|
|
a381eb3d5a | ||
|
|
70f2d82963 | ||
|
|
2dc0a6bc95 | ||
|
|
b37a458a1d | ||
|
|
e2257c5046 | ||
|
|
e3ee433b49 | ||
|
|
16e4b2ae40 | ||
|
|
0a513fe088 | ||
|
|
f0cd18e711 | ||
|
|
9559e9fff3 | ||
|
|
e6c869a438 | ||
|
|
f701a142c8 | ||
|
|
f02cfc5a1a | ||
|
|
14e5446696 | ||
|
|
61dc029867 | ||
|
|
9f00055454 | ||
|
|
bf4a01971d | ||
|
|
5b1d060e5a | ||
|
|
8582f74e3e | ||
|
|
fcfeacdd82 | ||
|
|
78902caf30 | ||
|
|
03d5a8357a | ||
|
|
c8f6f1b4f2 | ||
|
|
519df8c33b | ||
|
|
14205b4145 | ||
|
|
cf6eadcc8c | ||
|
|
ab5e9c8344 | ||
|
|
c1f9a86dd3 | ||
|
|
5204a34031 | ||
|
|
4c980e64ac | ||
|
|
ad772b7706 | ||
|
|
471299bd21 | ||
|
|
fc945fbab9 | ||
|
|
defc97dc35 | ||
|
|
e239cb551d | ||
|
|
bceecbf377 | ||
|
|
6bdbfe4aa0 | ||
|
|
243fab3a05 | ||
|
|
24470ffe11 | ||
|
|
cb04731319 | ||
|
|
16db12231a | ||
|
|
9e6385c00a | ||
|
|
5d79dfa6be | ||
|
|
6ccc65a85a | ||
|
|
58d2a2460b | ||
|
|
df887cba61 | ||
|
|
e68ad67070 | ||
|
|
8c9a4f9d3b | ||
|
|
d853f0e7f9 | ||
|
|
5e60f65711 | ||
|
|
ad72465a04 | ||
|
|
df75bc04f8 | ||
|
|
442c5870c4 | ||
|
|
08495a3cb2 | ||
|
|
06de76ed58 | ||
|
|
23f3ca2c5c | ||
|
|
4939c281aa | ||
|
|
02d15211fa | ||
|
|
be6f7671c8 | ||
|
|
76cd1b9cad | ||
|
|
57cfa6f5a0 | ||
|
|
aa5bcf97d2 | ||
|
|
fbf05d5263 | ||
|
|
f54a8002a7 | ||
|
|
c25b10bb78 | ||
|
|
703279a2f8 | ||
|
|
beae99c71b | ||
|
|
7478a323ab | ||
|
|
31a273446b | ||
|
|
e1e51eb124 | ||
|
|
95327fd3a3 | ||
|
|
533eed11f0 | ||
|
|
eb68a43544 | ||
|
|
7bd1156cda | ||
|
|
0c7e33b2f1 | ||
|
|
a9623ff698 | ||
|
|
44d97b64b9 | ||
|
|
e4778dea36 | ||
|
|
c3421b42c7 | ||
|
|
10bbe516d7 | ||
|
|
771e33109d | ||
|
|
ec81d5a964 | ||
|
|
ee1628dbdf | ||
|
|
a1c2c9efbd | ||
|
|
f2070332e9 | ||
|
|
5079ece2dc | ||
|
|
6a791713ea | ||
|
|
41c9568d80 | ||
|
|
698f3d2821 | ||
|
|
a86ea5d12f | ||
|
|
fea9837f30 | ||
|
|
72a11e51a2 | ||
|
|
b9e1406f5b | ||
|
|
564b425b8f | ||
|
|
532dd78aa8 | ||
|
|
5f969c703f | ||
|
|
675b0a39fc | ||
|
|
0a62472840 | ||
|
|
faa8545fcf | ||
|
|
7d98a01e9a | ||
|
|
d74d3b282d | ||
|
|
747e9438c9 | ||
|
|
b6ae809b56 | ||
|
|
c999ae9da4 | ||
|
|
61eff01008 | ||
|
|
f2ee9afa88 | ||
|
|
dc5ac7b3a3 | ||
|
|
612fbf8f38 | ||
|
|
f97a8728fd | ||
|
|
1c1ddaf3d0 | ||
|
|
30316222f3 | ||
|
|
d53e6b767c | ||
|
|
661a1b5839 | ||
|
|
cb2485ae3d | ||
|
|
fa70bf3ff8 | ||
|
|
a32419d07d | ||
|
|
c2e806e318 | ||
|
|
ba8bbc462d | ||
|
|
c4a04d3dca | ||
|
|
1135458d60 | ||
|
|
3d2aa17cf2 | ||
|
|
3baf1f17bf | ||
|
|
f8ecbb7806 | ||
|
|
8f3f2a20c1 | ||
|
|
7935644115 | ||
|
|
dde3eca10e | ||
|
|
ae60a08baa | ||
|
|
676e4a2cd4 | ||
|
|
7f66d4690e | ||
|
|
40fccc57ed | ||
|
|
df44cc0779 | ||
|
|
d29e2f3994 | ||
|
|
3c6b485321 | ||
|
|
4e08c0f3cf | ||
|
|
c9c45ec8d1 | ||
|
|
af4d1e650c | ||
|
|
3412cb6e45 | ||
|
|
9cbf9f3942 | ||
|
|
837e5764b8 | ||
|
|
491c27cd74 | ||
|
|
bddb517583 | ||
|
|
843cc89547 | ||
|
|
4324b8dfc5 | ||
|
|
078a65a8bf | ||
|
|
17aa37f17b | ||
|
|
d30d951494 | ||
|
|
7bc76bdee4 | ||
|
|
4fc1a87ead | ||
|
|
4b8e157098 | ||
|
|
8fef756172 | ||
|
|
7aab27a60f | ||
|
|
2ebcc52358 | ||
|
|
7e83bad920 | ||
|
|
052ea72e87 | ||
|
|
37dd04746b | ||
|
|
c0a815f36e | ||
|
|
8fa1e3dd79 | ||
|
|
61c9bdea92 | ||
|
|
d804ca40f4 | ||
|
|
aa3d09a55c | ||
|
|
5a65ee5254 | ||
|
|
a50c7d34ff | ||
|
|
b98ab87ae7 | ||
|
|
f90f1ec7c0 | ||
|
|
b8edecc092 | ||
|
|
3b73e3d49d | ||
|
|
580afb5a21 | ||
|
|
a673756664 | ||
|
|
0499639473 | ||
|
|
69dd14682c | ||
|
|
d9fa110156 | ||
|
|
3f9fc67ab4 | ||
|
|
43c82fb028 | ||
|
|
01c0fa9563 | ||
|
|
ffce78808e | ||
|
|
e4d5ffb281 | ||
|
|
b8422e7299 | ||
|
|
d7641455d4 | ||
|
|
b6e56ae42c | ||
|
|
52cfa061c4 | ||
|
|
9208debb1a | ||
|
|
5da4e9f4a8 | ||
|
|
f30bfb20ef | ||
|
|
798eee940c | ||
|
|
9c44356d5a | ||
|
|
e241ad349a | ||
|
|
25f5b82cff | ||
|
|
5776f56f7b | ||
|
|
20da15c931 | ||
|
|
0b68dd0e85 | ||
|
|
4e49e69c16 | ||
|
|
8c775896b2 | ||
|
|
9af1168004 | ||
|
|
c1986623ed | ||
|
|
700a39f4c5 | ||
|
|
738cae727e | ||
|
|
08536f0850 | ||
|
|
ddca72e8bd | ||
|
|
3ddbf3aca7 | ||
|
|
52ed21cae5 | ||
|
|
f7dd5d92ac | ||
|
|
4d3e1c713a | ||
|
|
b54f6310f3 | ||
|
|
008bdfdad5 | ||
|
|
ffa6c115e1 | ||
|
|
ae3d59fc47 | ||
|
|
3207aeb741 | ||
|
|
b3949aa3cc | ||
|
|
6e9d29937d | ||
|
|
96dca60a2b | ||
|
|
8d3a7f2526 | ||
|
|
ac9f51a0f3 | ||
|
|
8ffd06025e | ||
|
|
576f424bc0 | ||
|
|
ec5c92e369 | ||
|
|
6a97b3dee5 | ||
|
|
70070daf1c | ||
|
|
482e4097d8 | ||
|
|
f774b4bbcf | ||
|
|
47938a1072 | ||
|
|
93449c9320 | ||
|
|
e93310b9bf | ||
|
|
9a26889fc7 | ||
|
|
106fdc72c4 | ||
|
|
6224d8fbbe | ||
|
|
b1a195c67e | ||
|
|
607fbb609c | ||
|
|
13e186576b | ||
|
|
d30041dfe7 | ||
|
|
dc14024dd7 | ||
|
|
bd95bc12ba | ||
|
|
0b67883de8 | ||
|
|
64e1d6b27e | ||
|
|
7a840f1a6e | ||
|
|
35ac4e91f6 | ||
|
|
9a03074283 | ||
|
|
0ed68957db | ||
|
|
44d4e4f78f | ||
|
|
4506f06b01 | ||
|
|
813e3227ad | ||
|
|
3bbccf2c3c | ||
|
|
810677014c | ||
|
|
f81ef16012 | ||
|
|
c33a9ea975 | ||
|
|
f672231eec | ||
|
|
9876189c64 | ||
|
|
2f84ac6fee | ||
|
|
692904dc5e | ||
|
|
c02aceeead | ||
|
|
ee24b58a2c | ||
|
|
29d1cda756 | ||
|
|
343df3f97c | ||
|
|
089eeb2956 | ||
|
|
da2e2dbf20 | ||
|
|
8501a0b818 | ||
|
|
59a9f73872 | ||
|
|
b3438ccc86 | ||
|
|
72a57edaa3 | ||
|
|
b19a63f69a | ||
|
|
71a600e308 | ||
|
|
ebb9758d28 | ||
|
|
e9e25f8800 | ||
|
|
b42226c490 | ||
|
|
15965cd1b1 | ||
|
|
8fef564297 | ||
|
|
81f01996db | ||
|
|
00c378ad94 | ||
|
|
85eefe9a54 | ||
|
|
43cbc44941 | ||
|
|
f7540e7e36 | ||
|
|
c0a8c02c26 | ||
|
|
c054712828 | ||
|
|
f20616e6b7 | ||
|
|
e518c146f0 | ||
|
|
602115266a | ||
|
|
4e074af139 | ||
|
|
cceaf2bc02 | ||
|
|
acb49d2b69 | ||
|
|
4d84924da0 | ||
|
|
cc94913e16 | ||
|
|
13459bd136 | ||
|
|
b285b1c17f | ||
|
|
05c18658a0 | ||
|
|
f1a52f55d9 | ||
|
|
ea05052677 | ||
|
|
13311c374f | ||
|
|
daa288c1cc | ||
|
|
38b613ac5f | ||
|
|
7429f454eb | ||
|
|
3c119fe3e8 | ||
|
|
428525e1bd | ||
|
|
e07dbf374c | ||
|
|
f1306dfbee | ||
|
|
db4663cbf9 | ||
|
|
3760275937 | ||
|
|
b4afeac71f | ||
|
|
b19c543988 | ||
|
|
0a5ce00878 | ||
|
|
bfe256c578 | ||
|
|
af31c84982 | ||
|
|
67a2ad241a | ||
|
|
8a9449e240 | ||
|
|
95ef59be68 | ||
|
|
8463fb402e | ||
|
|
0f4391bdd1 | ||
|
|
2738019c3f | ||
|
|
ce3e76aa3d | ||
|
|
9d76b6c5cc | ||
|
|
6e023222de | ||
|
|
6b62fc7963 | ||
|
|
d38962868b | ||
|
|
3a0ee7de94 | ||
|
|
dff21145d0 | ||
|
|
81bf80d8b0 | ||
|
|
d2e1b556ba | ||
|
|
97b263cf57 | ||
|
|
fa140f09fc | ||
|
|
2cb824c1e1 | ||
|
|
9dc5c60100 | ||
|
|
8212810276 | ||
|
|
44d772a32f | ||
|
|
fbe3e1b44f | ||
|
|
d56fe9f9b0 | ||
|
|
9d3d347fb7 | ||
|
|
30fcab6626 | ||
|
|
44f25f7497 | ||
|
|
53c4a74074 | ||
|
|
a126c8f06d | ||
|
|
2ed81ef9be | ||
|
|
3a844767f0 | ||
|
|
3667b72634 | ||
|
|
3f8d272eee | ||
|
|
a15daa87c5 | ||
|
|
d6092fc3eb | ||
|
|
4d2c7bd776 | ||
|
|
78947d51dc | ||
|
|
8d7e482219 | ||
|
|
14d313686c | ||
|
|
b79bd9a30e | ||
|
|
891885fcb3 | ||
|
|
e1986612d5 | ||
|
|
4c9435594d | ||
|
|
cc353f5956 | ||
|
|
a90971b762 | ||
|
|
f32edcde74 | ||
|
|
177a7d3054 | ||
|
|
c693146e15 | ||
|
|
296358e473 | ||
|
|
06d5628180 | ||
|
|
9085bbff96 | ||
|
|
0171ce64e4 | ||
|
|
222ff4a6de | ||
|
|
1c46f2436c | ||
|
|
65654fdef2 | ||
|
|
9035d68d96 | ||
|
|
41b2d2bce7 | ||
|
|
b67c2dc625 | ||
|
|
ec0d738e9f | ||
|
|
028da06b34 | ||
|
|
dd5037cb07 | ||
|
|
5406c0156a | ||
|
|
2f97583289 | ||
|
|
fcde65eaee | ||
|
|
8fccdae675 | ||
|
|
50cb0528c6 | ||
|
|
3cf0c2f804 | ||
|
|
fad9e8516e | ||
|
|
7b3d4739aa | ||
|
|
e9f7046a05 | ||
|
|
9ce7239308 | ||
|
|
acc5a88a27 | ||
|
|
1cc99231ae | ||
|
|
39e0784714 | ||
|
|
9f0569cd0b | ||
|
|
d455ef3e33 | ||
|
|
691918cfc8 | ||
|
|
df294eee15 | ||
|
|
3a94ea35f6 | ||
|
|
4f711d8a34 | ||
|
|
c5ec653215 | ||
|
|
937b83d776 | ||
|
|
8b585a06e7 | ||
|
|
a53f88cbaf | ||
|
|
604a9212ca | ||
|
|
09d7e8abde | ||
|
|
1ddfcff441 | ||
|
|
08eb168f06 | ||
|
|
f0f6fd6887 | ||
|
|
892df7bd0c | ||
|
|
1a672a8aa3 | ||
|
|
8ec9a8ae22 | ||
|
|
defa18724c | ||
|
|
f56f965d06 | ||
|
|
1ea488024b | ||
|
|
4f85734de5 | ||
|
|
a3b6e6f161 | ||
|
|
ff1e851143 | ||
|
|
95f19bde45 | ||
|
|
457110fa62 | ||
|
|
23195e03b8 | ||
|
|
c9feaa7074 | ||
|
|
6ec5df9309 | ||
|
|
892e5fab1f | ||
|
|
15424a2617 | ||
|
|
5188c0f473 | ||
|
|
c91552339c | ||
|
|
8565b74510 | ||
|
|
7524bc3bc3 | ||
|
|
038d0e038b | ||
|
|
077e1a697b | ||
|
|
f5053bbc22 | ||
|
|
baf61c0bdb | ||
|
|
e3dcfb9136 | ||
|
|
e4c71fb3e4 | ||
|
|
44e947ac8a | ||
|
|
fc7e2400cf | ||
|
|
e30e164ba3 | ||
|
|
007e013514 | ||
|
|
10b5d2c4f7 | ||
|
|
ef9b15d924 | ||
|
|
a44bc68e81 | ||
|
|
ec75d17bcf | ||
|
|
ad5f9a3762 | ||
|
|
a720065a45 | ||
|
|
6342e0b243 | ||
|
|
e9814504db | ||
|
|
145cf9820a | ||
|
|
d7fae910fb | ||
|
|
d15474c243 | ||
|
|
805f377459 | ||
|
|
bf320261f9 | ||
|
|
fb94597409 | ||
|
|
93e4bd8cd0 | ||
|
|
dfa839526c | ||
|
|
0d1f138459 | ||
|
|
ace47d6515 | ||
|
|
87c1808b7e | ||
|
|
95627f3617 | ||
|
|
9c20ac68f5 | ||
|
|
ed1665d625 | ||
|
|
c6de70f57f | ||
|
|
28dcfd714e | ||
|
|
1ed6099878 | ||
|
|
5e9c2fc255 | ||
|
|
f9a4e3c9fc | ||
|
|
9d7582caa6 | ||
|
|
f9d47de8f2 | ||
|
|
e057b64055 | ||
|
|
5968e3d065 | ||
|
|
b22bb295af | ||
|
|
fb3ecd4cf7 | ||
|
|
65b4454f2c | ||
|
|
3e5f178c4d | ||
|
|
35f87f6361 | ||
|
|
c2141dc034 | ||
|
|
6e460c5584 | ||
|
|
3a523a514c | ||
|
|
e1e654c6b7 | ||
|
|
161009c4ac | ||
|
|
6cb2649981 | ||
|
|
6089e2e267 | ||
|
|
ac6bf02b2d | ||
|
|
365bbaf2ad | ||
|
|
f320ef4721 | ||
|
|
87a34f2fbb | ||
|
|
defdd904c8 | ||
|
|
3f91c33eae | ||
|
|
2e3642671f | ||
|
|
02e2f42481 | ||
|
|
168f37dc8a | ||
|
|
38aeda6d83 | ||
|
|
eb29b626d0 | ||
|
|
e50839b7cc | ||
|
|
082086ffa3 | ||
|
|
7327b995e1 | ||
|
|
a6fb23302e | ||
|
|
055518da79 | ||
|
|
6d903a526b | ||
|
|
8d0c230c30 | ||
|
|
440e71d983 | ||
|
|
328cc89e39 | ||
|
|
e4fd5d7293 | ||
|
|
77d8fbbfc5 | ||
|
|
fd4f484bab | ||
|
|
e116c52ea9 | ||
|
|
46fbd93d9b | ||
|
|
bd1805750b | ||
|
|
114663836c | ||
|
|
82c5e88c4a | ||
|
|
a0ec26a755 | ||
|
|
a29386c7a1 | ||
|
|
0ea25b46f7 | ||
|
|
63b471780d | ||
|
|
25065a66aa | ||
|
|
60c64fcb6c | ||
|
|
e5f8a83c7f | ||
|
|
39811e7a2e | ||
|
|
04cb611183 | ||
|
|
f15a73200f | ||
|
|
a6f3c879a5 | ||
|
|
811e5479f4 | ||
|
|
13af95f600 | ||
|
|
b6743725e0 | ||
|
|
d3579218f2 | ||
|
|
ff003d9603 | ||
|
|
805b27074c | ||
|
|
22e34da132 | ||
|
|
71119b8d81 | ||
|
|
ef2886ffc7 | ||
|
|
770b85ebd2 | ||
|
|
f75f992a59 | ||
|
|
113f1fac6a | ||
|
|
de58da6dab | ||
|
|
256eeb863c | ||
|
|
7420f2ff98 | ||
|
|
b2b968f915 | ||
|
|
12d89d8c4a | ||
|
|
476e64c389 | ||
|
|
e183f39dfd | ||
|
|
f9e34ce9d5 | ||
|
|
6bdd976209 | ||
|
|
efd64ecded | ||
|
|
50db978fa2 | ||
|
|
de410bf75f | ||
|
|
2ff7825b34 | ||
|
|
9b1ae75a00 | ||
|
|
e7f0911f8b | ||
|
|
c004beab02 | ||
|
|
fa758c51ee | ||
|
|
1aa2282321 | ||
|
|
9094c44b07 | ||
|
|
c46036761c | ||
|
|
5d2f3cd2a7 | ||
|
|
76f1902cae | ||
|
|
5801c329b2 | ||
|
|
302833eb22 | ||
|
|
f30b25e23f | ||
|
|
211e8c438a | ||
|
|
4a33ed8fc2 | ||
|
|
556ea8754c | ||
|
|
d2fdd37084 | ||
|
|
12e2f146bf | ||
|
|
eae701012a | ||
|
|
c4ae2c5c1b | ||
|
|
fb52bf3984 | ||
|
|
6c0ae235f0 | ||
|
|
399f867016 | ||
|
|
bb947ac0a9 | ||
|
|
30813f5efc | ||
|
|
411e6720e1 | ||
|
|
1255dc03b2 | ||
|
|
61e060b8ef | ||
|
|
18b009f6af | ||
|
|
d4b246e37f | ||
|
|
4da052279e | ||
|
|
12a9afe2fe | ||
|
|
e2a0314742 | ||
|
|
bdd4df9dd7 | ||
|
|
491a28c03e | ||
|
|
dc389e0f41 | ||
|
|
121f9b547c | ||
|
|
6c03a00f57 | ||
|
|
58ec18f47d | ||
|
|
973a92886b | ||
|
|
4497c4be66 | ||
|
|
33ec8d0041 | ||
|
|
215867ae21 | ||
|
|
4711c0f785 | ||
|
|
ad1dece946 | ||
|
|
dc202f987a | ||
|
|
12fbee8597 | ||
|
|
856621a8a7 | ||
|
|
2c4bda882f | ||
|
|
7f524153a6 | ||
|
|
6652f8cb65 | ||
|
|
b00dfb6135 | ||
|
|
93960dd1b8 | ||
|
|
d105045b75 | ||
|
|
49d21bbba8 | ||
|
|
b1f05c38b3 | ||
|
|
9f7ed802ea | ||
|
|
9b7313ce95 | ||
|
|
d42896a19c | ||
|
|
2729b8ece8 | ||
|
|
85ed99a1dc | ||
|
|
aa7959b91c | ||
|
|
781d9dd440 | ||
|
|
483a346faa | ||
|
|
6e9f368a0a | ||
|
|
84a3688525 | ||
|
|
3c08986889 | ||
|
|
477828beb9 | ||
|
|
fadc6c46ba | ||
|
|
3111166f89 | ||
|
|
f7c8b62f6c | ||
|
|
e6edc6ae03 | ||
|
|
3bc0799091 | ||
|
|
1285955e32 | ||
|
|
5fdc8cb32c | ||
|
|
8538a77db7 | ||
|
|
329b84f7b5 | ||
|
|
4dcb7acd58 | ||
|
|
d91f9cf29f | ||
|
|
1a04dec97b | ||
|
|
c6f95a9030 | ||
|
|
62d2157fd8 | ||
|
|
d0c61ea5fa | ||
|
|
b9c7d108e5 | ||
|
|
20a8597b45 | ||
|
|
9a1ada97ec | ||
|
|
0ebe32228d | ||
|
|
ad5da12154 | ||
|
|
cdd2e0dd1d | ||
|
|
3fe10212d5 | ||
|
|
97e97a6cfc | ||
|
|
9cb8d9d65e | ||
|
|
eadf3b46e0 | ||
|
|
5d97a16d75 | ||
|
|
e13ca70143 | ||
|
|
732493d663 | ||
|
|
569284ef60 | ||
|
|
85a1891b8c | ||
|
|
6a67344643 | ||
|
|
0bff0a7878 | ||
|
|
925d26f02b | ||
|
|
45539289fd | ||
|
|
4cbcddf3c0 | ||
|
|
304d63c6a2 | ||
|
|
ec784b4a98 | ||
|
|
1b899f2228 | ||
|
|
a8d437720b | ||
|
|
fc7c9e1c0a | ||
|
|
514607a731 | ||
|
|
9344e08d7b | ||
|
|
13cec0dd31 | ||
|
|
b80e890fd6 | ||
|
|
e54c07325e | ||
|
|
3107705e25 | ||
|
|
62db7b8382 | ||
|
|
8e8fefef36 | ||
|
|
0c178ec71f | ||
|
|
3c9c3cb709 | ||
|
|
2ebfd108ea | ||
|
|
31df3927c5 | ||
|
|
c1b7e06308 | ||
|
|
8368eb4541 | ||
|
|
ce995a9380 | ||
|
|
110d773e3c | ||
|
|
6965591e7b | ||
|
|
4b47cfda57 | ||
|
|
e7db4d6b67 | ||
|
|
c8a63044af | ||
|
|
622b27448f | ||
|
|
e2814141d4 | ||
|
|
1a0f70c56b | ||
|
|
e86ec32dd7 | ||
|
|
4667a14080 | ||
|
|
c8bd2ec1a1 | ||
|
|
933625011c | ||
|
|
c032541f69 | ||
|
|
78b9bf9823 | ||
|
|
3cf94bb728 | ||
|
|
ae1ee69d25 | ||
|
|
bf6bb93829 | ||
|
|
61ef7dfc75 | ||
|
|
82948e56d2 | ||
|
|
2338c5a4fa | ||
|
|
63b60999f8 | ||
|
|
5857a3aed7 | ||
|
|
364d41737f | ||
|
|
31c69477f4 | ||
|
|
d1e9477fb4 | ||
|
|
f325b778a9 | ||
|
|
a7270f7510 | ||
|
|
5da493713f | ||
|
|
ca0a7689be | ||
|
|
6efe19d50c | ||
|
|
08ce7c9186 | ||
|
|
cd25f0c723 | ||
|
|
fd6554658b | ||
|
|
8abc8ab0e4 | ||
|
|
7a16e7743e | ||
|
|
aac3cf2b69 | ||
|
|
c30a5e437f | ||
|
|
473c63267f | ||
|
|
318d8f8ccc | ||
|
|
ee24ab8f6e | ||
|
|
e89ca133cd | ||
|
|
c1292e5a52 | ||
|
|
a236b1f9da | ||
|
|
c9c7794e73 | ||
|
|
29c5717e79 | ||
|
|
ccc8e704b4 | ||
|
|
5991afc1f0 | ||
|
|
58329fd61f | ||
|
|
b7ed8ec246 | ||
|
|
c975ab7b05 | ||
|
|
fdf11d144f | ||
|
|
99f1821215 | ||
|
|
3d14646548 | ||
|
|
b826b1928e | ||
|
|
b6038285f4 | ||
|
|
0f8621d923 | ||
|
|
2d9e9a5e93 | ||
|
|
abeb5fc0e3 | ||
|
|
47e61cecdd | ||
|
|
17aaf08717 | ||
|
|
89e849d851 | ||
|
|
42098f477a | ||
|
|
e44ee9ca03 | ||
|
|
e7831ac960 | ||
|
|
8a48b71a0f | ||
|
|
2e4d50c7b5 | ||
|
|
df501e42b9 | ||
|
|
1d14d37c1d | ||
|
|
0d728ed4ce | ||
|
|
4e2ff445e0 | ||
|
|
f3818803fd | ||
|
|
329668322f | ||
|
|
0ffd0c1530 | ||
|
|
7b7c6fbfae | ||
|
|
b946228ee2 | ||
|
|
61177901e8 | ||
|
|
bb4f8b0d78 | ||
|
|
1a4e701f98 | ||
|
|
968ee917fc | ||
|
|
bbc01c0be9 | ||
|
|
3387b41841 | ||
|
|
d36a578708 | ||
|
|
36d42ab8ba | ||
|
|
ba71f10dee | ||
|
|
7bb1857d0c | ||
|
|
999ce51178 | ||
|
|
a2ebf69551 | ||
|
|
9ef3ba9342 | ||
|
|
88e82a511b | ||
|
|
495c49f277 | ||
|
|
0459091a52 | ||
|
|
ba67529d62 | ||
|
|
9bd16c0b5c | ||
|
|
a0c76052cc | ||
|
|
c4861c5efa | ||
|
|
6b8f46bf81 | ||
|
|
1a71f43c54 | ||
|
|
b4d732656f | ||
|
|
6a335269f4 | ||
|
|
c51f2fa401 | ||
|
|
69072cf0ca | ||
|
|
b023964aec | ||
|
|
59321dbd56 | ||
|
|
f1c282451b | ||
|
|
ff0c34c0b8 | ||
|
|
4380175c8b | ||
|
|
439598d7ee | ||
|
|
08fa24b095 | ||
|
|
c836548fc7 | ||
|
|
f109146379 | ||
|
|
8ff46bba74 | ||
|
|
af7f4e3bc4 | ||
|
|
06f1305f23 | ||
|
|
ddc299fa08 | ||
|
|
43df9d25f0 | ||
|
|
250ac0e8ba | ||
|
|
29d960878c | ||
|
|
8e6634ff0f | ||
|
|
15b5cf9750 | ||
|
|
c001c4b5bd | ||
|
|
43723697f7 | ||
|
|
99d6a0ab32 | ||
|
|
c2809ca091 | ||
|
|
108432c268 | ||
|
|
aa0db4b665 | ||
|
|
cda62b8a3e | ||
|
|
970242e860 | ||
|
|
9c741da4e8 | ||
|
|
2dfd43c8ba | ||
|
|
5536687d90 | ||
|
|
34c421733e | ||
|
|
b0b29443a5 | ||
|
|
a637dcd28d | ||
|
|
b6b3ec04be | ||
|
|
6586f51791 | ||
|
|
dff2e344a4 | ||
|
|
92e4e81788 | ||
|
|
aa9ee7e1af | ||
|
|
2d3f2f4b36 | ||
|
|
73fe4d68f1 | ||
|
|
d244602818 | ||
|
|
67d9c6ed4e | ||
|
|
55f8932495 | ||
|
|
24617f4a41 | ||
|
|
5d47009e07 | ||
|
|
c46acc1ad4 | ||
|
|
20051a835b | ||
|
|
2ae0f36241 | ||
|
|
873e33a04f | ||
|
|
e33c5d7cbc | ||
|
|
b729ec1a85 | ||
|
|
9b18ecf072 | ||
|
|
88c4ae5721 | ||
|
|
d2b94955d1 | ||
|
|
dbcc00fe1a | ||
|
|
b56ae68854 | ||
|
|
312ea7d962 | ||
|
|
ceb3b562e6 | ||
|
|
b211009e91 | ||
|
|
eec372c6df | ||
|
|
011e83fac6 | ||
|
|
70fa577e10 | ||
|
|
dd8e55c2ac | ||
|
|
b8f3f53d56 | ||
|
|
d5623dabb6 | ||
|
|
db50687a1e | ||
|
|
00fcd5a9b6 | ||
|
|
272fd58481 | ||
|
|
ecbde48f63 | ||
|
|
3dda43c70a | ||
|
|
39827e449b | ||
|
|
44d0c78077 | ||
|
|
34029c6f6f | ||
|
|
929b8c2d50 | ||
|
|
b71a64c214 | ||
|
|
66c5d408c6 | ||
|
|
ab1dbd0d5c | ||
|
|
cc307e3217 | ||
|
|
e3c45a5039 | ||
|
|
6754efc486 | ||
|
|
1e5d9d314b | ||
|
|
cea6aaf7ff | ||
|
|
c1f019e71c | ||
|
|
c00b511c17 | ||
|
|
51c6067c17 | ||
|
|
c032e74e58 | ||
|
|
412d40d041 | ||
|
|
2cc69a0725 | ||
|
|
89b3b6da61 | ||
|
|
77a7fffcb2 | ||
|
|
30a9c8c90e | ||
|
|
abd52c7a42 | ||
|
|
9bb164246e | ||
|
|
87d0e18696 | ||
|
|
e8f5864dd9 | ||
|
|
51d7b3f413 | ||
|
|
fb3de84aa4 | ||
|
|
4a2aa91b6d | ||
|
|
a4edac59c6 | ||
|
|
19af59b301 | ||
|
|
d1b27dfd9d | ||
|
|
274fb0f380 | ||
|
|
8e70567688 | ||
|
|
7cbc24feb8 | ||
|
|
2bdcf3919e | ||
|
|
8214f4ba20 | ||
|
|
d0a5fc24b1 | ||
|
|
c8084c670a | ||
|
|
82a9779b09 | ||
|
|
fdb887e43a | ||
|
|
7761244eec | ||
|
|
6580334bdd | ||
|
|
e2f7a22457 | ||
|
|
494382f5cb | ||
|
|
2ff248a4c4 | ||
|
|
7ed15a2dbc | ||
|
|
3d1725054a | ||
|
|
d6e37f9f13 | ||
|
|
2c78bef505 | ||
|
|
d60b9706b3 | ||
|
|
d20996d788 | ||
|
|
0010976803 | ||
|
|
bd422323ee | ||
|
|
6a66d99017 | ||
|
|
f1d87da9b6 | ||
|
|
ac8674a8b3 | ||
|
|
c2af7914e3 | ||
|
|
102db4c937 | ||
|
|
1f7d92b209 | ||
|
|
555cc74312 | ||
|
|
761319c13d | ||
|
|
828e867ac9 | ||
|
|
6a7b4f107e | ||
|
|
c0df364b4f | ||
|
|
71c72136f6 | ||
|
|
ec5f8fc4f5 | ||
|
|
f5e6ed914d | ||
|
|
2e7bc894f1 | ||
|
|
18537b9cdb | ||
|
|
ed5cb715da | ||
|
|
32cf86ede5 | ||
|
|
97f320c9a7 | ||
|
|
7c6dd75a23 | ||
|
|
6a59355514 | ||
|
|
91c3413c57 | ||
|
|
717f5f6e2e | ||
|
|
f48efae82d | ||
|
|
5f372ebee3 | ||
|
|
5b27fad3aa | ||
|
|
6149a951bd | ||
|
|
2529205359 | ||
|
|
81b71a7676 | ||
|
|
29c80f7845 | ||
|
|
05372fc4a4 | ||
|
|
50e433aba0 | ||
|
|
ac4797a943 | ||
|
|
3c7baa7237 | ||
|
|
3f9d6e48b5 | ||
|
|
79adfe70a4 | ||
|
|
ae8b616fed | ||
|
|
0b8b2db41e | ||
|
|
63183b33f1 | ||
|
|
de09d1dbd2 | ||
|
|
b59e318444 | ||
|
|
0a65da2fc4 | ||
|
|
e46be54688 | ||
|
|
e4f8a51df8 | ||
|
|
a51f48f060 | ||
|
|
32df0c1730 | ||
|
|
530c8818b7 | ||
|
|
6c99f73596 | ||
|
|
61acaaa054 | ||
|
|
25b695bc32 | ||
|
|
0f41cb5ad4 | ||
|
|
40e57e3a54 | ||
|
|
113b05ed05 | ||
|
|
824ce88914 | ||
|
|
a1e243714e | ||
|
|
1c0ed64f67 | ||
|
|
1f1cd1b6d7 | ||
|
|
e81725eb16 | ||
|
|
ee4220e1ce | ||
|
|
a733c6c68d | ||
|
|
d7c7619218 | ||
|
|
77066ba7e5 | ||
|
|
35c5919c44 | ||
|
|
fcdd286965 | ||
|
|
e84fa1d636 | ||
|
|
bfe9bad905 | ||
|
|
459b6bc6fe | ||
|
|
332211fb13 | ||
|
|
e5d42cf0eb | ||
|
|
424df8d4fe | ||
|
|
2f4422f719 | ||
|
|
831611af1e | ||
|
|
c302d362a4 | ||
|
|
69d4b1096f | ||
|
|
2514a89286 | ||
|
|
2034055148 | ||
|
|
3a3b1007b9 | ||
|
|
09a83b36ff | ||
|
|
32cc59228d | ||
|
|
31b2413953 | ||
|
|
c8eb643818 | ||
|
|
11b251003e | ||
|
|
28bb0e99cb | ||
|
|
5c9c686317 | ||
|
|
098425bdbf | ||
|
|
5189f6b392 | ||
|
|
f487479b1d | ||
|
|
03224cc4f6 | ||
|
|
482754eddb | ||
|
|
7fcf6874e3 | ||
|
|
a3e0eee8d4 | ||
|
|
b7ffb06f9c | ||
|
|
35a209bcb6 | ||
|
|
c3a2a15608 | ||
|
|
9acdfe5dcf | ||
|
|
9ec8056d89 | ||
|
|
b9c2cc2c4f | ||
|
|
675a2811d4 | ||
|
|
b1df5f533b | ||
|
|
a61cf3f889 | ||
|
|
ace09646c6 | ||
|
|
d2113c4379 | ||
|
|
9e60778075 | ||
|
|
4e78e4019f | ||
|
|
823d13af34 | ||
|
|
4007870bfb | ||
|
|
5d92f98548 | ||
|
|
cbbff69003 | ||
|
|
f40240d8cb | ||
|
|
9671599fc9 | ||
|
|
e1be421410 | ||
|
|
f4a80ed856 | ||
|
|
39610bce24 | ||
|
|
18e0044373 | ||
|
|
a9759a20c2 | ||
|
|
f5b9673044 |
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a bug report
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. ...
|
||||
2. ...
|
||||
3. ...
|
||||
...
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**EspoCRM version**
|
||||
Specify the EspoCRM version (or versions) on which the bug occurs.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
4
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
contact_links:
|
||||
- name: EspoCRM forum
|
||||
url: https://forum.espocrm.com/
|
||||
about: Please use our forum to ask questions not related to product development
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for EspoCRM
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is.
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
0
SECURITY.md → .github/SECURITY.md
vendored
0
SECURITY.md → .github/SECURITY.md
vendored
4
.gitignore
vendored
4
.gitignore
vendored
@@ -4,6 +4,7 @@
|
||||
/data/preferences/*
|
||||
/data/.backup/*
|
||||
/data/config.php
|
||||
/data/config-internal.php
|
||||
/data/tmp/*
|
||||
/build
|
||||
/node_modules
|
||||
@@ -18,4 +19,7 @@
|
||||
/composer.phar
|
||||
/vendor/
|
||||
/custom/Espo/Custom/*
|
||||
/custom/Espo/Modules/*
|
||||
!/custom/Espo/Custom/.htaccess
|
||||
!/custom/Espo/Modules/.htaccess
|
||||
/install/config.php
|
||||
|
||||
50
.htaccess
50
.htaccess
@@ -1,24 +1,44 @@
|
||||
<ifModule mod_headers.c>
|
||||
Header always set Access-Control-Allow-Methods "POST, GET, PUT, PATCH, DELETE"
|
||||
Header always set Access-Control-Allow-Methods "POST, GET, PUT, PATCH, DELETE"
|
||||
</ifModule>
|
||||
|
||||
DirectoryIndex index.php index.html
|
||||
DirectoryIndex index.php
|
||||
|
||||
Options -Indexes
|
||||
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteEngine On
|
||||
|
||||
# PROTECTED DIRECTORIES
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
RewriteRule ^/?(api|client)/ - [F]
|
||||
# Forbid access. Not actual as redirect to `public` is applied.
|
||||
# An extra security measure if redirect not fired.
|
||||
RewriteRule ^/?data/ - [F]
|
||||
RewriteRule ^/?application/ - [F]
|
||||
RewriteRule ^/?custom/ - [F]
|
||||
RewriteRule ^/?vendor/ - [F]
|
||||
RewriteRule /?web\.config - [F]
|
||||
|
||||
RewriteRule ^/?data/ - [F]
|
||||
RewriteRule ^/?application/ - [F]
|
||||
RewriteRule ^/?custom/ - [F]
|
||||
RewriteRule ^/?vendor/ - [F]
|
||||
RewriteRule ^/?client/?$ - [F]
|
||||
#END PROTECTED DIRECTORIES
|
||||
# Forbid `public` dir.
|
||||
RewriteCond %{ENV:REDIRECT_STATUS} !=200
|
||||
RewriteRule ^/?public/? - [F,L]
|
||||
|
||||
RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}]
|
||||
# Skip redirect for `client` dir.
|
||||
RewriteRule ^client/ - [L]
|
||||
|
||||
RewriteRule /?web\.config - [F]
|
||||
</IfModule>
|
||||
# {#dev}
|
||||
# Skip redirect for `node_modules` dir. Actual only for dev environment.
|
||||
RewriteRule ^node_modules/ - [L]
|
||||
# {/dev}
|
||||
|
||||
# Store base path.
|
||||
RewriteCond %{REQUEST_URI}::$1 ^(.*?/)(.*)::\2$
|
||||
RewriteRule ^(.*)$ - [E=BASE:%1]
|
||||
|
||||
# Add trailing slash.
|
||||
RewriteCond %{DOCUMENT_ROOT}/%{ENV:BASE}/public/$1 -d
|
||||
RewriteRule ^(.*?[^/])$ %{REQUEST_URI}/ [L,R=301,NE]
|
||||
|
||||
# Rewrite to `public` dir.
|
||||
RewriteRule ^((?!public/).*)$ %{ENV:BASE}/public/$1 [L,NC]
|
||||
|
||||
RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}]
|
||||
</IfModule>
|
||||
|
||||
383
Gruntfile.js
383
Gruntfile.js
@@ -19,113 +19,67 @@
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* * `grunt` - full build
|
||||
* * `grunt dev` - build only items needed for development (takes less time)
|
||||
* * `grunt offline` - build but skip *composer install*
|
||||
* * `grant release` - full build plus upgrade packages`
|
||||
* * `grant test` - build for test running
|
||||
* * `grant run-tests` - build and run unit and integratino tests
|
||||
*/
|
||||
/**
|
||||
* * `grunt` - full build
|
||||
* * `grunt dev` - build only items needed for development (takes less time)
|
||||
* * `grunt offline` - build but skip *composer install*
|
||||
* * `grant release` - full build plus upgrade packages`
|
||||
* * `grant test` - build for tests running
|
||||
* * `grant run-tests` - build and run unit and integration tests
|
||||
*/
|
||||
|
||||
module.exports = function (grunt) {
|
||||
const fs = require('fs');
|
||||
const cp = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
var jsFilesToMinify = [
|
||||
'client/lib/jquery-2.1.4.min.js',
|
||||
'client/lib/underscore-min.js',
|
||||
'client/lib/es6-promise.min.js',
|
||||
'client/lib/backbone-min.js',
|
||||
'client/lib/handlebars.js',
|
||||
'client/lib/base64.js',
|
||||
'client/lib/jquery-ui.min.js',
|
||||
'client/lib/jquery.ui.touch-punch.min.js',
|
||||
'client/lib/moment.min.js',
|
||||
'client/lib/moment-timezone.min.js',
|
||||
'client/lib/moment-timezone-data.js',
|
||||
'client/lib/jquery.timepicker.min.js',
|
||||
'client/lib/jquery.autocomplete.js',
|
||||
'client/lib/bootstrap.min.js',
|
||||
'client/lib/bootstrap-datepicker.js',
|
||||
'client/lib/bull.js',
|
||||
'client/lib/marked.min.js',
|
||||
'client/lib/autobahn.js',
|
||||
'client/lib/gridstack.all.js',
|
||||
module.exports = grunt => {
|
||||
|
||||
'client/src/namespace.js',
|
||||
'client/src/exceptions.js',
|
||||
'client/src/loader.js',
|
||||
'client/src/utils.js',
|
||||
const pkg = grunt.file.readJSON('package.json');
|
||||
const bundleConfig = require('./frontend/bundle-config.json');
|
||||
|
||||
'client/src/acl.js',
|
||||
'client/src/model.js',
|
||||
'client/src/model-offline.js',
|
||||
'client/src/ajax.js',
|
||||
'client/src/controller.js',
|
||||
let jsFilesToBundle = getBundleLibList().concat(bundleConfig.jsFiles);
|
||||
let jsFilesToCopy = getCopyLibDataList();
|
||||
|
||||
'client/src/ui.js',
|
||||
'client/src/acl-manager.js',
|
||||
'client/src/cache.js',
|
||||
'client/src/storage.js',
|
||||
'client/src/models/settings.js',
|
||||
'client/src/language.js',
|
||||
'client/src/metadata.js',
|
||||
'client/src/field-manager.js',
|
||||
'client/src/models/user.js',
|
||||
'client/src/models/preferences.js',
|
||||
'client/src/model-factory.js',
|
||||
'client/src/collection-factory.js',
|
||||
'client/src/pre-loader.js',
|
||||
'client/src/controllers/base.js',
|
||||
'client/src/router.js',
|
||||
'client/src/date-time.js',
|
||||
'client/src/layout-manager.js',
|
||||
'client/src/theme-manager.js',
|
||||
'client/src/session-storage.js',
|
||||
'client/src/view-helper.js',
|
||||
'client/src/page-title.js',
|
||||
let libFilesToMinify = jsFilesToCopy
|
||||
.filter(item => item.minify)
|
||||
.reduce((map, item) => (
|
||||
map[item.dest] = item.dest,
|
||||
map
|
||||
), {});
|
||||
|
||||
'client/src/app.js'
|
||||
];
|
||||
let currentPath = path.dirname(fs.realpathSync(__filename));
|
||||
|
||||
function camelCaseToHyphen (string){
|
||||
if (string == null) {
|
||||
return string;
|
||||
}
|
||||
return string.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
}
|
||||
let themeList = [];
|
||||
|
||||
var fs = require('fs');
|
||||
var cp = require('child_process');
|
||||
var path = require('path');
|
||||
|
||||
var currentPath = path.dirname(fs.realpathSync(__filename));
|
||||
|
||||
var themeList = [];
|
||||
fs.readdirSync('application/Espo/Resources/metadata/themes').forEach(function (file) {
|
||||
fs.readdirSync('application/Espo/Resources/metadata/themes').forEach(file => {
|
||||
themeList.push(file.substr(0, file.length - 5));
|
||||
});
|
||||
|
||||
var cssminFilesData = {};
|
||||
var lessData = {};
|
||||
themeList.forEach(function (theme) {
|
||||
var name = camelCaseToHyphen(theme);
|
||||
var files = {};
|
||||
let cssminFilesData = {};
|
||||
|
||||
let lessData = {};
|
||||
|
||||
themeList.forEach(theme => {
|
||||
let name = camelCaseToHyphen(theme);
|
||||
|
||||
let files = {};
|
||||
|
||||
files['client/css/espo/'+name+'.css'] = 'frontend/less/'+name+'/main.less';
|
||||
files['client/css/espo/'+name+'-iframe.css'] = 'frontend/less/'+name+'/iframe/main.less';
|
||||
|
||||
cssminFilesData['client/css/espo/'+name+'.css'] = 'client/css/espo/'+name+'.css';
|
||||
cssminFilesData['client/css/espo/'+name+'-iframe.css'] = 'client/css/espo/'+name+'-iframe.css';
|
||||
var o = {
|
||||
|
||||
let o = {
|
||||
options: {
|
||||
yuicompress: true,
|
||||
},
|
||||
files: files
|
||||
files: files,
|
||||
};
|
||||
|
||||
lessData[theme] = o;
|
||||
});
|
||||
|
||||
var pkg = grunt.file.readJSON('package.json');
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: pkg,
|
||||
|
||||
@@ -135,11 +89,11 @@ module.exports = function (grunt) {
|
||||
mode: 0755,
|
||||
create: [
|
||||
'build/tmp',
|
||||
]
|
||||
},
|
||||
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
clean: {
|
||||
start: ['build/EspoCRM-*'],
|
||||
final: ['build/tmp'],
|
||||
@@ -147,27 +101,48 @@ module.exports = function (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/*',
|
||||
'build/tmp/client/custom/*',
|
||||
'!build/tmp/client/custom/modules',
|
||||
'build/tmp/client/custom/modules/*',
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
less: lessData,
|
||||
|
||||
cssmin: {
|
||||
themes: {
|
||||
files: cssminFilesData
|
||||
}
|
||||
files: cssminFilesData,
|
||||
},
|
||||
},
|
||||
|
||||
uglify: {
|
||||
options: {
|
||||
mangle: false,
|
||||
mangle: true,
|
||||
sourceMap: true,
|
||||
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
|
||||
output: {
|
||||
comments: /^!/,
|
||||
},
|
||||
},
|
||||
bundle: {
|
||||
options: {
|
||||
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
|
||||
},
|
||||
files: {
|
||||
'build/tmp/client/espo.min.js': jsFilesToBundle,
|
||||
},
|
||||
},
|
||||
lib: {
|
||||
files: libFilesToMinify,
|
||||
},
|
||||
'build/tmp/client/espo.min.js': jsFilesToMinify.map(function (item) {
|
||||
return '' + item;
|
||||
})
|
||||
},
|
||||
|
||||
copy: {
|
||||
options: {
|
||||
mode: true,
|
||||
@@ -184,11 +159,14 @@ module.exports = function (grunt) {
|
||||
'img/**',
|
||||
'css/**',
|
||||
'sounds/**',
|
||||
'custom/**'
|
||||
'custom/**',
|
||||
],
|
||||
dest: 'build/tmp/client',
|
||||
},
|
||||
frontendLib: {
|
||||
files: jsFilesToCopy,
|
||||
},
|
||||
frontendCommitedLib: {
|
||||
expand: true,
|
||||
dot: true,
|
||||
cwd: 'client/lib',
|
||||
@@ -199,14 +177,14 @@ module.exports = function (grunt) {
|
||||
expand: true,
|
||||
dot: true,
|
||||
src: [
|
||||
'api/**',
|
||||
'application/**',
|
||||
'custom/**',
|
||||
'data/.data',
|
||||
'install/**',
|
||||
'portal/**',
|
||||
'vendor/**',
|
||||
'html/**',
|
||||
'public/**',
|
||||
'install/**',
|
||||
'bin/**',
|
||||
'bootstrap.php',
|
||||
'cron.php',
|
||||
'daemon.php',
|
||||
@@ -217,7 +195,6 @@ module.exports = function (grunt) {
|
||||
'extension.php',
|
||||
'websocket.php',
|
||||
'command.php',
|
||||
'oauth-callback.php',
|
||||
'index.php',
|
||||
'LICENSE.txt',
|
||||
'.htaccess',
|
||||
@@ -233,6 +210,7 @@ module.exports = function (grunt) {
|
||||
dest: 'build/EspoCRM-<%= pkg.version %>/',
|
||||
},
|
||||
},
|
||||
|
||||
chmod: {
|
||||
php: {
|
||||
options: {
|
||||
@@ -248,20 +226,20 @@ module.exports = function (grunt) {
|
||||
'build/EspoCRM-<%= pkg.version %>/client/**/*.tpl',
|
||||
'build/EspoCRM-<%= pkg.version %>/**/*.html',
|
||||
'build/EspoCRM-<%= pkg.version %>/**/*.txt',
|
||||
]
|
||||
],
|
||||
},
|
||||
folders: {
|
||||
options: {
|
||||
mode: '755'
|
||||
},
|
||||
src: [
|
||||
'build/EspoCRM-<%= pkg.version %>/install',
|
||||
'build/EspoCRM-<%= pkg.version %>/portal',
|
||||
'build/EspoCRM-<%= pkg.version %>/api',
|
||||
'build/EspoCRM-<%= pkg.version %>/api/v1',
|
||||
'build/EspoCRM-<%= pkg.version %>/api/v1/portal-access',
|
||||
'build/EspoCRM-<%= pkg.version %>/public/install',
|
||||
'build/EspoCRM-<%= pkg.version %>/public/portal',
|
||||
'build/EspoCRM-<%= pkg.version %>/public/api',
|
||||
'build/EspoCRM-<%= pkg.version %>/public/api/v1',
|
||||
'build/EspoCRM-<%= pkg.version %>/public/api/v1/portal-access',
|
||||
'build/EspoCRM-<%= pkg.version %>',
|
||||
]
|
||||
],
|
||||
},
|
||||
foldersWritable: {
|
||||
options: {
|
||||
@@ -277,83 +255,125 @@ module.exports = function (grunt) {
|
||||
'build/EspoCRM-<%= pkg.version %>/application/Espo/Modules',
|
||||
]
|
||||
},
|
||||
executable: {
|
||||
options: {
|
||||
mode: '754'
|
||||
},
|
||||
src: [
|
||||
'build/EspoCRM-<%= pkg.version %>/bin/*',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
replace: {
|
||||
version: {
|
||||
options: {
|
||||
patterns: [
|
||||
{
|
||||
match: 'version',
|
||||
replacement: '<%= pkg.version %>'
|
||||
replacement: '<%= pkg.version %>',
|
||||
}
|
||||
]
|
||||
},
|
||||
files: [
|
||||
{
|
||||
src: 'build/tmp/application/Espo/Resources/defaults/config.php',
|
||||
dest: 'build/tmp/application/Espo/Resources/defaults/config.php'
|
||||
dest: 'build/tmp/application/Espo/Resources/defaults/config.php',
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
dev: {
|
||||
options: {
|
||||
patterns: [
|
||||
{
|
||||
match: /\# \{\#dev\}(.*)\{\/dev\}/gs,
|
||||
replacement: '',
|
||||
}
|
||||
]
|
||||
},
|
||||
files: [
|
||||
{
|
||||
src: 'build/tmp/.htaccess',
|
||||
dest: 'build/tmp/.htaccess',
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
grunt.registerTask("chmod-folders", function() {
|
||||
cp.execSync("find . -type d -exec chmod 755 {} + ", {stdio: 'ignore', cwd: 'build/EspoCRM-' + pkg.version});
|
||||
grunt.registerTask('chmod-folders', () => {
|
||||
cp.execSync(
|
||||
"find . -type d -exec chmod 755 {} + ",
|
||||
{
|
||||
stdio: 'ignore',
|
||||
cwd: 'build/EspoCRM-' + pkg.version,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
grunt.registerTask("composer", function() {
|
||||
cp.execSync("composer install --ignore-platform-reqs --no-dev", {stdio: 'ignore'});
|
||||
grunt.registerTask('composer-install', () => {
|
||||
cp.execSync("composer install --no-dev", {stdio: 'ignore'});
|
||||
});
|
||||
|
||||
grunt.registerTask("composer-dev", function() {
|
||||
cp.execSync("composer install --ignore-platform-reqs", {stdio: 'ignore'});
|
||||
grunt.registerTask('composer-install-dev', () => {
|
||||
cp.execSync("composer install", {stdio: 'ignore'});
|
||||
});
|
||||
|
||||
grunt.registerTask("upgrade", function() {
|
||||
grunt.registerTask('upgrade', () => {
|
||||
cp.execSync("node diff --all --vendor", {stdio: 'inherit'});
|
||||
});
|
||||
|
||||
grunt.registerTask("unit-tests-run", function() {
|
||||
grunt.registerTask('unit-tests-run', () => {
|
||||
cp.execSync("vendor/bin/phpunit ./tests/unit", {stdio: 'inherit'});
|
||||
});
|
||||
|
||||
grunt.registerTask("integration-tests-run", function() {
|
||||
grunt.registerTask('integration-tests-run', () => {
|
||||
cp.execSync("vendor/bin/phpunit ./tests/integration", {stdio: 'inherit'});
|
||||
});
|
||||
|
||||
grunt.registerTask("zip", function() {
|
||||
var fs = require('fs');
|
||||
grunt.registerTask('zip', () => {
|
||||
const archiver = require('archiver');
|
||||
|
||||
var resolve = this.async();
|
||||
let resolve = this.async();
|
||||
|
||||
var folder = 'EspoCRM-' + pkg.version;
|
||||
let folder = 'EspoCRM-' + pkg.version;
|
||||
|
||||
var zipPath = 'build/' + folder +'.zip';
|
||||
if (fs.existsSync(zipPath)) fs.unlinkSync(zipPath);
|
||||
let zipPath = 'build/' + folder +'.zip';
|
||||
|
||||
var archiver = require('archiver');
|
||||
var archive = archiver('zip');
|
||||
if (fs.existsSync(zipPath)) {
|
||||
fs.unlinkSync(zipPath);
|
||||
}
|
||||
|
||||
archive.on('error', function (err) {
|
||||
let archive = archiver('zip');
|
||||
|
||||
archive.on('error', err => {
|
||||
grunt.fail.warn(err);
|
||||
});
|
||||
var zipOutput = fs.createWriteStream(zipPath);
|
||||
zipOutput.on('close', function () {
|
||||
|
||||
let zipOutput = fs.createWriteStream(zipPath);
|
||||
|
||||
zipOutput.on('close', () => {
|
||||
console.log("EspoCRM package has been built.");
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
||||
archive.directory(currentPath + '/build/' + folder, folder).pipe(zipOutput);
|
||||
archive
|
||||
.directory(currentPath + '/build/' + folder, folder)
|
||||
.pipe(zipOutput)
|
||||
.finalize();
|
||||
});
|
||||
|
||||
archive.finalize();
|
||||
grunt.registerTask('npm-install', () => {
|
||||
cp.execSync("npm install", {stdio: 'ignore'});
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-mkdir');
|
||||
grunt.loadNpmTasks('grunt-contrib-less');
|
||||
grunt.loadNpmTasks('grunt-contrib-cssmin');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify-es');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-replace');
|
||||
grunt.loadNpmTasks('grunt-chmod');
|
||||
@@ -363,10 +383,12 @@ module.exports = function (grunt) {
|
||||
'mkdir:tmp',
|
||||
'less',
|
||||
'cssmin',
|
||||
'uglify',
|
||||
'uglify:bundle',
|
||||
'copy:frontendFolders',
|
||||
'copy:frontendLib',
|
||||
'copy:frontendCommitedLib',
|
||||
'copy:backend',
|
||||
'uglify:lib',
|
||||
'replace',
|
||||
'clean:beforeFinal',
|
||||
'copy:final',
|
||||
@@ -374,16 +396,22 @@ module.exports = function (grunt) {
|
||||
'chmod:php',
|
||||
'chmod:folders',
|
||||
'chmod:foldersWritable',
|
||||
'chmod:executable',
|
||||
'clean:final',
|
||||
]);
|
||||
|
||||
grunt.registerTask('default', [
|
||||
'composer',
|
||||
grunt.registerTask('build', [
|
||||
'composer-install',
|
||||
'npm-install',
|
||||
'offline',
|
||||
]);
|
||||
|
||||
grunt.registerTask('default', [
|
||||
'build',
|
||||
]);
|
||||
|
||||
grunt.registerTask('release', [
|
||||
'default',
|
||||
'build',
|
||||
'upgrade',
|
||||
'zip',
|
||||
'clean:release',
|
||||
@@ -396,7 +424,7 @@ module.exports = function (grunt) {
|
||||
]);
|
||||
|
||||
grunt.registerTask('run-unit-tests', [
|
||||
'composer-dev',
|
||||
'composer-install-dev',
|
||||
'unit-tests-run',
|
||||
]);
|
||||
|
||||
@@ -406,12 +434,87 @@ module.exports = function (grunt) {
|
||||
]);
|
||||
|
||||
grunt.registerTask('dev', [
|
||||
'composer-dev',
|
||||
'composer-install-dev',
|
||||
'less',
|
||||
]);
|
||||
|
||||
grunt.registerTask('test', [
|
||||
'composer-dev',
|
||||
'composer-install-dev',
|
||||
'npm-install',
|
||||
'offline',
|
||||
]);
|
||||
};
|
||||
|
||||
function getBundleLibList() {
|
||||
const libs = require('./frontend/libs.json');
|
||||
|
||||
let list = [];
|
||||
|
||||
libs.forEach(item => {
|
||||
if (!item.bundle) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.files) {
|
||||
item.files.forEach(item => {
|
||||
list.push(item.src);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!item.src) {
|
||||
throw new Error("No lib src.");
|
||||
}
|
||||
|
||||
list.push(item.src);
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
function getCopyLibDataList() {
|
||||
const libs = require('./frontend/libs.json');
|
||||
|
||||
let list = [];
|
||||
|
||||
libs.forEach(item => {
|
||||
if (item.bundle) {
|
||||
return;
|
||||
}
|
||||
|
||||
let minify = item.minify;
|
||||
|
||||
if (item.files) {
|
||||
item.files.forEach(item => {
|
||||
list.push({
|
||||
src: item.src,
|
||||
dest: 'build/tmp/' + (item.dest || 'client/lib/' + item.src.split('/').pop()),
|
||||
minify: minify,
|
||||
});
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!item.src) {
|
||||
throw new Error("No lib src.");
|
||||
}
|
||||
|
||||
list.push({
|
||||
src: item.src,
|
||||
dest: 'build/tmp/' + (item.dest || 'client/lib/' + item.src.split('/').pop()),
|
||||
minify: minify,
|
||||
});
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
function camelCaseToHyphen(string){
|
||||
if (string === null) {
|
||||
return string;
|
||||
}
|
||||
|
||||
return string.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ It's a web application with a frontend designed as a single page application and
|
||||
|
||||
### Requirements
|
||||
|
||||
* PHP 7.2 and later (with pdo, json, gd, openssl, zip, imap, mbstring, curl extensions);
|
||||
* PHP 7.3 and later (with pdo, json, gd, openssl, zip, imap, mbstring, curl extensions);
|
||||
* MySQL 5.7 (and later), or MariaDB 10.1 (and later).
|
||||
|
||||
For more information about server configuration see [this article](https://docs.espocrm.com/administration/server-configuration/).
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl;
|
||||
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Attachment extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($entity->get('parentType') === 'Settings') {
|
||||
return true;
|
||||
}
|
||||
|
||||
$parent = null;
|
||||
$hasParent = false;
|
||||
if ($entity->get('parentId') && $entity->get('parentType')) {
|
||||
$hasParent = true;
|
||||
$parent = $this->getEntityManager()->getEntity($entity->get('parentType'), $entity->get('parentId'));
|
||||
} else if ($entity->get('relatedId') && $entity->get('relatedType')) {
|
||||
$hasParent = true;
|
||||
$parent = $this->getEntityManager()->getEntity($entity->get('relatedType'), $entity->get('relatedId'));
|
||||
}
|
||||
|
||||
if ($hasParent) {
|
||||
if ($parent) {
|
||||
if ($parent->getEntityType() === 'Note') {
|
||||
if ($parent->get('parentId') && $parent->get('parentType')) {
|
||||
$parentOfParent = $this->getEntityManager()->getEntity($parent->get('parentType'), $parent->get('parentId'));
|
||||
if ($parentOfParent && $this->getAclManager()->checkEntity($user, $parentOfParent)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if ($this->getAclManager()->checkEntity($user, $parent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->checkEntity($user, $entity, $data, 'read')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
{
|
||||
if ($user->id === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl;
|
||||
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class EmailAddress extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkEditInEntity(EntityUser $user, Entity $entity, Entity $excludeEntity)
|
||||
{
|
||||
$id = $entity->id;
|
||||
|
||||
$isFobidden = false;
|
||||
|
||||
$repository = $this->getEntityManager()->getRepository('EmailAddress');
|
||||
|
||||
if (!$user->isAdmin()) {
|
||||
$entityWithSameAddressList = $repository->getEntityListByAddressId($id, $excludeEntity);
|
||||
foreach ($entityWithSameAddressList as $e) {
|
||||
if (!$this->getAclManager()->check($user, $e, 'edit')) {
|
||||
$isFobidden = true;
|
||||
if (
|
||||
$e->getEntityType() === 'User' &&
|
||||
$e->isPortal() &&
|
||||
$excludeEntity->getEntityType() === 'Contact' &&
|
||||
$e->get('contactId') === $excludeEntity->id
|
||||
) {
|
||||
$isFobidden = false;
|
||||
}
|
||||
if ($isFobidden) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return !$isFobidden;
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl;
|
||||
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Note extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
protected $deleteThresholdPeriod = '1 month';
|
||||
|
||||
protected $editThresholdPeriod = '7 days';
|
||||
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
{
|
||||
if ($entity->get('type') === 'Post' && $user->id === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkEntityCreate(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
if ($entity->get('parentId') && $entity->get('parentType')) {
|
||||
$parent = $this->getEntityManager()->getEntity($entity->get('parentType'), $entity->get('parentId'));
|
||||
if ($parent) {
|
||||
if ($this->getAclManager()->checkEntity($user, $parent, 'stream')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkEntityEdit(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->checkEntity($user, $entity, $data, 'edit')) {
|
||||
if ($this->checkIsOwner($user, $entity)) {
|
||||
$createdAt = $entity->get('createdAt');
|
||||
if ($createdAt) {
|
||||
$noteEditThresholdPeriod = '-' . $this->getConfig()->get('noteEditThresholdPeriod', $this->editThresholdPeriod);
|
||||
$dt = new \DateTime();
|
||||
$dt->modify($noteEditThresholdPeriod);
|
||||
try {
|
||||
if ($dt->format('U') > (new \DateTime($createdAt))->format('U')) {
|
||||
return false;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkEntityDelete(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->checkEntity($user, $entity, $data, 'delete')) {
|
||||
if ($this->checkIsOwner($user, $entity)) {
|
||||
$createdAt = $entity->get('createdAt');
|
||||
if ($createdAt) {
|
||||
$deleteThresholdPeriod = '-' . $this->getConfig()->get('noteDeleteThresholdPeriod', $this->deleteThresholdPeriod);
|
||||
$dt = new \DateTime();
|
||||
$dt->modify($deleteThresholdPeriod);
|
||||
try {
|
||||
if ($dt->format('U') > (new \DateTime($createdAt))->format('U')) {
|
||||
return false;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl;
|
||||
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class PhoneNumber extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkEditInEntity(EntityUser $user, Entity $entity, Entity $excludeEntity)
|
||||
{
|
||||
$id = $entity->id;
|
||||
|
||||
$isFobidden = false;
|
||||
|
||||
$repository = $this->getEntityManager()->getRepository('PhoneNumber');
|
||||
|
||||
if (!$user->isAdmin()) {
|
||||
$entityWithSameNumberList = $repository->getEntityListByPhoneNumberId($id, $excludeEntity);
|
||||
foreach ($entityWithSameNumberList as $e) {
|
||||
if (!$this->getAclManager()->check($user, $e, 'edit')) {
|
||||
$isFobidden = true;
|
||||
if (
|
||||
$e->getEntityType() === 'User' &&
|
||||
$e->isPortal() &&
|
||||
$excludeEntity->getEntityType() === 'Contact' &&
|
||||
$e->get('contactId') === $excludeEntity->id
|
||||
) {
|
||||
$isFobidden = false;
|
||||
}
|
||||
if ($isFobidden) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !$isFobidden;
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\AclPortal;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
|
||||
class Attachment extends \Espo\Core\AclPortal\Base
|
||||
{
|
||||
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($entity->get('parentType') === 'Settings') {
|
||||
return true;
|
||||
}
|
||||
|
||||
$parent = null;
|
||||
$hasParent = false;
|
||||
if ($entity->get('parentId') && $entity->get('parentType')) {
|
||||
$hasParent = true;
|
||||
$parent = $this->getEntityManager()->getEntity($entity->get('parentType'), $entity->get('parentId'));
|
||||
} else if ($entity->get('relatedId') && $entity->get('relatedType')) {
|
||||
$hasParent = true;
|
||||
$parent = $this->getEntityManager()->getEntity($entity->get('relatedType'), $entity->get('relatedId'));
|
||||
}
|
||||
|
||||
if ($hasParent) {
|
||||
if ($parent) {
|
||||
if ($parent->getEntityType() === 'Note') {
|
||||
if ($parent->get('parentId') && $parent->get('parentType')) {
|
||||
$parentOfParent = $this->getEntityManager()->getEntity($parent->get('parentType'), $parent->get('parentId'));
|
||||
if ($parentOfParent && $this->getAclManager()->checkEntity($user, $parentOfParent)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if ($this->getAclManager()->checkEntity($user, $parent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->checkEntity($user, $entity, $data, 'read')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
{
|
||||
if ($user->id === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl\ActionHistoryRecord;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
};
|
||||
|
||||
class OwnershipChecker implements OwnershipOwnChecker
|
||||
{
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
return $entity->get('userId') === $user->getId();
|
||||
}
|
||||
}
|
||||
153
application/Espo/Classes/Acl/Attachment/AccessChecker.php
Normal file
153
application/Espo/Classes/Acl/Attachment/AccessChecker.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl\Attachment;
|
||||
|
||||
use Espo\Entities\{
|
||||
User,
|
||||
Note,
|
||||
};
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
ORM\EntityManager,
|
||||
AclManager,
|
||||
Acl\ScopeData,
|
||||
Acl\DefaultAccessChecker,
|
||||
Acl\AccessEntityCREDChecker,
|
||||
Acl\Traits\DefaultAccessCheckerDependency,
|
||||
};
|
||||
|
||||
class AccessChecker implements AccessEntityCREDChecker
|
||||
{
|
||||
use DefaultAccessCheckerDependency;
|
||||
|
||||
private $aclManager;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(
|
||||
DefaultAccessChecker $defaultAccessChecker,
|
||||
AclManager $aclManager,
|
||||
EntityManager $entityManager
|
||||
) {
|
||||
$this->defaultAccessChecker = $defaultAccessChecker;
|
||||
$this->aclManager = $aclManager;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($entity->get('parentType') === 'Settings') {
|
||||
return true;
|
||||
}
|
||||
|
||||
$parent = null;
|
||||
|
||||
$hasParent = false;
|
||||
|
||||
if ($entity->get('parentId') && $entity->get('parentType')) {
|
||||
$hasParent = true;
|
||||
|
||||
$parent = $this->entityManager->getEntity($entity->get('parentType'), $entity->get('parentId'));
|
||||
}
|
||||
else if ($entity->get('relatedId') && $entity->get('relatedType')) {
|
||||
$hasParent = true;
|
||||
|
||||
$parent = $this->entityManager->getEntity($entity->get('relatedType'), $entity->get('relatedId'));
|
||||
}
|
||||
|
||||
if (!$parent || !$hasParent) {
|
||||
if ($this->defaultAccessChecker->checkEntityRead($user, $entity, $data)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($parent->getEntityType() === 'Note') {
|
||||
$result = $this->checkEntityReadNoteParent($user, $parent);
|
||||
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
else if ($this->aclManager->checkEntity($user, $parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->defaultAccessChecker->checkEntityRead($user, $entity, $data)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function checkEntityReadNoteParent(User $user, Note $note): ?bool
|
||||
{
|
||||
if ($note->getTargetType() === Note::TARGET_TEAMS) {
|
||||
$intersect = array_intersect(
|
||||
$note->getLinkMultipleIdList('teams'),
|
||||
$user->getLinkMultipleIdList('teams')
|
||||
);
|
||||
|
||||
if (count($intersect)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($note->getTargetType() === Note::TARGET_USERS) {
|
||||
$isRelated = $this->entityManager
|
||||
->getRDBRepository('Note')
|
||||
->getRelation($note, 'users')
|
||||
->isRelated($user);
|
||||
|
||||
if ($isRelated) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$note->getParentId() || !$note->getParentType()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$parent = $this->entityManager->getEntity($note->getParentType(), $note->getParentId());
|
||||
|
||||
if ($parent && $this->aclManager->checkEntity($user, $parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -27,23 +27,26 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\AclPortal;
|
||||
namespace Espo\Classes\Acl\Attachment;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\AclPortal\Acl;
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
};
|
||||
|
||||
class Account extends Acl
|
||||
class OwnershipChecker implements OwnershipOwnChecker
|
||||
{
|
||||
public function checkInAccount(User $user, Entity $entity)
|
||||
private const ATTR_CREATED_BY_ID = 'createdById';
|
||||
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
$accountIdList = $user->getLinkMultipleIdList('accounts');
|
||||
if (count($accountIdList)) {
|
||||
if (in_array($entity->id, $accountIdList)) {
|
||||
return true;
|
||||
}
|
||||
if ($user->getId() === $entity->get(self::ATTR_CREATED_BY_ID)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -27,26 +27,30 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Acl;
|
||||
namespace Espo\Classes\Acl\AuthToken;
|
||||
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Entities\User;
|
||||
|
||||
class Import extends \Espo\Core\Acl\Acl
|
||||
use Espo\Core\{
|
||||
Acl\ScopeData,
|
||||
Acl\DefaultAccessChecker,
|
||||
Acl\AccessEntityCREDChecker,
|
||||
Acl\Traits\DefaultAccessCheckerDependency,
|
||||
};
|
||||
|
||||
class AccessChecker implements AccessEntityCREDChecker
|
||||
{
|
||||
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
if ($user->isAdmin()) return true;
|
||||
if ($user->id === $entity->get('createdById')) return true;
|
||||
use DefaultAccessCheckerDependency;
|
||||
|
||||
return false;
|
||||
private $defaultAccessChecker;
|
||||
|
||||
public function __construct(DefaultAccessChecker $defaultAccessChecker)
|
||||
{
|
||||
$this->defaultAccessChecker = $defaultAccessChecker;
|
||||
}
|
||||
|
||||
public function checkEntityDelete(EntityUser $user, Entity $entity, $data)
|
||||
public function checkCreate(User $user, ScopeData $data): bool
|
||||
{
|
||||
if ($user->isAdmin()) return true;
|
||||
if ($user->id === $entity->get('createdById')) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -27,93 +27,101 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Acl;
|
||||
namespace Espo\Classes\Acl\Email;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Email extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
protected $ownerUserIdAttribute = 'usersIds';
|
||||
use Espo\Core\{
|
||||
Acl\Table,
|
||||
Acl\ScopeData,
|
||||
Acl\DefaultAccessChecker,
|
||||
Acl\AccessEntityCREDSChecker,
|
||||
Acl\Traits\DefaultAccessCheckerDependency,
|
||||
};
|
||||
|
||||
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
|
||||
class AccessChecker implements AccessEntityCREDSChecker
|
||||
{
|
||||
use DefaultAccessCheckerDependency;
|
||||
|
||||
public function __construct(DefaultAccessChecker $defaultAccessChecker)
|
||||
{
|
||||
if ($this->checkEntity($user, $entity, $data, 'read')) {
|
||||
$this->defaultAccessChecker = $defaultAccessChecker;
|
||||
}
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($this->defaultAccessChecker->checkEntityRead($user, $entity, $data)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($data === false) {
|
||||
if ($data->isFalse()) {
|
||||
return false;
|
||||
}
|
||||
if (is_object($data)) {
|
||||
if ($data->read === false || $data->read === 'no') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($data->getRead() === Table::LEVEL_NO) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$entity->has('usersIds')) {
|
||||
$entity->loadLinkMultipleField('users');
|
||||
}
|
||||
|
||||
$userIdList = $entity->get('usersIds');
|
||||
if (is_array($userIdList) && in_array($user->id, $userIdList)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
{
|
||||
if ($user->id === $entity->get('assignedUserId')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($user->id === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($entity->hasLinkMultipleId('assignedUsers', $user->id)) {
|
||||
if (is_array($userIdList) && in_array($user->getId(), $userIdList)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkEntityDelete(EntityUser $user, Entity $entity, $data)
|
||||
public function checkEntityDelete(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($data === false) {
|
||||
if ($data->isFalse()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($data->delete === 'own') {
|
||||
if ($user->id === $entity->get('assignedUserId')) {
|
||||
if ($data->getDelete() === Table::LEVEL_OWN) {
|
||||
if ($user->getId() === $entity->get('assignedUserId')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($user->id === $entity->get('createdById')) {
|
||||
if ($user->getId() === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$assignedUserIdList = $entity->getLinkMultipleIdList('assignedUsers');
|
||||
if (count($assignedUserIdList) === 1 && $entity->hasLinkMultipleId('assignedUsers', $user->id)) {
|
||||
|
||||
if (
|
||||
count($assignedUserIdList) === 1 &&
|
||||
$entity->hasLinkMultipleId('assignedUsers', $user->getId())
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->checkEntity($user, $entity, $data, 'delete')) {
|
||||
if ($this->defaultAccessChecker->checkEntityDelete($user, $entity, $data)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($data->edit !== 'no' || $data->create !== 'no') {
|
||||
if ($entity->get('createdById') === $user->id) {
|
||||
if ($entity->get('status') !== 'Sent' && $entity->get('status') !== 'Archived') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ($data->getEdit() === Table::LEVEL_NO && $data->getCreate() === Table::LEVEL_NO) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($entity->get('createdById') !== $user->getId()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($entity->get('status') !== 'Sent' && $entity->get('status') !== 'Archived') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
51
application/Espo/Classes/Acl/Email/AssignmentChecker.php
Normal file
51
application/Espo/Classes/Acl/Email/AssignmentChecker.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl\Email;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\DefaultAssignmentChecker,
|
||||
};
|
||||
|
||||
class AssignmentChecker extends DefaultAssignmentChecker
|
||||
{
|
||||
protected function isPermittedAssignedUser(User $user, Entity $entity): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isPermittedAssignedUsers(User $user, Entity $entity): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -27,46 +27,46 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\AclPortal;
|
||||
namespace Espo\Classes\Acl\Email;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User;
|
||||
|
||||
class Email extends \Espo\Core\AclPortal\Base
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\DefaultOwnershipChecker,
|
||||
Acl\OwnershipOwnChecker,
|
||||
Acl\OwnershipTeamChecker,
|
||||
};
|
||||
|
||||
class OwnershipChecker implements OwnershipOwnChecker, OwnershipTeamChecker
|
||||
{
|
||||
protected $ownerUserIdAttribute = 'usersIds';
|
||||
private $defaultOwnershipChecker;
|
||||
|
||||
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
|
||||
public function __construct(DefaultOwnershipChecker $defaultOwnershipChecker)
|
||||
{
|
||||
if ($this->checkEntity($user, $entity, $data, 'read')) {
|
||||
$this->defaultOwnershipChecker = $defaultOwnershipChecker;
|
||||
}
|
||||
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
if ($user->getId() === $entity->get('assignedUserId')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($data === false) {
|
||||
return false;
|
||||
}
|
||||
if (is_object($data)) {
|
||||
if ($data->read === false || $data->read === 'no') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$entity->has('usersIds')) {
|
||||
$entity->loadLinkMultipleField('users');
|
||||
}
|
||||
$userIdList = $entity->get('usersIds');
|
||||
if (is_array($userIdList) && in_array($user->id, $userIdList)) {
|
||||
if ($user->getId() === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($entity->hasLinkMultipleId('assignedUsers', $user->getId())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
public function checkTeam(User $user, Entity $entity): bool
|
||||
{
|
||||
if ($user->id === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return $this->defaultOwnershipChecker->checkTeam($user, $entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,57 +27,53 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Authentication\TwoFactor\Methods;
|
||||
namespace Espo\Classes\Acl\EmailFilter;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\Core\Authentication\TwoFactor\Utils\Totp as TotpUtils;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use StdClass;
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
class Totp implements CodeVerify
|
||||
class OwnershipChecker implements OwnershipOwnChecker
|
||||
{
|
||||
protected $entityManager;
|
||||
protected $totp;
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager, TotpUtils $totp)
|
||||
public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->totp = $totp;
|
||||
}
|
||||
|
||||
public function verifyCode(User $user, string $code) : bool
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
$userData = $this->entityManager
|
||||
->getRepository('UserData')
|
||||
->getByUserId($user->id);
|
||||
|
||||
if (!$userData) {
|
||||
if (!$entity->has('parentId') || !$entity->has('parentType')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$userData->get('auth2FA')) {
|
||||
$parentType = $entity->get('parentType');
|
||||
$parentId = $entity->get('parentId');
|
||||
|
||||
if (!$parentType || !$parentId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($userData->get('auth2FAMethod') != 'Totp') {
|
||||
$parent = $this->entityManager->getEntity($parentType, $parentId);
|
||||
|
||||
if (!$parent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$secret = $userData->get('auth2FATotpSecret');
|
||||
|
||||
if (!$secret) {
|
||||
return false;
|
||||
if ($parent->getEntityType() === 'User') {
|
||||
return $parent->getId() === $user->getId();
|
||||
}
|
||||
|
||||
return $this->totp->verifyCode($secret, $code);
|
||||
}
|
||||
if ($parent->has('assignedUserId') && $parent->get('assignedUserId') === $user->getId()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getLoginData(User $user) : StdClass
|
||||
{
|
||||
return (object) [
|
||||
'message' => 'enterTotpCode',
|
||||
];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
84
application/Espo/Classes/Acl/Import/AccessChecker.php
Normal file
84
application/Espo/Classes/Acl/Import/AccessChecker.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl\Import;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\ScopeData,
|
||||
Acl\AccessEntityReadChecker,
|
||||
Acl\AccessEntityDeleteChecker,
|
||||
};
|
||||
|
||||
class AccessChecker implements AccessEntityReadChecker, AccessEntityDeleteChecker
|
||||
{
|
||||
public function check(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $data->isTrue();
|
||||
}
|
||||
|
||||
public function checkRead(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $data->isTrue();
|
||||
}
|
||||
|
||||
public function checkDelete(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $data->isTrue();
|
||||
}
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($user->getId() === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkEntityDelete(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($user->getId() === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
172
application/Espo/Classes/Acl/Note/AccessChecker.php
Normal file
172
application/Espo/Classes/Acl/Note/AccessChecker.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl\Note;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\ScopeData,
|
||||
Acl\DefaultAccessChecker,
|
||||
Acl\AccessEntityCREDChecker,
|
||||
Acl\Traits\DefaultAccessCheckerDependency,
|
||||
AclManager,
|
||||
ORM\EntityManager,
|
||||
Utils\Config,
|
||||
};
|
||||
|
||||
use DateTime;
|
||||
use Exception;
|
||||
|
||||
class AccessChecker implements AccessEntityCREDChecker
|
||||
{
|
||||
use DefaultAccessCheckerDependency;
|
||||
|
||||
private const EDIT_PERIOD = '7 days';
|
||||
|
||||
private const DELETE_PERIOD = '1 month';
|
||||
|
||||
private $defaultAccessChecker;
|
||||
|
||||
private $aclManager;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
private $config;
|
||||
|
||||
public function __construct(
|
||||
DefaultAccessChecker $defaultAccessChecker,
|
||||
AclManager $aclManager,
|
||||
EntityManager $entityManager,
|
||||
Config $config
|
||||
) {
|
||||
$this->defaultAccessChecker = $defaultAccessChecker;
|
||||
$this->aclManager = $aclManager;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function checkEntityCreate(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
$parentId = $entity->get('parentId');
|
||||
$parentType = $entity->get('parentType');
|
||||
|
||||
if (!$parentId || !$parentType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$parent = $this->entityManager->getEntity($parentType, $parentId);
|
||||
|
||||
if ($parent && $this->aclManager->checkEntityStream($user, $parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkEntityEdit(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$this->defaultAccessChecker->checkEntityEdit($user, $entity, $data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->aclManager->checkOwnershipOwn($user, $entity)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$createdAt = $entity->get('createdAt');
|
||||
|
||||
if (!$createdAt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$noteEditThresholdPeriod =
|
||||
'-' . $this->config->get('noteEditThresholdPeriod', self::EDIT_PERIOD);
|
||||
|
||||
$dt = new DateTime();
|
||||
|
||||
$dt->modify($noteEditThresholdPeriod);
|
||||
|
||||
try {
|
||||
if ($dt->format('U') > (new DateTime($createdAt))->format('U')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkEntityDelete(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$this->defaultAccessChecker->checkEntityDelete($user, $entity, $data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->aclManager->checkOwnershipOwn($user, $entity)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$createdAt = $entity->get('createdAt');
|
||||
|
||||
if (!$createdAt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$deleteThresholdPeriod =
|
||||
'-' . $this->config->get('noteDeleteThresholdPeriod', self::DELETE_PERIOD);
|
||||
|
||||
$dt = new DateTime();
|
||||
|
||||
$dt->modify($deleteThresholdPeriod);
|
||||
|
||||
try {
|
||||
if ($dt->format('U') > (new DateTime($createdAt))->format('U')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
51
application/Espo/Classes/Acl/Note/OwnershipChecker.php
Normal file
51
application/Espo/Classes/Acl/Note/OwnershipChecker.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl\Note;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
};
|
||||
|
||||
class OwnershipChecker implements OwnershipOwnChecker
|
||||
{
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
|
||||
if ($entity->get('type') === 'Post' && $user->getId() === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -27,18 +27,24 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Acl;
|
||||
namespace Espo\Classes\Acl\Notification;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Notification extends \Espo\Core\Acl\Acl
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
};
|
||||
|
||||
class OwnershipChecker implements OwnershipOwnChecker
|
||||
{
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
if ($user->id === $entity->get('userId')) {
|
||||
if ($user->getId() === $entity->get('userId')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -27,41 +27,37 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Jobs;
|
||||
namespace Espo\Classes\Acl\Portal;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\{
|
||||
Jobs\Job,
|
||||
Acl\ScopeData,
|
||||
Acl\DefaultAccessChecker,
|
||||
Acl\AccessEntityCREDChecker,
|
||||
Acl\Traits\DefaultAccessCheckerDependency,
|
||||
Acl\Table,
|
||||
AclManager,
|
||||
Utils\Config,
|
||||
ORM\EntityManager,
|
||||
Webhook\Sender,
|
||||
Webhook\Queue,
|
||||
};
|
||||
|
||||
class ProcessWebhookQueue implements Job
|
||||
class AccessChecker implements AccessEntityCREDChecker
|
||||
{
|
||||
protected $config;
|
||||
protected $entityManager;
|
||||
protected $aclManager;
|
||||
use DefaultAccessCheckerDependency;
|
||||
|
||||
public function __construct(Config $config, EntityManager $entityManager, AclManager $aclManager)
|
||||
private $defaultAccessChecker;
|
||||
|
||||
private $aclManager;
|
||||
|
||||
public function __construct(DefaultAccessChecker $defaultAccessChecker, AclManager $aclManager)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->defaultAccessChecker = $defaultAccessChecker;
|
||||
$this->aclManager = $aclManager;
|
||||
}
|
||||
|
||||
public function run()
|
||||
public function check(User $user, ScopeData $data): bool
|
||||
{
|
||||
$sender = new Sender($this->config);
|
||||
$level = $this->aclManager->getPermissionLevel($user, 'portal');
|
||||
|
||||
$webhookQueue = new Queue(
|
||||
$sender,
|
||||
$this->config,
|
||||
$this->entityManager,
|
||||
$this->aclManager
|
||||
);
|
||||
|
||||
$webhookQueue->process();
|
||||
return $level === Table::LEVEL_YES;
|
||||
}
|
||||
}
|
||||
89
application/Espo/Classes/Acl/ScheduledJob/AccessChecker.php
Normal file
89
application/Espo/Classes/Acl/ScheduledJob/AccessChecker.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl\ScheduledJob;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\ScopeData,
|
||||
Acl\DefaultAccessChecker,
|
||||
Acl\AccessEntityCREDChecker,
|
||||
Acl\Traits\DefaultAccessCheckerDependency,
|
||||
};
|
||||
|
||||
class AccessChecker implements AccessEntityCREDChecker
|
||||
{
|
||||
use DefaultAccessCheckerDependency;
|
||||
|
||||
private $defaultAccessChecker;
|
||||
|
||||
public function __construct(DefaultAccessChecker $defaultAccessChecker)
|
||||
{
|
||||
$this->defaultAccessChecker = $defaultAccessChecker;
|
||||
}
|
||||
|
||||
public function checkEntityCreate(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($entity->get('isInternal')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->defaultAccessChecker->checkEntityCreate($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($entity->get('isInternal')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->defaultAccessChecker->checkEntityRead($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityEdit(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($entity->get('isInternal')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->defaultAccessChecker->checkEntityEdit($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityDelete(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($entity->get('isInternal')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->defaultAccessChecker->checkEntityDelete($user, $entity, $data);
|
||||
}
|
||||
}
|
||||
@@ -27,17 +27,22 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Acl;
|
||||
namespace Espo\Classes\Acl\Team;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Entities\User as UserEntity;
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
};
|
||||
|
||||
class Team extends \Espo\Core\Acl\Acl
|
||||
class OwnershipChecker implements OwnershipOwnChecker
|
||||
{
|
||||
public function checkInTeam(UserEntity $user, Entity $entity)
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
$userTeamIdList = $user->getLinkMultipleIdList('teams');
|
||||
return in_array($entity->id, $userTeamIdList);
|
||||
|
||||
return in_array($entity->getId(), $userTeamIdList);
|
||||
}
|
||||
}
|
||||
@@ -27,72 +27,103 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Acl;
|
||||
namespace Espo\Classes\Acl\User;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
|
||||
class User extends \Espo\Core\Acl\Acl
|
||||
use Espo\Core\{
|
||||
Acl\Table,
|
||||
Acl\ScopeData,
|
||||
Acl\DefaultAccessChecker,
|
||||
Acl\AccessEntityCREDSChecker,
|
||||
Acl\Traits\DefaultAccessCheckerDependency,
|
||||
AclManager,
|
||||
};
|
||||
|
||||
class AccessChecker implements AccessEntityCREDSChecker
|
||||
{
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
use DefaultAccessCheckerDependency;
|
||||
|
||||
private $defaultAccessChecker;
|
||||
|
||||
private $aclManager;
|
||||
|
||||
public function __construct(DefaultAccessChecker $defaultAccessChecker, AclManager $aclManager)
|
||||
{
|
||||
return $user->id === $entity->id;
|
||||
$this->defaultAccessChecker = $defaultAccessChecker;
|
||||
$this->aclManager = $aclManager;
|
||||
}
|
||||
|
||||
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
|
||||
public function checkEntityCreate(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if (!$user->isAdmin() && $entity->isPortal()) {
|
||||
if ($this->getAclManager()->get($user, 'portalPermission') === 'yes') {
|
||||
if (!$user->isAdmin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($entity->isSuperAdmin() && !$user->isSuperAdmin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->defaultAccessChecker->checkEntityCreate($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($entity->isPortal()) {
|
||||
if ($this->aclManager->getPermissionLevel($user, 'portal') === Table::LEVEL_YES) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return $this->checkEntity($user, $entity, $data, 'read');
|
||||
}
|
||||
|
||||
public function checkEntityCreate(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
if (!$user->isAdmin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($entity->isSuperAdmin() && !$user->isSuperAdmin()) {
|
||||
return false;
|
||||
}
|
||||
return $this->checkEntity($user, $entity, $data, 'create');
|
||||
|
||||
return $this->defaultAccessChecker->checkEntityRead($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityDelete(EntityUser $user, Entity $entity, $data)
|
||||
public function checkEntityEdit(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($entity->id === 'system') {
|
||||
return false;
|
||||
}
|
||||
if (!$user->isAdmin()) {
|
||||
return false;
|
||||
}
|
||||
if ($entity->isSystem()) {
|
||||
return false;
|
||||
}
|
||||
if ($entity->isSuperAdmin() && !$user->isSuperAdmin()) {
|
||||
return false;
|
||||
}
|
||||
return parent::checkEntityDelete($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityEdit(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
if ($entity->id === 'system') {
|
||||
return false;
|
||||
}
|
||||
if ($entity->isSystem()) {
|
||||
return false;
|
||||
}
|
||||
if (!$user->isAdmin()) {
|
||||
if ($user->id !== $entity->id) {
|
||||
if ($user->getId() !== $entity->getId()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->isSuperAdmin() && !$user->isSuperAdmin()) {
|
||||
return false;
|
||||
}
|
||||
return $this->checkEntity($user, $entity, $data, 'edit');
|
||||
|
||||
return $this->defaultAccessChecker->checkEntityEdit($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityDelete(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if (!$user->isAdmin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($entity->isSystem()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($entity->isSuperAdmin() && !$user->isSuperAdmin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->defaultAccessChecker->checkEntityDelete($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityStream(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->aclManager->checkUserPermission($user, $entity, 'user');
|
||||
}
|
||||
}
|
||||
@@ -27,30 +27,35 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\Acl;
|
||||
namespace Espo\Classes\Acl\User;
|
||||
|
||||
use \Espo\Entities\User;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User;
|
||||
|
||||
class Meeting extends \Espo\Core\Acl\Base
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
Acl\OwnershipTeamChecker,
|
||||
};
|
||||
|
||||
class OwnershipChecker implements OwnershipOwnChecker, OwnershipTeamChecker
|
||||
{
|
||||
protected $ownerUserIdAttribute = 'usersIds';
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, $data)
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
if ($this->checkEntity($user, $entity, $data, 'read')) {
|
||||
return true;
|
||||
}
|
||||
return $user->getId() === $entity->getId();
|
||||
}
|
||||
|
||||
if (is_object($data)) {
|
||||
if ($data->read === 'own' || $data->read === 'team') {
|
||||
if ($entity->hasLinkMultipleId('users', $user->id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public function checkTeam(User $user, Entity $entity): bool
|
||||
{
|
||||
$intersect = array_intersect(
|
||||
$user->getLinkMultipleIdList('teams'),
|
||||
$entity->getLinkMultipleIdList('teams')
|
||||
);
|
||||
|
||||
if (count($intersect)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
107
application/Espo/Classes/Acl/Webhook/AccessChecker.php
Normal file
107
application/Espo/Classes/Acl/Webhook/AccessChecker.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl\Webhook;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\ScopeData,
|
||||
Acl\DefaultAccessChecker,
|
||||
Acl\AccessEntityCREDChecker,
|
||||
Acl\Traits\DefaultAccessCheckerDependency,
|
||||
};
|
||||
|
||||
class AccessChecker implements AccessEntityCREDChecker
|
||||
{
|
||||
use DefaultAccessCheckerDependency;
|
||||
|
||||
private $defaultAccessChecker;
|
||||
|
||||
public function __construct(DefaultAccessChecker $defaultAccessChecker)
|
||||
{
|
||||
$this->defaultAccessChecker = $defaultAccessChecker;
|
||||
}
|
||||
|
||||
public function check(User $user, ScopeData $data): bool
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$user->isApi()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($data->isFalse()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkEntityCreate(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkEntityInternal($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkEntityInternal($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityEdit(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkEntityInternal($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityDelete(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkEntityInternal($user, $entity, $data);
|
||||
}
|
||||
|
||||
private function checkEntityInternal(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($data->isFalse()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($user->isApi() && $user->getId() === $entity->get('userId')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
46
application/Espo/Classes/Acl/Webhook/OwnershipChecker.php
Normal file
46
application/Espo/Classes/Acl/Webhook/OwnershipChecker.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Acl\Webhook;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
};
|
||||
|
||||
class OwnershipChecker implements OwnershipOwnChecker
|
||||
{
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
return $user->getId() === $entity->get('userId') && $user->isApi();
|
||||
}
|
||||
}
|
||||
158
application/Espo/Classes/AclPortal/Attachment/AccessChecker.php
Normal file
158
application/Espo/Classes/AclPortal/Attachment/AccessChecker.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\AclPortal\Attachment;
|
||||
|
||||
use Espo\Entities\{
|
||||
User,
|
||||
Note,
|
||||
};
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
ORM\EntityManager,
|
||||
Portal\AclManager,
|
||||
Acl\ScopeData,
|
||||
Acl\AccessEntityCREDChecker,
|
||||
Portal\Acl\DefaultAccessChecker,
|
||||
Portal\Acl\Traits\DefaultAccessCheckerDependency,
|
||||
};
|
||||
|
||||
class AccessChecker implements AccessEntityCREDChecker
|
||||
{
|
||||
use DefaultAccessCheckerDependency;
|
||||
|
||||
private $defaultAccessChecker;
|
||||
|
||||
private $aclManager;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(
|
||||
DefaultAccessChecker $defaultAccessChecker,
|
||||
AclManager $aclManager,
|
||||
EntityManager $entityManager
|
||||
) {
|
||||
$this->defaultAccessChecker = $defaultAccessChecker;
|
||||
$this->aclManager = $aclManager;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($entity->get('parentType') === 'Settings') {
|
||||
return true;
|
||||
}
|
||||
|
||||
$parent = null;
|
||||
$hasParent = false;
|
||||
|
||||
if ($entity->get('parentId') && $entity->get('parentType')) {
|
||||
$hasParent = true;
|
||||
|
||||
$parent = $this->entityManager->getEntity($entity->get('parentType'), $entity->get('parentId'));
|
||||
}
|
||||
else if ($entity->get('relatedId') && $entity->get('relatedType')) {
|
||||
$hasParent = true;
|
||||
|
||||
$parent = $this->entityManager->getEntity($entity->get('relatedType'), $entity->get('relatedId'));
|
||||
}
|
||||
|
||||
if (!$hasParent) {
|
||||
if ($entity->get('createdById') === $user->getId()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($parent->getEntityType() === 'Note') {
|
||||
$result = $this->checkEntityReadNoteParent($user, $parent);
|
||||
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
else if ($this->aclManager->checkEntity($user, $parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->defaultAccessChecker->checkEntityRead($user, $entity, $data)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function checkEntityReadNoteParent(User $user, Note $note): ?bool
|
||||
{
|
||||
if ($note->isInternal()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($note->getTargetType() === Note::TARGET_PORTALS) {
|
||||
$intersect = array_intersect(
|
||||
$note->getLinkMultipleIdList('portals'),
|
||||
$user->getLinkMultipleIdList('portals')
|
||||
);
|
||||
|
||||
if (count($intersect)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($note->getTargetType() === Note::TARGET_USERS) {
|
||||
$isRelated = $this->entityManager
|
||||
->getRDBRepository('Note')
|
||||
->getRelation($note, 'users')
|
||||
->isRelated($user);
|
||||
|
||||
if ($isRelated) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$note->getParentId() || !$note->getParentType()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$parent = $this->entityManager->getEntity($note->getParentType(), $note->getParentId());
|
||||
|
||||
if ($parent && $this->aclManager->checkEntity($user, $parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\AclPortal\Attachment;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
};
|
||||
|
||||
class OwnershipChecker implements OwnershipOwnChecker
|
||||
{
|
||||
private const ATTR_CREATED_BY_ID = 'createdById';
|
||||
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
if ($user->getId() === $entity->get(self::ATTR_CREATED_BY_ID)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
83
application/Espo/Classes/AclPortal/Email/AccessChecker.php
Normal file
83
application/Espo/Classes/AclPortal/Email/AccessChecker.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\AclPortal\Email;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Portal\AclManager,
|
||||
Acl\Table,
|
||||
Acl\ScopeData,
|
||||
Acl\AccessEntityCREDSChecker,
|
||||
Portal\Acl\DefaultAccessChecker,
|
||||
Portal\Acl\Traits\DefaultAccessCheckerDependency,
|
||||
};
|
||||
|
||||
class AccessChecker implements AccessEntityCREDSChecker
|
||||
{
|
||||
use DefaultAccessCheckerDependency;
|
||||
|
||||
private $defaultAccessChecker;
|
||||
|
||||
private $aclManager;
|
||||
|
||||
public function __construct(
|
||||
DefaultAccessChecker $defaultAccessChecker,
|
||||
AclManager $aclManager
|
||||
) {
|
||||
$this->defaultAccessChecker = $defaultAccessChecker;
|
||||
$this->aclManager = $aclManager;
|
||||
}
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($this->defaultAccessChecker->checkEntityRead($user, $entity, $data)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($data->isFalse()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($data->getRead() === Table::LEVEL_NO) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$userIdList = $entity->getLinkMultipleIdLIst('users');
|
||||
|
||||
if (is_array($userIdList) && in_array($user->getId(), $userIdList)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -27,19 +27,24 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\AclPortal;
|
||||
namespace Espo\Classes\AclPortal\Email;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User;
|
||||
|
||||
class Notification extends \Espo\Core\AclPortal\Base
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
};
|
||||
|
||||
class OwnershipChecker implements OwnershipOwnChecker
|
||||
{
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
if ($user->id === $entity->get('userId')) {
|
||||
if ($user->getId() === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
189
application/Espo/Classes/AclPortal/Note/AccessChecker.php
Normal file
189
application/Espo/Classes/AclPortal/Note/AccessChecker.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\AclPortal\Note;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Portal\AclManager,
|
||||
Acl\ScopeData,
|
||||
Acl\AccessEntityCREDChecker,
|
||||
Portal\Acl\DefaultAccessChecker,
|
||||
Portal\Acl\Traits\DefaultAccessCheckerDependency,
|
||||
ORM\EntityManager,
|
||||
Utils\Config,
|
||||
};
|
||||
|
||||
use DateTime;
|
||||
use Exception;
|
||||
|
||||
class AccessChecker implements AccessEntityCREDChecker
|
||||
{
|
||||
use DefaultAccessCheckerDependency;
|
||||
|
||||
private const EDIT_PERIOD = '7 days';
|
||||
|
||||
private const DELETE_PERIOD = '1 month';
|
||||
|
||||
private $defaultAccessChecker;
|
||||
|
||||
private $aclManager;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
private $config;
|
||||
|
||||
public function __construct(
|
||||
DefaultAccessChecker $defaultAccessChecker,
|
||||
AclManager $aclManager,
|
||||
EntityManager $entityManager,
|
||||
Config $config
|
||||
) {
|
||||
$this->defaultAccessChecker = $defaultAccessChecker;
|
||||
$this->aclManager = $aclManager;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function checkEntityCreate(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
$parentId = $entity->get('parentId');
|
||||
$parentType = $entity->get('parentType');
|
||||
|
||||
if (!$parentId || !$parentType) {
|
||||
return $this->defaultAccessChecker->checkEntityCreate($user, $entity, $data);
|
||||
}
|
||||
|
||||
$parent = $this->entityManager->getEntity($parentType, $parentId);
|
||||
|
||||
if ($parent && $this->aclManager->checkEntityStream($user, $parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->defaultAccessChecker->checkEntityCreate($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if ($entity->get('type') !== 'Post') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($entity->get('type') === 'Post' && $entity->get('targetType')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$entity->get('parentId') || !$entity->get('parentType')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$parent = $this->entityManager->getEntity($entity->get('parentType'), $entity->get('parentId'));
|
||||
|
||||
if ($parent) {
|
||||
if ($this->aclManager->checkEntityStream($user, $parent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkEntityEdit(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if (!$this->defaultAccessChecker->checkEntityEdit($user, $entity, $data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->aclManager->checkOwnershipOwn($user, $entity)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$createdAt = $entity->get('createdAt');
|
||||
|
||||
if (!$createdAt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$noteEditThresholdPeriod =
|
||||
'-' . $this->config->get('noteEditThresholdPeriod', self::EDIT_PERIOD);
|
||||
|
||||
$dt = new DateTime();
|
||||
|
||||
$dt->modify($noteEditThresholdPeriod);
|
||||
|
||||
try {
|
||||
if ($dt->format('U') > (new DateTime($createdAt))->format('U')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkEntityDelete(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
if (!$this->defaultAccessChecker->checkEntityDelete($user, $entity, $data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->aclManager->checkOwnershipOwn($user, $entity)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$createdAt = $entity->get('createdAt');
|
||||
|
||||
if (!$createdAt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$deleteThresholdPeriod =
|
||||
'-' . $this->config->get('noteDeleteThresholdPeriod', self::DELETE_PERIOD);
|
||||
|
||||
$dt = new DateTime();
|
||||
|
||||
$dt->modify($deleteThresholdPeriod);
|
||||
|
||||
try {
|
||||
if ($dt->format('U') > (new DateTime($createdAt))->format('U')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
50
application/Espo/Classes/AclPortal/Note/OwnershipChecker.php
Normal file
50
application/Espo/Classes/AclPortal/Note/OwnershipChecker.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\AclPortal\Note;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
};
|
||||
|
||||
class OwnershipChecker implements OwnershipOwnChecker
|
||||
{
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
if ($entity->get('type') === 'Post' && $user->getId() === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -27,23 +27,24 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\AclPortal;
|
||||
namespace Espo\Classes\AclPortal\Notification;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\AclPortal\Acl;
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
};
|
||||
|
||||
class Contact extends Acl
|
||||
class OwnershipChecker implements OwnershipOwnChecker
|
||||
{
|
||||
public function checkIsOwnContact(User $user, Entity $entity)
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
$contactId = $user->get('contactId');
|
||||
if ($contactId) {
|
||||
if ($entity->id === $contactId) {
|
||||
return true;
|
||||
}
|
||||
if ($user->getId() === $entity->get('userId')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
46
application/Espo/Classes/AclPortal/User/OwnershipChecker.php
Normal file
46
application/Espo/Classes/AclPortal/User/OwnershipChecker.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\AclPortal\User;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl\OwnershipOwnChecker,
|
||||
};
|
||||
|
||||
class OwnershipChecker implements OwnershipOwnChecker
|
||||
{
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
return $user->getId() === $entity->getId();
|
||||
}
|
||||
}
|
||||
@@ -29,14 +29,14 @@
|
||||
|
||||
namespace Espo\Classes\AddressFormatters;
|
||||
|
||||
use Espo\Core\FieldUtils\Address\{
|
||||
AddressFormatter,
|
||||
AddressValue,
|
||||
use Espo\Core\{
|
||||
Field\Address,
|
||||
Field\Address\AddressFormatter,
|
||||
};
|
||||
|
||||
class Formatter1 implements AddressFormatter
|
||||
{
|
||||
public function format(AddressValue $address) : string
|
||||
public function format(Address $address): string
|
||||
{
|
||||
$result = '';
|
||||
|
||||
|
||||
@@ -29,14 +29,14 @@
|
||||
|
||||
namespace Espo\Classes\AddressFormatters;
|
||||
|
||||
use Espo\Core\FieldUtils\Address\{
|
||||
AddressFormatter,
|
||||
AddressValue,
|
||||
use Espo\Core\{
|
||||
Field\Address,
|
||||
Field\Address\AddressFormatter,
|
||||
};
|
||||
|
||||
class Formatter2 implements AddressFormatter
|
||||
{
|
||||
public function format(AddressValue $address) : string
|
||||
public function format(Address $address): string
|
||||
{
|
||||
$result = '';
|
||||
|
||||
|
||||
@@ -29,14 +29,14 @@
|
||||
|
||||
namespace Espo\Classes\AddressFormatters;
|
||||
|
||||
use Espo\Core\FieldUtils\Address\{
|
||||
AddressFormatter,
|
||||
AddressValue,
|
||||
use Espo\Core\{
|
||||
Field\Address,
|
||||
Field\Address\AddressFormatter,
|
||||
};
|
||||
|
||||
class Formatter3 implements AddressFormatter
|
||||
{
|
||||
public function format(AddressValue $address) : string
|
||||
public function format(Address $address): string
|
||||
{
|
||||
$result = '';
|
||||
|
||||
|
||||
@@ -29,14 +29,14 @@
|
||||
|
||||
namespace Espo\Classes\AddressFormatters;
|
||||
|
||||
use Espo\Core\FieldUtils\Address\{
|
||||
AddressFormatter,
|
||||
AddressValue,
|
||||
use Espo\Core\{
|
||||
Field\Address,
|
||||
Field\Address\AddressFormatter,
|
||||
};
|
||||
|
||||
class Formatter4 implements AddressFormatter
|
||||
{
|
||||
public function format(AddressValue $address) : string
|
||||
public function format(Address $address): string
|
||||
{
|
||||
$result = '';
|
||||
|
||||
|
||||
@@ -30,28 +30,26 @@
|
||||
namespace Espo\Classes\AppInfo;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\File\Manager as FileManager,
|
||||
Utils\Module,
|
||||
Binding\EspoBindingLoader,
|
||||
Binding\Binding as BindingItem,
|
||||
Console\Command\Params,
|
||||
};
|
||||
|
||||
class Binding
|
||||
{
|
||||
protected $fileManager;
|
||||
private $module;
|
||||
|
||||
public function __construct(FileManager $fileManager)
|
||||
public function __construct(Module $module)
|
||||
{
|
||||
$this->fileManager = $fileManager;
|
||||
$this->module = $module;
|
||||
}
|
||||
|
||||
public function process(array $options, array $flagList) : ?string
|
||||
public function process(Params $params): string
|
||||
{
|
||||
$result = '';
|
||||
|
||||
$bindingLoader = new EspoBindingLoader(
|
||||
new Module($this->fileManager)
|
||||
);
|
||||
$bindingLoader = new EspoBindingLoader($this->module);
|
||||
|
||||
$data = $bindingLoader->load();
|
||||
|
||||
@@ -78,7 +76,7 @@ class Binding
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function printItem(string $key, BindingItem $binding) : string
|
||||
private function printItem(string $key, BindingItem $binding): string
|
||||
{
|
||||
$result = '';
|
||||
|
||||
@@ -94,6 +92,7 @@ class Binding
|
||||
BindingItem::CONTAINER_SERVICE => 'Service',
|
||||
BindingItem::VALUE => 'Value',
|
||||
BindingItem::CALLBACK => 'Callback',
|
||||
BindingItem::FACTORY_CLASS_NAME => 'Factory',
|
||||
][$type];
|
||||
|
||||
$result .= $tab . "Type: {$typeString}\n";
|
||||
|
||||
@@ -32,12 +32,14 @@ namespace Espo\Classes\AppInfo;
|
||||
use Espo\Core\{
|
||||
Container as ContainerService,
|
||||
Utils\Metadata,
|
||||
Console\Command\Params,
|
||||
};
|
||||
|
||||
class Container
|
||||
{
|
||||
protected $container;
|
||||
protected $metadata;
|
||||
private $container;
|
||||
|
||||
private $metadata;
|
||||
|
||||
public function __construct(ContainerService $container, Metadata $metadata)
|
||||
{
|
||||
@@ -45,9 +47,9 @@ class Container
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
|
||||
public function process(array $options, array $flagList) : ?string
|
||||
public function process(Params $params): string
|
||||
{
|
||||
$nameOnly = in_array('nameOnly', $flagList);
|
||||
$nameOnly = $params->hasFlag('nameOnly');
|
||||
|
||||
$result = '';
|
||||
|
||||
|
||||
68
application/Espo/Classes/AppInfo/Jobs.php
Normal file
68
application/Espo/Classes/AppInfo/Jobs.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\AppInfo;
|
||||
|
||||
use Espo\Core\Console\Command\Params;
|
||||
use Espo\Core\Utils\ClassFinder;
|
||||
use Espo\Core\Job\MetadataProvider;
|
||||
|
||||
class Jobs
|
||||
{
|
||||
private $classFinder;
|
||||
|
||||
private $metadataProvider;
|
||||
|
||||
public function __construct(ClassFinder $classFinder, MetadataProvider $metadataProvider)
|
||||
{
|
||||
$this->classFinder = $classFinder;
|
||||
$this->metadataProvider = $metadataProvider;
|
||||
}
|
||||
|
||||
public function process(Params $params): string
|
||||
{
|
||||
$result = "Available jobs:\n\n";
|
||||
|
||||
$list = array_map(
|
||||
function ($item) {
|
||||
return ' ' . $item;
|
||||
},
|
||||
array_unique(
|
||||
array_merge(
|
||||
array_keys($this->classFinder->getMap('Jobs')),
|
||||
$this->metadataProvider->getScheduledJobNameList()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
asort($list);
|
||||
|
||||
return $result . implode("\n", $list) . "\n";
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace Espo\Classes\AppParams;
|
||||
|
||||
use Espo\Core\{
|
||||
Acl,
|
||||
Select\SelectManagerFactory,
|
||||
Select\SelectBuilderFactory,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
@@ -41,17 +41,17 @@ use Espo\Core\{
|
||||
class TemplateEntityTypeList
|
||||
{
|
||||
protected $acl;
|
||||
protected $selectManagerFactory;
|
||||
protected $selectBuilderFactory;
|
||||
protected $entityManager;
|
||||
|
||||
public function __construct(Acl $acl, SelectManagerFactory $selectManagerFactory, EntityManager $entityManager)
|
||||
public function __construct(Acl $acl, SelectBuilderFactory $selectBuilderFactory, EntityManager $entityManager)
|
||||
{
|
||||
$this->acl = $acl;
|
||||
$this->selectManagerFactory = $selectManagerFactory;
|
||||
$this->selectBuilderFactory = $selectBuilderFactory;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function get()
|
||||
public function get() : array
|
||||
{
|
||||
if (!$this->acl->checkScope('Template')) {
|
||||
return [];
|
||||
@@ -59,17 +59,21 @@ class TemplateEntityTypeList
|
||||
|
||||
$list = [];
|
||||
|
||||
$selectManager = $this->selectManagerFactory->create('Template');
|
||||
|
||||
$selectParams = $selectManager->getEmptySelectParams();
|
||||
$selectManager->applyAccess($selectParams);
|
||||
|
||||
$templateList = $this->entityManager->getRepository('Template')
|
||||
$query = $this->selectBuilderFactory
|
||||
->create()
|
||||
->from('Template')
|
||||
->withAccessControlFilter()
|
||||
->buildQueryBuilder()
|
||||
->select(['entityType'])
|
||||
->groupBy(['entityType'])
|
||||
->find($selectParams);
|
||||
->group(['entityType'])
|
||||
->build();
|
||||
|
||||
foreach ($templateList as $template) {
|
||||
$templateCollection = $this->entityManager
|
||||
->getRepository('Template')
|
||||
->clone($query)
|
||||
->find();
|
||||
|
||||
foreach ($templateCollection as $template) {
|
||||
$list[] = $template->get('entityType');
|
||||
}
|
||||
|
||||
|
||||
@@ -27,78 +27,93 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Notificators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\Notificators\DefaultNotificator;
|
||||
namespace Espo\Classes\AssignmentNotificators;
|
||||
|
||||
use Espo\Services\Email as EmailService;
|
||||
use Espo\Services\Stream as StreamService;
|
||||
|
||||
use Espo\Core\Notification\AssignmentNotificator;
|
||||
use Espo\Core\Notification\AssignmentNotificator\Params;
|
||||
use Espo\Core\Notification\UserEnabledChecker;
|
||||
use Espo\Core\ServiceFactory;
|
||||
use Espo\Core\AclManager;
|
||||
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Entities\User;
|
||||
use Espo\Entities\Notification;
|
||||
|
||||
use Espo\Core\{
|
||||
ORM\EntityManager,
|
||||
ServiceFactory,
|
||||
AclManager,
|
||||
};
|
||||
use DateTime;
|
||||
use Exception;
|
||||
|
||||
class Email extends DefaultNotificator
|
||||
class Email implements AssignmentNotificator
|
||||
{
|
||||
const DAYS_THRESHOLD = 2;
|
||||
private const DAYS_THRESHOLD = 2;
|
||||
|
||||
private $streamService = null;
|
||||
|
||||
protected $user;
|
||||
protected $entityManager;
|
||||
protected $serviceFactory;
|
||||
protected $aclManager;
|
||||
private $user;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
private $serviceFactory;
|
||||
|
||||
private $aclManager;
|
||||
|
||||
private $userChecker;
|
||||
|
||||
public function __construct(
|
||||
User $user,
|
||||
EntityManager $entityManager,
|
||||
UserEnabledChecker $userChecker,
|
||||
ServiceFactory $serviceFactory,
|
||||
AclManager $aclManager
|
||||
) {
|
||||
$this->user = $user;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->userChecker = $userChecker;
|
||||
$this->serviceFactory = $serviceFactory;
|
||||
$this->aclManager = $aclManager;
|
||||
}
|
||||
|
||||
protected function getStreamService()
|
||||
{
|
||||
if (empty($this->streamService)) {
|
||||
$this->streamService = $this->serviceFactory->create('Stream');
|
||||
}
|
||||
return $this->streamService;
|
||||
}
|
||||
|
||||
public function process(Entity $entity, array $options = [])
|
||||
public function process(Entity $entity, Params $params): void
|
||||
{
|
||||
if (!in_array($entity->get('status'), ['Archived', 'Sent', 'Being Imported'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($options['isJustSent'])) {
|
||||
if ($params->getOption('isJustSent')) {
|
||||
$previousUserIdList = [];
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$previousUserIdList = $entity->getFetched('usersIds');
|
||||
|
||||
if (!is_array($previousUserIdList)) {
|
||||
$previousUserIdList = [];
|
||||
}
|
||||
}
|
||||
|
||||
$dateSent = $entity->get('dateSent');
|
||||
if (!$dateSent) return;
|
||||
|
||||
$dt = null;
|
||||
if (!$dateSent) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$dt = new \DateTime($dateSent);
|
||||
} catch (\Exception $e) {}
|
||||
if (!$dt) return;
|
||||
$dt = new DateTime($dateSent);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($dt->diff(new \DateTime())->days > self::DAYS_THRESHOLD) return;
|
||||
if (!$dt) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($dt->diff(new DateTime())->days > self::DAYS_THRESHOLD) {
|
||||
return;
|
||||
}
|
||||
|
||||
$emailUserIdList = $entity->get('usersIds');
|
||||
|
||||
@@ -107,14 +122,19 @@ class Email extends DefaultNotificator
|
||||
}
|
||||
|
||||
$userIdList = [];
|
||||
|
||||
foreach ($emailUserIdList as $userId) {
|
||||
if (!in_array($userId, $userIdList) && !in_array($userId, $previousUserIdList) && $userId != $this->user->id) {
|
||||
if (
|
||||
!in_array($userId, $userIdList) &&
|
||||
!in_array($userId, $previousUserIdList) &&
|
||||
$userId !== $this->user->getId()
|
||||
) {
|
||||
$userIdList[] = $userId;
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'emailId' => $entity->id,
|
||||
'emailId' => $entity->getId(),
|
||||
'emailName' => $entity->get('name'),
|
||||
];
|
||||
|
||||
@@ -125,54 +145,81 @@ class Email extends DefaultNotificator
|
||||
if (!$entity->has('to')) {
|
||||
$this->entityManager->getRepository('Email')->loadToField($entity);
|
||||
}
|
||||
|
||||
$person = null;
|
||||
|
||||
$from = $entity->get('from');
|
||||
|
||||
if ($from) {
|
||||
$person = $this->entityManager->getRepository('EmailAddress')
|
||||
$person = $this->entityManager
|
||||
->getRepository('EmailAddress')
|
||||
->getEntityByAddress($from, null, ['User', 'Contact', 'Lead']);
|
||||
|
||||
if ($person) {
|
||||
$data['personEntityType'] = $person->getEntityType();
|
||||
$data['personEntityName'] = $person->get('name');
|
||||
$data['personEntityId'] = $person->id;
|
||||
$data['personEntityId'] = $person->getId();
|
||||
}
|
||||
}
|
||||
|
||||
$userIdFrom = null;
|
||||
if ($person && $person->getEntityType() == 'User') {
|
||||
|
||||
if ($person && $person->getEntityType() === 'User') {
|
||||
$userIdFrom = $person->id;
|
||||
}
|
||||
|
||||
if (empty($data['personEntityId'])) {
|
||||
$data['fromString'] = EmailService::parseFromName($entity->get('fromString'));
|
||||
|
||||
if (empty($data['fromString']) && $from) {
|
||||
$data['fromString'] = $from;
|
||||
}
|
||||
}
|
||||
|
||||
$parent = null;
|
||||
|
||||
if ($entity->get('parentId') && $entity->get('parentType')) {
|
||||
$parent = $this->entityManager->getEntity($entity->get('parentType'), $entity->get('parentId'));
|
||||
}
|
||||
|
||||
$account = null;
|
||||
|
||||
if ($entity->get('accountId')) {
|
||||
$account = $this->entityManager->getEntity('Account', $entity->get('accountId'));
|
||||
}
|
||||
|
||||
foreach ($userIdList as $userId) {
|
||||
if (!$userId) continue;
|
||||
if ($userIdFrom === $userId) continue;
|
||||
if ($entity->getLinkMultipleColumn('users', 'inTrash', $userId)) continue;
|
||||
if (!$this->isNotificationsEnabledForUser($userId)) return;
|
||||
if (!$userId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!empty($options['isBeingImported']) || !empty($options['isJustSent'])) {
|
||||
if ($userIdFrom === $userId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($entity->getLinkMultipleColumn('users', 'inTrash', $userId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->userChecker->checkAssignment('Email', $userId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
$params->getOption('isBeingImported') ||
|
||||
$params->getOption('isJustSent')
|
||||
) {
|
||||
$folderId = $entity->getLinkMultipleColumn('users', 'folderId', $userId);
|
||||
|
||||
if ($folderId) {
|
||||
if (
|
||||
$this->entityManager->getRepository('EmailFolder')->where([
|
||||
'id' => $folderId,
|
||||
'skipNotifications' => true
|
||||
])->count()
|
||||
$this->entityManager
|
||||
->getRepository('EmailFolder')
|
||||
->where([
|
||||
'id' => $folderId,
|
||||
'skipNotifications' => true,
|
||||
])
|
||||
->count()
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
@@ -180,41 +227,70 @@ class Email extends DefaultNotificator
|
||||
}
|
||||
|
||||
$user = $this->entityManager->getEntity('User', $userId);
|
||||
if (!$user) continue;
|
||||
if ($user->isPortal()) continue;
|
||||
|
||||
if (!$user) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($user->isPortal()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->aclManager->checkScope($user, 'Email')) {
|
||||
continue;
|
||||
}
|
||||
if ($entity->get('status') == 'Archived' || !empty($options['isBeingImported'])) {
|
||||
if ($parent) {
|
||||
if ($this->getStreamService()->checkIsFollowed($parent, $userId)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($account) {
|
||||
if ($this->getStreamService()->checkIsFollowed($account, $userId)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
$this->entityManager->getRepository('Notification')->where([
|
||||
'type' => 'EmailReceived',
|
||||
'userId' => $userId,
|
||||
'relatedId' => $entity->id,
|
||||
'relatedType' => 'Email',
|
||||
])->select(['id'])->findOne()
|
||||
) continue;
|
||||
|
||||
$notification = $this->entityManager->getEntity('Notification');
|
||||
$notification->set([
|
||||
'type' => 'EmailReceived',
|
||||
$isArchivedOrBeingImported =
|
||||
$entity->get('status') === 'Archived' ||
|
||||
$params->getOption('isBeingImported');
|
||||
|
||||
if (
|
||||
$isArchivedOrBeingImported &&
|
||||
$parent &&
|
||||
$this->getStreamService()->checkIsFollowed($parent, $userId)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
$isArchivedOrBeingImported &&
|
||||
$account &&
|
||||
$this->getStreamService()->checkIsFollowed($account, $userId)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$existing = $this->entityManager
|
||||
->getRepository(Notification::ENTITY_TYPE)
|
||||
->where([
|
||||
'type' => Notification::TYPE_EMAIL_RECEIVED,
|
||||
'userId' => $userId,
|
||||
'relatedId' => $entity->getId(),
|
||||
'relatedType' => 'Email',
|
||||
])
|
||||
->select(['id'])
|
||||
->findOne();
|
||||
|
||||
if ($existing) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->entityManager->createEntity(Notification::ENTITY_TYPE, [
|
||||
'type' => Notification::TYPE_EMAIL_RECEIVED,
|
||||
'userId' => $userId,
|
||||
'data' => $data,
|
||||
'relatedId' => $entity->id,
|
||||
'relatedId' => $entity->getId(),
|
||||
'relatedType' => 'Email',
|
||||
]);
|
||||
$this->entityManager->saveEntity($notification);
|
||||
}
|
||||
}
|
||||
|
||||
private function getStreamService(): StreamService
|
||||
{
|
||||
if (empty($this->streamService)) {
|
||||
$this->streamService = $this->serviceFactory->create('Stream');
|
||||
}
|
||||
|
||||
return $this->streamService;
|
||||
}
|
||||
}
|
||||
@@ -29,17 +29,19 @@
|
||||
|
||||
namespace Espo\Classes\Cleanup;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
use Espo\Core\Cleanup\Cleanup;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class Reminders
|
||||
class Reminders implements Cleanup
|
||||
{
|
||||
protected $config;
|
||||
protected $entityManager;
|
||||
private $config;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
private $cleanupRemindersPeriod = '15 days';
|
||||
|
||||
public function __construct(Config $config, EntityManager $entityManager)
|
||||
{
|
||||
@@ -47,9 +49,7 @@ class Reminders
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
protected $cleanupRemindersPeriod = '15 days';
|
||||
|
||||
public function process()
|
||||
public function process(): void
|
||||
{
|
||||
$period = '-' . $this->config->get('cleanupRemindersPeriod', $this->cleanupRemindersPeriod);
|
||||
|
||||
@@ -57,7 +57,8 @@ class Reminders
|
||||
|
||||
$dt->modify($period);
|
||||
|
||||
$delete = $this->entityManager->getQueryBuilder()
|
||||
$delete = $this->entityManager
|
||||
->getQueryBuilder()
|
||||
->delete()
|
||||
->from('Reminder')
|
||||
->where([
|
||||
|
||||
77
application/Espo/Classes/Cleanup/TwoFactorCodes.php
Normal file
77
application/Espo/Classes/Cleanup/TwoFactorCodes.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Cleanup;
|
||||
|
||||
use Espo\Core\Cleanup\Cleanup;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Core\Utils\DateTime as DateTimeUtil;
|
||||
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
use Espo\Entities\TwoFactorCode;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class TwoFactorCodes implements Cleanup
|
||||
{
|
||||
private const PERIOD = '5 days';
|
||||
|
||||
private $config;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(Config $config, EntityManager $entityManager)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function process(): void
|
||||
{
|
||||
$period = '-' . $this->config->get('cleanupTwoFactorCodesPeriod', self::PERIOD);
|
||||
|
||||
$from = (new DateTime())
|
||||
->modify($period)
|
||||
->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT);
|
||||
|
||||
$query = $this->entityManager
|
||||
->getQueryBuilder()
|
||||
->delete()
|
||||
->from(TwoFactorCode::ENTITY_TYPE)
|
||||
->where([
|
||||
'createdAt<' => $from,
|
||||
])
|
||||
->build();
|
||||
|
||||
$this->entityManager
|
||||
->getQueryExecutor()
|
||||
->execute($query);
|
||||
}
|
||||
}
|
||||
@@ -29,19 +29,19 @@
|
||||
|
||||
namespace Espo\Classes\Cleanup;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
use Espo\Core\Cleanup\Cleanup;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class WebhookQueue
|
||||
class WebhookQueue implements Cleanup
|
||||
{
|
||||
protected $cleanupWebhookQueuePeriod = '10 days';
|
||||
private $cleanupWebhookQueuePeriod = '10 days';
|
||||
|
||||
protected $config;
|
||||
protected $entityManager;
|
||||
private $config;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(Config $config, EntityManager $entityManager)
|
||||
{
|
||||
@@ -49,7 +49,7 @@ class WebhookQueue
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function process()
|
||||
public function process(): void
|
||||
{
|
||||
$period = '-' . $this->config->get('cleanupWebhookQueuePeriod', $this->cleanupWebhookQueuePeriod);
|
||||
|
||||
@@ -58,7 +58,8 @@ class WebhookQueue
|
||||
$datetime->modify($period);
|
||||
$from = $datetime->format('Y-m-d H:i:s');
|
||||
|
||||
$query = $this->entityManager->getQueryBuilder()
|
||||
$query1 = $this->entityManager
|
||||
->getQueryBuilder()
|
||||
->delete()
|
||||
->from('WebhookQueueItem')
|
||||
->where([
|
||||
@@ -70,9 +71,10 @@ class WebhookQueue
|
||||
])
|
||||
->build();
|
||||
|
||||
$this->entityManager->getQueryExecutor()->execute($query);
|
||||
$this->entityManager->getQueryExecutor()->execute($query1);
|
||||
|
||||
$query = $this->entityManager->getQueryBuilder()
|
||||
$query2 = $this->entityManager
|
||||
->getQueryBuilder()
|
||||
->delete()
|
||||
->from('WebhookEventQueueItem')
|
||||
->where([
|
||||
@@ -84,6 +86,6 @@ class WebhookQueue
|
||||
])
|
||||
->build();
|
||||
|
||||
$this->entityManager->getQueryExecutor()->execute($query);
|
||||
$this->entityManager->getQueryExecutor()->execute($query2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,42 +29,43 @@
|
||||
|
||||
namespace Espo\Classes\ConsoleCommands;
|
||||
|
||||
use Espo\Tools\Import\Service;
|
||||
|
||||
use Espo\Core\{
|
||||
ServiceFactory,
|
||||
Console\Commands\Command,
|
||||
Console\Command,
|
||||
Console\Command\Params,
|
||||
Console\IO,
|
||||
};
|
||||
|
||||
use Throwable;
|
||||
|
||||
class Import implements Command
|
||||
{
|
||||
protected $serviceFactory;
|
||||
private $service;
|
||||
|
||||
public function __construct(ServiceFactory $serviceFactory)
|
||||
public function __construct(Service $service)
|
||||
{
|
||||
$this->serviceFactory = $serviceFactory;
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
public function run(array $options, array $flagList)
|
||||
public function run(Params $params, IO $io) : void
|
||||
{
|
||||
$id = $options['id'] ?? null;
|
||||
$filePath = $options['file'] ?? null;
|
||||
$paramsId = $options['paramsId'] ?? null;
|
||||
$id = $params->getOption('id');
|
||||
$filePath = $params->getOption('file');
|
||||
$paramsId = $params->getOption('paramsId');
|
||||
|
||||
$service = $this->serviceFactory->create('Import');
|
||||
|
||||
$forceResume = in_array('resume', $flagList);
|
||||
$revert = in_array('revert', $flagList);
|
||||
$forceResume = $params->hasFlag('resume');
|
||||
$revert = $params->hasFlag('revert');
|
||||
|
||||
if (!$id && $filePath) {
|
||||
if (!$paramsId) {
|
||||
$this->out("You need to specify --params-id option.\n");
|
||||
$io->writeLine("You need to specify --params-id option.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file_exists($filePath)) {
|
||||
$this->out("File not found.\n");
|
||||
$io->writeLine("File not found.");
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -72,67 +73,60 @@ class Import implements Command
|
||||
$contents = file_get_contents($filePath);
|
||||
|
||||
try {
|
||||
$result = $service->importFileWithParamsId($contents, $paramsId);
|
||||
$result = $this->service->importContentsWithParamsId($contents, $paramsId);
|
||||
|
||||
$resultId = $result->id;
|
||||
$countCreated = $result->countCreated;
|
||||
$countUpdated = $result->countUpdated;
|
||||
$resultId = $result->getId();
|
||||
$countCreated = $result->getCountCreated();
|
||||
$countUpdated = $result->getCountUpdated();
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
$this->out("Error occured: ".$e->getMessage()."\n");
|
||||
$io->writeLine("Error occurred: ". $e->getMessage() . "");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->out("Finished. Import ID: {$resultId}. Created: {$countCreated}. Updated: {$countUpdated}.\n");
|
||||
$io->writeLine("Finished. Import ID: {$resultId}. Created: {$countCreated}. Updated: {$countUpdated}.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($id && $revert) {
|
||||
$this->out("Reverting import...\n");
|
||||
$io->writeLine("Reverting import...");
|
||||
|
||||
try {
|
||||
$service->revert($id);
|
||||
$this->service->revert($id);
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
$this->out("Error occured: " . $e->getMessage() . "\n");
|
||||
$io->writeLine("Error occurred: " . $e->getMessage() . "");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->out("Finished.\n");
|
||||
$io->writeLine("Finished.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
$this->out("Running import, this may take a while...\n");
|
||||
$io->writeLine("Running import, this may take a while...");
|
||||
|
||||
try {
|
||||
$result = $service->importById($id, true, $forceResume);
|
||||
$result = $this->service->importById($id, true, $forceResume);
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
$this->out("Error occured: " . $e->getMessage() . "\n");
|
||||
$io->writeLine("Error occurred: " . $e->getMessage() . "");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$countCreated = $result->countCreated;
|
||||
$countUpdated = $result->countUpdated;
|
||||
$countCreated = $result->getCountCreated();
|
||||
$countUpdated = $result->getCountUpdated();
|
||||
|
||||
$this->out("Finished. Created: {$countCreated}. Updated: {$countUpdated}.\n");
|
||||
$io->writeLine("Finished. Created: {$countCreated}. Updated: {$countUpdated}.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->out("Not enough params passed.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
protected function out($string)
|
||||
{
|
||||
fwrite(\STDOUT, $string);
|
||||
$io->writeLine("Not enough params passed.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ class DefaultSidePanelType
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
|
||||
public function get(string $scope) : array
|
||||
public function get(string $scope): array
|
||||
{
|
||||
$list = [];
|
||||
|
||||
|
||||
104
application/Espo/Classes/DuplicateWhereBuilders/Company.php
Normal file
104
application/Espo/Classes/DuplicateWhereBuilders/Company.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\{
|
||||
Query\Part\Condition as Cond,
|
||||
Query\Part\WhereItem,
|
||||
Query\Part\Where\OrGroup,
|
||||
Entity,
|
||||
};
|
||||
|
||||
class Company implements WhereBuilder
|
||||
{
|
||||
public function build(Entity $entity): ?WhereItem
|
||||
{
|
||||
$orBuilder = OrGroup::createBuilder();
|
||||
|
||||
$toCheck = false;
|
||||
|
||||
if ($entity->get('name')) {
|
||||
$orBuilder->add(
|
||||
Cond::equal(
|
||||
Cond::column('name'),
|
||||
$entity->get('name')
|
||||
),
|
||||
);
|
||||
|
||||
$toCheck = true;
|
||||
}
|
||||
|
||||
if (
|
||||
($entity->get('emailAddress') || $entity->get('emailAddressData')) &&
|
||||
(
|
||||
$entity->isNew() ||
|
||||
$entity->isAttributeChanged('emailAddress') ||
|
||||
$entity->isAttributeChanged('emailAddressData')
|
||||
)
|
||||
) {
|
||||
foreach ($this->getEmailAddressList($entity) as $emailAddress) {
|
||||
$orBuilder->add(
|
||||
Cond::equal(
|
||||
Cond::column('emailAddress'),
|
||||
$emailAddress
|
||||
)
|
||||
);
|
||||
|
||||
$toCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$toCheck) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $orBuilder->build();
|
||||
}
|
||||
|
||||
private function getEmailAddressList(Entity $entity): array
|
||||
{
|
||||
if ($entity->get('emailAddressData')) {
|
||||
/* @var $eaGroup EmailAddressGroup */
|
||||
$eaGroup = $entity->getValueObject('emailAddress');
|
||||
|
||||
return $eaGroup->getAddressList();
|
||||
}
|
||||
|
||||
if ($entity->get('emailAddress')) {
|
||||
return [
|
||||
$entity->get('emailAddress')
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
113
application/Espo/Classes/DuplicateWhereBuilders/Person.php
Normal file
113
application/Espo/Classes/DuplicateWhereBuilders/Person.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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,
|
||||
Field\EmailAddressGroup,
|
||||
};
|
||||
|
||||
use Espo\ORM\{
|
||||
Query\Part\Condition as Cond,
|
||||
Query\Part\WhereItem,
|
||||
Query\Part\Where\OrGroup,
|
||||
Entity,
|
||||
};
|
||||
|
||||
class Person implements WhereBuilder
|
||||
{
|
||||
public function build(Entity $entity): ?WhereItem
|
||||
{
|
||||
$orBuilder = OrGroup::createBuilder();
|
||||
|
||||
$toCheck = false;
|
||||
|
||||
if ($entity->get('firstName') || $entity->get('lastName')) {
|
||||
$orBuilder->add(
|
||||
Cond::and(
|
||||
Cond::equal(
|
||||
Cond::column('firstName'),
|
||||
$entity->get('firstName')
|
||||
),
|
||||
Cond::equal(
|
||||
Cond::column('lastName'),
|
||||
$entity->get('lastName')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$toCheck = true;
|
||||
}
|
||||
|
||||
if (
|
||||
($entity->get('emailAddress') || $entity->get('emailAddressData')) &&
|
||||
(
|
||||
$entity->isNew() ||
|
||||
$entity->isAttributeChanged('emailAddress') ||
|
||||
$entity->isAttributeChanged('emailAddressData')
|
||||
)
|
||||
) {
|
||||
foreach ($this->getEmailAddressList($entity) as $emailAddress) {
|
||||
$orBuilder->add(
|
||||
Cond::equal(
|
||||
Cond::column('emailAddress'),
|
||||
$emailAddress
|
||||
)
|
||||
);
|
||||
|
||||
$toCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$toCheck) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $orBuilder->build();
|
||||
}
|
||||
|
||||
private function getEmailAddressList(Entity $entity): array
|
||||
{
|
||||
if ($entity->get('emailAddressData')) {
|
||||
/* @var $eaGroup EmailAddressGroup */
|
||||
$eaGroup = $entity->getValueObject('emailAddress');
|
||||
|
||||
return $eaGroup->getAddressList();
|
||||
}
|
||||
|
||||
if ($entity->get('emailAddress')) {
|
||||
return [
|
||||
$entity->get('emailAddress')
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\FieldProcessing\Email;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
FieldProcessing\Loader,
|
||||
FieldProcessing\Loader\Params,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
use Espo\Repositories\Email as EmailRepository;
|
||||
|
||||
class AddressDataLoader implements Loader
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function process(Entity $entity, Params $params): void
|
||||
{
|
||||
/* @var $repository EmailRepository */
|
||||
$repository = $this->entityManager->getRepository('Email');
|
||||
|
||||
$repository->loadFromField($entity);
|
||||
$repository->loadToField($entity);
|
||||
$repository->loadCcField($entity);
|
||||
$repository->loadBccField($entity);
|
||||
$repository->loadReplyToField($entity);
|
||||
$repository->loadNameHash($entity);
|
||||
}
|
||||
}
|
||||
205
application/Espo/Classes/FieldProcessing/Email/IcsDataLoader.php
Normal file
205
application/Espo/Classes/FieldProcessing/Email/IcsDataLoader.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\FieldProcessing\Email;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\Repositories\EmailAddress as EmailAddressRepository;
|
||||
use Espo\Entities\EmailAddress;
|
||||
use Espo\Entities\Email;
|
||||
|
||||
use Espo\Core\{
|
||||
FieldProcessing\Loader,
|
||||
FieldProcessing\Loader\Params,
|
||||
Mail\Event\Event as EspoEvent,
|
||||
Mail\Event\EventFactory,
|
||||
Utils\Log,
|
||||
};
|
||||
|
||||
use ICal\ICal;
|
||||
use ICal\Event;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class IcsDataLoader implements Loader
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
private $log;
|
||||
|
||||
private $entityTypeLinkMap = [
|
||||
'User' => 'users',
|
||||
'Contact' => 'contacts',
|
||||
'Lead' => 'leads',
|
||||
];
|
||||
|
||||
public function __construct(EntityManager $entityManager, Log $log)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->log = $log;
|
||||
}
|
||||
|
||||
public function process(Entity $entity, Params $params): void
|
||||
{
|
||||
$icsContents = $entity->get('icsContents');
|
||||
|
||||
if ($icsContents === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ical = new ICal();
|
||||
|
||||
$ical->initString($icsContents);
|
||||
|
||||
/* @var $event Event */
|
||||
$event = $ical->events()[0] ?? null;
|
||||
|
||||
if ($event === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event->status === 'CANCELLED') {
|
||||
return;
|
||||
}
|
||||
|
||||
$espoEvent = EventFactory::createFromU01jmg3Ical($ical);
|
||||
|
||||
$valueMap = (object) [
|
||||
'sourceEmailId' => $entity->getId(),
|
||||
];
|
||||
|
||||
try {
|
||||
$valueMap->name = $espoEvent->getName();
|
||||
$valueMap->description = $espoEvent->getDescription();
|
||||
$valueMap->dateStart = $espoEvent->getDateStart();
|
||||
$valueMap->dateEnd = $espoEvent->getDateEnd();
|
||||
$valueMap->location = $espoEvent->getLocation();
|
||||
$valueMap->isAllDay = $espoEvent->isAllDay();
|
||||
|
||||
if ($espoEvent->isAllDay()) {
|
||||
$valueMap->dateStartDate = $espoEvent->getDateStart();
|
||||
$valueMap->dateEndDate = $espoEvent->getDateEnd();
|
||||
}
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
$this->log->warning("Error while converting ICS event '" . $entity->getId() . "': " . $e->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* @var $emailAddressRepository EmailAddressRepository */
|
||||
$emailAddressRepository = $this->entityManager->getRepository(EmailAddress::ENTITY_TYPE);
|
||||
|
||||
$attendeeEmailAddressList = $espoEvent->getAttendeeEmailAddressList();
|
||||
|
||||
$organizerEmailAddress = $espoEvent->getOrganizerEmailAddress();
|
||||
|
||||
if ($organizerEmailAddress) {
|
||||
$attendeeEmailAddressList[] = $organizerEmailAddress;
|
||||
}
|
||||
|
||||
foreach ($attendeeEmailAddressList as $address) {
|
||||
$personEntity = $emailAddressRepository->getEntityByAddress($address);
|
||||
|
||||
if (!$personEntity) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$link = $this->entityTypeLinkMap[$personEntity->getEntityType()] ?? null;
|
||||
|
||||
if (!$link) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$idsAttribute = $link . 'Ids';
|
||||
$namesAttribute = $link . 'Names';
|
||||
|
||||
$idList = $valueMap->$idsAttribute ?? [];
|
||||
$nameMap = $valueMap->$namesAttribute ?? (object) [];
|
||||
|
||||
$idList[] = $personEntity->getId();
|
||||
$nameMap->{$personEntity->getId()} = $personEntity->get('name');
|
||||
|
||||
$valueMap->$idsAttribute = $idList;
|
||||
$valueMap->$namesAttribute = $nameMap;
|
||||
}
|
||||
|
||||
$eventData = (object) [
|
||||
'valueMap' => $valueMap,
|
||||
'uid' => $espoEvent->getUid(),
|
||||
'createdEvent' => null,
|
||||
];
|
||||
|
||||
$this->loadCreatedEvent($entity, $espoEvent, $eventData);
|
||||
|
||||
$entity->set('icsEventData', $eventData);
|
||||
|
||||
$entity->set('icsEventDateStart', $espoEvent->getDateStart());
|
||||
|
||||
if ($espoEvent->isAllDay()) {
|
||||
$entity->set('icsEventDateStartDate', $espoEvent->getDateStart());
|
||||
}
|
||||
}
|
||||
|
||||
private function loadCreatedEvent(Entity $entity, EspoEvent $espoEvent, object $eventData): void
|
||||
{
|
||||
$emailSameEvent = $this->entityManager
|
||||
->getRDBRepository(Email::ENTITY_TYPE)
|
||||
->where([
|
||||
'icsEventUid' => $espoEvent->getUid(),
|
||||
'id!=' => $entity->getId()
|
||||
])
|
||||
->findOne();
|
||||
|
||||
if (!$emailSameEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!$emailSameEvent->get('createdEventId') ||
|
||||
!$emailSameEvent->get('createdEventType')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$createdEvent = $this->entityManager
|
||||
->getEntity($emailSameEvent->get('createdEventType'), $emailSameEvent->get('createdEventId'));
|
||||
|
||||
if (!$createdEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
$eventData->createdEvent = (object) [
|
||||
'id' => $createdEvent->getId(),
|
||||
'entityType' => $emailSameEvent->getEntityType(),
|
||||
'name' => $createdEvent->get('name'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\FieldProcessing\Email;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
FieldProcessing\Loader,
|
||||
FieldProcessing\Loader\Params,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
use Espo\Entities\Email;
|
||||
use Espo\Entities\User;
|
||||
|
||||
class StringDataLoader implements Loader
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
private $user;
|
||||
|
||||
private $fromEmailAddressNameCache = [];
|
||||
|
||||
public function __construct(EntityManager $entityManager, User $user)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function process(Entity $entity, Params $params): void
|
||||
{
|
||||
$userEmailAdddressIdList = [];
|
||||
|
||||
$emailAddressCollection = $this->entityManager
|
||||
->getRDBRepository('User')
|
||||
->getRelation($this->user, 'emailAddresses')
|
||||
->select(['id'])
|
||||
->find();
|
||||
|
||||
foreach ($emailAddressCollection as $emailAddress) {
|
||||
$userEmailAdddressIdList[] = $emailAddress->getId();
|
||||
}
|
||||
|
||||
if (
|
||||
in_array($entity->get('fromEmailAddressId'), $userEmailAdddressIdList) ||
|
||||
$entity->get('createdById') === $this->user->getId() && $entity->get('status') === Email::STATUS_SENT
|
||||
) {
|
||||
$entity->loadLinkMultipleField('toEmailAddresses');
|
||||
|
||||
$idList = $entity->get('toEmailAddressesIds');
|
||||
$names = $entity->get('toEmailAddressesNames');
|
||||
|
||||
if (empty($idList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach ($idList as $emailAddressId) {
|
||||
$person = $this->entityManager
|
||||
->getRepository('EmailAddress')
|
||||
->getEntityByAddressId($emailAddressId, null, true);
|
||||
|
||||
$list[] = $person ? $person->get('name') : $names->$emailAddressId;
|
||||
}
|
||||
|
||||
$entity->set('personStringData', 'To: ' . implode(', ', $list));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$fromEmailAddressId = $entity->get('fromEmailAddressId');
|
||||
|
||||
if (!$fromEmailAddressId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!array_key_exists($fromEmailAddressId, $this->fromEmailAddressNameCache)) {
|
||||
$person = $this->entityManager
|
||||
->getRepository('EmailAddress')
|
||||
->getEntityByAddressId($fromEmailAddressId, null, true);
|
||||
|
||||
$fromName = $person ? $person->get('name') : null;
|
||||
|
||||
$this->fromEmailAddressNameCache[$fromEmailAddressId] = $fromName;
|
||||
}
|
||||
|
||||
$fromName =
|
||||
$this->fromEmailAddressNameCache[$fromEmailAddressId] ??
|
||||
$entity->get('fromName') ??
|
||||
$entity->get('fromEmailAddressName');
|
||||
|
||||
$entity->set('personStringData', $fromName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\FieldProcessing\Email;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
FieldProcessing\Loader,
|
||||
FieldProcessing\Loader\Params,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
class UserColumnsLoader implements Loader
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
private $user;
|
||||
|
||||
public function __construct(EntityManager $entityManager, User $user)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function process(Entity $entity, Params $params): void
|
||||
{
|
||||
$emailUser = $this->entityManager
|
||||
->getRepository('EmailUser')
|
||||
->select(['isRead', 'isImportant', 'inTrash'])
|
||||
->where([
|
||||
'deleted' => false,
|
||||
'userId' => $this->user->getId(),
|
||||
'emailId' => $entity->getId(),
|
||||
])
|
||||
->findOne();
|
||||
|
||||
if (!$emailUser) {
|
||||
$entity->set('isRead', null);
|
||||
$entity->clear('isImportant');
|
||||
$entity->clear('inTrash');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$entity->set([
|
||||
'isRead' => $emailUser->get('isRead'),
|
||||
'isImportant' => $emailUser->get('isImportant'),
|
||||
'inTrash' => $emailUser->get('inTrash'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\FieldProcessing\Import;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
FieldProcessing\Loader,
|
||||
FieldProcessing\Loader\Params,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
use Espo\Repositories\Import as ImportRepository;
|
||||
|
||||
class CountsLoader implements Loader
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function process(Entity $entity, Params $params): void
|
||||
{
|
||||
/* @var $repository ImportRepository */
|
||||
$repository = $this->entityManager->getRepository('Import');
|
||||
|
||||
$importedCount = $repository->countResultRecords($entity, 'imported');
|
||||
$duplicateCount = $repository->countResultRecords($entity, 'duplicates');
|
||||
$updatedCount = $repository->countResultRecords($entity, 'updated');
|
||||
|
||||
$entity->set([
|
||||
'importedCount' => $importedCount,
|
||||
'duplicateCount' => $duplicateCount,
|
||||
'updatedCount' => $updatedCount,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\FieldProcessing\Note;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
FieldProcessing\Loader,
|
||||
FieldProcessing\Loader\Params,
|
||||
};
|
||||
|
||||
use Espo\Entities\Note;
|
||||
|
||||
class AttachmentsLoader implements Loader
|
||||
{
|
||||
public function process(Entity $entity, Params $params): void
|
||||
{
|
||||
/* @var $entity Note */
|
||||
$entity->loadAttachments();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\FieldProcessing\Portal;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
FieldProcessing\Loader,
|
||||
FieldProcessing\Loader\Params,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
class UrlLoader implements Loader
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function process(Entity $entity, Params $params): void
|
||||
{
|
||||
$this->entityManager
|
||||
->getRepository('Portal')
|
||||
->loadUrlField($entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\FieldProcessing\User;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
FieldProcessing\Loader,
|
||||
FieldProcessing\Loader\Params,
|
||||
ORM\EntityManager,
|
||||
Acl,
|
||||
Acl\Table,
|
||||
};
|
||||
|
||||
use DateTime;
|
||||
use Exception;
|
||||
|
||||
class LastAccessLoader implements Loader
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
private $acl;
|
||||
|
||||
public function __construct(EntityManager $entityManager, Acl $acl)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->acl = $acl;
|
||||
}
|
||||
|
||||
public function process(Entity $entity, Params $params): void
|
||||
{
|
||||
$forbiddenFieldList = $this->acl
|
||||
->getScopeForbiddenFieldList($entity->getEntityType(), Table::ACTION_READ);
|
||||
|
||||
if (in_array('lastAccess', $forbiddenFieldList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$authToken = $this->entityManager
|
||||
->getRDBRepository('AuthToken')
|
||||
->select(['id', 'lastAccess'])
|
||||
->where([
|
||||
'userId' => $entity->getId(),
|
||||
])
|
||||
->order('lastAccess', 'DESC')
|
||||
->findOne();
|
||||
|
||||
$lastAccess = null;
|
||||
|
||||
if ($authToken) {
|
||||
$lastAccess = $authToken->get('lastAccess');
|
||||
}
|
||||
|
||||
$dt = null;
|
||||
|
||||
if ($lastAccess) {
|
||||
try {
|
||||
$dt = new DateTime($lastAccess);
|
||||
}
|
||||
catch (Exception $e) {}
|
||||
}
|
||||
|
||||
$where = [
|
||||
'userId' => $entity->getId(),
|
||||
'isDenied' => false,
|
||||
];
|
||||
|
||||
if ($dt) {
|
||||
$where['requestTime>'] = $dt->format('U');
|
||||
}
|
||||
|
||||
$authLogRecord = $this->entityManager
|
||||
->getRDBRepository('AuthLogRecord')
|
||||
->select(['id', 'createdAt'])
|
||||
->where($where)
|
||||
->order('requestTime', true)
|
||||
->findOne();
|
||||
|
||||
if ($authLogRecord) {
|
||||
$lastAccess = $authLogRecord->get('createdAt');
|
||||
}
|
||||
|
||||
$entity->set('lastAccess', $lastAccess);
|
||||
}
|
||||
}
|
||||
@@ -31,22 +31,31 @@ namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class ArrayType extends BaseType
|
||||
use StdClass;
|
||||
|
||||
class ArrayType
|
||||
{
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
return $this->isNotEmpty($entity, $field);
|
||||
}
|
||||
|
||||
public function checkMaxCount(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkMaxCount(Entity $entity, string $field, int $validationValue): bool
|
||||
{
|
||||
if (!$this->isNotEmpty($entity, $field)) return true;
|
||||
if (!$this->isNotEmpty($entity, $field)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$list = $entity->get($field);
|
||||
if (count($list) > $validationValue) return false;
|
||||
|
||||
if (count($list) > $validationValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkArray(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function rawCheckArray(StdClass $data, string $field): bool
|
||||
{
|
||||
if (isset($data->$field) && $data->$field !== null && !is_array($data->$field)) {
|
||||
return false;
|
||||
@@ -55,12 +64,22 @@ class ArrayType extends BaseType
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, string $field): bool
|
||||
{
|
||||
if (!$entity->has($field) || $entity->get($field) === null) return false;
|
||||
if (!$entity->has($field) || $entity->get($field) === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$list = $entity->get($field);
|
||||
if (!is_array($list)) return false;
|
||||
if (count($list)) return true;
|
||||
|
||||
if (!is_array($list)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count($list)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ use Espo\ORM\Entity;
|
||||
|
||||
class CurrencyType extends FloatType
|
||||
{
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, string $field): bool
|
||||
{
|
||||
return
|
||||
$entity->has($field) && $entity->get($field) !== null &&
|
||||
|
||||
@@ -31,14 +31,14 @@ namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class DateType extends BaseType
|
||||
class DateType
|
||||
{
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
return $this->isNotEmpty($entity, $field);
|
||||
}
|
||||
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, string $field): bool
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== null;
|
||||
}
|
||||
|
||||
@@ -33,15 +33,21 @@ use Espo\ORM\Entity;
|
||||
|
||||
class DatetimeOptionalType extends DatetimeType
|
||||
{
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
return $this->isNotEmpty($entity, $field);
|
||||
}
|
||||
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, string $field): bool
|
||||
{
|
||||
if ($entity->has($field) && $entity->get($field) !== null) return true;
|
||||
if ($entity->has($field . 'Date') && $entity->get($field . 'Date') !== null) return true;
|
||||
if ($entity->has($field) && $entity->get($field) !== null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($entity->has($field . 'Date') && $entity->get($field . 'Date') !== null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,46 +31,61 @@ namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class EmailType extends BaseType
|
||||
class EmailType
|
||||
{
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
if ($this->isNotEmpty($entity, $field)) return true;
|
||||
if ($this->isNotEmpty($entity, $field)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$dataList = $entity->get($field . 'Data');
|
||||
if (!is_array($dataList)) return false;
|
||||
|
||||
if (!is_array($dataList)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($dataList as $item) {
|
||||
if (!empty($item->emailAddress)) return true;
|
||||
if (!empty($item->emailAddress)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkEmailAddress(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkEmailAddress(Entity $entity, string $field): bool
|
||||
{
|
||||
if ($this->isNotEmpty($entity, $field)) {
|
||||
$address = $entity->get($field);
|
||||
|
||||
if (!filter_var($address, FILTER_VALIDATE_EMAIL)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$dataList = $entity->get($field . 'Data');
|
||||
if (is_array($dataList)) {
|
||||
foreach ($dataList as $item) {
|
||||
if (empty($item->emailAddress)) continue;
|
||||
$address = $item->emailAddress;
|
||||
if (!filter_var($address, FILTER_VALIDATE_EMAIL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_array($dataList)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($dataList as $item) {
|
||||
if (empty($item->emailAddress)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$address = $item->emailAddress;
|
||||
|
||||
if (!filter_var($address, FILTER_VALIDATE_EMAIL)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, string $field): bool
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== '' && $entity->get($field) !== null;
|
||||
}
|
||||
|
||||
@@ -31,14 +31,14 @@ namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class EnumType extends BaseType
|
||||
class EnumType
|
||||
{
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
return $this->isNotEmpty($entity, $field);
|
||||
}
|
||||
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, string $field): bool
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== null;
|
||||
}
|
||||
|
||||
@@ -31,28 +31,40 @@ namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class IntType extends BaseType
|
||||
class IntType
|
||||
{
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
return $this->isNotEmpty($entity, $field);
|
||||
}
|
||||
|
||||
public function checkMax(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkMax(Entity $entity, string $field, $validationValue): bool
|
||||
{
|
||||
if (!$this->isNotEmpty($entity, $field)) return true;
|
||||
if ($entity->get($field) > $validationValue) return false;
|
||||
if (!$this->isNotEmpty($entity, $field)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($entity->get($field) > $validationValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkMin(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkMin(Entity $entity, string $field, $validationValue): bool
|
||||
{
|
||||
if (!$this->isNotEmpty($entity, $field)) return true;
|
||||
if ($entity->get($field) < $validationValue) return false;
|
||||
if (!$this->isNotEmpty($entity, $field)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($entity->get($field) < $validationValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, string $field): bool
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== null;
|
||||
}
|
||||
|
||||
@@ -31,21 +31,35 @@ namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class JsonArrayType extends BaseType
|
||||
{
|
||||
public function checkArray(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
if (!$entity->has($field) || $entity->get($field) === null) return true;
|
||||
use StdClass;
|
||||
|
||||
return is_array($entity->get($field));
|
||||
class JsonArrayType
|
||||
{
|
||||
public function rawCheckArray(StdClass $data, string $field): bool
|
||||
{
|
||||
if (isset($data->$field) && $data->$field !== null && !is_array($data->$field)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, string $field): bool
|
||||
{
|
||||
if (!$entity->has($field) || $entity->get($field) === null) return false;
|
||||
if (!$entity->has($field) || $entity->get($field) === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$list = $entity->get($field);
|
||||
if (!is_array($list)) return false;
|
||||
if (count($list)) return true;
|
||||
|
||||
if (!is_array($list)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count($list)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,9 +31,9 @@ namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class LinkMultipleType extends BaseType
|
||||
class LinkMultipleType
|
||||
{
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
return count($entity->getLinkMultipleIdList($field)) > 0;
|
||||
}
|
||||
|
||||
@@ -31,14 +31,18 @@ namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class LinkParentType extends BaseType
|
||||
class LinkParentType
|
||||
{
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
$idAttribute = $field . 'Id';
|
||||
$typeAttribute = $field . 'Type';
|
||||
|
||||
if (!$entity->has($idAttribute) || $entity->get($idAttribute) === '' || $entity->get($idAttribute) === null) {
|
||||
if (
|
||||
!$entity->has($idAttribute) ||
|
||||
$entity->get($idAttribute) === '' ||
|
||||
$entity->get($idAttribute) === null
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,9 +31,9 @@ namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class LinkType extends BaseType
|
||||
class LinkType
|
||||
{
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
$idAttribute = $field . 'Id';
|
||||
|
||||
|
||||
@@ -31,21 +31,41 @@ namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class PersonNameType extends BaseType
|
||||
use Espo\Core\{
|
||||
Utils\FieldUtil,
|
||||
};
|
||||
|
||||
class PersonNameType
|
||||
{
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
private $fieldUtil;
|
||||
|
||||
public function __construct(FieldUtil $fieldUtil)
|
||||
{
|
||||
$this->fieldUtil = $fieldUtil;
|
||||
}
|
||||
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
$isEmpty = true;
|
||||
foreach ($this->getActualAttributeList($entity, $field) as $attribute) {
|
||||
|
||||
$attributeList = $this->fieldUtil->getActualAttributeList($entity->getEntityType(), $field);
|
||||
|
||||
foreach ($attributeList as $attribute) {
|
||||
if ($attribute === 'salutation' . ucfirst($field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($entity->has($attribute) && $entity->get($attribute) !== '') {
|
||||
$isEmpty = false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($isEmpty) return false;
|
||||
|
||||
if ($isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,23 +31,30 @@ namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class PhoneType extends BaseType
|
||||
class PhoneType
|
||||
{
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
if ($this->isNotEmpty($entity, $field)) return true;
|
||||
if ($this->isNotEmpty($entity, $field)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$dataList = $entity->get($field . 'Data');
|
||||
if (!is_array($dataList)) return false;
|
||||
|
||||
if (!is_array($dataList)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($dataList as $item) {
|
||||
if (!empty($item->phoneNumber)) return true;
|
||||
if (!empty($item->phoneNumber)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, string $field): bool
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== '' && $entity->get($field) !== null;
|
||||
}
|
||||
|
||||
@@ -31,25 +31,27 @@ namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class VarcharType extends BaseType
|
||||
class VarcharType
|
||||
{
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
{
|
||||
return $this->isNotEmpty($entity, $field);
|
||||
}
|
||||
|
||||
public function checkMaxLength(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkMaxLength(Entity $entity, string $field, int $validationValue): bool
|
||||
{
|
||||
if ($this->isNotEmpty($entity, $field)) {
|
||||
$value = $entity->get($field);
|
||||
|
||||
if (mb_strlen($value) > $validationValue) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, string $field): bool
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== '' && $entity->get($field) !== null;
|
||||
}
|
||||
|
||||
109
application/Espo/Classes/JobPreparators/CheckEmailAccounts.php
Normal file
109
application/Espo/Classes/JobPreparators/CheckEmailAccounts.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\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\ORM\EntityManager;
|
||||
|
||||
use Espo\Entities\Job as JobEntity;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
class CheckEmailAccounts implements Preparator
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function prepare(Data $data, DateTimeImmutable $executeTime): void
|
||||
{
|
||||
$collection = $this->entityManager
|
||||
->getRDBRepository('EmailAccount')
|
||||
->join('assignedUser', 'assignedUserAdditional')
|
||||
->where([
|
||||
'status' => 'Active',
|
||||
'useImap' => true,
|
||||
'assignedUserAdditional.isActive' => true,
|
||||
])
|
||||
->find();
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
$running = $this->entityManager
|
||||
->getRDBRepository(JobEntity::ENTITY_TYPE)
|
||||
->where([
|
||||
'scheduledJobId' => $data->getId(),
|
||||
'status' => [
|
||||
Status::RUNNING,
|
||||
Status::READY,
|
||||
],
|
||||
'targetType' => 'EmailAccount',
|
||||
'targetId' => $entity->getId(),
|
||||
])
|
||||
->findOne();
|
||||
|
||||
if ($running) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$countPending = $this->entityManager
|
||||
->getRDBRepository(JobEntity::ENTITY_TYPE)
|
||||
->where([
|
||||
'scheduledJobId' => $data->getId(),
|
||||
'status' => Status::PENDING,
|
||||
'targetType' => 'EmailAccount',
|
||||
'targetId' => $entity->getId(),
|
||||
])
|
||||
->count();
|
||||
|
||||
if ($countPending > 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$jobEntity = $this->entityManager->getEntity(JobEntity::ENTITY_TYPE);
|
||||
|
||||
$jobEntity->set([
|
||||
'name' => $data->getName(),
|
||||
'scheduledJobId' => $data->getId(),
|
||||
'executeTime' => $executeTime->format(DateTime::SYSTEM_DATE_TIME_FORMAT),
|
||||
'targetType' => 'EmailAccount',
|
||||
'targetId' => $entity->getId(),
|
||||
]);
|
||||
|
||||
$this->entityManager->saveEntity($jobEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
107
application/Espo/Classes/JobPreparators/CheckInboundEmails.php
Normal file
107
application/Espo/Classes/JobPreparators/CheckInboundEmails.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\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\ORM\EntityManager;
|
||||
|
||||
use Espo\Entities\Job as JobEntity;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
class CheckInboundEmails implements Preparator
|
||||
{
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function prepare(Data $data, DateTimeImmutable $executeTime): void
|
||||
{
|
||||
$collection = $this->entityManager
|
||||
->getRDBRepository('InboundEmail')
|
||||
->where([
|
||||
'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',
|
||||
'targetId' => $entity->getId(),
|
||||
])
|
||||
->findOne();
|
||||
|
||||
if ($running) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$countPending = $this->entityManager
|
||||
->getRDBRepository(JobEntity::ENTITY_TYPE)
|
||||
->where([
|
||||
'scheduledJobId' => $data->getId(),
|
||||
'status' => Status::PENDING,
|
||||
'targetType' => 'InboundEmail',
|
||||
'targetId' => $entity->getId(),
|
||||
])
|
||||
->count();
|
||||
|
||||
if ($countPending > 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$jobEntity = $this->entityManager->getEntity(JobEntity::ENTITY_TYPE);
|
||||
|
||||
$jobEntity->set([
|
||||
'name' => $data->getName(),
|
||||
'scheduledJobId' => $data->getId(),
|
||||
'executeTime' => $executeTime->format(DateTime::SYSTEM_DATE_TIME_FORMAT),
|
||||
'targetType' => 'InboundEmail',
|
||||
'targetId' => $entity->getId(),
|
||||
]);
|
||||
|
||||
$this->entityManager->saveEntity($jobEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,18 +27,21 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Jobs;
|
||||
namespace Espo\Classes\Jobs;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
ORM\EntityManager,
|
||||
Jobs\Job,
|
||||
Job\JobDataLess,
|
||||
};
|
||||
|
||||
class AuthTokenControl implements Job
|
||||
use DateTime;
|
||||
|
||||
class AuthTokenControl implements JobDataLess
|
||||
{
|
||||
protected $config;
|
||||
protected $entityManager;
|
||||
private $config;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(Config $config, EntityManager $entityManager)
|
||||
{
|
||||
@@ -46,7 +49,7 @@ class AuthTokenControl implements Job
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function run()
|
||||
public function run(): void
|
||||
{
|
||||
$authTokenLifetime = $this->config->get('authTokenLifetime');
|
||||
$authTokenMaxIdleTime = $this->config->get('authTokenMaxIdleTime');
|
||||
@@ -55,30 +58,39 @@ class AuthTokenControl implements Job
|
||||
return;
|
||||
}
|
||||
|
||||
$whereClause = array(
|
||||
'isActive' => true
|
||||
);
|
||||
$whereClause = [
|
||||
'isActive' => true,
|
||||
];
|
||||
|
||||
if ($authTokenLifetime) {
|
||||
$dt = new \DateTime();
|
||||
$dt = new DateTime();
|
||||
|
||||
$dt->modify('-' . $authTokenLifetime . ' hours');
|
||||
|
||||
$authTokenLifetimeThreshold = $dt->format('Y-m-d H:i:s');
|
||||
|
||||
$whereClause['createdAt<'] = $authTokenLifetimeThreshold;
|
||||
}
|
||||
|
||||
if ($authTokenMaxIdleTime) {
|
||||
$dt = new \DateTime();
|
||||
$dt = new DateTime();
|
||||
|
||||
$dt->modify('-' . $authTokenMaxIdleTime . ' hours');
|
||||
|
||||
$authTokenMaxIdleTimeThreshold = $dt->format('Y-m-d H:i:s');
|
||||
|
||||
$whereClause['lastAccess<'] = $authTokenMaxIdleTimeThreshold;
|
||||
}
|
||||
|
||||
$tokenList = $this->entityManager->getRepository('AuthToken')->where($whereClause)->limit(0, 500)->find();
|
||||
$tokenList = $this->entityManager
|
||||
->getRepository('AuthToken')
|
||||
->where($whereClause)
|
||||
->limit(0, 500)
|
||||
->find();
|
||||
|
||||
foreach ($tokenList as $token) {
|
||||
$token->set('isActive', false);
|
||||
|
||||
$this->entityManager->saveEntity($token);
|
||||
}
|
||||
}
|
||||
83
application/Espo/Classes/Jobs/CheckEmailAccounts.php
Normal file
83
application/Espo/Classes/Jobs/CheckEmailAccounts.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Jobs;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
use Espo\Services\EmailAccount as Service;
|
||||
|
||||
use Espo\Core\{
|
||||
Job\Job,
|
||||
Job\Job\Data,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
use Throwable;
|
||||
|
||||
class CheckEmailAccounts implements Job
|
||||
{
|
||||
private $service;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(Service $service, EntityManager $entityManager)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function run(Data $data): void
|
||||
{
|
||||
$targetId = $data->getTargetId();
|
||||
|
||||
if (!$targetId) {
|
||||
throw new Error("No target.");
|
||||
}
|
||||
|
||||
$entity = $this->entityManager->getEntity('EmailAccount', $targetId);
|
||||
|
||||
if (!$entity) {
|
||||
throw new Error("Job CheckEmailAccounts '{$targetId}': EmailAccount does not exist.", -1);
|
||||
}
|
||||
|
||||
if ($entity->get('status') !== 'Active') {
|
||||
throw new Error("Job CheckEmailAccounts '{$targetId}': EmailAccount is not active.", -1);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->service->fetchFromMailServer($entity);
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
throw new Error(
|
||||
'Job CheckEmailAccounts ' . $entity->getId() . ': [' . $e->getCode() . '] ' .$e->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
83
application/Espo/Classes/Jobs/CheckInboundEmails.php
Normal file
83
application/Espo/Classes/Jobs/CheckInboundEmails.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Jobs;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
use Espo\Services\InboundEmail as Service;
|
||||
|
||||
use Espo\Core\{
|
||||
Job\Job,
|
||||
Job\Job\Data,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
use Throwable;
|
||||
|
||||
class CheckInboundEmails implements Job
|
||||
{
|
||||
private $service;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(Service $service, EntityManager $entityManager)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function run(Data $data): void
|
||||
{
|
||||
$targetId = $data->getTargetId();
|
||||
|
||||
if (!$targetId) {
|
||||
throw new Error("No target.");
|
||||
}
|
||||
|
||||
$entity = $this->entityManager->getEntity('InboundEmail', $targetId);
|
||||
|
||||
if (!$entity) {
|
||||
throw new Error("Job CheckInboundEmails '{$targetId}': InboundEmail does not exist.", -1);
|
||||
}
|
||||
|
||||
if ($entity->get('status') !== 'Active') {
|
||||
throw new Error("Job CheckInboundEmails '{$targetId}': InboundEmail is not active.", -1);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->service->fetchFromMailServer($entity);
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
throw new Error(
|
||||
'Job CheckInboundEmails ' . $entity->getId() . ': [' . $e->getCode() . '] ' .$e->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,16 +27,17 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Jobs;
|
||||
|
||||
use Espo\Core\Exceptions;
|
||||
namespace Espo\Classes\Jobs;
|
||||
|
||||
class CheckNewExtensionVersion extends CheckNewVersion
|
||||
{
|
||||
public function run()
|
||||
public function run(): void
|
||||
{
|
||||
if (!$this->config->get('adminNotifications') || !$this->config->get('adminNotificationsNewExtensionVersion')) {
|
||||
return true;
|
||||
if (
|
||||
!$this->config->get('adminNotifications') ||
|
||||
!$this->config->get('adminNotificationsNewExtensionVersion')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$job = $this->entityManager->getEntity('Job');
|
||||
@@ -48,7 +49,5 @@ class CheckNewExtensionVersion extends CheckNewVersion
|
||||
]);
|
||||
|
||||
$this->entityManager->saveEntity($job);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,20 +27,21 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Jobs;
|
||||
namespace Espo\Classes\Jobs;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
ORM\EntityManager,
|
||||
Jobs\Job,
|
||||
Job\JobDataLess,
|
||||
};
|
||||
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
|
||||
class CheckNewVersion implements Job
|
||||
class CheckNewVersion implements JobDataLess
|
||||
{
|
||||
protected $config;
|
||||
|
||||
protected $entityManager;
|
||||
|
||||
public function __construct(Config $config, EntityManager $entityManager)
|
||||
@@ -49,13 +50,14 @@ class CheckNewVersion implements Job
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function run()
|
||||
public function run(): void
|
||||
{
|
||||
if (!$this->config->get('adminNotifications') || !$this->config->get('adminNotificationsNewVersion')) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
$job = $this->entityManager->getEntity('Job');
|
||||
|
||||
$job->set([
|
||||
'name' => 'Check for New Version (job)',
|
||||
'serviceName' => 'AdminNotifications',
|
||||
@@ -65,7 +67,7 @@ class CheckNewVersion implements Job
|
||||
|
||||
$this->entityManager->saveEntity($job);
|
||||
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
protected function getRunTime()
|
||||
@@ -77,6 +79,7 @@ class CheckNewVersion implements Job
|
||||
$time = $nextDay->format('Y-m-d') . ' ' . $hour . ':' . $minute . ':00';
|
||||
|
||||
$timeZone = $this->config->get('timeZone');
|
||||
|
||||
if (empty($timeZone)) {
|
||||
$timeZone = 'UTC';
|
||||
}
|
||||
@@ -88,6 +91,7 @@ class CheckNewVersion implements Job
|
||||
|
||||
/**
|
||||
* For backward compatibility.
|
||||
* @deprecated
|
||||
*/
|
||||
protected function getEntityManager()
|
||||
{
|
||||
@@ -27,19 +27,19 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Jobs;
|
||||
namespace Espo\Classes\Jobs;
|
||||
|
||||
use Espo\Core\Exceptions;
|
||||
use Espo\Core\Record\ServiceContainer;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
ORM\EntityManager,
|
||||
Jobs\Job,
|
||||
Job\JobDataLess,
|
||||
Utils\Metadata,
|
||||
Utils\File\Manager as FileManager,
|
||||
InjectableFactory,
|
||||
Select\SelectManagerFactory,
|
||||
ServiceFactory,
|
||||
Select\SelectBuilderFactory,
|
||||
Utils\Log,
|
||||
};
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
@@ -49,25 +49,41 @@ use SplFileInfo;
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
class Cleanup implements Job
|
||||
class Cleanup implements JobDataLess
|
||||
{
|
||||
protected $cleanupJobPeriod = '10 days';
|
||||
protected $cleanupActionHistoryPeriod = '15 days';
|
||||
protected $cleanupAuthTokenPeriod = '1 month';
|
||||
protected $cleanupAuthLogPeriod = '2 months';
|
||||
protected $cleanupNotificationsPeriod = '2 months';
|
||||
protected $cleanupAttachmentsPeriod = '15 days';
|
||||
protected $cleanupAttachmentsFromPeriod = '3 months';
|
||||
protected $cleanupBackupPeriod = '2 month';
|
||||
protected $cleanupDeletedRecordsPeriod = '3 months';
|
||||
private $cleanupJobPeriod = '10 days';
|
||||
|
||||
protected $config;
|
||||
protected $entityManager;
|
||||
protected $metedata;
|
||||
protected $fileManager;
|
||||
protected $injectableFactory;
|
||||
protected $selectManagerFactory;
|
||||
protected $serviceFactory;
|
||||
private $cleanupActionHistoryPeriod = '15 days';
|
||||
|
||||
private $cleanupAuthTokenPeriod = '1 month';
|
||||
|
||||
private $cleanupAuthLogPeriod = '2 months';
|
||||
|
||||
private $cleanupNotificationsPeriod = '2 months';
|
||||
|
||||
private $cleanupAttachmentsPeriod = '15 days';
|
||||
|
||||
private $cleanupAttachmentsFromPeriod = '3 months';
|
||||
|
||||
private $cleanupBackupPeriod = '2 month';
|
||||
|
||||
private $cleanupDeletedRecordsPeriod = '3 months';
|
||||
|
||||
private $config;
|
||||
|
||||
private $entityManager;
|
||||
|
||||
private $metadata;
|
||||
|
||||
private $fileManager;
|
||||
|
||||
private $injectableFactory;
|
||||
|
||||
private $selectBuilderFactory;
|
||||
|
||||
private $recordServiceContainer;
|
||||
|
||||
private $log;
|
||||
|
||||
public function __construct(
|
||||
Config $config,
|
||||
@@ -75,19 +91,21 @@ class Cleanup implements Job
|
||||
Metadata $metadata,
|
||||
FileManager $fileManager,
|
||||
InjectableFactory $injectableFactory,
|
||||
SelectManagerFactory $selectManagerFactory,
|
||||
ServiceFactory $serviceFactory
|
||||
SelectBuilderFactory $selectBuilderFactory,
|
||||
ServiceContainer $recordServiceContainer,
|
||||
Log $log
|
||||
) {
|
||||
$this->config = $config;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->metadata = $metadata;
|
||||
$this->fileManager = $fileManager;
|
||||
$this->injectableFactory = $injectableFactory;
|
||||
$this->selectManagerFactory = $selectManagerFactory;
|
||||
$this->serviceFactory = $serviceFactory;
|
||||
$this->selectBuilderFactory = $selectBuilderFactory;
|
||||
$this->recordServiceContainer = $recordServiceContainer;
|
||||
$this->log = $log;
|
||||
}
|
||||
|
||||
public function run()
|
||||
public function run(): void
|
||||
{
|
||||
$this->cleanupJobs();
|
||||
$this->cleanupScheduledJobLog();
|
||||
@@ -115,15 +133,16 @@ class Cleanup implements Job
|
||||
foreach ($items as $name => $item) {
|
||||
try {
|
||||
$className = $item['className'];
|
||||
|
||||
$injectableFactory->create($className)->process();
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
$GLOBALS['log']->error("Cleanup: {$name}: " . $e->getMessage());
|
||||
$this->log->error("Cleanup: {$name}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function cleanupJobs()
|
||||
private function cleanupJobs(): void
|
||||
{
|
||||
$delete = $this->entityManager->getQueryBuilder()->delete()
|
||||
->from('Job')
|
||||
@@ -147,9 +166,11 @@ class Cleanup implements Job
|
||||
$this->entityManager->getQueryExecutor()->execute($delete);
|
||||
}
|
||||
|
||||
protected function cleanupUniqueIds()
|
||||
private function cleanupUniqueIds(): void
|
||||
{
|
||||
$delete = $this->entityManager->getQueryBuilder()->delete()
|
||||
$delete = $this->entityManager
|
||||
->getQueryBuilder()
|
||||
->delete()
|
||||
->from('UniqueId')
|
||||
->where([
|
||||
'terminateAt!=' => null,
|
||||
@@ -160,7 +181,7 @@ class Cleanup implements Job
|
||||
$this->entityManager->getQueryExecutor()->execute($delete);
|
||||
}
|
||||
|
||||
protected function cleanupScheduledJobLog()
|
||||
private function cleanupScheduledJobLog(): void
|
||||
{
|
||||
$scheduledJobList = $this->entityManager->getRepository('ScheduledJob')
|
||||
->select(['id'])
|
||||
@@ -187,7 +208,9 @@ class Cleanup implements Job
|
||||
$ignoreIdList[] = $logRecord->get('id');
|
||||
}
|
||||
|
||||
$delete = $this->entityManager->getQueryBuilder()->delete()
|
||||
$delete = $this->entityManager
|
||||
->getQueryBuilder()
|
||||
->delete()
|
||||
->from('ScheduledJobLogRecord')
|
||||
->where([
|
||||
'scheduledJobId' => $scheduledJobId,
|
||||
@@ -200,7 +223,7 @@ class Cleanup implements Job
|
||||
}
|
||||
}
|
||||
|
||||
protected function cleanupActionHistory()
|
||||
private function cleanupActionHistory(): void
|
||||
{
|
||||
$period = '-' . $this->config->get('cleanupActionHistoryPeriod', $this->cleanupActionHistoryPeriod);
|
||||
|
||||
@@ -218,14 +241,16 @@ class Cleanup implements Job
|
||||
$this->entityManager->getQueryExecutor()->execute($delete);
|
||||
}
|
||||
|
||||
protected function cleanupAuthToken()
|
||||
private function cleanupAuthToken(): void
|
||||
{
|
||||
$period = '-' . $this->config->get('cleanupAuthTokenPeriod', $this->cleanupAuthTokenPeriod);
|
||||
|
||||
$datetime = new DateTime();
|
||||
$datetime->modify($period);
|
||||
|
||||
$delete = $this->entityManager->getQueryBuilder()->delete()
|
||||
$delete = $this->entityManager
|
||||
->getQueryBuilder()
|
||||
->delete()
|
||||
->from('AuthToken')
|
||||
->where([
|
||||
'DATE:modifiedAt<' => $datetime->format('Y-m-d'),
|
||||
@@ -236,7 +261,7 @@ class Cleanup implements Job
|
||||
$this->entityManager->getQueryExecutor()->execute($delete);
|
||||
}
|
||||
|
||||
protected function cleanupAuthLog()
|
||||
private function cleanupAuthLog(): void
|
||||
{
|
||||
$period = '-' . $this->config->get('cleanupAuthLogPeriod', $this->cleanupAuthLogPeriod);
|
||||
|
||||
@@ -244,7 +269,9 @@ class Cleanup implements Job
|
||||
|
||||
$datetime->modify($period);
|
||||
|
||||
$delete = $this->entityManager->getQueryBuilder()->delete()
|
||||
$delete = $this->entityManager
|
||||
->getQueryBuilder()
|
||||
->delete()
|
||||
->from('AuthLogRecord')
|
||||
->where([
|
||||
'DATE:createdAt<' => $datetime->format('Y-m-d'),
|
||||
@@ -254,21 +281,18 @@ class Cleanup implements Job
|
||||
$this->entityManager->getQueryExecutor()->execute($delete);
|
||||
}
|
||||
|
||||
protected function getCleanupJobFromDate()
|
||||
private function getCleanupJobFromDate(): string
|
||||
{
|
||||
$period = '-' . $this->config->get('cleanupJobPeriod', $this->cleanupJobPeriod);
|
||||
|
||||
$datetime = new DateTime();
|
||||
|
||||
$datetime->modify($period);
|
||||
|
||||
return $datetime->format('Y-m-d');
|
||||
}
|
||||
|
||||
protected function cleanupAttachments()
|
||||
private function cleanupAttachments(): void
|
||||
{
|
||||
$pdo = $this->entityManager->getPDO();
|
||||
|
||||
$period = '-' . $this->config->get('cleanupAttachmentsPeriod', $this->cleanupAttachmentsPeriod);
|
||||
|
||||
$datetime = new DateTime();
|
||||
@@ -293,17 +317,22 @@ class Cleanup implements Job
|
||||
}
|
||||
|
||||
if ($this->config->get('cleanupOrphanAttachments')) {
|
||||
$selectManager = $this->selectManagerFactory->create('Attachment');
|
||||
$orphanQueryBuilder = $this->selectBuilderFactory
|
||||
->create()
|
||||
->from('Attachment')
|
||||
->withPrimaryFilter('orphan')
|
||||
->buildQueryBuilder();
|
||||
|
||||
$selectParams = $selectManager->getEmptySelectParams();
|
||||
$selectManager->applyFilter('orphan', $selectParams);
|
||||
|
||||
$selectParams['whereClause'][] = [
|
||||
$orphanQueryBuilder->where([
|
||||
'createdAt<' => $datetime->format('Y-m-d H:i:s'),
|
||||
'createdAt>' => '2018-01-01 00:00:00',
|
||||
];
|
||||
]);
|
||||
|
||||
$collection = $this->entityManager->getRepository('Attachment')->limit(0, 5000)->find($selectParams);
|
||||
$collection = $this->entityManager
|
||||
->getRepository('Attachment')
|
||||
->clone($orphanQueryBuilder->build())
|
||||
->limit(0, 5000)
|
||||
->find();
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
$this->entityManager->removeEntity($entity);
|
||||
@@ -418,7 +447,7 @@ class Cleanup implements Job
|
||||
$this->entityManager->getQueryExecutor()->execute($delete);
|
||||
}
|
||||
|
||||
protected function cleanupEmails()
|
||||
private function cleanupEmails(): void
|
||||
{
|
||||
$dateBefore = date('Y-m-d H:i:s', time() - 3600 * 24 * 20);
|
||||
|
||||
@@ -474,7 +503,7 @@ class Cleanup implements Job
|
||||
}
|
||||
}
|
||||
|
||||
protected function cleanupNotifications()
|
||||
private function cleanupNotifications(): void
|
||||
{
|
||||
$period = '-' . $this->config->get('cleanupNotificationsPeriod', $this->cleanupNotificationsPeriod);
|
||||
|
||||
@@ -492,7 +521,7 @@ class Cleanup implements Job
|
||||
}
|
||||
}
|
||||
|
||||
protected function cleanupUpgradeBackups()
|
||||
private function cleanupUpgradeBackups(): void
|
||||
{
|
||||
$path = 'data/.backup/upgrades';
|
||||
|
||||
@@ -514,7 +543,7 @@ class Cleanup implements Job
|
||||
}
|
||||
}
|
||||
|
||||
protected function cleanupDeletedEntity(Entity $entity)
|
||||
private function cleanupDeletedEntity(Entity $entity): void
|
||||
{
|
||||
$scope = $entity->getEntityType();
|
||||
|
||||
@@ -574,7 +603,7 @@ class Cleanup implements Job
|
||||
$this->entityManager->getQueryExecutor()->execute($delete);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$GLOBALS['log']->error("Cleanup: " . $e->getMessage());
|
||||
$this->log->error("Cleanup: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,7 +666,7 @@ class Cleanup implements Job
|
||||
}
|
||||
}
|
||||
|
||||
protected function cleanupDeletedRecords()
|
||||
private function cleanupDeletedRecords(): void
|
||||
{
|
||||
if (!$this->config->get('cleanupDeletedRecords')) {
|
||||
return;
|
||||
@@ -647,8 +676,6 @@ class Cleanup implements Job
|
||||
|
||||
$datetime = new DateTime($period);
|
||||
|
||||
$serviceFactory = $this->serviceFactory;
|
||||
|
||||
$scopeList = array_keys($this->metadata->get(['scopes']));
|
||||
|
||||
foreach ($scopeList as $scope) {
|
||||
@@ -677,14 +704,11 @@ class Cleanup implements Job
|
||||
if (!method_exists($repository, 'deleteFromDb')) continue;
|
||||
|
||||
$hasCleanupMethod = false;
|
||||
$service = null;
|
||||
|
||||
if ($serviceFactory->checkExists($scope)) {
|
||||
$service = $serviceFactory->create($scope);
|
||||
$service = $this->recordServiceContainer->get($scope);
|
||||
|
||||
if (method_exists($service, 'cleanup')) {
|
||||
$hasCleanupMethod = true;
|
||||
}
|
||||
if (method_exists($service, 'cleanup')) {
|
||||
$hasCleanupMethod = true;
|
||||
}
|
||||
|
||||
$whereClause = [
|
||||
@@ -693,8 +717,8 @@ class Cleanup implements Job
|
||||
|
||||
if ($this->metadata->get(['entityDefs', $scope, 'fields', 'modifiedAt'])) {
|
||||
$whereClause['modifiedAt<'] = $datetime->format('Y-m-d H:i:s');
|
||||
} else
|
||||
if ($this->metadata->get(['entityDefs', $scope, 'fields', 'createdAt'])) {
|
||||
}
|
||||
else if ($this->metadata->get(['entityDefs', $scope, 'fields', 'createdAt'])) {
|
||||
$whereClause['createdAt<'] = $datetime->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
@@ -716,7 +740,7 @@ class Cleanup implements Job
|
||||
$service->cleanup($entity->id);
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
$GLOBALS['log']->error("Cleanup job: Cleanup scope {$scope}: " . $e->getMessage());
|
||||
$this->log->error("Cleanup job: Cleanup scope {$scope}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,15 +27,11 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Jobs;
|
||||
namespace Espo\Classes\Jobs;
|
||||
|
||||
use Espo\Core\{
|
||||
Jobs\Job,
|
||||
};
|
||||
use Espo\Core\Job\JobDataLess;
|
||||
|
||||
class Dummy implements Job
|
||||
class Dummy implements JobDataLess
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
public function run(): void {}
|
||||
}
|
||||
50
application/Espo/Classes/Jobs/ProcessWebhookQueue.php
Normal file
50
application/Espo/Classes/Jobs/ProcessWebhookQueue.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\Jobs;
|
||||
|
||||
use Espo\Core\{
|
||||
Job\JobDataLess,
|
||||
Webhook\Queue,
|
||||
};
|
||||
|
||||
class ProcessWebhookQueue implements JobDataLess
|
||||
{
|
||||
private $queue;
|
||||
|
||||
public function __construct(Queue $queue)
|
||||
{
|
||||
$this->queue = $queue;
|
||||
}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$this->queue->process();
|
||||
}
|
||||
}
|
||||
@@ -27,25 +27,23 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Jobs;
|
||||
namespace Espo\Classes\Jobs;
|
||||
|
||||
use Espo\Core\{
|
||||
ServiceFactory,
|
||||
Jobs\Job,
|
||||
};
|
||||
use Espo\Core\Job\JobDataLess;
|
||||
|
||||
class SendEmailNotifications implements Job
|
||||
use Espo\Tools\EmailNotification\Processor;
|
||||
|
||||
class SendEmailNotifications implements JobDataLess
|
||||
{
|
||||
protected $serviceFactory;
|
||||
private $processor;
|
||||
|
||||
public function __construct(ServiceFactory $serviceFactory)
|
||||
public function __construct(Processor $processor)
|
||||
{
|
||||
$this->serviceFactory = $serviceFactory;
|
||||
$this->processor = $processor;
|
||||
}
|
||||
|
||||
public function run()
|
||||
public function run(): void
|
||||
{
|
||||
$service = $this->serviceFactory->create('EmailNotification');
|
||||
$service->process();
|
||||
$this->processor->process();
|
||||
}
|
||||
}
|
||||
113
application/Espo/Classes/MassAction/User/MassDelete.php
Normal file
113
application/Espo/Classes/MassAction/User/MassDelete.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\MassAction\User;
|
||||
|
||||
use Espo\Core\{
|
||||
MassAction\Actions\MassDelete as MassDeleteOriginal,
|
||||
MassAction\QueryBuilder,
|
||||
MassAction\Params,
|
||||
MassAction\Result,
|
||||
MassAction\Data,
|
||||
MassAction\MassAction,
|
||||
Acl,
|
||||
ORM\EntityManager,
|
||||
Exceptions\Forbidden,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
Entities\User,
|
||||
ORM\Entity,
|
||||
};
|
||||
|
||||
class MassDelete implements MassAction
|
||||
{
|
||||
protected $massDeleteOriginal;
|
||||
|
||||
protected $queryBuilder;
|
||||
|
||||
protected $entityManager;
|
||||
|
||||
protected $acl;
|
||||
|
||||
protected $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;
|
||||
}
|
||||
|
||||
public function process(Params $params, Data $data): Result
|
||||
{
|
||||
$entityType = $params->getEntityType();
|
||||
|
||||
if (!$this->acl->check($entityType, 'delete')) {
|
||||
throw new Forbidden("No delete access for '{$entityType}'.");
|
||||
}
|
||||
|
||||
if (!$params->hasIds() && $this->acl->get('massUpdatePermission') !== 'yes') {
|
||||
throw new Forbidden("No mass-update permission.");
|
||||
}
|
||||
|
||||
$query = $this->queryBuilder->build($params);
|
||||
|
||||
$collection = $this->entityManager
|
||||
->getRepository('User')
|
||||
->clone($query)
|
||||
->sth()
|
||||
->select(['id'])
|
||||
->find();
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
$this->checkEntity($entity, $data);
|
||||
}
|
||||
|
||||
return $this->massDeleteOriginal->process($params, $data);
|
||||
}
|
||||
|
||||
protected function checkEntity(Entity $entity): void
|
||||
{
|
||||
if ($entity->id === 'system') {
|
||||
throw new Forbidden("Can't delete 'system' user.");
|
||||
}
|
||||
|
||||
if ($entity->id === $this->user->id) {
|
||||
throw new Forbidden("Can't delete own user.");
|
||||
}
|
||||
}
|
||||
}
|
||||
180
application/Espo/Classes/MassAction/User/MassUpdate.php
Normal file
180
application/Espo/Classes/MassAction/User/MassUpdate.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\MassAction\User;
|
||||
|
||||
use Espo\Core\{
|
||||
MassAction\Actions\MassUpdate as MassUpdateOriginal,
|
||||
MassAction\QueryBuilder,
|
||||
MassAction\Params,
|
||||
MassAction\Result,
|
||||
MassAction\Data,
|
||||
MassAction\MassAction,
|
||||
Utils\File\Manager as FileManager,
|
||||
DataManager,
|
||||
Acl,
|
||||
ORM\EntityManager,
|
||||
Exceptions\Forbidden,
|
||||
};
|
||||
|
||||
use Espo\{
|
||||
Entities\User,
|
||||
ORM\Entity,
|
||||
};
|
||||
|
||||
class MassUpdate implements MassAction
|
||||
{
|
||||
protected $massUpdateOriginal;
|
||||
|
||||
protected $queryBuilder;
|
||||
|
||||
protected $entityManager;
|
||||
|
||||
protected $acl;
|
||||
|
||||
protected $user;
|
||||
|
||||
protected $fileManager;
|
||||
|
||||
protected $dataManager;
|
||||
|
||||
public function __construct(
|
||||
MassUpdateOriginal $massUpdateOriginal,
|
||||
QueryBuilder $queryBuilder,
|
||||
EntityManager $entityManager,
|
||||
Acl $acl,
|
||||
User $user,
|
||||
FileManager $fileManager,
|
||||
DataManager $dataMaanger
|
||||
) {
|
||||
$this->massUpdateOriginal = $massUpdateOriginal;
|
||||
$this->queryBuilder = $queryBuilder;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->acl = $acl;
|
||||
$this->user = $user;
|
||||
$this->fileManager = $fileManager;
|
||||
$this->dataManager = $dataMaanger;
|
||||
}
|
||||
|
||||
public function process(Params $params, Data $data): Result
|
||||
{
|
||||
$entityType = $params->getEntityType();
|
||||
|
||||
if (!$this->acl->check($entityType, 'edit')) {
|
||||
throw new Forbidden("No edit access for '{$entityType}'.");
|
||||
}
|
||||
|
||||
if ($this->acl->get('massUpdatePermission') !== 'yes') {
|
||||
throw new Forbidden("No mass-update permission.");
|
||||
}
|
||||
|
||||
if (
|
||||
$data->has('type') ||
|
||||
$data->has('password') ||
|
||||
$data->has('emailAddress') ||
|
||||
$data->has('isAdmin') ||
|
||||
$data->has('isSuperAdmin') ||
|
||||
$data->has('isPortalUser')
|
||||
) {
|
||||
throw new Forbidden("Not allowed fields.");
|
||||
}
|
||||
|
||||
$query = $this->queryBuilder->build($params);
|
||||
|
||||
$collection = $this->entityManager
|
||||
->getRepository('User')
|
||||
->clone($query)
|
||||
->sth()
|
||||
->select(['id'])
|
||||
->find();
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
$this->checkEntity($entity, $data);
|
||||
}
|
||||
|
||||
$result = $this->massUpdateOriginal->process($params, $data);
|
||||
|
||||
$this->afterProcess($result, $data);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function checkEntity(Entity $entity, Data $data): void
|
||||
{
|
||||
if ($entity->id === 'system') {
|
||||
throw new Forbidden("Can't update 'system' user.");
|
||||
}
|
||||
|
||||
if ($entity->id === $this->user->id) {
|
||||
if ($data->has('isActive')) {
|
||||
throw new Forbidden("Can't change 'isActive' field for own user.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function afterProcess(Result $result, Data $dataWrapped): void
|
||||
{
|
||||
$data = $dataWrapped->getRaw();
|
||||
|
||||
if (
|
||||
property_exists($data, 'rolesIds') ||
|
||||
property_exists($data, 'teamsIds') ||
|
||||
property_exists($data, 'type') ||
|
||||
property_exists($data, 'portalRolesIds') ||
|
||||
property_exists($data, 'portalsIds')
|
||||
) {
|
||||
foreach ($result->getIds() as $id) {
|
||||
$this->clearRoleCache($id);
|
||||
}
|
||||
|
||||
$this->dataManager->updateCacheTimestamp();
|
||||
}
|
||||
|
||||
if (
|
||||
property_exists($data, 'portalRolesIds') ||
|
||||
property_exists($data, 'portalsIds') ||
|
||||
property_exists($data, 'contactId') ||
|
||||
property_exists($data, 'accountsIds')
|
||||
) {
|
||||
$this->clearPortalRolesCache();
|
||||
|
||||
$this->dataManager->updateCacheTimestamp();
|
||||
}
|
||||
}
|
||||
|
||||
protected function clearRoleCache(string $id): void
|
||||
{
|
||||
$this->fileManager->removeFile('data/cache/application/acl/' . $id . '.php');
|
||||
}
|
||||
|
||||
protected function clearPortalRolesCache(): void
|
||||
{
|
||||
$this->fileManager->removeInDir('data/cache/application/aclPortal');
|
||||
}
|
||||
}
|
||||
@@ -27,29 +27,34 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\AclPortal;
|
||||
namespace Espo\Classes\RecordHooks\Team;
|
||||
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Record\Hook\LinkHook;
|
||||
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\AclPortal\Acl;
|
||||
use Espo\Entities\User;
|
||||
|
||||
class KnowledgeBaseArticle extends Acl
|
||||
class BeforeLinkUserCheck implements LinkHook
|
||||
{
|
||||
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
|
||||
public function process(Entity $entity, string $link, Entity $foreignEntity): void
|
||||
{
|
||||
if (!$this->checkEntity($user, $entity, $data, 'read')) {
|
||||
return false;
|
||||
if ($link !== 'users') {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($entity->get('status') !== 'Published') return false;
|
||||
$this->processUserCheck($foreignEntity);
|
||||
}
|
||||
|
||||
$portalIdList = $entity->getLinkMultipleIdList('portals');
|
||||
|
||||
if ($user->get('portalId') && !in_array($user->get('portalId'), $portalIdList)) {
|
||||
return false;
|
||||
private function processUserCheck(User $user): void
|
||||
{
|
||||
if ($user->isPortal()) {
|
||||
throw new Forbidden("Can't add portal users to team.");
|
||||
}
|
||||
|
||||
return true;
|
||||
if ($user->isSystem()) {
|
||||
throw new Forbidden("Can't add system users to team.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\ActionHistoryRecord\AccessControlFilters;
|
||||
|
||||
use Espo\{
|
||||
Core\Select\AccessControl\Filter,
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
Entities\User,
|
||||
};
|
||||
|
||||
class OnlyOwn implements Filter
|
||||
{
|
||||
private $user;
|
||||
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function apply(QueryBuilder $queryBuilder): void
|
||||
{
|
||||
$queryBuilder->where([
|
||||
'userId' => $this->user->getId(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\ActionHistoryRecord\BoolFilters;
|
||||
|
||||
use Espo\{
|
||||
Core\Select\Bool\Filter,
|
||||
ORM\Query\SelectBuilder as QueryBuilder,
|
||||
ORM\Query\Part\WhereClause,
|
||||
ORM\Query\Part\Where\OrGroupBuilder,
|
||||
Entities\User,
|
||||
};
|
||||
|
||||
class OnlyMy implements Filter
|
||||
{
|
||||
private $user;
|
||||
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function apply(QueryBuilder $queryBuilder, OrGroupBuilder $orGroupBuilder): void
|
||||
{
|
||||
$item = WhereClause::fromRaw([
|
||||
'userId' => $this->user->getId(),
|
||||
]);
|
||||
|
||||
$orGroupBuilder->add($item);
|
||||
}
|
||||
}
|
||||
@@ -27,13 +27,16 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\SelectManagers;
|
||||
namespace Espo\Classes\Select\Attachment\PrimaryFilters;
|
||||
|
||||
class Attachment extends \Espo\Core\Select\SelectManager
|
||||
use Espo\Core\Select\Primary\Filter;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
|
||||
class Orphan implements Filter
|
||||
{
|
||||
protected function filterOrphan(&$result)
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
$result['whereClause'][] = [
|
||||
$queryBuilder->where([
|
||||
'role' => ['Attachment', 'Inline Attachment'],
|
||||
[
|
||||
'OR' => [
|
||||
@@ -56,13 +59,17 @@ class Attachment extends \Espo\Core\Select\SelectManager
|
||||
],
|
||||
],
|
||||
'attachmentChild.id' => null,
|
||||
];
|
||||
]);
|
||||
|
||||
$this->addLeftJoin(['Attachment', 'attachmentChild', [
|
||||
'attachmentChild.sourceId:' => 'attachment.id',
|
||||
'attachmentChild.deleted' => false
|
||||
]], $result);
|
||||
$queryBuilder->leftJoin(
|
||||
'Attachment',
|
||||
'attachmentChild',
|
||||
[
|
||||
'attachmentChild.sourceId:' => 'attachment.id',
|
||||
'attachmentChild.deleted' => false,
|
||||
]
|
||||
);
|
||||
|
||||
$this->setDistinct(true, $result);
|
||||
$queryBuilder->distinct();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\AuthLogRecord\PrimaryFilters;
|
||||
|
||||
use Espo\Core\Select\Primary\Filter;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
|
||||
class Accepted implements Filter
|
||||
{
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
$queryBuilder->where([
|
||||
'isDenied' => false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\AuthLogRecord\PrimaryFilters;
|
||||
|
||||
use Espo\Core\Select\Primary\Filter;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
|
||||
class Denied implements Filter
|
||||
{
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
$queryBuilder->where([
|
||||
'isDenied' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -27,16 +27,17 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Di;
|
||||
namespace Espo\Classes\Select\AuthToken\PrimaryFilters;
|
||||
|
||||
use Espo\Core\Utils\FieldValidatorManager;
|
||||
use Espo\Core\Select\Primary\Filter;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
|
||||
trait FieldValidatorManagerSetter
|
||||
class Active implements Filter
|
||||
{
|
||||
protected $fieldValidatorManager;
|
||||
|
||||
public function setFieldValidatorManager(FieldValidatorManager $fieldValidatorManager)
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
$this->fieldValidatorManager = $fieldValidatorManager;
|
||||
$queryBuilder->where([
|
||||
'isActive' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2021 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\AuthToken\PrimaryFilters;
|
||||
|
||||
use Espo\Core\Select\Primary\Filter;
|
||||
use Espo\ORM\Query\SelectBuilder;
|
||||
|
||||
class Inactive implements Filter
|
||||
{
|
||||
public function apply(SelectBuilder $queryBuilder): void
|
||||
{
|
||||
$queryBuilder->where([
|
||||
'isActive' => false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user