Compare commits
843 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| af9b411a4c | |||
| cd49d951d8 | |||
| 7d63c114aa | |||
| af6f05ba07 | |||
| 46f8eb0cdb | |||
| c543bb5a5b | |||
| d1997089e4 | |||
| 57dd0177f9 | |||
| ba76e5ee3d | |||
| 76c93b842c | |||
| e73bff5ddf | |||
| 7d5c0d754e | |||
| e08a74b129 | |||
| be07aafaf4 | |||
| e2bf27e524 | |||
| b0157adbe2 | |||
| 239593afb5 | |||
| b97d764588 | |||
| bf8e7af984 | |||
| bf68c475e5 | |||
| 29624239ba | |||
| 4cb3c4918b | |||
| 26fa0d65e1 | |||
| 958baed3df | |||
| 40d6fb7565 | |||
| a7551b7dbf | |||
| 9ed33c4dc4 | |||
| 6b18fbe8f7 | |||
| 53b9880ea8 | |||
| 62538664df | |||
| f678fb16cc | |||
| fe09aa1cd9 | |||
| 710decc610 | |||
| 5d481d3528 | |||
| 8bcd3b72c5 | |||
| 0a0da810e9 | |||
| e630c046fe | |||
| 2857b5c53d | |||
| 0965c61f55 | |||
| 9dd318b176 | |||
| f8beca720c | |||
| d8f58dcc1d | |||
| 32aaaa350e | |||
| 0f6d1c6817 | |||
| 8c5a342a5a | |||
| 257401898b | |||
| e7ff3f903a | |||
| 6f82638b5d | |||
| 0625ce51c4 | |||
| f5670436d0 | |||
| 5d20a56ac8 | |||
| 020cf9713a | |||
| fe1361fc9c | |||
| 36621be496 | |||
| 25690030d1 | |||
| fcd6be3a0c | |||
| ad8dfa487c | |||
| 7f6f54628d | |||
| 8ea0b072c6 | |||
| 0df6248226 | |||
| 26a132658e | |||
| d02529ee86 | |||
| 0cec0fef51 | |||
| e56f6ab75d | |||
| a4980aa8f2 | |||
| fd219b49be | |||
| b90579aadc | |||
| 0b39d7f6b6 | |||
| a44ce06162 | |||
| f1eb2ab5d5 | |||
| 9a965bfba4 | |||
| 7349f37786 | |||
| 3d03dfaef7 | |||
| 5bf88eaff1 | |||
| f3c4b2ba39 | |||
| 92f6fb4588 | |||
| 2d6d7fd618 | |||
| 3a1d997d5a | |||
| 5bbb259c95 | |||
| b8e44767b3 | |||
| 6b486beb5c | |||
| aab1265e4e | |||
| 676181a4be | |||
| 839e5b7c74 | |||
| aff7003ceb | |||
| 66aa60f303 | |||
| b196811cf9 | |||
| 3fdddadd53 | |||
| 7af2d1d3ac | |||
| 63670e3245 | |||
| 389931bf22 | |||
| 76a67d15a3 | |||
| 8e65f2d375 | |||
| 56737f5d67 | |||
| 20f8fae2f0 | |||
| 17b5d77d33 | |||
| cbe32c88b6 | |||
| dee291f3f6 | |||
| 0b20c8e13f | |||
| c0af0173e9 | |||
| 79f4c4b5d2 | |||
| 31c8be2ee1 | |||
| 061b237032 | |||
| d3466e201d | |||
| c69c7d2194 | |||
| 05e1624e47 | |||
| 03e32412ca | |||
| 451a2376a8 | |||
| 167c774446 | |||
| 054262a002 | |||
| ecbc3c537f | |||
| d51bbfdfab | |||
| ae343cddbe | |||
| bb03fec604 | |||
| 248c9a6b00 | |||
| dec5e0be5f | |||
| bcbb29d94e | |||
| 3e2f995ba8 | |||
| 56b3b9d94d | |||
| 9b2ac0d443 | |||
| 3ee78c29cb | |||
| 548e829f2f | |||
| 749c161aaa | |||
| aee6b99a47 | |||
| 700262e07b | |||
| c4cd9d3ee8 | |||
| 235d8f2264 | |||
| 6268f84b45 | |||
| e2b49931c3 | |||
| 9cfab5a7ea | |||
| 66114e4748 | |||
| 4ea9868285 | |||
| 2c09eacbd4 | |||
| 2d5c01f25d | |||
| 9610695701 | |||
| b7062a2b75 | |||
| 3100d43af0 | |||
| 53606cbde5 | |||
| ca6d1d24f4 | |||
| 928a8c75e8 | |||
| 693df2d6fb | |||
| bc3cea0b86 | |||
| feba3cd05e | |||
| e6b31b8c45 | |||
| 79efc87ed2 | |||
| e17b88ca74 | |||
| 0020a5ea4a | |||
| 5778167b01 | |||
| 2b11414445 | |||
| e7b51ef61d | |||
| ca969ee79b | |||
| 9ff62f9e28 | |||
| 5c5cbf2933 | |||
| 91c5caee63 | |||
| 7aa439efbb | |||
| 7baf49aa7e | |||
| d7476c1de8 | |||
| d3e99a6de8 | |||
| 893f9d50c3 | |||
| a565766fcb | |||
| 89e517e47b | |||
| 39d51bb68f | |||
| 5e3168039a | |||
| f75062694f | |||
| cb3c3f18ee | |||
| 2415b29d45 | |||
| 7fb162be77 | |||
| bf93834fd3 | |||
| 63452d1bb2 | |||
| 5e26dbd870 | |||
| fb782d67ed | |||
| 864c91cd18 | |||
| 038479564b | |||
| 08c0dfc4ef | |||
| 019291b707 | |||
| 1d84bbb548 | |||
| 5ceb5c848e | |||
| b00e94bae9 | |||
| 46f6584577 | |||
| e3c651fcb9 | |||
| 86a85ba177 | |||
| 36a4cb2451 | |||
| ab726e9490 | |||
| b9f75395b6 | |||
| c0e4f83d83 | |||
| 08e94694b2 | |||
| 5112fd4fd3 | |||
| 2aafc6a82e | |||
| 1f200d53f8 | |||
| 77a5c75007 | |||
| c44d4357a7 | |||
| 2bf70e88ba | |||
| 442bb998e4 | |||
| 6f60a73c62 | |||
| 106a5a77e7 | |||
| 2f3f13f34c | |||
| bc4a9a07b6 | |||
| 5ca5ee55ee | |||
| 08636b550f | |||
| b2aab26ded | |||
| 6d629d40e6 | |||
| 6e433ec9a4 | |||
| 802a0229fa | |||
| 41b4b86033 | |||
| 63dca2712b | |||
| e06d104e10 | |||
| 4ab2ee875e | |||
| ac8debbb4b | |||
| 8a7a2071b6 | |||
| df471cf5a0 | |||
| 79665cc552 | |||
| 9c6932b124 | |||
| 4e30caf894 | |||
| 1bbff54c07 | |||
| 81ccf2a860 | |||
| 463007b218 | |||
| ee53fffc67 | |||
| 63351ed6b7 | |||
| 87ba6f6ccc | |||
| efeceb3a5b | |||
| bb6fddad09 | |||
| def9f6b70c | |||
| 95bbbb1daa | |||
| 0c759b9016 | |||
| cb2d2dd363 | |||
| 88948c4b66 | |||
| 799626cfdc | |||
| ab82a8748f | |||
| 6f78840aec | |||
| b94dc3c733 | |||
| de3c6bc45b | |||
| c17ae13fcf | |||
| e936ecbabd | |||
| 0f5105fee2 | |||
| 07571ecc32 | |||
| 3a4bc97abb | |||
| 412966d8d0 | |||
| d8bf6048c1 | |||
| f13f72ea16 | |||
| a7818227bd | |||
| a4c45ecdcd | |||
| a21671f1b7 | |||
| 3fc0349550 | |||
| fa177c41b7 | |||
| f3675fb838 | |||
| 72fd9184f4 | |||
| 2196020705 | |||
| 81465a50d6 | |||
| a0ccbfcac5 | |||
| eaa3cf6137 | |||
| 32d4e2f281 | |||
| 6454f6843b | |||
| 22e67d39b0 | |||
| 7efbf6fd66 | |||
| eaf9c97f52 | |||
| 5f7cee768d | |||
| 9c3b0aa289 | |||
| b3bf52bd9b | |||
| 1f07688881 | |||
| aafa30dbf9 | |||
| e8f2e5efd1 | |||
| c39e5bc02c | |||
| 6576b5ef79 | |||
| bec4b2d627 | |||
| a36798534d | |||
| dbd945e828 | |||
| b5655bf8ee | |||
| 3637cf4512 | |||
| 4693d2aae8 | |||
| ece49bc4dd | |||
| f60115f18d | |||
| 90fdbc872e | |||
| 7d5ad5d030 | |||
| bd0e7909a1 | |||
| cf3229a3c9 | |||
| 407f5fa53a | |||
| b1edce46ff | |||
| 551ed091e7 | |||
| 7645fa4e90 | |||
| 396ce79d22 | |||
| 60ad79fd64 | |||
| 2c9a6aa456 | |||
| 3577dfda9f | |||
| 31549f2851 | |||
| c8ea3f869e | |||
| bc01c9f7c6 | |||
| 592df35acf | |||
| 66f98aadf9 | |||
| 17e420f01b | |||
| 44f6d57832 | |||
| ae2cb10382 | |||
| d68e08c3fd | |||
| 3921e8c287 | |||
| caf79d1657 | |||
| 7477ba64d2 | |||
| e006261fcf | |||
| 2ddd9c2fc6 | |||
| 5a7253f89b | |||
| b68bc0f0b8 | |||
| edc4984f58 | |||
| c8a2ca87ba | |||
| 4dcc9c42c8 | |||
| 912fa4a85c | |||
| a64a4608be | |||
| b20773f2f5 | |||
| f9a440c708 | |||
| d002768a5f | |||
| e0fcb9f225 | |||
| a7ed16c72f | |||
| 1129d1c145 | |||
| ee599c7ab8 | |||
| 1a5be5bf91 | |||
| db0020d428 | |||
| 138ca4299b | |||
| e9af1ebd80 | |||
| 4d26e404b0 | |||
| b41813fa23 | |||
| b18796fd45 | |||
| d44898ed8c | |||
| bb246cb4fd | |||
| 17ceb3e721 | |||
| 8435c579c9 | |||
| 3b4eb893b6 | |||
| 54704bcee6 | |||
| 8bbfd862e4 | |||
| c909de0271 | |||
| bd7f80a64e | |||
| 2e15b5b271 | |||
| 0a61820f15 | |||
| 4b1af45cd6 | |||
| 756e3fcf39 | |||
| bb34ec1be3 | |||
| f98b86ae4d | |||
| eaa9a869f2 | |||
| d1f3dbf89b | |||
| 58c6208716 | |||
| 83eb252e82 | |||
| fd7da4d2fc | |||
| 4f76c98cec | |||
| b7186e5da9 | |||
| b3276fb329 | |||
| 5d2a31e65e | |||
| 8eaa01f1bc | |||
| 9bee6e12b4 | |||
| 50b2de8ce2 | |||
| 78b9e608e9 | |||
| 944c91d842 | |||
| a936b9fec8 | |||
| 1efdc626e0 | |||
| afca969668 | |||
| f72178f142 | |||
| 2f4d744078 | |||
| 8563129dd5 | |||
| ef1427bc95 | |||
| 20c07aaca1 | |||
| 4470b3fdec | |||
| 1e4705d20b | |||
| 0a5ae621b4 | |||
| 4e588f6d0e | |||
| f60c5e29de | |||
| 1662cfd97d | |||
| 8fdc0ab84d | |||
| 7c96fd391f | |||
| 2acbde70cc | |||
| cb7d100315 | |||
| d96e1bb8a8 | |||
| d27a67f567 | |||
| 47ae974304 | |||
| 6ce168faa2 | |||
| f9a8e1d9a7 | |||
| 18543534fb | |||
| 5349bd8d36 | |||
| 9a140571c3 | |||
| a4e0dc8bb7 | |||
| 14788e2a65 | |||
| c8118245e4 | |||
| fcff23e0c1 | |||
| 85f07ca15d | |||
| ed5a83c4f2 | |||
| 98e3ac0603 | |||
| df01ef4e14 | |||
| 24a3e6872c | |||
| 3d491b63f2 | |||
| 65dda61ff3 | |||
| 6d72a784fc | |||
| 388e4a71e1 | |||
| 1f77c6468c | |||
| a242c283f3 | |||
| a09ed79242 | |||
| 5116469856 | |||
| 81c5583b5c | |||
| 9d1233fe24 | |||
| 43c59f8d3e | |||
| 3bebb7ff07 | |||
| 05409dacde | |||
| 65929eec4b | |||
| 3d7a04be8e | |||
| 0f1b8ecb39 | |||
| 177d48e5a6 | |||
| 8b6b7dec06 | |||
| 7011ef7615 | |||
| a8beabcd23 | |||
| c114ee8acb | |||
| aa121e326b | |||
| ad0c5a01dd | |||
| b66d60dd7d | |||
| 14993ad169 | |||
| dbf7147f22 | |||
| d3a8de29e3 | |||
| 98c42569ea | |||
| 1deebf0833 | |||
| 3bc6b156a2 | |||
| 0a52c50c47 | |||
| 04c29294d6 | |||
| 9c28933882 | |||
| a5d8aed6fb | |||
| 4c52e36a0e | |||
| 7c2403f470 | |||
| 99dfa52915 | |||
| 3c5b61eca4 | |||
| 2185479c01 | |||
| fcbd48bc49 | |||
| db03f4f408 | |||
| 2f0e0d2a3b | |||
| 1aeb5639c7 | |||
| d14da8af12 | |||
| 38e529ec14 | |||
| b44f055013 | |||
| 18aee37057 | |||
| 83b5b9051d | |||
| e4141283f1 | |||
| 209ad19164 | |||
| 52afb8d9d1 | |||
| ec6c1b0578 | |||
| 7e97a9b2a4 | |||
| 8230dd07c4 | |||
| 16e7826981 | |||
| 17b9ae5089 | |||
| 85b38bc0e1 | |||
| ab8a9c8d36 | |||
| c8fb6d9805 | |||
| 35d0d7956d | |||
| 1e6cc7e8a2 | |||
| 6dff9d06c9 | |||
| 6de31ead9d | |||
| 6dc8cd7031 | |||
| 60209027fc | |||
| 7d186672ec | |||
| 6dd757e70f | |||
| 56207f7f48 | |||
| bf5dc8a282 | |||
| 0ec56ef0d3 | |||
| 07b49d0147 | |||
| 39d8b8f8ec | |||
| 50564c5db8 | |||
| e9aad35e70 | |||
| 47d82ac120 | |||
| 4cb7d22657 | |||
| e7992e356a | |||
| 0fd8f9d29f | |||
| bf033c31af | |||
| aa788a17d9 | |||
| 96c598d454 | |||
| 7cddf329d0 | |||
| f95660406f | |||
| 338caebfaf | |||
| 77ba946861 | |||
| cb37282a14 | |||
| 3d40aefef5 | |||
| e7b0489294 | |||
| 2690fcdacd | |||
| 0cc6d69c66 | |||
| 3312d440c1 | |||
| dba5650f1a | |||
| 81cab7acbf | |||
| 42cb2eb9bb | |||
| 1d0476e1b8 | |||
| 4ea2455958 | |||
| 2338c57357 | |||
| 019e1579f6 | |||
| df547b2022 | |||
| ce3b8b6f50 | |||
| 4e24ee66f5 | |||
| f82495c1cc | |||
| c78c88cf92 | |||
| 03b82e81f0 | |||
| 90fe6a7416 | |||
| 30014d640b | |||
| 2be2b7f459 | |||
| 659ae36ca6 | |||
| c92a4bcf36 | |||
| 931786eadb | |||
| 068e8121dc | |||
| 4e938d98fc | |||
| da3e214ecd | |||
| e88799265f | |||
| dcb717db48 | |||
| 9e78c0f9e1 | |||
| 3b0596a93c | |||
| 0c8593a958 | |||
| 4e75524d6f | |||
| e17b8dba4b | |||
| 11dc206fac | |||
| f2ebd47ded | |||
| 036ad99ba6 | |||
| 904830579c | |||
| a37d380440 | |||
| 1d6889879d | |||
| b54cd7fbd9 | |||
| 113b0ac446 | |||
| e30061e2a0 | |||
| 2b406aa7cc | |||
| 6cf5bbed95 | |||
| 1579671259 | |||
| 567d8416ec | |||
| 644e848011 | |||
| dc4eccb043 | |||
| be8ea6bab3 | |||
| 246d42469f | |||
| 8890aa6618 | |||
| 2b2620c954 | |||
| e594957c0b | |||
| a3b2f18a32 | |||
| 742b28a3c8 | |||
| 8340c5ba1d | |||
| d44935bc29 | |||
| efcbae5554 | |||
| 73c22bf815 | |||
| e715d9e5b5 | |||
| d1c1995018 | |||
| 7fda7abbe6 | |||
| bea8bd4057 | |||
| 5d3996ae03 | |||
| 3d5bc3bb0c | |||
| 2ec8022001 | |||
| 2dbbf72a6c | |||
| fbbe0e06cf | |||
| 455ef1138f | |||
| 2398ef7efe | |||
| f68c594a7e | |||
| 8004e4eda8 | |||
| 1e682a3e9a | |||
| 6546d987e5 | |||
| e4195f7b60 | |||
| 27cdb68240 | |||
| a59ea11aac | |||
| 5fde8f9f4b | |||
| 3d05606ad6 | |||
| f2da244a3c | |||
| c6e26b1323 | |||
| 1550d289df | |||
| 81a6d05621 | |||
| 78c372b2f8 | |||
| 59ec071908 | |||
| 687e67faed | |||
| 46e98d4660 | |||
| fa0cf9c9fd | |||
| 0e851eb687 | |||
| 3c651f8633 | |||
| 2b5f1c28e8 | |||
| 7fea881d17 | |||
| 61de366e05 | |||
| ada64bba0c | |||
| ab582b92c9 | |||
| 506a6a7779 | |||
| f87dcda391 | |||
| 2d94ad60f3 | |||
| 333ed98e37 | |||
| 69b5f8a1cc | |||
| cefad1c76f | |||
| 8fe96b140a | |||
| 3b25a1a001 | |||
| f4d98f177c | |||
| 9f4f38bb0d | |||
| b42ebfde2f | |||
| 1bd73d7872 | |||
| 6d83f77fcf | |||
| 17c1070fc1 | |||
| f86a493ba6 | |||
| 32119b6afd | |||
| e11661eadc | |||
| 0fc2201d80 | |||
| bbe96f67f6 | |||
| f4b2d9b1df | |||
| 42d894fd5a | |||
| e8c750c18f | |||
| 89cb84d784 | |||
| daa6e8360a | |||
| 24429255dc | |||
| 7c55ae98e5 | |||
| 81ed21962f | |||
| d9752ed970 | |||
| c6293580d9 | |||
| 5ddb76c137 | |||
| 20893622d4 | |||
| 35445dbf2e | |||
| fbe6e3c1e6 | |||
| 1d35922155 | |||
| ea31174cc4 | |||
| f5ea5f673c | |||
| e76490880a | |||
| e12bb1320c | |||
| 827e16cf93 | |||
| 1b61205281 | |||
| 269f2b4850 | |||
| d346e35901 | |||
| 2f87691309 | |||
| 8e6c778a82 | |||
| f36732f7d4 | |||
| e63d60ab3d | |||
| 460f3fcfd6 | |||
| 1f52ab9a3f | |||
| 397a9cdf1f | |||
| 4560ef7ef7 | |||
| dc41dff9a0 | |||
| 3e6d9d1b11 | |||
| 1513f45662 | |||
| 3e8426da1a | |||
| bb29373e16 | |||
| da7ac548c5 | |||
| b37441eaa8 | |||
| a546b77c10 | |||
| 392cb956d2 | |||
| 76273a4d86 | |||
| eb32b41bd4 | |||
| 767456ca9a | |||
| c12354138a | |||
| 1fd93a1fb8 | |||
| 9c36937a9e | |||
| 3d382e67b6 | |||
| ecdcab7371 | |||
| a5609f3cad | |||
| 5c0bc397c1 | |||
| 21e9131c65 | |||
| 8159e33fef | |||
| d2411e380b | |||
| a2017a0a75 | |||
| 16fcc4d61e | |||
| b6b4909f3c | |||
| 773abf3028 | |||
| f8f7c4fbff | |||
| c84abfb542 | |||
| 656f66f567 | |||
| 75386b4355 | |||
| 434b3020a0 | |||
| 64b0adee30 | |||
| 6351dc030c | |||
| f261690d76 | |||
| de37982a64 | |||
| 4266a38c01 | |||
| 8daec77bb4 | |||
| 4267c78f68 | |||
| 2f7843687f | |||
| 1648eb78f0 | |||
| 2b8143b4fb | |||
| b2d6e7c37e | |||
| 22d41a144f | |||
| f71d52c5ba | |||
| 1a86438f32 | |||
| 20aadf26a5 | |||
| d6514bc946 | |||
| 3f417198d7 | |||
| 62da2245c1 | |||
| 627fa8f89e | |||
| 13e24501e5 | |||
| 0002ec1a8e | |||
| 62d7948b67 | |||
| 54ca25571e | |||
| a64bf2e97f | |||
| 029a5587e6 | |||
| 918ce84b1b | |||
| 4622e9fe01 | |||
| d707979b7d | |||
| 0c224e2a22 | |||
| b4b4ec2f89 | |||
| 07b297f7ef | |||
| e7804062f3 | |||
| efed7969fc | |||
| c8a1edea1a | |||
| 8a0d2c9b6a | |||
| 784b0e8e40 | |||
| 9ac3cc23f7 | |||
| 0e1b88fd25 | |||
| 7084b38a5a | |||
| 7cba7fad95 | |||
| 73d67763c9 | |||
| 29217453ab | |||
| eca5bdea71 | |||
| 34fe3f53c3 | |||
| 78353460d1 | |||
| 210c76bad1 | |||
| d7326b927d | |||
| a4cf749d6d | |||
| b7d256687a | |||
| ccce2eb137 | |||
| 46a0c1f7bf | |||
| a84d6f4121 | |||
| 10793ebdda | |||
| 9c6bec3761 | |||
| 2ab4173e85 | |||
| 195db973dc | |||
| b15148f9f7 | |||
| ae6f669629 | |||
| a50c66557e | |||
| 9a09822f7a | |||
| 0a3174cba9 | |||
| d5414ece84 | |||
| fc4de43db3 | |||
| e4138b894c | |||
| 5b74430751 | |||
| 22f6d2d1b9 | |||
| 318e164a01 | |||
| 969d40f5d8 | |||
| c7f8b4899a | |||
| a81086493f | |||
| b773f22bd2 | |||
| 2b34b86746 | |||
| 78c4350ff7 | |||
| ecd33b0f54 | |||
| 7753eb32af | |||
| 9d3fbf8d27 | |||
| 7f3d099148 | |||
| 518ed97ed4 | |||
| 6b46ac2fde | |||
| 6b9f0f07ec | |||
| 553c7e9caa | |||
| bef0826f9d | |||
| 8fa4ec20a8 | |||
| 5ad7562f17 | |||
| b74d95894b | |||
| 562cd42344 | |||
| 078bdfc28f | |||
| 3c5e84bc44 | |||
| e61a6a00d8 | |||
| f7b1441050 | |||
| d0e6689dc4 | |||
| 9af8dde878 | |||
| bfed745758 | |||
| cc22abba50 | |||
| ca84177e87 | |||
| 4508991ca2 | |||
| 0b1ddecd32 | |||
| 59025f7d4c | |||
| 8c75651650 | |||
| 44ea2aee40 | |||
| 7401647d6a | |||
| fbd496e663 | |||
| e22818f51f | |||
| cd5537cc26 | |||
| 1933194d35 | |||
| aef08dcd75 | |||
| fd4c49d3d2 | |||
| c1518cb509 | |||
| 43e424d44d | |||
| 4dfd313d10 | |||
| 9e68f4cd2c | |||
| 3fe373e20c | |||
| 1f2852a369 | |||
| abe4d91622 | |||
| 0649b18952 | |||
| aee81c1533 | |||
| 451b8ea1e5 | |||
| 578cf90f85 | |||
| 869fa35353 | |||
| 4d8cfb05ee | |||
| b9d9463cc9 | |||
| 2c01caa7be | |||
| 65e925ec22 | |||
| 1144956c99 | |||
| cf586dcd75 | |||
| 94008f5a53 | |||
| 6c5dd4a120 | |||
| e87490aad8 | |||
| cb55cec3f0 | |||
| 8bfec9ec7e | |||
| bf410b2258 | |||
| 6eaab67081 | |||
| d1ff4b0ede | |||
| 5bc4dc297d | |||
| 79f8a5e87c | |||
| 5c0eec9c83 | |||
| 42f6dab4ce | |||
| 7bcb6a320e | |||
| 771acbea35 | |||
| 8520bbcf85 | |||
| 253838bba9 | |||
| 0f2a26b744 | |||
| 53db712015 | |||
| 6f2fc808cd | |||
| 6b2fdf5400 | |||
| b2fa393673 | |||
| 5292d13ae6 | |||
| bfa3a2948d | |||
| 2340a58e8f | |||
| 6d696d94d8 | |||
| 57360e5fea | |||
| 5c8d6ee901 | |||
| 7850eda22e | |||
| 38bda84426 | |||
| 954267c830 | |||
| 0dc5437ddd | |||
| 36dbc16fcf | |||
| d20cc4c45e | |||
| 8b9e376609 | |||
| bc9395029b | |||
| 6a2af9ffe4 | |||
| 9005656062 | |||
| 965dc73351 | |||
| 5dc31fac5b | |||
| 4254382e7f | |||
| 9c0a8266ab | |||
| 407c8204aa | |||
| e218aaaed2 | |||
| d07a21fdaa | |||
| e8b69e133e | |||
| b02d2a7f8d | |||
| b9e3c22a1e | |||
| 80ab030c4a | |||
| 5483919dd3 | |||
| b21daf47a7 | |||
| 917ec1091a | |||
| 30bb9f4fcc | |||
| 626da4c8bb | |||
| 813462744b | |||
| 970b648145 | |||
| b9fce4527a | |||
| 597b157f83 | |||
| 4f82ae38cf | |||
| 74e4012fee | |||
| 74d18be94a | |||
| 56788af48b | |||
| e618b3d0aa | |||
| 9f9cfbd581 | |||
| c2e5f3ac2f | |||
| 9ccf4f6083 | |||
| eb3fb9ec1c | |||
| 69f0f8d8bf | |||
| af7a73ec42 | |||
| c0b68e7da5 | |||
| 050c88ca55 | |||
| cc4f5b9ff5 | |||
| 1645034f6e | |||
| b5e9f98fd1 |
+6
-4
@@ -49,6 +49,7 @@ module.exports = function (grunt) {
|
||||
'client/lib/bull.js',
|
||||
'client/lib/marked.min.js',
|
||||
'client/lib/autobahn.js',
|
||||
'client/lib/gridstack.all.js',
|
||||
|
||||
'client/src/namespace.js',
|
||||
'client/src/exceptions.js',
|
||||
@@ -211,6 +212,7 @@ module.exports = function (grunt) {
|
||||
'daemon.php',
|
||||
'rebuild.php',
|
||||
'clear_cache.php',
|
||||
'preload.php',
|
||||
'upgrade.php',
|
||||
'extension.php',
|
||||
'websocket.php',
|
||||
@@ -288,8 +290,8 @@ module.exports = function (grunt) {
|
||||
},
|
||||
files: [
|
||||
{
|
||||
src: 'build/tmp/application/Espo/Core/defaults/config.php',
|
||||
dest: 'build/tmp/application/Espo/Core/defaults/config.php'
|
||||
src: 'build/tmp/application/Espo/Resources/defaults/config.php',
|
||||
dest: 'build/tmp/application/Espo/Resources/defaults/config.php'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -313,11 +315,11 @@ module.exports = function (grunt) {
|
||||
});
|
||||
|
||||
grunt.registerTask("unit-tests-run", function() {
|
||||
cp.execSync("vendor/bin/phpunit --bootstrap=./vendor/autoload.php tests/unit", {stdio: 'inherit'});
|
||||
cp.execSync("vendor/bin/phpunit --bootstrap=./vendor/autoload.php ./tests/unit", {stdio: 'inherit'});
|
||||
});
|
||||
|
||||
grunt.registerTask("integration-tests-run", function() {
|
||||
cp.execSync("vendor/bin/phpunit --bootstrap=./vendor/autoload.php tests/integration", {stdio: 'inherit'});
|
||||
cp.execSync("vendor/bin/phpunit --bootstrap=./vendor/autoload.php ./tests/integration", {stdio: 'inherit'});
|
||||
});
|
||||
|
||||
grunt.registerTask("zip", function() {
|
||||
|
||||
+7
-3
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
@@ -29,5 +29,9 @@
|
||||
|
||||
require_once('../../bootstrap.php');
|
||||
|
||||
$app = new \Espo\Core\Application();
|
||||
$app->run();
|
||||
use Espo\Core\{
|
||||
Application,
|
||||
ApplicationRunners\Api,
|
||||
};
|
||||
|
||||
(new Application())->run(Api::class);
|
||||
|
||||
@@ -29,11 +29,15 @@
|
||||
|
||||
require_once('../../../bootstrap.php');
|
||||
|
||||
use Espo\Core\{
|
||||
Portal\Application,
|
||||
Portal\ApplicationRunners\Api,
|
||||
};
|
||||
|
||||
if (!empty($_GET['portalId'])) {
|
||||
$portalId = $_GET['portalId'];
|
||||
} else {
|
||||
$portalId = explode('/', $_SERVER['REQUEST_URI'])[count(explode('/', $_SERVER['SCRIPT_NAME'])) - 1];
|
||||
}
|
||||
|
||||
$app = new \Espo\Core\Portal\Application($portalId);
|
||||
$app->run();
|
||||
(new Application($portalId))->run(Api::class);
|
||||
|
||||
@@ -29,14 +29,13 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class ActionHistoryRecord extends \Espo\Core\Acl\Base
|
||||
class ActionHistoryRecord extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
{
|
||||
return $entity->get('userId') === $user->id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Attachment extends \Espo\Core\Acl\Base
|
||||
class Attachment extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
@@ -90,4 +90,3 @@ class Attachment extends \Espo\Core\Acl\Base
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Email extends \Espo\Core\Acl\Base
|
||||
class Email extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
protected $ownerUserIdAttribute = 'usersIds';
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class EmailAddress extends \Espo\Core\Acl\Base
|
||||
class EmailAddress extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkEditInEntity(EntityUser $user, Entity $entity, Entity $excludeEntity)
|
||||
{
|
||||
@@ -62,4 +62,3 @@ class EmailAddress extends \Espo\Core\Acl\Base
|
||||
return !$isFobidden;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class EmailFilter extends \Espo\Core\Acl\Base
|
||||
class EmailFilter extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
{
|
||||
@@ -53,4 +53,3 @@ class EmailFilter extends \Espo\Core\Acl\Base
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,12 +29,11 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Import extends \Espo\Core\Acl\Base
|
||||
class Import extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
|
||||
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
if ($user->isAdmin()) return true;
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Note extends \Espo\Core\Acl\Base
|
||||
class Note extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
protected $deleteThresholdPeriod = '1 month';
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Notification extends \Espo\Core\Acl\Base
|
||||
class Notification extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
{
|
||||
@@ -42,4 +42,3 @@ class Notification extends \Espo\Core\Acl\Base
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class PhoneNumber extends \Espo\Core\Acl\Base
|
||||
class PhoneNumber extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkEditInEntity(EntityUser $user, Entity $entity, Entity $excludeEntity)
|
||||
{
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class ScheduledJob extends \Espo\Core\Acl\Base
|
||||
class ScheduledJob extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkEntityRead(EntityUser $user, Entity $entity, $data)
|
||||
{
|
||||
@@ -58,4 +58,3 @@ class ScheduledJob extends \Espo\Core\Acl\Base
|
||||
return $this->checkEntity($user, $entity, $data, 'create');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,13 +29,15 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Team extends \Espo\Core\Acl\Base
|
||||
use Espo\Entities\User as UserEntity;
|
||||
|
||||
class Team extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkInTeam(\Espo\Entities\User $user, Entity $entity)
|
||||
public function checkInTeam(UserEntity $user, Entity $entity)
|
||||
{
|
||||
$userTeamIdList = $user->getLinkMultipleIdList('teams');
|
||||
return in_array($entity->id, $userTeamIdList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\ORM\Entity;
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
|
||||
class User extends \Espo\Core\Acl\Base
|
||||
class User extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkIsOwner(\Espo\Entities\User $user, Entity $entity)
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
{
|
||||
return $user->id === $entity->id;
|
||||
}
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
namespace Espo\Acl;
|
||||
|
||||
use \Espo\Entities\User as EntityUser;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User as EntityUser;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Webhook extends \Espo\Core\Acl\Base
|
||||
class Webhook extends \Espo\Core\Acl\Acl
|
||||
{
|
||||
public function checkIsOwner(EntityUser $user, Entity $entity)
|
||||
{
|
||||
|
||||
+22
-9
@@ -27,31 +27,44 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\AppParams;
|
||||
namespace Espo\Classes\AppParams;
|
||||
|
||||
class TemplateEntityTypeList extends \Espo\Core\Injectable
|
||||
use Espo\Core\{
|
||||
Acl,
|
||||
Select\SelectManagerFactory,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a list of entity types for which a PDF template exists.
|
||||
*/
|
||||
class TemplateEntityTypeList
|
||||
{
|
||||
protected function init()
|
||||
protected $acl;
|
||||
protected $selectManagerFactory;
|
||||
protected $entityManager;
|
||||
|
||||
public function __construct(Acl $acl, SelectManagerFactory $selectManagerFactory, EntityManager $entityManager)
|
||||
{
|
||||
$this->addDependency('acl');
|
||||
$this->addDependency('selectManagerFactory');
|
||||
$this->addDependency('entityManager');
|
||||
$this->acl = $acl;
|
||||
$this->selectManagerFactory = $selectManagerFactory;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function get()
|
||||
{
|
||||
if (!$this->getInjection('acl')->checkScope('Template')) {
|
||||
if (!$this->acl->checkScope('Template')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
|
||||
$selectManager = $this->getInjection('selectManagerFactory')->create('Template');
|
||||
$selectManager = $this->selectManagerFactory->create('Template');
|
||||
|
||||
$selectParams = $selectManager->getEmptySelectParams();
|
||||
$selectManager->applyAccess($selectParams);
|
||||
|
||||
$templateList = $this->getInjection('entityManager')->getRepository('Template')
|
||||
$templateList = $this->entityManager->getRepository('Template')
|
||||
->select(['entityType'])
|
||||
->groupBy(['entityType'])
|
||||
->find($selectParams);
|
||||
+23
-21
@@ -27,42 +27,44 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Authentication;
|
||||
namespace Espo\Classes\Cleanup;
|
||||
|
||||
use \Espo\Core\Utils\Config;
|
||||
use \Espo\Core\ORM\EntityManager;
|
||||
use \Espo\Core\Utils\Auth;
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
abstract class Base
|
||||
use DateTime;
|
||||
|
||||
class Reminders
|
||||
{
|
||||
protected $config;
|
||||
|
||||
protected $entityManager;
|
||||
|
||||
private $passwordHash;
|
||||
|
||||
public function __construct(Config $config, EntityManager $entityManager)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
protected $cleanupRemindersPeriod = '15 days';
|
||||
|
||||
protected function getEntityManager()
|
||||
public function process()
|
||||
{
|
||||
return $this->entityManager;
|
||||
}
|
||||
$period = '-' . $this->config->get('cleanupRemindersPeriod', $this->cleanupRemindersPeriod);
|
||||
|
||||
protected function getPasswordHash()
|
||||
{
|
||||
if (!isset($this->passwordHash)) {
|
||||
$this->passwordHash = new \Espo\Core\Utils\PasswordHash($this->config);
|
||||
}
|
||||
$dt = new DateTime();
|
||||
|
||||
return $this->passwordHash;
|
||||
$dt->modify($period);
|
||||
|
||||
$delete = $this->entityManager->getQueryBuilder()
|
||||
->delete()
|
||||
->from('Reminder')
|
||||
->where([
|
||||
'remindAt<' => $dt->format('Y-m-d'),
|
||||
])
|
||||
->build();
|
||||
|
||||
$this->entityManager->getQueryExecutor()->execute($delete);
|
||||
}
|
||||
}
|
||||
+47
-17
@@ -27,33 +27,63 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Cleanup;
|
||||
namespace Espo\Classes\Cleanup;
|
||||
|
||||
class WebhookQueue extends Base
|
||||
use Espo\Core\{
|
||||
Utils\Config,
|
||||
ORM\EntityManager,
|
||||
};
|
||||
|
||||
use DateTime;
|
||||
|
||||
class WebhookQueue
|
||||
{
|
||||
protected $cleanupWebhookQueuePeriod = '10 days';
|
||||
|
||||
protected $config;
|
||||
protected $entityManager;
|
||||
|
||||
public function __construct(Config $config, EntityManager $entityManager)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function process()
|
||||
{
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
$period = '-' . $this->config->get('cleanupWebhookQueuePeriod', $this->cleanupWebhookQueuePeriod);
|
||||
|
||||
$datetime = new DateTime();
|
||||
|
||||
$period = '-' . $this->getConfig()->get('cleanupWebhookQueuePeriod', $this->cleanupWebhookQueuePeriod);
|
||||
$datetime = new \DateTime();
|
||||
$datetime->modify($period);
|
||||
$from = $datetime->format('Y-m-d H:i:s');
|
||||
|
||||
$query = "
|
||||
DELETE FROM `webhook_queue_item`
|
||||
WHERE
|
||||
DATE(created_at) < ".$pdo->quote($from)." AND
|
||||
(status <> 'Pending' OR deleted = 1)
|
||||
";
|
||||
$pdo->query($query);
|
||||
$query = $this->entityManager->getQueryBuilder()
|
||||
->delete()
|
||||
->from('WebhookQueueItem')
|
||||
->where([
|
||||
'DATE:(createdAt)<' => $from,
|
||||
'OR' => [
|
||||
'status!=' => 'Pending',
|
||||
'deleted' => true,
|
||||
],
|
||||
])
|
||||
->build();
|
||||
|
||||
$query = "
|
||||
DELETE FROM `webhook_event_queue_item`
|
||||
WHERE DATE(created_at) < ".$pdo->quote($from)." AND (is_processed = 1 OR deleted = 1)
|
||||
";
|
||||
$pdo->query($query);
|
||||
$this->entityManager->getQueryExecutor()->execute($query);
|
||||
|
||||
$query = $this->entityManager->getQueryBuilder()
|
||||
->delete()
|
||||
->from('WebhookEventQueueItem')
|
||||
->where([
|
||||
'DATE:(createdAt)<' => $from,
|
||||
'OR' => [
|
||||
'isProcessed' => true,
|
||||
'deleted' => true,
|
||||
],
|
||||
])
|
||||
->build();
|
||||
|
||||
$this->entityManager->getQueryExecutor()->execute($query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Classes\ConsoleCommands;
|
||||
|
||||
use Espo\Core\{
|
||||
ServiceFactory,
|
||||
Console\Commands\Command,
|
||||
};
|
||||
|
||||
use Throwable;
|
||||
|
||||
class Import implements Command
|
||||
{
|
||||
protected $serviceFactory;
|
||||
|
||||
public function __construct(ServiceFactory $serviceFactory)
|
||||
{
|
||||
$this->serviceFactory = $serviceFactory;
|
||||
}
|
||||
|
||||
public function run(array $options, array $flagList)
|
||||
{
|
||||
$id = $options['id'] ?? null;
|
||||
$filePath = $options['file'] ?? null;
|
||||
$paramsId = $options['paramsId'] ?? null;
|
||||
|
||||
$service = $this->serviceFactory->create('Import');
|
||||
|
||||
$forceResume = in_array('resume', $flagList);
|
||||
$revert = in_array('revert', $flagList);
|
||||
|
||||
if (!$id && $filePath) {
|
||||
if (!$paramsId) {
|
||||
$this->out("You need to specify --params-id option.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file_exists($filePath)) {
|
||||
$this->out("File not found.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$contents = file_get_contents($filePath);
|
||||
|
||||
try {
|
||||
$result = $service->importFileWithParamsId($contents, $paramsId);
|
||||
|
||||
$resultId = $result->id;
|
||||
$countCreated = $result->countCreated;
|
||||
$countUpdated = $result->countUpdated;
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
$this->out("Error occured: ".$e->getMessage()."\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->out("Finished. Import ID: {$resultId}. Created: {$countCreated}. Updated: {$countUpdated}.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($id && $revert) {
|
||||
$this->out("Reverting import...\n");
|
||||
|
||||
try {
|
||||
$service->revert($id);
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
$this->out("Error occured: " . $e->getMessage() . "\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->out("Finished.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
$this->out("Running import, this may take a while...\n");
|
||||
|
||||
try {
|
||||
$result = $service->importById($id, true, $forceResume);
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
$this->out("Error occured: " . $e->getMessage() . "\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$countCreated = $result->countCreated;
|
||||
$countUpdated = $result->countUpdated;
|
||||
|
||||
$this->out("Finished. Created: {$countCreated}. Updated: {$countUpdated}.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->out("Not enough params passed.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
protected function out($string)
|
||||
{
|
||||
fwrite(\STDOUT, $string);
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -27,13 +27,15 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Layout\Defaults;
|
||||
namespace Espo\Classes\DefaultLayouts;
|
||||
|
||||
use Espo\Core\Utils\Metadata;
|
||||
|
||||
class DefaultSidePanelType
|
||||
{
|
||||
protected $metadata;
|
||||
|
||||
public function __construct(\Espo\Core\Utils\Metadata $metadata)
|
||||
public function __construct(Metadata $metadata)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
class ArrayIntType extends ArrayType
|
||||
{
|
||||
+7
-5
@@ -27,16 +27,18 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class ArrayType extends BaseType
|
||||
{
|
||||
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
return $this->isNotEmpty($entity, $field);
|
||||
}
|
||||
|
||||
public function checkMaxCount(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkMaxCount(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
if (!$this->isNotEmpty($entity, $field)) return true;
|
||||
$list = $entity->get($field);
|
||||
@@ -44,7 +46,7 @@ class ArrayType extends BaseType
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkArray(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkArray(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
if (isset($data->$field) && $data->$field !== null && !is_array($data->$field)) {
|
||||
return false;
|
||||
@@ -53,7 +55,7 @@ class ArrayType extends BaseType
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isNotEmpty(\Espo\ORM\Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
{
|
||||
if (!$entity->has($field) || $entity->get($field) === null) return false;
|
||||
$list = $entity->get($field);
|
||||
+13
-13
@@ -27,33 +27,33 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Metadata,
|
||||
Utils\FieldUtil,
|
||||
};
|
||||
|
||||
class BaseType
|
||||
{
|
||||
private $metadata;
|
||||
private $fieldManagerUtil;
|
||||
protected $metadata;
|
||||
protected $fieldUtil;
|
||||
|
||||
public function __construct(\Espo\Core\Utils\Metadata $metadata, \Espo\Core\Utils\FieldManagerUtil $fieldManagerUtil)
|
||||
public function __construct(Metadata $metadata, FieldUtil $fieldUtil)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
$this->fieldManagerUtil = $fieldManagerUtil;
|
||||
$this->fieldUtil = $fieldUtil;
|
||||
}
|
||||
|
||||
protected function getActualAttributeList(Entity $entity, string $field) : array
|
||||
{
|
||||
return $this->getFieldManagerUtil()->getActualAttributeList($entity->getEntityType(), $field);
|
||||
return $this->fieldUtil->getActualAttributeList($entity->getEntityType(), $field);
|
||||
}
|
||||
|
||||
protected function getMetadata() : \Espo\Core\Utils\Metadata
|
||||
protected function getMetadata() : Metadata
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
protected function getFieldManagerUtil() : \Espo\Core\Utils\FieldManagerUtil
|
||||
{
|
||||
return $this->fieldManagerUtil;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
class ChecklistType extends ArrayType
|
||||
{
|
||||
+4
-2
@@ -27,11 +27,13 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class CurrencyType extends FloatType
|
||||
{
|
||||
protected function isNotEmpty(\Espo\ORM\Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
{
|
||||
return
|
||||
$entity->has($field) && $entity->get($field) !== null &&
|
||||
+5
-3
@@ -27,16 +27,18 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class DateType extends BaseType
|
||||
{
|
||||
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
return $this->isNotEmpty($entity, $field);
|
||||
}
|
||||
|
||||
protected function isNotEmpty(\Espo\ORM\Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== null;
|
||||
}
|
||||
+5
-3
@@ -27,16 +27,18 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class DatetimeOptionalType extends DatetimeType
|
||||
{
|
||||
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
return $this->isNotEmpty($entity, $field);
|
||||
}
|
||||
|
||||
protected function isNotEmpty(\Espo\ORM\Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
{
|
||||
if ($entity->has($field) && $entity->get($field) !== null) return true;
|
||||
if ($entity->has($field . 'Date') && $entity->get($field . 'Date') !== null) return true;
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
class DatetimeType extends DateType
|
||||
{
|
||||
+6
-4
@@ -27,11 +27,13 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class EmailType extends BaseType
|
||||
{
|
||||
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
if ($this->isNotEmpty($entity, $field)) return true;
|
||||
|
||||
@@ -45,7 +47,7 @@ class EmailType extends BaseType
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkEmailAddress(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkEmailAddress(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
if ($this->isNotEmpty($entity, $field)) {
|
||||
$address = $entity->get($field);
|
||||
@@ -68,7 +70,7 @@ class EmailType extends BaseType
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isNotEmpty(\Espo\ORM\Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== '' && $entity->get($field) !== null;
|
||||
}
|
||||
+5
-3
@@ -27,16 +27,18 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class EnumType extends BaseType
|
||||
{
|
||||
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
return $this->isNotEmpty($entity, $field);
|
||||
}
|
||||
|
||||
protected function isNotEmpty(\Espo\ORM\Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== null;
|
||||
}
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
class FileType extends LinkType
|
||||
{
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
class FloatType extends IntType
|
||||
{
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
class ImageType extends FileType
|
||||
{
|
||||
+7
-5
@@ -27,30 +27,32 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class IntType extends BaseType
|
||||
{
|
||||
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
return $this->isNotEmpty($entity, $field);
|
||||
}
|
||||
|
||||
public function checkMax(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkMax(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
if (!$this->isNotEmpty($entity, $field)) return true;
|
||||
if ($entity->get($field) > $validationValue) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkMin(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkMin(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
if (!$this->isNotEmpty($entity, $field)) return true;
|
||||
if ($entity->get($field) < $validationValue) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isNotEmpty(\Espo\ORM\Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== null;
|
||||
}
|
||||
+5
-3
@@ -27,18 +27,20 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class JsonArrayType extends BaseType
|
||||
{
|
||||
public function checkArray(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkArray(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
if (!$entity->has($field) || $entity->get($field) === null) return true;
|
||||
|
||||
return is_array($entity->get($field));
|
||||
}
|
||||
|
||||
protected function isNotEmpty(\Espo\ORM\Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
{
|
||||
if (!$entity->has($field) || $entity->get($field) === null) return false;
|
||||
$list = $entity->get($field);
|
||||
+4
-2
@@ -27,11 +27,13 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class LinkMultipleType extends BaseType
|
||||
{
|
||||
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
return count($entity->getLinkMultipleIdList($field)) > 0;
|
||||
}
|
||||
+4
-2
@@ -27,11 +27,13 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class LinkParentType extends BaseType
|
||||
{
|
||||
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
$idAttribute = $field . 'Id';
|
||||
$typeAttribute = $field . 'Type';
|
||||
+4
-2
@@ -27,11 +27,13 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class LinkType extends BaseType
|
||||
{
|
||||
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
$idAttribute = $field . 'Id';
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
class MultiEnumType extends ArrayType
|
||||
{
|
||||
+4
-2
@@ -27,11 +27,13 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class PersonNameType extends BaseType
|
||||
{
|
||||
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
$isEmpty = true;
|
||||
foreach ($this->getActualAttributeList($entity, $field) as $attribute) {
|
||||
+5
-3
@@ -27,11 +27,13 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class PhoneType extends BaseType
|
||||
{
|
||||
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
if ($this->isNotEmpty($entity, $field)) return true;
|
||||
|
||||
@@ -45,7 +47,7 @@ class PhoneType extends BaseType
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isNotEmpty(\Espo\ORM\Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== '' && $entity->get($field) !== null;
|
||||
}
|
||||
+6
-4
@@ -27,16 +27,18 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\FieldValidators;
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class VarcharType extends BaseType
|
||||
{
|
||||
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkRequired(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
return $this->isNotEmpty($entity, $field);
|
||||
}
|
||||
|
||||
public function checkMaxLength(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
|
||||
public function checkMaxLength(Entity $entity, string $field, $validationValue, $data) : bool
|
||||
{
|
||||
if ($this->isNotEmpty($entity, $field)) {
|
||||
$value = $entity->get($field);
|
||||
@@ -47,7 +49,7 @@ class VarcharType extends BaseType
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isNotEmpty(\Espo\ORM\Entity $entity, $field)
|
||||
protected function isNotEmpty(Entity $entity, $field)
|
||||
{
|
||||
return $entity->has($field) && $entity->get($field) !== '' && $entity->get($field) !== null;
|
||||
}
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\TemplateHelpers;
|
||||
namespace Espo\Classes\TemplateHelpers;
|
||||
|
||||
class GoogleMaps
|
||||
{
|
||||
@@ -29,10 +29,12 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
use Espo\Core\UpgradeManager;
|
||||
use Espo\Core\Utils\AdminNotificationManager;
|
||||
use Espo\Core\Utils\SystemRequirements;
|
||||
|
||||
class Admin extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
@@ -48,15 +50,17 @@ class Admin extends \Espo\Core\Controllers\Base
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$result = $this->getContainer()->get('dataManager')->rebuild();
|
||||
|
||||
return $result;
|
||||
$this->getContainer()->get('dataManager')->rebuild();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function postActionClearCache($params)
|
||||
{
|
||||
$result = $this->getContainer()->get('dataManager')->clearCache();
|
||||
return $result;
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function actionJobs()
|
||||
@@ -73,15 +77,16 @@ class Admin extends \Espo\Core\Controllers\Base
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
$upgradeManager = new \Espo\Core\UpgradeManager($this->getContainer());
|
||||
|
||||
$upgradeManager = new UpgradeManager($this->getContainer());
|
||||
|
||||
$upgradeId = $upgradeManager->upload($data);
|
||||
$manifest = $upgradeManager->getManifest();
|
||||
|
||||
return array(
|
||||
return [
|
||||
'id' => $upgradeId,
|
||||
'version' => $manifest['version'],
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
public function postActionRunUpgrade($params, $data)
|
||||
@@ -92,7 +97,7 @@ class Admin extends \Espo\Core\Controllers\Base
|
||||
}
|
||||
}
|
||||
|
||||
$upgradeManager = new \Espo\Core\UpgradeManager($this->getContainer());
|
||||
$upgradeManager = new UpgradeManager($this->getContainer());
|
||||
$upgradeManager->install(get_object_vars($data));
|
||||
|
||||
return true;
|
||||
@@ -105,13 +110,15 @@ class Admin extends \Espo\Core\Controllers\Base
|
||||
|
||||
public function actionAdminNotificationList($params)
|
||||
{
|
||||
$adminNotificationManager = new \Espo\Core\Utils\AdminNotificationManager($this->getContainer());
|
||||
$adminNotificationManager = new AdminNotificationManager($this->getContainer());
|
||||
|
||||
return $adminNotificationManager->getNotificationList();
|
||||
}
|
||||
|
||||
public function actionSystemRequirementList($params)
|
||||
{
|
||||
$systemRequirementManager = new \Espo\Core\Utils\SystemRequirements($this->getContainer());
|
||||
$systemRequirementManager = new SystemRequirements($this->getContainer());
|
||||
|
||||
return $systemRequirementManager->getAllRequiredList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
class ApiIndex {
|
||||
|
||||
public function getActionIndex()
|
||||
{
|
||||
return "EspoCRM REST API";
|
||||
}
|
||||
}
|
||||
@@ -29,22 +29,33 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class App extends \Espo\Core\Controllers\Base
|
||||
use Espo\Core\Authentication\Authentication;
|
||||
use Espo\Core\Di;
|
||||
use Espo\Core\Api\Request;
|
||||
|
||||
use StdClass;
|
||||
|
||||
class App implements
|
||||
|
||||
Di\ServiceFactoryAware,
|
||||
Di\InjectableFactoryAware
|
||||
{
|
||||
use Di\ServiceFactorySetter;
|
||||
use Di\InjectableFactorySetter;
|
||||
|
||||
public function actionUser()
|
||||
{
|
||||
return $this->getServiceFactory()->create('App')->getUserData();
|
||||
return $this->serviceFactory->create('App')->getUserData();
|
||||
}
|
||||
|
||||
public function postActionDestroyAuthToken($params, $data)
|
||||
public function postActionDestroyAuthToken(array $params, StdClass $data, Request $request)
|
||||
{
|
||||
if (empty($data->token)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$auth = new \Espo\Core\Utils\Auth($this->getContainer());
|
||||
return $auth->destroyAuthToken($data->token);
|
||||
$auth = $this->injectableFactory->create(Authentication::class);
|
||||
return $auth->destroyAuthToken($data->token, $request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class Attachment extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
@@ -66,10 +66,10 @@ class Attachment extends \Espo\Core\Controllers\Record
|
||||
|
||||
$fileData = $this->getRecordService()->getFileData($id);
|
||||
|
||||
$response->headers->set('Content-Type', $fileData->type);
|
||||
$response->headers->set('Content-Disposition', 'Content-Disposition: attachment; filename="'.$fileData->name.'"');
|
||||
$response->setHeader('Content-Type', $fileData->type);
|
||||
$response->setHeader('Content-Disposition', 'Content-Disposition: attachment; filename="'.$fileData->name.'"');
|
||||
if ($fileData->size) {
|
||||
$response->headers->set('Content-Length', $fileData->size);
|
||||
$response->setHeader('Content-Length', $fileData->size);
|
||||
}
|
||||
|
||||
return $fileData->contents;
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class AuthLogRecord extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class AuthToken extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
@@ -29,31 +29,34 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\{
|
||||
Forbidden,
|
||||
BadRequest,
|
||||
};
|
||||
|
||||
class CurrencyRate extends \Espo\Core\Controllers\Base
|
||||
use Espo\Core\{
|
||||
ServiceFactory,
|
||||
Api\Request,
|
||||
};
|
||||
|
||||
class CurrencyRate
|
||||
{
|
||||
protected function checkControllerAccess()
|
||||
protected $serviceFactory;
|
||||
|
||||
public function __construct(ServiceFactory $serviceFactory)
|
||||
{
|
||||
if (!$this->getAcl()->check('Currency')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
$this->serviceFactory = $serviceFactory;
|
||||
}
|
||||
|
||||
public function getActionIndex()
|
||||
public function getActionIndex(Request $request)
|
||||
{
|
||||
if ($this->getAcl()->getLevel('Currency', 'read') !== 'yes') throw new Forbidden();
|
||||
|
||||
return $this->getService('CurrencyRate')->get();
|
||||
return $this->serviceFactory->create('CurrencyRate')->get();
|
||||
}
|
||||
|
||||
public function putActionUpdate($params, $data)
|
||||
public function putActionUpdate(Request $request)
|
||||
{
|
||||
if ($this->getAcl()->getLevel('Currency', 'edit') !== 'yes') throw new Forbidden();
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (empty($data) || !is_object($data)) throw new BadRequest();
|
||||
|
||||
return $this->getService('CurrencyRate')->set($data);
|
||||
return $this->serviceFactory->create('CurrencyRate')->set($data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class DashboardTemplate extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
@@ -29,27 +29,33 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class DataPrivacy extends \Espo\Core\Controllers\Base
|
||||
use Espo\Core\ServiceFactory;
|
||||
use Espo\Core\Acl;
|
||||
|
||||
class DataPrivacy
|
||||
{
|
||||
protected function checkControllerAccess()
|
||||
protected $serviceFactory;
|
||||
protected $acl;
|
||||
|
||||
public function __construct(ServiceFactory $serviceFactory, Acl $acl)
|
||||
{
|
||||
if ($this->getAcl()->get('dataPrivacyPermission') === 'no') {
|
||||
$this->serviceFactory = $serviceFactory;
|
||||
$this->acl = $acl;
|
||||
|
||||
if ($this->acl->get('dataPrivacyPermission') === 'no') {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
public function postActionErase($params, $data)
|
||||
public function postActionErase($params, \StdClass $data)
|
||||
{
|
||||
if (empty($data->entityType) || empty($data->id) || empty($data->fieldList) || !is_array($data->fieldList)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
return $this->getServiceFactory()->create('DataPrivacy')->erase($data->entityType, $data->id, $data->fieldList);
|
||||
return $this->serviceFactory->create('DataPrivacy')->erase($data->entityType, $data->id, $data->fieldList);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,10 +29,9 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
|
||||
class Email extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
@@ -230,4 +229,15 @@ class Email extends \Espo\Core\Controllers\Record
|
||||
}
|
||||
return $this->getRecordService()->moveToFolderByIdList($idList, $data->folderId);
|
||||
}
|
||||
|
||||
public function getActionGetInsertFieldData($params, $data, $request)
|
||||
{
|
||||
if (!$this->getAcl()->checkScope('Email', 'create')) throw new Forbidden();
|
||||
|
||||
return $this->getServiceFactory()->create('EmailTemplate')->getInsertFieldData([
|
||||
'parentId' => $request->get('parentId'),
|
||||
'parentType' => $request->get('parentType'),
|
||||
'to' => $request->get('to'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
class EmailAccount extends \Espo\Core\Controllers\Record
|
||||
@@ -40,7 +39,7 @@ class EmailAccount extends \Espo\Core\Controllers\Record
|
||||
return $this->getRecordService()->getFolders([
|
||||
'host' => $data->host ?? null,
|
||||
'port' => $data->port ?? null,
|
||||
'ssl' => $data->ssl ?? false,
|
||||
'security' => $data->security ?? null,
|
||||
'username' => $data->username ?? null,
|
||||
'password' => $data->password ?? null,
|
||||
'id' => $data->id ?? null,
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class EmailAddress extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
@@ -33,4 +33,3 @@ class EmailFilter extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class EmailFolder extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
class EmailTemplate extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
@@ -49,6 +49,4 @@ class EmailTemplate extends \Espo\Core\Controllers\Record
|
||||
'relatedId' => $request->get('relatedId')
|
||||
), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -29,26 +29,49 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use Espo\{
|
||||
Entities\User,
|
||||
Tools\EntityManager\EntityManager as EntityManagerTool,
|
||||
};
|
||||
|
||||
class EntityManager extends \Espo\Core\Controllers\Base
|
||||
use Espo\Core\{
|
||||
Exceptions\Error,
|
||||
Exceptions\Forbidden,
|
||||
Exceptions\BadRequest,
|
||||
Api\Request,
|
||||
DataManager,
|
||||
Utils\Config,
|
||||
};
|
||||
|
||||
class EntityManager
|
||||
{
|
||||
protected $user;
|
||||
protected $dataManager;
|
||||
protected $config;
|
||||
protected $entityManagerTool;
|
||||
|
||||
public function __construct(User $user, DataManager $dataManager, Config $config, EntityManagerTool $entityManagerTool)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->dataManager = $dataManager;
|
||||
$this->config = $config;
|
||||
$this->entityManagerTool = $entityManagerTool;
|
||||
|
||||
$this->checkControllerAccess();
|
||||
}
|
||||
|
||||
protected function checkControllerAccess()
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
public function actionCreateEntity($params, $data, $request)
|
||||
public function postActionCreateEntity(Request $request)
|
||||
{
|
||||
$data = get_object_vars($data);
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$data = get_object_vars($data);
|
||||
|
||||
if (empty($data['name']) || empty($data['type'])) {
|
||||
throw new BadRequest();
|
||||
@@ -101,18 +124,18 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
$params['kanbanStatusIgnoreList'] = $data['kanbanStatusIgnoreList'];
|
||||
}
|
||||
|
||||
$result = $this->getContainer()->get('entityManagerUtil')->create($name, $type, $params);
|
||||
$result = $this->entityManagerTool->create($name, $type, $params);
|
||||
|
||||
if ($result) {
|
||||
$tabList = $this->getConfig()->get('tabList', []);
|
||||
$tabList = $this->config->get('tabList', []);
|
||||
|
||||
if (!in_array($name, $tabList)) {
|
||||
$tabList[] = $name;
|
||||
$this->getConfig()->set('tabList', $tabList);
|
||||
$this->getConfig()->save();
|
||||
$this->config->set('tabList', $tabList);
|
||||
$this->config->save();
|
||||
}
|
||||
|
||||
$this->getContainer()->get('dataManager')->rebuild();
|
||||
$this->dataManager->rebuild();
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
@@ -120,23 +143,23 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
return true;
|
||||
}
|
||||
|
||||
public function actionUpdateEntity($params, $data, $request)
|
||||
public function postActionUpdateEntity(Request $request)
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$data = get_object_vars($data);
|
||||
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
if (empty($data['name'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$name = $data['name'];
|
||||
$name = filter_var($name, \FILTER_SANITIZE_STRING);
|
||||
|
||||
$result = $this->getContainer()->get('entityManagerUtil')->update($name, $data);
|
||||
$result = $this->entityManagerTool->update($name, $data);
|
||||
|
||||
if ($result) {
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
$this->dataManager->clearCache();
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
@@ -144,32 +167,31 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
return true;
|
||||
}
|
||||
|
||||
public function actionRemoveEntity($params, $data, $request)
|
||||
public function postActionRemoveEntity(Request $request)
|
||||
{
|
||||
$data = get_object_vars($data);
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$data = get_object_vars($data);
|
||||
|
||||
if (empty($data['name'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$name = $data['name'];
|
||||
$name = filter_var($name, \FILTER_SANITIZE_STRING);
|
||||
|
||||
$result = $this->getContainer()->get('entityManagerUtil')->delete($name);
|
||||
$result = $this->entityManagerTool->delete($name);
|
||||
|
||||
if ($result) {
|
||||
$tabList = $this->getConfig()->get('tabList', []);
|
||||
$tabList = $this->config->get('tabList', []);
|
||||
if (($key = array_search($name, $tabList)) !== false) {
|
||||
unset($tabList[$key]);
|
||||
$tabList = array_values($tabList);
|
||||
}
|
||||
$this->getConfig()->set('tabList', $tabList);
|
||||
$this->getConfig()->save();
|
||||
$this->config->set('tabList', $tabList);
|
||||
$this->config->save();
|
||||
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
$this->dataManager->clearCache();
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
@@ -177,13 +199,11 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
return true;
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data, $request)
|
||||
public function postActionCreateLink(Request $request)
|
||||
{
|
||||
$data = get_object_vars($data);
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$data = get_object_vars($data);
|
||||
|
||||
$paramList = [
|
||||
'entity',
|
||||
@@ -234,10 +254,10 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
$params['foreignLinkEntityTypeList'] = $data['foreignLinkEntityTypeList'];
|
||||
}
|
||||
|
||||
$result = $this->getContainer()->get('entityManagerUtil')->createLink($params);
|
||||
$result = $this->entityManagerTool->createLink($params);
|
||||
|
||||
if ($result) {
|
||||
$this->getContainer()->get('dataManager')->rebuild();
|
||||
$this->dataManager->rebuild();
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
@@ -245,13 +265,11 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
return true;
|
||||
}
|
||||
|
||||
public function actionUpdateLink($params, $data, $request)
|
||||
public function postActionUpdateLink(Request $request)
|
||||
{
|
||||
$data = get_object_vars($data);
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$data = get_object_vars($data);
|
||||
|
||||
$paramList = [
|
||||
'entity',
|
||||
@@ -295,10 +313,10 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
$params['foreignLinkEntityTypeList'] = $data['foreignLinkEntityTypeList'];
|
||||
}
|
||||
|
||||
$result = $this->getContainer()->get('entityManagerUtil')->updateLink($params);
|
||||
$result = $this->entityManagerTool->updateLink($params);
|
||||
|
||||
if ($result) {
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
$this->dataManager->clearCache();
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
@@ -306,27 +324,27 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
return true;
|
||||
}
|
||||
|
||||
public function actionRemoveLink($params, $data, $request)
|
||||
public function postActionRemoveLink(Request $request)
|
||||
{
|
||||
$data = get_object_vars($data);
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$data = get_object_vars($data);
|
||||
|
||||
$paramList = [
|
||||
'entity',
|
||||
'link',
|
||||
];
|
||||
$d = array();
|
||||
|
||||
$d = [];
|
||||
|
||||
foreach ($paramList as $item) {
|
||||
$d[$item] = filter_var($data[$item], \FILTER_SANITIZE_STRING);
|
||||
}
|
||||
|
||||
$result = $this->getContainer()->get('entityManagerUtil')->deleteLink($d);
|
||||
$result = $this->entityManagerTool->deleteLink($d);
|
||||
|
||||
if ($result) {
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
$this->dataManager->clearCache();
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
@@ -334,32 +352,37 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
return true;
|
||||
}
|
||||
|
||||
public function postActionFormula($params, $data, $request)
|
||||
public function postActionFormula(Request $request)
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (empty($data->scope)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
if (!property_exists($data, 'data')) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$formulaData = get_object_vars($data->data);
|
||||
|
||||
$this->getContainer()->get('entityManagerUtil')->setFormulaData($data->scope, $formulaData);
|
||||
$this->entityManagerTool->setFormulaData($data->scope, $formulaData);
|
||||
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
$this->dataManager->clearCache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function postActionResetToDefault($params, $data, $request)
|
||||
public function postActionResetToDefault(Request $request)
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (empty($data->scope)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$this->getContainer()->get('entityManagerUtil')->resetToDefaults($data->scope);
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
$this->entityManagerTool->resetToDefaults($data->scope);
|
||||
$this->dataManager->clearCache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,8 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class Extension extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class ExternalAccount extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
@@ -29,27 +29,52 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\{
|
||||
Entities\User,
|
||||
Tools\FieldManager\FieldManager as FieldManagerTool,
|
||||
};
|
||||
|
||||
class FieldManager extends \Espo\Core\Controllers\Base
|
||||
use Espo\Core\{
|
||||
Exceptions\Error,
|
||||
Exceptions\Forbidden,
|
||||
Exceptions\NotFound,
|
||||
Exceptions\BadRequest,
|
||||
Api\Request,
|
||||
DataManager,
|
||||
};
|
||||
|
||||
class FieldManager
|
||||
{
|
||||
protected $user;
|
||||
protected $dataManager;
|
||||
protected $fieldManagerTool;
|
||||
|
||||
public function __construct(User $user, DataManager $dataManager, FieldManagerTool $fieldManagerTool)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->dataManager = $dataManager;
|
||||
$this->fieldManagerTool = $fieldManagerTool;
|
||||
|
||||
$this->checkControllerAccess();
|
||||
}
|
||||
|
||||
protected function checkControllerAccess()
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
public function actionRead($params, $data)
|
||||
public function getActionRead(Request $request)
|
||||
{
|
||||
if (empty($params['scope']) || empty($params['name'])) {
|
||||
$scope = $request->getRouteParam('scope');
|
||||
$name = $request->getRouteParam('name');
|
||||
|
||||
if (!$scope || !$name) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$data = $this->getContainer()->get('fieldManager')->read($params['scope'], $params['name']);
|
||||
$data = $this->fieldManagerTool->read($scope, $name);
|
||||
|
||||
if (!isset($data)) {
|
||||
throw new BadRequest();
|
||||
@@ -58,72 +83,91 @@ class FieldManager extends \Espo\Core\Controllers\Base
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function postActionCreate($params, $data)
|
||||
public function postActionCreate(Request $request)
|
||||
{
|
||||
if (empty($params['scope']) || empty($data->name)) {
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$scope = $request->getRouteParam('scope');
|
||||
$name = $data->name ?? null;
|
||||
|
||||
if (!$scope || !$name) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$fieldManager = $this->getContainer()->get('fieldManager');
|
||||
$fieldManager->create($params['scope'], $data->name, get_object_vars($data));
|
||||
$fieldManagerTool = $this->fieldManagerTool;
|
||||
|
||||
$fieldManagerTool->create($scope, $name, get_object_vars($data));
|
||||
|
||||
try {
|
||||
$this->getContainer()->get('dataManager')->rebuild($params['scope']);
|
||||
} catch (Error $e) {
|
||||
$fieldManager->delete($params['scope'], $data->name);
|
||||
$this->dataManager->rebuild([$scope]);
|
||||
}
|
||||
catch (Error $e) {
|
||||
$fieldManagerTool->delete($scope, $data->name);
|
||||
|
||||
throw new Error($e->getMessage());
|
||||
}
|
||||
|
||||
return $fieldManager->read($params['scope'], $data->name);
|
||||
return $fieldManagerTool->read($scope, $data->name);
|
||||
}
|
||||
|
||||
public function patchActionUpdate($params, $data)
|
||||
public function patchActionUpdate(Request $request)
|
||||
{
|
||||
return $this->putActionUpdate($params, $data);
|
||||
return $this->putActionUpdate($request);
|
||||
}
|
||||
|
||||
public function putActionUpdate($params, $data)
|
||||
public function putActionUpdate(Request $request)
|
||||
{
|
||||
if (empty($params['scope']) || empty($params['name'])) {
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$scope = $request->getRouteParam('scope');
|
||||
$name = $request->getRouteParam('name');
|
||||
|
||||
if (!$scope || !$name) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$fieldManager = $this->getContainer()->get('fieldManager');
|
||||
$fieldManager->update($params['scope'], $params['name'], get_object_vars($data));
|
||||
$fieldManagerTool = $this->fieldManagerTool;
|
||||
|
||||
if ($fieldManager->isChanged()) {
|
||||
$this->getContainer()->get('dataManager')->rebuild($params['scope']);
|
||||
$fieldManagerTool->update($scope, $name, get_object_vars($data));
|
||||
|
||||
if ($fieldManagerTool->isChanged()) {
|
||||
$this->dataManager->rebuild([$scope]);
|
||||
} else {
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
$this->dataManager->clearCache();
|
||||
}
|
||||
|
||||
return $fieldManager->read($params['scope'], $params['name']);
|
||||
return $fieldManagerTool->read($scope, $name);
|
||||
}
|
||||
|
||||
public function deleteActionDelete($params, $data)
|
||||
public function deleteActionDelete(Request $request)
|
||||
{
|
||||
if (empty($params['scope']) || empty($params['name'])) {
|
||||
$scope = $request->getRouteParam('scope');
|
||||
$name = $request->getRouteParam('name');
|
||||
|
||||
if (!$scope || !$name) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$result = $this->getContainer()->get('fieldManager')->delete($params['scope'], $params['name']);
|
||||
$result = $this->fieldManagerTool->delete($scope, $name);
|
||||
|
||||
$this->getContainer()->get('dataManager')->rebuildMetadata();
|
||||
$this->dataManager->rebuildMetadata();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function postActionResetToDefault($params, $data)
|
||||
public function postActionResetToDefault(Request $request)
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (empty($data->scope) || empty($data->name)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$this->getContainer()->get('fieldManager')->resetToDefault($data->scope, $data->name);
|
||||
$this->fieldManagerTool->resetToDefault($data->scope, $data->name);
|
||||
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
$this->dataManager->clearCache();
|
||||
|
||||
$this->getContainer()->get('dataManager')->rebuildMetadata();
|
||||
$this->dataManager->rebuildMetadata();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,11 +29,17 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error,
|
||||
\Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\ServiceFactory;
|
||||
|
||||
class GlobalSearch extends \Espo\Core\Controllers\Base
|
||||
class GlobalSearch
|
||||
{
|
||||
protected $serviceFactory;
|
||||
|
||||
public function __construct(ServiceFactory $serviceFactory)
|
||||
{
|
||||
$this->serviceFactory = $serviceFactory;
|
||||
}
|
||||
|
||||
public function actionSearch($params, $data, $request)
|
||||
{
|
||||
$query = $request->get('q');
|
||||
@@ -41,7 +47,6 @@ class GlobalSearch extends \Espo\Core\Controllers\Base
|
||||
$offset = intval($request->get('offset'));
|
||||
$maxSize = intval($request->get('maxSize'));
|
||||
|
||||
return $this->getService('GlobalSearch')->find($query, $offset, $maxSize);
|
||||
return $this->serviceFactory->create('GlobalSearch')->find($query, $offset, $maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,17 +29,21 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
class I18n extends \Espo\Core\Controllers\Base
|
||||
use Espo\Core\ServiceFactory;
|
||||
|
||||
class I18n
|
||||
{
|
||||
protected $serviceFactory;
|
||||
|
||||
public function __construct(ServiceFactory $serviceFactory)
|
||||
{
|
||||
$this->serviceFactory = $serviceFactory;
|
||||
}
|
||||
|
||||
public function actionRead($params, $data, $request)
|
||||
{
|
||||
$default = $request->get('default') === 'true';
|
||||
|
||||
return $this->getServiceFactory()->create('Language')->getDataForFrontend($default);
|
||||
|
||||
/*if ($request->get('default')) {
|
||||
return $this->getContainer()->get('defaultLanguage')->getAll();
|
||||
}
|
||||
return $this->getContainer()->get('language')->getAll();*/
|
||||
return $this->serviceFactory->create('Language')->getDataForFrontend($default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Utils as Utils;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class Import extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
@@ -78,24 +78,13 @@ class Import extends \Espo\Core\Controllers\Record
|
||||
return $this->getContainer()->get('entityManager');
|
||||
}
|
||||
|
||||
public function actionUploadFile($params, $data, $request)
|
||||
public function postActionUploadFile($params, $data)
|
||||
{
|
||||
$contents = $data;
|
||||
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$attachmentId = $this->getService('Import')->uploadFile($contents);
|
||||
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment');
|
||||
$attachment->set('type', 'text/csv');
|
||||
$attachment->set('role', 'Import File');
|
||||
$attachment->set('name', 'import-file.csv');
|
||||
$attachment->set('contents', $contents);
|
||||
$this->getEntityManager()->saveEntity($attachment);
|
||||
|
||||
return [
|
||||
'attachmentId' => $attachment->id
|
||||
];
|
||||
return ['attachmentId' => $attachmentId];
|
||||
}
|
||||
|
||||
public function actionRevert($params, $data, $request)
|
||||
@@ -106,7 +95,9 @@ class Import extends \Espo\Core\Controllers\Record
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
return $this->getService('Import')->revert($data->id);
|
||||
$this->getService('Import')->revert($data->id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function actionRemoveDuplicates($params, $data, $request)
|
||||
@@ -117,7 +108,9 @@ class Import extends \Espo\Core\Controllers\Record
|
||||
if (!$request->isPost()) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
return $this->getService('Import')->removeDuplicates($data->id);
|
||||
$this->getService('Import')->removeDuplicates($data->id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function actionCreate($params, $data, $request)
|
||||
@@ -190,6 +183,8 @@ class Import extends \Espo\Core\Controllers\Record
|
||||
'skipDuplicateChecking' => !empty($data->skipDuplicateChecking),
|
||||
'idleMode' => !empty($data->idleMode),
|
||||
'silentMode' => !empty($data->silentMode),
|
||||
'manualMode' => !empty($data->manualMode),
|
||||
'defaultFieldList' => $data->defaultFieldList ?? [],
|
||||
];
|
||||
|
||||
if (property_exists($data, 'updateBy')) {
|
||||
@@ -210,7 +205,9 @@ class Import extends \Espo\Core\Controllers\Record
|
||||
if (empty($data->id) || empty($data->entityType) || empty($data->entityId)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$this->getService('Import')->unmarkAsDuplicate($data->id, $data->entityType, $data->entityId);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class InboundEmail extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
@@ -46,7 +45,7 @@ class InboundEmail extends \Espo\Core\Controllers\Record
|
||||
return $this->getRecordService()->getFolders([
|
||||
'host' => $data->host ?? null,
|
||||
'port' => $data->port ?? null,
|
||||
'ssl' => $data->ssl ?? false,
|
||||
'security' => $data->security ?? null,
|
||||
'username' => $data->username ?? null,
|
||||
'password' => $data->password ?? null,
|
||||
'id' => $data->id ?? null,
|
||||
|
||||
@@ -29,9 +29,8 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class Integration extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
@@ -82,4 +81,3 @@ class Integration extends \Espo\Core\Controllers\Record
|
||||
return $entity->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,8 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class Job extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
@@ -29,49 +29,69 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Utils as Utils;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\{
|
||||
Exceptions\Forbidden,
|
||||
Exceptions\BadRequest,
|
||||
Api\Request,
|
||||
DataManager,
|
||||
};
|
||||
|
||||
class LabelManager extends \Espo\Core\Controllers\Base
|
||||
use Espo\{
|
||||
Tools\LabelManager\LabelManager as LabelManagerTool,
|
||||
Entities\User,
|
||||
};
|
||||
|
||||
class LabelManager
|
||||
{
|
||||
protected $user;
|
||||
protected $dataManager;
|
||||
protected $labelManagerTool;
|
||||
|
||||
public function __construct(User $user, DataManager $dataManager, LabelManagerTool $labelManagerTool)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->dataManager = $dataManager;
|
||||
$this->labelManagerTool = $labelManagerTool;
|
||||
|
||||
$this->checkControllerAccess();
|
||||
}
|
||||
|
||||
protected function checkControllerAccess()
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
public function postActionGetScopeList($params)
|
||||
public function postActionGetScopeList()
|
||||
{
|
||||
$labelManager = $this->getContainer()->get('injectableFactory')->createByClassName('\\Espo\\Core\\Utils\\LabelManager');
|
||||
|
||||
return $labelManager->getScopeList();
|
||||
return $this->labelManagerTool->getScopeList();
|
||||
}
|
||||
|
||||
public function postActionGetScopeData($params, $data, $request)
|
||||
public function postActionGetScopeData(Request $request)
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (empty($data->scope) || empty($data->language)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$labelManager = $this->getContainer()->get('injectableFactory')->createByClassName('\\Espo\\Core\\Utils\\LabelManager');
|
||||
return $labelManager->getScopeData($data->language, $data->scope);
|
||||
|
||||
return $this->labelManagerTool->getScopeData($data->language, $data->scope);
|
||||
}
|
||||
|
||||
public function postActionSaveLabels($params, $data)
|
||||
public function postActionSaveLabels(Request $request)
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (empty($data->scope) || empty($data->language) || !isset($data->labels)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$labels = get_object_vars($data->labels);
|
||||
|
||||
$labelManager = $this->getContainer()->get('injectableFactory')->createByClassName('\\Espo\\Core\\Utils\\LabelManager');
|
||||
$returnData = $labelManager->saveLabels($data->language, $data->scope, $labels);
|
||||
$returnData = $this->labelManagerTool->saveLabels($data->language, $data->scope, $labels);
|
||||
|
||||
$this->getContainer()->get('dataManager')->clearCache();
|
||||
$this->dataManager->clearCache();
|
||||
|
||||
return $returnData;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class LastViewed extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
|
||||
@@ -47,6 +47,8 @@ class Layout extends \Espo\Core\Controllers\Base
|
||||
|
||||
public function putActionUpdate($params, $data, $request)
|
||||
{
|
||||
$data = json_decode($request->getBodyContents());
|
||||
|
||||
if (is_object($data)) $data = get_object_vars($data);
|
||||
|
||||
if (!$this->getUser()->isAdmin()) throw new Forbidden();
|
||||
|
||||
@@ -29,26 +29,36 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
|
||||
class LeadCapture extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
public function postActionLeadCapture($params, $data, $request, $response)
|
||||
{
|
||||
if (empty($params['apiKey'])) throw new BadRequest('No API key provided.');
|
||||
if (empty($data)) throw new BadRequest('No payload provided.');
|
||||
if (empty($params['apiKey'])) {
|
||||
throw new BadRequest('No API key provided.');
|
||||
}
|
||||
|
||||
if (empty($data)) {
|
||||
throw new BadRequest('No payload provided.');
|
||||
}
|
||||
|
||||
$allowOrigin = $this->getConfig()->get('leadCaptureAllowOrigin', '*');
|
||||
$response->headers->set('Access-Control-Allow-Origin', $allowOrigin);
|
||||
|
||||
return $this->getRecordService()->leadCapture($params['apiKey'], $data);
|
||||
$response->setHeader('Access-Control-Allow-Origin', $allowOrigin);
|
||||
|
||||
$this->getRecordService()->leadCapture($params['apiKey'], $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function optionsActionLeadCapture($params, $data, $request, $response)
|
||||
{
|
||||
if (empty($params['apiKey'])) throw new BadRequest('No API key provided.');
|
||||
if (empty($params['apiKey'])) {
|
||||
throw new BadRequest('No API key provided.');
|
||||
}
|
||||
|
||||
if (!$this->getRecordService()->isApiKeyValid($params['apiKey'])) {
|
||||
throw new NotFound();
|
||||
@@ -56,23 +66,27 @@ class LeadCapture extends \Espo\Core\Controllers\Record
|
||||
|
||||
$allowOrigin = $this->getConfig()->get('leadCaptureAllowOrigin', '*');
|
||||
|
||||
$response->headers->set('Access-Control-Allow-Headers', 'Content-Type, Accept');
|
||||
$response->headers->set('Access-Control-Allow-Origin', $allowOrigin);
|
||||
$response->headers->set('Access-Control-Allow-Methods', 'POST');
|
||||
$response->setHeader('Access-Control-Allow-Headers', 'Content-Type, Accept');
|
||||
$response->setHeader('Access-Control-Allow-Origin', $allowOrigin);
|
||||
$response->setHeader('Access-Control-Allow-Methods', 'POST');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function postActionGenerateNewApiKey($params, $data, $request)
|
||||
{
|
||||
if (empty($data->id)) throw new BadRequest();
|
||||
if (empty($data->id)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
return $this->getRecordService()->generateNewApiKeyForEntity($data->id)->getValueMap();
|
||||
}
|
||||
|
||||
public function getActionSmtpAccountDataList()
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) throw new Forbidden();
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
return $this->getServiceFactory()->create('LeadCapture')->getSmtpAccountDataList();
|
||||
}
|
||||
|
||||
@@ -29,9 +29,6 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class LeadCaptureLogRecord extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
|
||||
@@ -29,11 +29,10 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class Metadata extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
|
||||
public function actionRead($params, $data)
|
||||
{
|
||||
return $this->getServiceFactory()->create('Metadata')->getDataForFrontend();
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
class Notification extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
@@ -47,18 +47,18 @@ class Notification extends \Espo\Core\Controllers\Record
|
||||
$maxSize = self::MAX_SIZE_LIMIT;
|
||||
}
|
||||
|
||||
$params = array(
|
||||
$params = [
|
||||
'offset' => $offset,
|
||||
'maxSize' => $maxSize,
|
||||
'after' => $after
|
||||
);
|
||||
'after' => $after,
|
||||
];
|
||||
|
||||
$result = $this->getService('Notification')->getList($userId, $params);
|
||||
$recordCollection = $this->getService('Notification')->getList($userId, $params);
|
||||
|
||||
return array(
|
||||
'total' => $result['total'],
|
||||
'list' => $result['collection']->toArray()
|
||||
);
|
||||
return (object) [
|
||||
'total' => $recordCollection->getTotal(),
|
||||
'list' => $recordCollection->getValueMapList(),
|
||||
];
|
||||
}
|
||||
|
||||
public function actionNotReadCount()
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
class Pdf extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class PhoneNumber extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class Portal extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
|
||||
class Preferences extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
|
||||
@@ -32,6 +32,11 @@ namespace Espo\Controllers;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
use Espo\Core\{
|
||||
Authentication\LDAP\Utils as LDAPUtils,
|
||||
Authentication\LDAP\Client as LDAPClient,
|
||||
};
|
||||
|
||||
class Settings extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
protected function getConfigData()
|
||||
@@ -86,11 +91,14 @@ class Settings extends \Espo\Core\Controllers\Base
|
||||
|
||||
$data = get_object_vars($data);
|
||||
|
||||
$ldapUtils = new \Espo\Core\Utils\Authentication\LDAP\Utils();
|
||||
$ldapUtils = new LDAPUtils();
|
||||
|
||||
$options = $ldapUtils->normalizeOptions($data);
|
||||
|
||||
$ldapClient = new \Espo\Core\Utils\Authentication\LDAP\Client($options);
|
||||
$ldapClient->bind(); //an exception if no connection
|
||||
$ldapClient = new LDAPClient($options);
|
||||
|
||||
//an exception if no connection
|
||||
$ldapClient->bind();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,14 +29,26 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
class Stream extends \Espo\Core\Controllers\Base
|
||||
use Espo\Core\ServiceFactory;
|
||||
use Espo\Core\Utils\Config;
|
||||
|
||||
class Stream
|
||||
{
|
||||
const MAX_SIZE_LIMIT = 200;
|
||||
|
||||
public static $defaultAction = 'list';
|
||||
|
||||
protected $serviceFactory;
|
||||
protected $config;
|
||||
|
||||
public function __construct(ServiceFactory $serviceFactory, Config $config)
|
||||
{
|
||||
$this->serviceFactory = $serviceFactory;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function actionList($params, $data, $request)
|
||||
{
|
||||
$scope = $params['scope'];
|
||||
@@ -48,9 +60,7 @@ class Stream extends \Espo\Core\Controllers\Base
|
||||
$filter = $request->get('filter');
|
||||
$skipOwn = $request->get('skipOwn') === 'true';
|
||||
|
||||
$service = $this->getService('Stream');
|
||||
|
||||
$maxSizeLimit = $this->getConfig()->get('recordListMaxSizeLimit', self::MAX_SIZE_LIMIT);
|
||||
$maxSizeLimit = $this->config->get('recordListMaxSizeLimit', self::MAX_SIZE_LIMIT);
|
||||
if (empty($maxSize)) {
|
||||
$maxSize = $maxSizeLimit;
|
||||
}
|
||||
@@ -58,7 +68,7 @@ class Stream extends \Espo\Core\Controllers\Base
|
||||
throw new Forbidden("Max size should should not exceed " . $maxSizeLimit . ". Use offset and limit.");
|
||||
}
|
||||
|
||||
$result = $service->find($scope, $id, [
|
||||
$result = $this->serviceFactory->create('Stream')->find($scope, $id, [
|
||||
'offset' => $offset,
|
||||
'maxSize' => $maxSize,
|
||||
'after' => $after,
|
||||
@@ -83,9 +93,7 @@ class Stream extends \Espo\Core\Controllers\Base
|
||||
|
||||
$where = $request->get('where');
|
||||
|
||||
$service = $this->getService('Stream');
|
||||
|
||||
$maxSizeLimit = $this->getConfig()->get('recordListMaxSizeLimit', self::MAX_SIZE_LIMIT);
|
||||
$maxSizeLimit = $this->config->get('recordListMaxSizeLimit', self::MAX_SIZE_LIMIT);
|
||||
if (empty($maxSize)) {
|
||||
$maxSize = $maxSizeLimit;
|
||||
}
|
||||
@@ -93,7 +101,7 @@ class Stream extends \Espo\Core\Controllers\Base
|
||||
throw new Forbidden("Max size should should not exceed " . $maxSizeLimit . ". Use offset and limit.");
|
||||
}
|
||||
|
||||
$result = $service->find($scope, $id, [
|
||||
$result = $this->serviceFactory->create('Stream')->find($scope, $id, [
|
||||
'offset' => $offset,
|
||||
'maxSize' => $maxSize,
|
||||
'after' => $after,
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
|
||||
class Template extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
|
||||
@@ -29,17 +29,26 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Utils as Utils;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class TemplateManager extends \Espo\Core\Controllers\Base
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Core\Utils\TemplateFileManager;
|
||||
use Espo\Core\ApplicationState;
|
||||
|
||||
class TemplateManager
|
||||
{
|
||||
protected function checkControllerAccess()
|
||||
protected $metadata;
|
||||
protected $templateFileManager;
|
||||
protected $applicationState;
|
||||
|
||||
public function __construct(Metadata $metadata, TemplateFileManager $templateFileManager, ApplicationState $applicationState)
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
$this->metadata = $metadata;
|
||||
$this->templateFileManager = $templateFileManager;
|
||||
$this->applicationState = $applicationState;
|
||||
|
||||
if (!$this->applicationState->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
@@ -50,10 +59,10 @@ class TemplateManager extends \Espo\Core\Controllers\Base
|
||||
if (empty($name)) throw new BadRequest();
|
||||
$scope = $request->get('scope');
|
||||
$module = null;
|
||||
$module = $this->getMetadata()->get(['app', 'templates', $name, 'module']);
|
||||
$hasSubject = !$this->getMetadata()->get(['app', 'templates', $name, 'noSubject']);
|
||||
$module = $this->metadata->get(['app', 'templates', $name, 'module']);
|
||||
$hasSubject = !$this->metadata->get(['app', 'templates', $name, 'noSubject']);
|
||||
|
||||
$templateFileManager = $this->getContainer()->get('templateFileManager');
|
||||
$templateFileManager = $this->templateFileManager;
|
||||
|
||||
$returnData = (object) [];
|
||||
$returnData->body = $templateFileManager->getTemplate($name, 'body', $scope, $module);
|
||||
@@ -75,7 +84,7 @@ class TemplateManager extends \Espo\Core\Controllers\Base
|
||||
$scope = $data->scope;
|
||||
}
|
||||
|
||||
$templateFileManager = $this->getContainer()->get('templateFileManager');
|
||||
$templateFileManager = $this->templateFileManager;
|
||||
|
||||
if (isset($data->subject)) {
|
||||
$templateFileManager->saveTemplate($data->name, 'subject', $data->subject, $scope);
|
||||
@@ -99,10 +108,10 @@ class TemplateManager extends \Espo\Core\Controllers\Base
|
||||
}
|
||||
|
||||
$module = null;
|
||||
$module = $this->getMetadata()->get(['app', 'templates', $data->name, 'module']);
|
||||
$hasSubject = !$this->getMetadata()->get(['app', 'templates', $data->name, 'noSubject']);
|
||||
$module = $this->metadata->get(['app', 'templates', $data->name, 'module']);
|
||||
$hasSubject = !$this->metadata->get(['app', 'templates', $data->name, 'noSubject']);
|
||||
|
||||
$templateFileManager = $this->getContainer()->get('templateFileManager');
|
||||
$templateFileManager = $this->templateFileManager;
|
||||
|
||||
if ($hasSubject) {
|
||||
$templateFileManager->resetTemplate($data->name, 'subject', $scope);
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class User extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
@@ -29,10 +29,8 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class UserSecurity extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
|
||||
@@ -29,8 +29,7 @@
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
class Webhook extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
|
||||
@@ -29,9 +29,12 @@
|
||||
|
||||
namespace Espo\Core;
|
||||
|
||||
use \Espo\ORM\Entity;
|
||||
use \Espo\Entities\User;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Entities\User;
|
||||
|
||||
/**
|
||||
* A wrapper for AclManager. To check access for a current user.
|
||||
*/
|
||||
class Acl
|
||||
{
|
||||
private $user;
|
||||
@@ -54,102 +57,154 @@ class Acl
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function getMap()
|
||||
public function getMap() : \StdClass
|
||||
{
|
||||
return $this->getAclManager()->getMap($this->getUser());
|
||||
}
|
||||
|
||||
public function getLevel($scope, $action)
|
||||
/**
|
||||
* Get an access level for a specific scope and action.
|
||||
*/
|
||||
public function getLevel(string $scope, string $action) : string
|
||||
{
|
||||
return $this->getAclManager()->getLevel($this->getUser(), $scope, $action);
|
||||
}
|
||||
|
||||
public function get($permission)
|
||||
/**
|
||||
* Get a permission. E.g. 'assignment' permission.
|
||||
*/
|
||||
public function get(string $permission) : ?string
|
||||
{
|
||||
return $this->getAclManager()->get($this->getUser(), $permission);
|
||||
}
|
||||
|
||||
public function checkReadNo($scope)
|
||||
/**
|
||||
* Whether there's no 'read' access for a specific scope.
|
||||
*/
|
||||
public function checkReadNo(string $scope) : bool
|
||||
{
|
||||
return $this->getAclManager()->checkReadNo($this->getUser(), $scope);
|
||||
}
|
||||
|
||||
public function checkReadOnlyTeam($scope)
|
||||
/**
|
||||
* Whether 'read' access is set to 'team' for a specific scope.
|
||||
*/
|
||||
public function checkReadOnlyTeam(string $scope) : bool
|
||||
{
|
||||
return $this->getAclManager()->checkReadOnlyTeam($this->getUser(), $scope);
|
||||
}
|
||||
|
||||
public function checkReadOnlyOwn($scope)
|
||||
/**
|
||||
* Whether 'read' access is set to 'own' for a specific scope.
|
||||
*/
|
||||
public function checkReadOnlyOwn(string $scope) : bool
|
||||
{
|
||||
return $this->getAclManager()->checkReadOnlyOwn($this->getUser(), $scope);
|
||||
}
|
||||
|
||||
public function check($subject, $action = null)
|
||||
/**
|
||||
* Check a scope or entity. If $action is omitted, it will check whether a scope level is set to 'enabled'.
|
||||
*/
|
||||
public function check($subject, ?string $action = null) : bool
|
||||
{
|
||||
return $this->getAclManager()->check($this->getUser(), $subject, $action);
|
||||
}
|
||||
|
||||
public function checkScope($scope, $action = null)
|
||||
/**
|
||||
* Check access to scope. If $action is omitted, it will check whether a scope level is set to 'enabled'.
|
||||
*/
|
||||
public function checkScope(string $scope, ?string $action = null) : bool
|
||||
{
|
||||
return $this->getAclManager()->checkScope($this->getUser(), $scope, $action);
|
||||
}
|
||||
|
||||
public function checkEntity(Entity $entity, $action = 'read')
|
||||
/**
|
||||
* Check access to a specific entity (record).
|
||||
*/
|
||||
public function checkEntity(Entity $entity, string $action = 'read') : bool
|
||||
{
|
||||
return $this->getAclManager()->checkEntity($this->getUser(), $entity, $action);
|
||||
}
|
||||
|
||||
public function checkUser($permission, User $entity)
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function checkUser(string $permission, User $entity) : bool
|
||||
{
|
||||
return $this->getAclManager()->checkUser($this->getUser(), $permission, $entity);
|
||||
}
|
||||
|
||||
public function checkIsOwner(Entity $entity)
|
||||
/**
|
||||
* Whether a user is owned of an entity (record). Usually 'assignedUser' field is used for checking.
|
||||
*/
|
||||
public function checkIsOwner(Entity $entity) : bool
|
||||
{
|
||||
return $this->getAclManager()->checkIsOwner($this->getUser(), $entity);
|
||||
}
|
||||
|
||||
public function checkInTeam(Entity $entity)
|
||||
/**
|
||||
* Whether a user team list overlaps with teams set in an entity.
|
||||
*/
|
||||
public function checkInTeam(Entity $entity) : bool
|
||||
{
|
||||
return $this->getAclManager()->checkInTeam($this->getUser(), $entity);
|
||||
}
|
||||
|
||||
public function getScopeForbiddenAttributeList($scope, $action = 'read', $thresholdLevel = 'no')
|
||||
/**
|
||||
* Get attributes forbidden for a user.
|
||||
*/
|
||||
public function getScopeForbiddenAttributeList(string $scope, string $action = 'read', string $thresholdLevel = 'no') : array
|
||||
{
|
||||
return $this->getAclManager()->getScopeForbiddenAttributeList($this->getUser(), $scope, $action, $thresholdLevel);
|
||||
}
|
||||
|
||||
public function getScopeForbiddenFieldList($scope, $action = 'read', $thresholdLevel = 'no')
|
||||
/**
|
||||
* Get fields forbidden for a user.
|
||||
*/
|
||||
public function getScopeForbiddenFieldList(string $scope, string $action = 'read', string $thresholdLevel = 'no') : array
|
||||
{
|
||||
return $this->getAclManager()->getScopeForbiddenFieldList($this->getUser(), $scope, $action, $thresholdLevel);
|
||||
}
|
||||
|
||||
public function getScopeForbiddenLinkList($scope, $action = 'read', $thresholdLevel = 'no')
|
||||
/**
|
||||
* Get links forbidden for a user.
|
||||
*/
|
||||
public function getScopeForbiddenLinkList(string $scope, string $action = 'read', string $thresholdLevel = 'no') : array
|
||||
{
|
||||
return $this->getAclManager()->getScopeForbiddenLinkList($this->getUser(), $scope, $action, $thresholdLevel);
|
||||
}
|
||||
|
||||
public function checkUserPermission($target, $permissionType = 'userPermission')
|
||||
/**
|
||||
* Whether a user has an access to another user over a specific permission.
|
||||
*
|
||||
* @param $target User|string User entity or user ID.
|
||||
*/
|
||||
public function checkUserPermission($target, string $permissionType = 'user') : bool
|
||||
{
|
||||
return $this->getAclManager()->checkUserPermission($this->getUser(), $target, $permissionType);
|
||||
}
|
||||
|
||||
public function checkAssignmentPermission($target)
|
||||
/**
|
||||
* Whether a user can assign to another user.
|
||||
*
|
||||
* @param $target User|string User entity or user ID.
|
||||
*/
|
||||
public function checkAssignmentPermission($target) : bool
|
||||
{
|
||||
return $this->getAclManager()->checkAssignmentPermission($this->getUser(), $target);
|
||||
}
|
||||
|
||||
public function getScopeRestrictedFieldList($scope, $type)
|
||||
public function getScopeRestrictedFieldList(string $scope, $type) : array
|
||||
{
|
||||
return $this->getAclManager()->getScopeRestrictedFieldList($scope, $type);
|
||||
}
|
||||
|
||||
public function getScopeRestrictedAttributeList($scope, $type)
|
||||
public function getScopeRestrictedAttributeList(string $scope, $type) : array
|
||||
{
|
||||
return $this->getAclManager()->getScopeRestrictedAttributeList($scope, $type);
|
||||
}
|
||||
|
||||
public function getScopeRestrictedLinkList($scope, $type)
|
||||
public function getScopeRestrictedLinkList(string $scope, $type) : array
|
||||
{
|
||||
return $this->getAclManager()->getScopeRestrictedLinkList($scope, $type);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy 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\Core\Acl;
|
||||
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\{
|
||||
ORM\EntityManager,
|
||||
AclManager,
|
||||
Utils\Config,
|
||||
};
|
||||
|
||||
/**
|
||||
* An implementation for access checking for entities. Can be overriden in `Acl` namespece.
|
||||
*/
|
||||
class Acl implements ScopeAcl, EntityAcl
|
||||
{
|
||||
protected $scope;
|
||||
|
||||
protected $ownerUserIdAttribute = null;
|
||||
|
||||
protected $allowDeleteCreatedThresholdPeriod = '24 hours';
|
||||
|
||||
protected $entityManager;
|
||||
protected $aclManager;
|
||||
protected $config;
|
||||
|
||||
public function __construct(string $scope, EntityManager $entityManager, AclManager $aclManager, Config $config)
|
||||
{
|
||||
$this->scope = $scope;
|
||||
|
||||
$this->entityManager = $entityManager;
|
||||
$this->aclManager = $aclManager;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
protected function getEntityManager()
|
||||
{
|
||||
return $this->entityManager;
|
||||
}
|
||||
|
||||
protected function getAclManager()
|
||||
{
|
||||
return $this->aclManager;
|
||||
}
|
||||
|
||||
public function checkReadOnlyTeam(User $user, $data)
|
||||
{
|
||||
if (empty($data) || !is_object($data) || !isset($data->read)) {
|
||||
return false;
|
||||
}
|
||||
return $data->read === 'team';
|
||||
}
|
||||
|
||||
public function checkReadNo(User $user, $data)
|
||||
{
|
||||
if (empty($data) || !is_object($data) || !isset($data->read)) {
|
||||
return false;
|
||||
}
|
||||
return $data->read === 'no';
|
||||
}
|
||||
|
||||
public function checkReadOnlyOwn(User $user, $data)
|
||||
{
|
||||
if (empty($data) || !is_object($data) || !isset($data->read)) {
|
||||
return false;
|
||||
}
|
||||
return $data->read === 'own';
|
||||
}
|
||||
|
||||
public function checkEntity(User $user, Entity $entity, $data, $action)
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
return $this->checkScope($user, $data, $action, $entity);
|
||||
}
|
||||
|
||||
public function checkScope(User $user, $data, $action = null, Entity $entity = null, $entityAccessData = [])
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_null($data)) {
|
||||
return false;
|
||||
}
|
||||
if ($data === false) {
|
||||
return false;
|
||||
}
|
||||
if ($data === true) {
|
||||
return true;
|
||||
}
|
||||
if (is_string($data)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$isOwner = null;
|
||||
if (isset($entityAccessData['isOwner'])) {
|
||||
$isOwner = $entityAccessData['isOwner'];
|
||||
}
|
||||
$inTeam = null;
|
||||
if (isset($entityAccessData['inTeam'])) {
|
||||
$inTeam = $entityAccessData['inTeam'];
|
||||
}
|
||||
|
||||
if (is_null($action)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isset($data->$action)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = $data->$action;
|
||||
|
||||
if ($value === 'all' || $value === 'yes' || $value === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$value || $value === 'no') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_null($isOwner)) {
|
||||
if ($entity) {
|
||||
$isOwner = $this->checkIsOwner($user, $entity);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isOwner) {
|
||||
if ($value === 'own' || $value === 'team') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (is_null($inTeam) && $entity) {
|
||||
$inTeam = $this->checkInTeam($user, $entity);
|
||||
}
|
||||
|
||||
if ($inTeam) {
|
||||
if ($value === 'team') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkIsOwner(User $user, Entity $entity)
|
||||
{
|
||||
if ($entity->hasAttribute('assignedUserId')) {
|
||||
if ($entity->has('assignedUserId')) {
|
||||
if ($user->id === $entity->get('assignedUserId')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if ($entity->hasAttribute('createdById')) {
|
||||
if ($entity->has('createdById')) {
|
||||
if ($user->id === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->hasLinkMultipleField('assignedUsers')) {
|
||||
if ($entity->hasLinkMultipleId('assignedUsers', $user->id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkInTeam(User $user, Entity $entity)
|
||||
{
|
||||
$userTeamIdList = $user->getLinkMultipleIdList('teams');
|
||||
|
||||
if (!$entity->hasRelation('teams') || !$entity->hasAttribute('teamsIds')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$entityTeamIdList = $entity->getLinkMultipleIdList('teams');
|
||||
|
||||
if (empty($entityTeamIdList)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($userTeamIdList as $id) {
|
||||
if (in_array($id, $entityTeamIdList)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkEntityDelete(User $user, Entity $entity, $data)
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->checkEntity($user, $entity, $data, 'delete')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_object($data)) {
|
||||
if ($data->edit !== 'no' || $data->create !== 'no') {
|
||||
if (
|
||||
$this->config->get('aclAllowDeleteCreated')
|
||||
&&
|
||||
$entity->has('createdById') && $entity->get('createdById') == $user->id
|
||||
) {
|
||||
$isDeletedAllowed = false;
|
||||
if (!$entity->has('assignedUserId')) {
|
||||
$isDeletedAllowed = true;
|
||||
} else {
|
||||
if (!$entity->get('assignedUserId')) {
|
||||
$isDeletedAllowed = true;
|
||||
} else if ($entity->get('assignedUserId') == $entity->get('createdById')) {
|
||||
$isDeletedAllowed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isDeletedAllowed) {
|
||||
$createdAt = $entity->get('createdAt');
|
||||
if ($createdAt) {
|
||||
$deleteThresholdPeriod = $this->config->get(
|
||||
'aclAllowDeleteCreatedThresholdPeriod',
|
||||
$this->allowDeleteCreatedThresholdPeriod
|
||||
);
|
||||
if (\Espo\Core\Utils\DateTime::isAfterThreshold($createdAt, $deleteThresholdPeriod)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getOwnerUserIdAttribute(Entity $entity)
|
||||
{
|
||||
if ($this->ownerUserIdAttribute) {
|
||||
return $this->ownerUserIdAttribute;
|
||||
}
|
||||
|
||||
if ($entity->hasLinkMultipleField('assignedUsers')) {
|
||||
return 'assignedUsersIds';
|
||||
}
|
||||
|
||||
if ($entity->hasAttribute('assignedUserId')) {
|
||||
return 'assignedUserId';
|
||||
}
|
||||
|
||||
if ($entity->hasAttribute('createdById')) {
|
||||
return 'createdById';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,39 +29,39 @@
|
||||
|
||||
namespace Espo\Core\Acl;
|
||||
|
||||
use \Espo\Core\Interfaces\Injectable;
|
||||
use Espo\Core\Interfaces\Injectable;
|
||||
|
||||
use \Espo\Entities\User;
|
||||
use \Espo\ORM\Entity;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class Base implements Injectable
|
||||
use Espo\Core\{
|
||||
ORM\EntityManager,
|
||||
AclManager,
|
||||
Utils\Config,
|
||||
};
|
||||
|
||||
/** @deprecated */
|
||||
class Base extends Acl implements Injectable
|
||||
{
|
||||
protected $dependencyList = [
|
||||
'config',
|
||||
'entityManager',
|
||||
'aclManager',
|
||||
];
|
||||
protected $dependencyList = [];
|
||||
|
||||
protected $dependencies = []; // for backward compatibility
|
||||
|
||||
protected $scope;
|
||||
protected $dependencies = [];
|
||||
|
||||
protected $injections = [];
|
||||
|
||||
protected $ownerUserIdAttribute = null;
|
||||
public function __construct(string $scope, EntityManager $entityManager, AclManager $aclManager, Config $config)
|
||||
{
|
||||
$this->scope = $scope;
|
||||
parent::__construct($scope, $entityManager, $aclManager, $config);
|
||||
|
||||
protected $allowDeleteCreatedThresholdPeriod = '24 hours';
|
||||
$this->init();
|
||||
}
|
||||
|
||||
public function inject($name, $object)
|
||||
{
|
||||
$this->injections[$name] = $object;
|
||||
}
|
||||
|
||||
public function __construct($scope)
|
||||
{
|
||||
$this->init();
|
||||
$this->scope = $scope;
|
||||
}
|
||||
|
||||
protected function init()
|
||||
{
|
||||
@@ -69,7 +69,7 @@ class Base implements Injectable
|
||||
|
||||
protected function getInjection($name)
|
||||
{
|
||||
return $this->injections[$name];
|
||||
return $this->injections[$name] ?? $this->$name ?? null;
|
||||
}
|
||||
|
||||
protected function addDependencyList(array $list)
|
||||
@@ -88,233 +88,4 @@ class Base implements Injectable
|
||||
{
|
||||
return array_merge($this->dependencyList, $this->dependencies);
|
||||
}
|
||||
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->getInjection('config');
|
||||
}
|
||||
|
||||
protected function getEntityManager()
|
||||
{
|
||||
return $this->getInjection('entityManager');
|
||||
}
|
||||
|
||||
protected function getAclManager()
|
||||
{
|
||||
return $this->getInjection('aclManager');
|
||||
}
|
||||
|
||||
public function checkReadOnlyTeam(User $user, $data)
|
||||
{
|
||||
if (empty($data) || !is_object($data) || !isset($data->read)) {
|
||||
return false;
|
||||
}
|
||||
return $data->read === 'team';
|
||||
}
|
||||
|
||||
public function checkReadNo(User $user, $data)
|
||||
{
|
||||
if (empty($data) || !is_object($data) || !isset($data->read)) {
|
||||
return false;
|
||||
}
|
||||
return $data->read === 'no';
|
||||
}
|
||||
|
||||
public function checkReadOnlyOwn(User $user, $data)
|
||||
{
|
||||
if (empty($data) || !is_object($data) || !isset($data->read)) {
|
||||
return false;
|
||||
}
|
||||
return $data->read === 'own';
|
||||
}
|
||||
|
||||
public function checkEntity(User $user, Entity $entity, $data, $action)
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
return $this->checkScope($user, $data, $action, $entity);
|
||||
}
|
||||
|
||||
public function checkScope(User $user, $data, $action = null, Entity $entity = null, $entityAccessData = array())
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_null($data)) {
|
||||
return false;
|
||||
}
|
||||
if ($data === false) {
|
||||
return false;
|
||||
}
|
||||
if ($data === true) {
|
||||
return true;
|
||||
}
|
||||
if (is_string($data)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$isOwner = null;
|
||||
if (isset($entityAccessData['isOwner'])) {
|
||||
$isOwner = $entityAccessData['isOwner'];
|
||||
}
|
||||
$inTeam = null;
|
||||
if (isset($entityAccessData['inTeam'])) {
|
||||
$inTeam = $entityAccessData['inTeam'];
|
||||
}
|
||||
|
||||
if (is_null($action)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isset($data->$action)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = $data->$action;
|
||||
|
||||
if ($value === 'all' || $value === 'yes' || $value === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$value || $value === 'no') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_null($isOwner)) {
|
||||
if ($entity) {
|
||||
$isOwner = $this->checkIsOwner($user, $entity);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isOwner) {
|
||||
if ($value === 'own' || $value === 'team') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (is_null($inTeam) && $entity) {
|
||||
$inTeam = $this->checkInTeam($user, $entity);
|
||||
}
|
||||
|
||||
if ($inTeam) {
|
||||
if ($value === 'team') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkIsOwner(User $user, Entity $entity)
|
||||
{
|
||||
if ($entity->hasAttribute('assignedUserId')) {
|
||||
if ($entity->has('assignedUserId')) {
|
||||
if ($user->id === $entity->get('assignedUserId')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if ($entity->hasAttribute('createdById')) {
|
||||
if ($entity->has('createdById')) {
|
||||
if ($user->id === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->hasLinkMultipleField('assignedUsers')) {
|
||||
if ($entity->hasLinkMultipleId('assignedUsers', $user->id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkInTeam(User $user, Entity $entity)
|
||||
{
|
||||
$userTeamIdList = $user->getLinkMultipleIdList('teams');
|
||||
|
||||
if (!$entity->hasRelation('teams') || !$entity->hasAttribute('teamsIds')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$entityTeamIdList = $entity->getLinkMultipleIdList('teams');
|
||||
|
||||
if (empty($entityTeamIdList)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($userTeamIdList as $id) {
|
||||
if (in_array($id, $entityTeamIdList)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkEntityDelete(User $user, Entity $entity, $data)
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->checkEntity($user, $entity, $data, 'delete')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_object($data)) {
|
||||
if ($data->edit !== 'no' || $data->create !== 'no') {
|
||||
if (
|
||||
$this->getConfig()->get('aclAllowDeleteCreated')
|
||||
&&
|
||||
$entity->has('createdById') && $entity->get('createdById') == $user->id
|
||||
) {
|
||||
$isDeletedAllowed = false;
|
||||
if (!$entity->has('assignedUserId')) {
|
||||
$isDeletedAllowed = true;
|
||||
} else {
|
||||
if (!$entity->get('assignedUserId')) {
|
||||
$isDeletedAllowed = true;
|
||||
} else if ($entity->get('assignedUserId') == $entity->get('createdById')) {
|
||||
$isDeletedAllowed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isDeletedAllowed) {
|
||||
$createdAt = $entity->get('createdAt');
|
||||
if ($createdAt) {
|
||||
$deleteThresholdPeriod = $this->getConfig()->get('aclAllowDeleteCreatedThresholdPeriod', $this->allowDeleteCreatedThresholdPeriod);
|
||||
if (\Espo\Core\Utils\DateTime::isAfterThreshold($createdAt, $deleteThresholdPeriod)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getOwnerUserIdAttribute(Entity $entity)
|
||||
{
|
||||
if ($this->ownerUserIdAttribute) {
|
||||
return $this->ownerUserIdAttribute;
|
||||
}
|
||||
|
||||
if ($entity->hasLinkMultipleField('assignedUsers')) {
|
||||
return 'assignedUsersIds';
|
||||
}
|
||||
|
||||
if ($entity->hasAttribute('assignedUserId')) {
|
||||
return 'assignedUserId';
|
||||
}
|
||||
|
||||
if ($entity->hasAttribute('createdById')) {
|
||||
return 'createdById';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy 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\Core\Acl;
|
||||
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
/**
|
||||
* @todo Add methods.
|
||||
*/
|
||||
interface EntityAcl
|
||||
{
|
||||
|
||||
}
|
||||
@@ -29,6 +29,17 @@
|
||||
|
||||
namespace Espo\Core\Acl;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\Metadata,
|
||||
Utils\DataCache,
|
||||
Utils\FieldUtil,
|
||||
};
|
||||
|
||||
use StdClass;
|
||||
|
||||
/**
|
||||
* Lists of restricted fields can be obtained from here. Restricted fields are specified in metadata > entityAcl.
|
||||
*/
|
||||
class GlobalRestricton
|
||||
{
|
||||
protected $fieldTypeList = [
|
||||
@@ -47,36 +58,32 @@ class GlobalRestricton
|
||||
'nonAdminReadOnly' // read-only for non-admin users
|
||||
];
|
||||
|
||||
protected $cacheFilePath = 'data/cache/application/entityAcl.php';
|
||||
|
||||
private $metadata;
|
||||
|
||||
private $fileManager;
|
||||
|
||||
private $fieldManagerUtil;
|
||||
|
||||
private $data;
|
||||
|
||||
protected $cacheKey = 'entityAcl';
|
||||
|
||||
private $metadata;
|
||||
private $dataCache;
|
||||
private $fieldUtil;
|
||||
|
||||
public function __construct(
|
||||
\Espo\Core\Utils\Metadata $metadata,
|
||||
\Espo\Core\Utils\File\Manager $fileManager,
|
||||
\Espo\Core\Utils\FieldManagerUtil $fieldManagerUtil,
|
||||
bool $useCache = true
|
||||
)
|
||||
{
|
||||
Metadata $metadata, DataCache $dataCache, FieldUtil $fieldUtil, bool $useCache = true
|
||||
) {
|
||||
$this->metadata = $metadata;
|
||||
$this->fileManager = $fileManager;
|
||||
$this->fieldManagerUtil = $fieldManagerUtil;
|
||||
$this->dataCache = $dataCache;
|
||||
$this->fieldUtil = $fieldUtil;
|
||||
|
||||
$isFromCache = false;
|
||||
|
||||
if ($useCache) {
|
||||
if (file_exists($this->cacheFilePath)) {
|
||||
$this->data = include($this->cacheFilePath);
|
||||
if ($this->dataCache->has($this->cacheKey)) {
|
||||
$this->data = $this->dataCache->get($this->cacheKey);
|
||||
|
||||
$isFromCache = true;
|
||||
|
||||
if (!($this->data instanceof \StdClass)) {
|
||||
if (! $this->data instanceof StdClass) {
|
||||
$GLOBALS['log']->error("ACL GlobalRestricton: Bad data fetched from cache.");
|
||||
|
||||
$this->data = null;
|
||||
}
|
||||
}
|
||||
@@ -95,25 +102,25 @@ class GlobalRestricton
|
||||
|
||||
protected function storeCacheFile()
|
||||
{
|
||||
$this->getFileManager()->putPhpContents($this->cacheFilePath, $this->data, true);
|
||||
$this->dataCache->store($this->cacheKey, $this->data, true);
|
||||
}
|
||||
|
||||
protected function buildData()
|
||||
{
|
||||
$scopeList = array_keys($this->getMetadata()->get(['entityDefs'], []));
|
||||
$scopeList = array_keys($this->metadata->get(['entityDefs'], []));
|
||||
|
||||
$data = (object) [];
|
||||
|
||||
foreach ($scopeList as $scope) {
|
||||
$fieldList = array_keys($this->getMetadata()->get(['entityDefs', $scope, 'fields'], []));
|
||||
$linkList = array_keys($this->getMetadata()->get(['entityDefs', $scope, 'links'], []));
|
||||
$fieldList = array_keys($this->metadata->get(['entityDefs', $scope, 'fields'], []));
|
||||
$linkList = array_keys($this->metadata->get(['entityDefs', $scope, 'links'], []));
|
||||
|
||||
$isNotEmpty = false;
|
||||
|
||||
$scopeData = (object) [
|
||||
'fields' => (object) [],
|
||||
'attributes' => (object) [],
|
||||
'links' => (object) []
|
||||
'links' => (object) [],
|
||||
];
|
||||
|
||||
foreach ($this->fieldTypeList as $type) {
|
||||
@@ -121,10 +128,13 @@ class GlobalRestricton
|
||||
$resultAttributeList = [];
|
||||
|
||||
foreach ($fieldList as $field) {
|
||||
if ($this->getMetadata()->get(['entityAcl', $scope, 'fields', $field, $type])) {
|
||||
if ($this->metadata->get(['entityAcl', $scope, 'fields', $field, $type])) {
|
||||
$isNotEmpty = true;
|
||||
|
||||
$resultFieldList[] = $field;
|
||||
$fieldAttributeList = $this->getFieldManagerUtil()->getAttributeList($scope, $field);
|
||||
|
||||
$fieldAttributeList = $this->fieldUtil->getAttributeList($scope, $field);
|
||||
|
||||
foreach ($fieldAttributeList as $attribute) {
|
||||
$resultAttributeList[] = $attribute;
|
||||
}
|
||||
@@ -136,9 +146,11 @@ class GlobalRestricton
|
||||
}
|
||||
foreach ($this->linkTypeList as $type) {
|
||||
$resultLinkList = [];
|
||||
|
||||
foreach ($linkList as $link) {
|
||||
if ($this->getMetadata()->get(['entityAcl', $scope, 'links', $link, $type])) {
|
||||
if ($this->metadata->get(['entityAcl', $scope, 'links', $link, $type])) {
|
||||
$isNotEmpty = true;
|
||||
|
||||
$resultLinkList[] = $link;
|
||||
}
|
||||
}
|
||||
@@ -153,44 +165,52 @@ class GlobalRestricton
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
protected function getMetadata()
|
||||
public function getScopeRestrictedFieldList(string $scope, string $type) : array
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
if (!property_exists($this->data, $scope)) {
|
||||
return [];
|
||||
}
|
||||
if (!property_exists($this->data->$scope, 'fields')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function getFileManager()
|
||||
{
|
||||
return $this->fileManager;
|
||||
}
|
||||
|
||||
protected function getFieldManagerUtil()
|
||||
{
|
||||
return $this->fieldManagerUtil;
|
||||
}
|
||||
|
||||
public function getScopeRestrictedFieldList($scope, $type)
|
||||
{
|
||||
if (!property_exists($this->data, $scope)) return [];
|
||||
if (!property_exists($this->data->$scope, 'fields')) return [];
|
||||
if (!property_exists($this->data->$scope->fields, $type)) return [];
|
||||
if (!property_exists($this->data->$scope->fields, $type)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->data->$scope->fields->$type;
|
||||
}
|
||||
|
||||
public function getScopeRestrictedAttributeList($scope, $type)
|
||||
public function getScopeRestrictedAttributeList(string $scope, string $type) : array
|
||||
{
|
||||
if (!property_exists($this->data, $scope)) return [];
|
||||
if (!property_exists($this->data->$scope, 'attributes')) return [];
|
||||
if (!property_exists($this->data->$scope->attributes, $type)) return [];
|
||||
if (!property_exists($this->data, $scope)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!property_exists($this->data->$scope, 'attributes')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!property_exists($this->data->$scope->attributes, $type)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->data->$scope->attributes->$type;
|
||||
}
|
||||
|
||||
public function getScopeRestrictedLinkList($scope, $type)
|
||||
public function getScopeRestrictedLinkList(string $scope, string $type) : array
|
||||
{
|
||||
if (!property_exists($this->data, $scope)) return [];
|
||||
if (!property_exists($this->data->$scope, 'links')) return [];
|
||||
if (!property_exists($this->data->$scope->links, $type)) return [];
|
||||
if (!property_exists($this->data, $scope)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!property_exists($this->data->$scope, 'links')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!property_exists($this->data->$scope->links, $type)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->data->$scope->links->$type;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy 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\Core\Acl;
|
||||
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
/**
|
||||
* @todo Add methods.
|
||||
*/
|
||||
interface ScopeAcl
|
||||
{
|
||||
|
||||
}
|
||||
+245
-111
@@ -29,16 +29,26 @@
|
||||
|
||||
namespace Espo\Core\Acl;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
use \Espo\ORM\Entity;
|
||||
use \Espo\Entities\User;
|
||||
use Espo\Entities\User;
|
||||
|
||||
use \Espo\Core\Utils\Config;
|
||||
use \Espo\Core\Utils\Metadata;
|
||||
use \Espo\Core\Utils\FieldManagerUtil;
|
||||
use \Espo\Core\Utils\File\Manager as FileManager;
|
||||
use Espo\Core\{
|
||||
ORM\EntityManager,
|
||||
ORM\Entity,
|
||||
Utils\Config,
|
||||
Utils\Metadata,
|
||||
Utils\FieldUtil,
|
||||
Utils\DataCache,
|
||||
};
|
||||
|
||||
use StdClass;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* A table is generated for each user. Multiple roles are merged into a single table.
|
||||
* This table is used for access checking.
|
||||
*/
|
||||
class Table
|
||||
{
|
||||
protected $type = 'acl';
|
||||
@@ -47,7 +57,7 @@ class Table
|
||||
|
||||
private $data = null;
|
||||
|
||||
protected $cacheFilePath;
|
||||
protected $cacheKey;
|
||||
|
||||
protected $actionList = ['read', 'stream', 'edit', 'delete', 'create'];
|
||||
|
||||
@@ -59,26 +69,35 @@ class Table
|
||||
|
||||
protected $fieldLevelList = ['yes', 'no'];
|
||||
|
||||
protected $valuePermissionHighestLevels = array();
|
||||
protected $valuePermissionHighestLevels = [];
|
||||
|
||||
protected $valuePermissionList = [];
|
||||
|
||||
private $fileManager;
|
||||
protected $forbiddenAttributesCache = [];
|
||||
|
||||
private $metadata;
|
||||
|
||||
private $fieldManager;
|
||||
|
||||
protected $forbiddenAttributesCache = array();
|
||||
|
||||
protected $forbiddenFieldsCache = array();
|
||||
protected $forbiddenFieldsCache = [];
|
||||
|
||||
protected $isStrictModeForced = false;
|
||||
|
||||
protected $isStrictMode = false;
|
||||
|
||||
public function __construct(User $user, Config $config = null, FileManager $fileManager = null, Metadata $metadata = null, FieldManagerUtil $fieldManager = null)
|
||||
{
|
||||
protected $entityManager;
|
||||
protected $user;
|
||||
protected $config;
|
||||
protected $metadata;
|
||||
protected $fieldUtil;
|
||||
protected $dataCache;
|
||||
|
||||
public function __construct(
|
||||
EntityManager $entityManager,
|
||||
User $user,
|
||||
Config $config = null,
|
||||
Metadata $metadata = null,
|
||||
FieldUtil $fieldUtil = null,
|
||||
DataCache $dataCache
|
||||
) {
|
||||
$this->entityManager = $entityManager;
|
||||
|
||||
$this->data = (object) [
|
||||
'table' => (object) [],
|
||||
'fieldTable' => (object) [],
|
||||
@@ -92,39 +111,34 @@ class Table
|
||||
}
|
||||
|
||||
$this->user = $user;
|
||||
|
||||
$this->metadata = $metadata;
|
||||
|
||||
if ($fieldManager) {
|
||||
$this->fieldManager = $fieldManager;
|
||||
}
|
||||
$this->fieldUtil = $fieldUtil;
|
||||
$this->dataCache = $dataCache;
|
||||
|
||||
if (!$this->user->isFetched()) {
|
||||
throw new Error('User must be fetched before ACL check.');
|
||||
}
|
||||
|
||||
if ($fileManager) {
|
||||
$this->fileManager = $fileManager;
|
||||
}
|
||||
$this->valuePermissionList = $this->metadata->get(['app', $this->type, 'valuePermissionList'], []);
|
||||
$this->valuePermissionHighestLevels = $this->metadata->get(['app', $this->type, 'valuePermissionHighestLevels'], array());
|
||||
$this->valuePermissionHighestLevels = $this->metadata->get(['app', $this->type, 'valuePermissionHighestLevels'], []);
|
||||
|
||||
$this->initCacheFilePath();
|
||||
$this->initCacheKey();
|
||||
|
||||
if ($config && $config->get('useCache') && file_exists($this->cacheFilePath)) {
|
||||
$cached = include $this->cacheFilePath;
|
||||
$this->data = $cached;
|
||||
} else {
|
||||
if ($config && $config->get('useCache') && $this->dataCache->has($this->cacheKey)) {
|
||||
$this->data = $this->dataCache->get($this->cacheKey);
|
||||
}
|
||||
else {
|
||||
$this->load();
|
||||
if ($config && $fileManager && $config->get('useCache')) {
|
||||
|
||||
if ($config && $config->get('useCache')) {
|
||||
$this->buildCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function initCacheFilePath()
|
||||
protected function initCacheKey()
|
||||
{
|
||||
$this->cacheFilePath = 'data/cache/application/acl/' . $this->getUser()->id . '.php';
|
||||
$this->cacheKey = 'acl/' . $this->getUser()->id;
|
||||
}
|
||||
|
||||
protected function getUser()
|
||||
@@ -137,12 +151,12 @@ class Table
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
protected function getFieldManager()
|
||||
protected function getFieldUtil()
|
||||
{
|
||||
return $this->fieldManager;
|
||||
return $this->fieldUtil;
|
||||
}
|
||||
|
||||
public function getMap()
|
||||
public function getMap() : StdClass
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
@@ -151,16 +165,20 @@ class Table
|
||||
{
|
||||
if (isset($this->data->table->$scope)) {
|
||||
$data = $this->data->table->$scope;
|
||||
|
||||
if (is_string($data)) {
|
||||
$data = $this->getScopeData($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function get($permission)
|
||||
public function get(string $permission) : ?string
|
||||
{
|
||||
if ($permission == 'table') {
|
||||
return null;
|
||||
@@ -169,32 +187,36 @@ class Table
|
||||
if (isset($this->data->$permission)) {
|
||||
return $this->data->$permission;
|
||||
}
|
||||
|
||||
return 'no';
|
||||
}
|
||||
|
||||
public function getLevel($scope, $action)
|
||||
public function getLevel(string $scope, string $action) : string
|
||||
{
|
||||
if (isset($this->data->table->$scope)) {
|
||||
if (isset($this->data->table->$scope->$action)) {
|
||||
return $this->data->table->$scope->$action;
|
||||
}
|
||||
}
|
||||
|
||||
return 'no';
|
||||
}
|
||||
|
||||
public function getHighestLevel($scope, $action)
|
||||
public function getHighestLevel(string $scope, string $action) : string
|
||||
{
|
||||
if (in_array($action, $this->booleanActionList)) {
|
||||
return 'yes';
|
||||
} else {
|
||||
$level = $this->metadata->get(['scopes', $scope, $this->type . 'HighestLevel']);
|
||||
return $level ?? 'all';
|
||||
}
|
||||
|
||||
$level = $this->metadata->get(['scopes', $scope, $this->type . 'HighestLevel']);
|
||||
|
||||
return $level ?? 'all';
|
||||
}
|
||||
|
||||
private function load()
|
||||
{
|
||||
$valuePermissionLists = (object)[];
|
||||
$valuePermissionLists = (object) [];
|
||||
|
||||
foreach ($this->valuePermissionList as $permission) {
|
||||
$valuePermissionLists->$permission = [];
|
||||
}
|
||||
@@ -208,6 +230,7 @@ class Table
|
||||
foreach ($roleList as $role) {
|
||||
$aclTableList[] = $role->get('data');
|
||||
$fieldTableList[] = $role->get('fieldData');
|
||||
|
||||
foreach ($this->valuePermissionList as $permission) {
|
||||
$valuePermissionLists->{$permission}[] = $role->get($permission);
|
||||
}
|
||||
@@ -220,17 +243,20 @@ class Table
|
||||
$this->applyDisabled($aclTable, $fieldTable);
|
||||
$this->applyMandatory($aclTable, $fieldTable);
|
||||
$this->applyAdditional($aclTable, $fieldTable, $valuePermissionLists);
|
||||
$this->applyReadOnlyFields($fieldTable);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$aclTable = (object) [];
|
||||
|
||||
foreach ($this->getScopeList() as $scope) {
|
||||
if ($this->metadata->get("scopes.{$scope}.{$this->type}") === 'boolean') {
|
||||
$aclTable->$scope = true;
|
||||
} else {
|
||||
if ($this->metadata->get("scopes.{$scope}.entity")) {
|
||||
$aclTable->$scope = (object) [];
|
||||
|
||||
foreach ($this->actionList as $action) {
|
||||
$aclTable->$scope->$action = 'all';
|
||||
|
||||
if (in_array($action, $this->booleanActionList)) {
|
||||
$aclTable->$scope->$action = 'yes';
|
||||
}
|
||||
@@ -256,11 +282,17 @@ class Table
|
||||
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
$permissionsDefaultsGroupName = 'permissionsDefaults';
|
||||
|
||||
if ($this->isStrictMode) {
|
||||
$permissionsDefaultsGroupName = 'permissionsStrictDefaults';
|
||||
}
|
||||
|
||||
foreach ($this->valuePermissionList as $permission) {
|
||||
$this->data->$permission = $this->mergeValueList($valuePermissionLists->$permission, $this->metadata->get(['app', $this->type, $permissionsDefaultsGroupName, $permission, 'yes']));
|
||||
$this->data->$permission = $this->mergeValueList(
|
||||
$valuePermissionLists->$permission,
|
||||
$this->metadata->get(['app', $this->type, $permissionsDefaultsGroupName, $permission, 'yes'])
|
||||
);
|
||||
|
||||
if ($this->metadata->get('app.'.$this->type.'.mandatory.' . $permission)) {
|
||||
$this->data->$permission = $this->metadata->get('app.'.$this->type.'.mandatory.' . $permission);
|
||||
}
|
||||
@@ -270,8 +302,10 @@ class Table
|
||||
foreach ($this->valuePermissionList as $permission) {
|
||||
if (isset($this->valuePermissionHighestLevels[$permission])) {
|
||||
$this->data->$permission = $this->valuePermissionHighestLevels[$permission];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->data->$permission = 'all';
|
||||
}
|
||||
}
|
||||
@@ -281,20 +315,34 @@ class Table
|
||||
{
|
||||
$roleList = [];
|
||||
|
||||
$userRoleList = $this->getUser()->get('roles');
|
||||
if (!(is_array($userRoleList) || $userRoleList instanceof \Traversable)) {
|
||||
$userRoleList = $this->entityManager
|
||||
->getRepository('User')
|
||||
->getRelation($this->getUser(), 'roles')
|
||||
->find();
|
||||
|
||||
if (! $userRoleList instanceof Traversable) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
foreach ($userRoleList as $role) {
|
||||
$roleList[] = $role;
|
||||
}
|
||||
|
||||
$teamList = $this->getUser()->get('teams');
|
||||
if (!(is_array($teamList) || $teamList instanceof \Traversable)) {
|
||||
$teamList = $this->entityManager
|
||||
->getRepository('User')
|
||||
->getRelation($this->getUser(), 'teams')
|
||||
->find();
|
||||
|
||||
if (! $teamList instanceof Traversable) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
foreach ($teamList as $team) {
|
||||
$teamRoleList = $team->get('roles');
|
||||
$teamRoleList = $this->entityManager
|
||||
->getRepository('Team')
|
||||
->getRelation($team, 'roles')
|
||||
->find();
|
||||
|
||||
foreach ($teamRoleList as $role) {
|
||||
$roleList[] = $role;
|
||||
}
|
||||
@@ -303,21 +351,27 @@ class Table
|
||||
return $roleList;
|
||||
}
|
||||
|
||||
public function getScopeForbiddenAttributeList($scope, $action = 'read', $thresholdLevel = 'no')
|
||||
public function getScopeForbiddenAttributeList(string $scope, string $action = 'read', string $thresholdLevel = 'no') : array
|
||||
{
|
||||
$key = $scope . '_'. $action . '_' . $thresholdLevel;
|
||||
|
||||
if (isset($this->forbiddenAttributesCache[$key])) {
|
||||
return $this->forbiddenAttributesCache[$key];
|
||||
}
|
||||
|
||||
$fieldTableQuickAccess = $this->data->fieldTableQuickAccess;
|
||||
|
||||
if (!isset($fieldTableQuickAccess->$scope) || !isset($fieldTableQuickAccess->$scope->attributes) || !isset($fieldTableQuickAccess->$scope->attributes->$action)) {
|
||||
if (
|
||||
!isset($fieldTableQuickAccess->$scope) || !isset($fieldTableQuickAccess->$scope->attributes) ||
|
||||
!isset($fieldTableQuickAccess->$scope->attributes->$action)
|
||||
) {
|
||||
$this->forbiddenAttributesCache[$key] = [];
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
$levelList = [];
|
||||
|
||||
foreach ($this->fieldLevelList as $level) {
|
||||
if (array_search($level, $this->fieldLevelList) >= array_search($thresholdLevel, $this->fieldLevelList)) {
|
||||
$levelList[] = $level;
|
||||
@@ -327,9 +381,15 @@ class Table
|
||||
$attributeList = [];
|
||||
|
||||
foreach ($levelList as $level) {
|
||||
if (!isset($fieldTableQuickAccess->$scope->attributes->$action->$level)) continue;
|
||||
if (!isset($fieldTableQuickAccess->$scope->attributes->$action->$level)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($fieldTableQuickAccess->$scope->attributes->$action->$level as $attribute) {
|
||||
if (in_array($attribute, $attributeList)) continue;
|
||||
if (in_array($attribute, $attributeList)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attributeList[] = $attribute;
|
||||
}
|
||||
}
|
||||
@@ -339,7 +399,7 @@ class Table
|
||||
return $attributeList;
|
||||
}
|
||||
|
||||
public function getScopeForbiddenFieldList($scope, $action = 'read', $thresholdLevel = 'no')
|
||||
public function getScopeForbiddenFieldList(string $scope, string $action = 'read', string $thresholdLevel = 'no') : array
|
||||
{
|
||||
$key = $scope . '_'. $action . '_' . $thresholdLevel;
|
||||
if (isset($this->forbiddenFieldsCache[$key])) {
|
||||
@@ -348,12 +408,17 @@ class Table
|
||||
|
||||
$fieldTableQuickAccess = $this->data->fieldTableQuickAccess;
|
||||
|
||||
if (!isset($fieldTableQuickAccess->$scope) || !isset($fieldTableQuickAccess->$scope->fields) || !isset($fieldTableQuickAccess->$scope->fields->$action)) {
|
||||
if (
|
||||
!isset($fieldTableQuickAccess->$scope) || !isset($fieldTableQuickAccess->$scope->fields) ||
|
||||
!isset($fieldTableQuickAccess->$scope->fields->$action)
|
||||
) {
|
||||
$this->forbiddenFieldsCache[$key] = [];
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
$levelList = [];
|
||||
|
||||
foreach ($this->fieldLevelList as $level) {
|
||||
if (array_search($level, $this->fieldLevelList) >= array_search($thresholdLevel, $this->fieldLevelList)) {
|
||||
$levelList[] = $level;
|
||||
@@ -363,9 +428,15 @@ class Table
|
||||
$fieldList = [];
|
||||
|
||||
foreach ($levelList as $level) {
|
||||
if (!isset($fieldTableQuickAccess->$scope->fields->$action->$level)) continue;
|
||||
if (!isset($fieldTableQuickAccess->$scope->fields->$action->$level)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($fieldTableQuickAccess->$scope->fields->$action->$level as $field) {
|
||||
if (in_array($field, $fieldList)) continue;
|
||||
if (in_array($field, $fieldList)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldList[] = $field;
|
||||
}
|
||||
}
|
||||
@@ -390,6 +461,7 @@ class Table
|
||||
foreach ($this->fieldActionList as $action) {
|
||||
$fieldTableQuickAccess->$scope->attributes->$action = (object) [];
|
||||
$fieldTableQuickAccess->$scope->fields->$action = (object) [];
|
||||
|
||||
foreach ($this->fieldLevelList as $level) {
|
||||
$fieldTableQuickAccess->$scope->attributes->$action->$level = [];
|
||||
$fieldTableQuickAccess->$scope->fields->$action->$level = [];
|
||||
@@ -397,13 +469,17 @@ class Table
|
||||
}
|
||||
|
||||
foreach (get_object_vars($scopeData) as $field => $fieldData) {
|
||||
$attributeList = $this->getFieldManager()->getAttributeList($scope, $field);
|
||||
$attributeList = $this->getFieldUtil()->getAttributeList($scope, $field);
|
||||
|
||||
foreach ($this->fieldActionList as $action) {
|
||||
if (!isset($fieldData->$action)) continue;
|
||||
if (!isset($fieldData->$action)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($this->fieldLevelList as $level) {
|
||||
if ($fieldData->$action === $level) {
|
||||
$fieldTableQuickAccess->$scope->fields->$action->{$level}[] = $field;
|
||||
|
||||
foreach ($attributeList as $attribute) {
|
||||
$fieldTableQuickAccess->$scope->attributes->$action->{$level}[] = $attribute;
|
||||
}
|
||||
@@ -423,6 +499,7 @@ class Table
|
||||
}
|
||||
|
||||
$defaultsGroupName = 'default';
|
||||
|
||||
if ($this->isStrictMode) {
|
||||
$defaultsGroupName = 'strictDefault';
|
||||
}
|
||||
@@ -430,33 +507,53 @@ class Table
|
||||
$data = $this->metadata->get(['app', $this->type, $defaultsGroupName, 'scopeLevel'], []);
|
||||
|
||||
foreach ($data as $scope => $item) {
|
||||
if (isset($table->$scope)) continue;
|
||||
if (isset($table->$scope)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $item;
|
||||
|
||||
if (is_array($item)) {
|
||||
$value = (object) $item;
|
||||
}
|
||||
|
||||
$table->$scope = $value;
|
||||
}
|
||||
|
||||
$defaultFieldData = $this->metadata->get(['app', $this->type, $defaultsGroupName, 'fieldLevel'], []);
|
||||
|
||||
foreach ($this->getScopeList() as $scope) {
|
||||
if (isset($table->$scope) && $table->$scope === false) continue;
|
||||
if (!$this->getMetadata()->get('scopes.' . $scope . '.entity')) continue;
|
||||
if (isset($table->$scope) && $table->$scope === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->getMetadata()->get('scopes.' . $scope . '.entity')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldList = array_keys($this->getMetadata()->get("entityDefs.{$scope}.fields", []));
|
||||
|
||||
$defaultScopeFieldData = $this->metadata->get('app.'.$this->type.'.'.$defaultsGroupName.'.scopeFieldLevel.' . $scope, []);
|
||||
$defaultScopeFieldData = $this->metadata->get(
|
||||
'app.'.$this->type.'.'.$defaultsGroupName.'.scopeFieldLevel.' . $scope, []);
|
||||
|
||||
foreach (array_merge($defaultFieldData, $defaultScopeFieldData) as $field => $f) {
|
||||
if (!in_array($field, $fieldList)) continue;
|
||||
if (!in_array($field, $fieldList)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($fieldTable->$scope)) {
|
||||
$fieldTable->$scope = (object) [];
|
||||
}
|
||||
if (isset($fieldTable->$scope->$field)) continue;
|
||||
|
||||
if (isset($fieldTable->$scope->$field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldTable->$scope->$field = (object) [];
|
||||
|
||||
foreach ($this->fieldActionList as $action) {
|
||||
$level = 'no';
|
||||
|
||||
if ($f === true) {
|
||||
$level = 'yes';
|
||||
} else {
|
||||
@@ -472,22 +569,32 @@ class Table
|
||||
foreach ($this->getScopeWithAclList() as $scope) {
|
||||
if (!isset($table->$scope)) {
|
||||
$aclType = $this->metadata->get('scopes.' . $scope . '.' . $this->type);
|
||||
|
||||
if ($aclType === true) {
|
||||
$aclType = $this->defaultAclType;
|
||||
}
|
||||
|
||||
if (!empty($aclType)) {
|
||||
$paramDefaultsName = 'scopeLevelTypesDefaults';
|
||||
|
||||
if ($this->isStrictMode) {
|
||||
$paramDefaultsName = 'scopeLevelTypesStrictDefaults';
|
||||
}
|
||||
$defaultValue = $this->metadata->get(['app', $this->type, $paramDefaultsName, $aclType], $this->metadata->get(['app', $this->type, $paramDefaultsName, 'record']));
|
||||
|
||||
$defaultValue = $this->metadata->get(
|
||||
['app', $this->type, $paramDefaultsName, $aclType],
|
||||
$this->metadata->get(['app', $this->type, $paramDefaultsName, 'record'])
|
||||
);
|
||||
|
||||
if (is_array($defaultValue)) {
|
||||
$defaultValue = (object) $defaultValue;
|
||||
}
|
||||
|
||||
$table->$scope = $defaultValue;
|
||||
|
||||
if (is_object($table->$scope)) {
|
||||
$actionList = $this->getMetadata()->get(['scopes', $scope, $this->type . 'ActionList']);
|
||||
|
||||
if ($actionList) {
|
||||
foreach (get_object_vars($table->$scope) as $action => $level) {
|
||||
if (!in_array($action, $actionList)) {
|
||||
@@ -511,30 +618,43 @@ class Table
|
||||
|
||||
foreach ($data as $scope => $item) {
|
||||
$value = $item;
|
||||
|
||||
if (is_array($item)) {
|
||||
$value = (object) $item;
|
||||
}
|
||||
|
||||
$table->$scope = $value;
|
||||
}
|
||||
|
||||
$mandatoryFieldData = $this->metadata->get('app.'.$this->type.'.mandatory.fieldLevel', array());
|
||||
|
||||
foreach ($this->getScopeList() as $scope) {
|
||||
if (isset($table->$scope) && $table->$scope === false) continue;
|
||||
if (!$this->getMetadata()->get('scopes.' . $scope . '.entity')) continue;
|
||||
if (isset($table->$scope) && $table->$scope === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->getMetadata()->get('scopes.' . $scope . '.entity')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldList = array_keys($this->getMetadata()->get("entityDefs.{$scope}.fields", []));
|
||||
|
||||
$mandatoryScopeFieldData = $this->metadata->get('app.'.$this->type.'.mandatory.scopeFieldLevel.' . $scope, array());
|
||||
|
||||
foreach (array_merge($mandatoryFieldData, $mandatoryScopeFieldData) as $field => $f) {
|
||||
if (!in_array($field, $fieldList)) continue;
|
||||
if (!in_array($field, $fieldList)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($fieldTable->$scope)) {
|
||||
$fieldTable->$scope = (object) [];
|
||||
}
|
||||
|
||||
$fieldTable->$scope->$field = (object) [];
|
||||
|
||||
foreach ($this->fieldActionList as $action) {
|
||||
$level = 'no';
|
||||
|
||||
if ($f === true) {
|
||||
$level = 'yes';
|
||||
} else {
|
||||
@@ -569,6 +689,7 @@ class Table
|
||||
$table->$scope = false;
|
||||
unset($fieldTable->$scope);
|
||||
}
|
||||
|
||||
foreach ($this->valuePermissionList as $permission) {
|
||||
$valuePermissionLists->{$permission}[] = 'no';
|
||||
}
|
||||
@@ -578,29 +699,38 @@ class Table
|
||||
private function mergeValueList(array $list, $defaultValue)
|
||||
{
|
||||
$result = null;
|
||||
|
||||
foreach ($list as $level) {
|
||||
if ($level != 'not-set') {
|
||||
if (is_null($result)) {
|
||||
$result = $level;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (array_search($result, $this->levelList) > array_search($level, $this->levelList)) {
|
||||
$result = $level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($result)) {
|
||||
$result = $defaultValue;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function getScopeWithAclList()
|
||||
{
|
||||
$scopeList = [];
|
||||
|
||||
$scopes = $this->metadata->get('scopes');
|
||||
|
||||
foreach ($scopes as $scope => $d) {
|
||||
if (empty($d['acl'])) continue;
|
||||
if (empty($d['acl'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$scopeList[] = $scope;
|
||||
}
|
||||
return $scopeList;
|
||||
@@ -609,10 +739,13 @@ class Table
|
||||
protected function getScopeList()
|
||||
{
|
||||
$scopeList = [];
|
||||
|
||||
$scopes = $this->metadata->get('scopes');
|
||||
|
||||
foreach ($scopes as $scope => $d) {
|
||||
$scopeList[] = $scope;
|
||||
}
|
||||
|
||||
return $scopeList;
|
||||
}
|
||||
|
||||
@@ -623,7 +756,9 @@ class Table
|
||||
|
||||
foreach ($tableList as $table) {
|
||||
foreach ($scopeList as $scope) {
|
||||
if (!isset($table->$scope)) continue;
|
||||
if (!isset($table->$scope)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$row = $table->$scope;
|
||||
|
||||
@@ -631,9 +766,11 @@ class Table
|
||||
if (!isset($data->$scope)) {
|
||||
$data->$scope = false;
|
||||
}
|
||||
} else if ($row === true) {
|
||||
}
|
||||
else if ($row === true) {
|
||||
$data->$scope = true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (!isset($data->$scope)) {
|
||||
$data->$scope = (object) [];
|
||||
}
|
||||
@@ -641,7 +778,9 @@ class Table
|
||||
$data->$scope = (object) [];
|
||||
}
|
||||
|
||||
if (!is_object($row)) continue;
|
||||
if (!is_object($row)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$actionList = $this->getMetadata()->get(['scopes', $scope, $this->type . 'ActionList'], $this->actionList);
|
||||
|
||||
@@ -651,7 +790,9 @@ class Table
|
||||
if (!isset($data->$scope->$action)) {
|
||||
$data->$scope->$action = $level;
|
||||
} else {
|
||||
if (array_search($data->$scope->$action, $this->levelList) > array_search($level, $this->levelList)) {
|
||||
if (
|
||||
array_search($data->$scope->$action, $this->levelList) > array_search($level, $this->levelList)
|
||||
) {
|
||||
$data->$scope->$action = $level;
|
||||
}
|
||||
}
|
||||
@@ -679,37 +820,54 @@ class Table
|
||||
private function mergeFieldTableList(array $tableList)
|
||||
{
|
||||
$data = (object) [];
|
||||
|
||||
$scopeList = $this->getScopeWithAclList();
|
||||
|
||||
foreach ($tableList as $table) {
|
||||
foreach ($scopeList as $scope) {
|
||||
if (!isset($table->$scope)) continue;
|
||||
if (!isset($table->$scope)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($data->$scope)) {
|
||||
$data->$scope = (object) [];
|
||||
}
|
||||
|
||||
if (!is_object($table->$scope)) continue;
|
||||
if (!is_object($table->$scope)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldList = array_keys($this->getMetadata()->get("entityDefs.{$scope}.fields", []));
|
||||
|
||||
foreach (get_object_vars($table->$scope) as $field => $row) {
|
||||
if (!is_object($row)) continue;
|
||||
if (!is_object($row)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_array($field, $fieldList)) continue;
|
||||
if (!in_array($field, $fieldList)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($data->$scope->$field)) {
|
||||
$data->$scope->$field = (object) [];
|
||||
}
|
||||
|
||||
foreach ($this->fieldActionList as $i => $action) {
|
||||
if (!isset($row->$action)) continue;
|
||||
if (!isset($row->$action)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$level = $row->$action;
|
||||
|
||||
if (!isset($data->$scope->$field->$action)) {
|
||||
$data->$scope->$field->$action = $level;
|
||||
} else {
|
||||
if (array_search($data->$scope->$field->$action, $this->fieldLevelList) > array_search($level, $this->fieldLevelList)) {
|
||||
if (
|
||||
array_search(
|
||||
$data->$scope->$field->$action,
|
||||
$this->fieldLevelList
|
||||
) > array_search($level, $this->fieldLevelList)
|
||||
) {
|
||||
$data->$scope->$field->$action = $level;
|
||||
}
|
||||
}
|
||||
@@ -723,30 +881,6 @@ class Table
|
||||
|
||||
private function buildCache()
|
||||
{
|
||||
$this->fileManager->putPhpContents($this->cacheFilePath, $this->data, true);
|
||||
}
|
||||
|
||||
protected function applyReadOnlyFields(&$fieldTable)
|
||||
{
|
||||
// TODO Enable in 5.4.0
|
||||
return;
|
||||
$scopeList = $this->getScopeWithAclList();
|
||||
foreach ($scopeList as $scope) {
|
||||
if (!property_exists($fieldTable, $scope)) continue;
|
||||
$fieldList = array_keys($this->getMetadata()->get(['entityDefs', $scope, 'fields'], []));
|
||||
foreach ($fieldList as $field) {
|
||||
if ($this->getMetadata()->get(['entityDefs', $scope, 'fields', $field, 'readOnly'])) {
|
||||
if (property_exists($fieldTable->$scope, $field)) {
|
||||
$fieldTable->$scope->$field->edit = 'no';
|
||||
} else {
|
||||
$fieldTable->$scope->$field = (object) [];
|
||||
foreach ($this->fieldActionList as $action) {
|
||||
$fieldTable->$scope->$field->$action = 'yes';
|
||||
}
|
||||
$fieldTable->$scope->$field->edit = 'no';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->dataCache->store($this->cacheKey, $this->data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,79 +29,78 @@
|
||||
|
||||
namespace Espo\Core;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
use \Espo\ORM\Entity;
|
||||
use \Espo\Entities\User;
|
||||
use \Espo\Core\Utils\Util;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\{
|
||||
Utils\ClassFinder,
|
||||
Utils\Config,
|
||||
ORM\EntityManager,
|
||||
Acl\Acl as BaseAcl,
|
||||
Acl\ScopeAcl,
|
||||
Acl\GlobalRestricton,
|
||||
Acl as UserAclWrapper,
|
||||
Acl\Table as AclTable,
|
||||
Utils\Util,
|
||||
};
|
||||
|
||||
use StdClass;
|
||||
|
||||
/**
|
||||
* Used to check access for a specific user.
|
||||
*/
|
||||
class AclManager
|
||||
{
|
||||
private $container;
|
||||
|
||||
private $metadata;
|
||||
|
||||
private $implementationHashMap = [];
|
||||
|
||||
private $tableHashMap = [];
|
||||
|
||||
protected $tableClassName = '\\Espo\\Core\\Acl\\Table';
|
||||
protected $tableClassName = AclTable::class;
|
||||
|
||||
protected $userAclClassName = '\\Espo\\Core\\Acl';
|
||||
protected $userAclClassName = UserAclWrapper::class;
|
||||
|
||||
protected $baseImplementationClassName = BaseAcl::class;
|
||||
|
||||
protected $globalRestricton;
|
||||
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->metadata = $container->get('metadata');
|
||||
protected $injectableFactory;
|
||||
protected $classFinder;
|
||||
protected $config;
|
||||
protected $entityManager;
|
||||
|
||||
$this->globalRestricton = new \Espo\Core\Acl\GlobalRestricton(
|
||||
$container->get('metadata'),
|
||||
$container->get('fileManager'),
|
||||
$container->get('fieldManagerUtil'),
|
||||
$container->get('config')->get('useCache')
|
||||
);
|
||||
public function __construct(
|
||||
InjectableFactory $injectableFactory, ClassFinder $classFinder, Config $config, EntityManager $entityManager
|
||||
) {
|
||||
$this->injectableFactory = $injectableFactory;
|
||||
$this->classFinder = $classFinder;
|
||||
$this->config = $config;
|
||||
$this->entityManager = $entityManager;
|
||||
|
||||
$this->globalRestricton = $this->injectableFactory->createWith(GlobalRestricton::class, [
|
||||
'useCache' => $config->get('useCache'),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getContainer()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
protected function getMetadata()
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
public function getImplementation($scope)
|
||||
public function getImplementation(string $scope) : ScopeAcl
|
||||
{
|
||||
if (empty($this->implementationHashMap[$scope])) {
|
||||
$normalizedName = Util::normilizeClassName($scope);
|
||||
$className = $this->classFinder->find('Acl', $scope);
|
||||
|
||||
if (!$className) {
|
||||
$className = $this->baseImplementationClassName;
|
||||
}
|
||||
|
||||
$className = '\\Espo\\Custom\\Acl\\' . $normalizedName;
|
||||
if (!class_exists($className)) {
|
||||
$moduleName = $this->metadata->getScopeModuleName($scope);
|
||||
if ($moduleName) {
|
||||
$className = '\\Espo\\Modules\\' . $moduleName . '\\Acl\\' . $normalizedName;
|
||||
} else {
|
||||
$className = '\\Espo\\Acl\\' . $normalizedName;
|
||||
}
|
||||
if (!class_exists($className)) {
|
||||
$className = '\\Espo\\Core\\Acl\\Base';
|
||||
}
|
||||
throw new Error("{$className} does not exist.");
|
||||
}
|
||||
|
||||
if (class_exists($className)) {
|
||||
$acl = new $className($scope);
|
||||
$dependencyList = $acl->getDependencyList();
|
||||
foreach ($dependencyList as $name) {
|
||||
$acl->inject($name, $this->getContainer()->get($name));
|
||||
}
|
||||
$this->implementationHashMap[$scope] = $acl;
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
$acl = $this->injectableFactory->createWith($className, [
|
||||
'scope' => $scope,
|
||||
]);
|
||||
|
||||
$this->implementationHashMap[$scope] = $acl;
|
||||
}
|
||||
|
||||
return $this->implementationHashMap[$scope];
|
||||
@@ -110,80 +109,115 @@ class AclManager
|
||||
protected function getTable(User $user)
|
||||
{
|
||||
$key = $user->id;
|
||||
|
||||
if (empty($key)) {
|
||||
$key = spl_object_hash($user);
|
||||
}
|
||||
|
||||
if (empty($this->tableHashMap[$key])) {
|
||||
$config = $this->getContainer()->get('config');
|
||||
$fileManager = $this->getContainer()->get('fileManager');
|
||||
$metadata = $this->getContainer()->get('metadata');
|
||||
$fieldManager = $this->getContainer()->get('fieldManagerUtil');
|
||||
|
||||
$this->tableHashMap[$key] = new $this->tableClassName($user, $config, $fileManager, $metadata, $fieldManager);
|
||||
$this->tableHashMap[$key] = $this->injectableFactory->createWith($this->tableClassName, [
|
||||
'user' => $user,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->tableHashMap[$key];
|
||||
}
|
||||
|
||||
public function getMap(User $user)
|
||||
public function getMap(User $user) : StdClass
|
||||
{
|
||||
return $this->getTable($user)->getMap();
|
||||
}
|
||||
|
||||
public function getLevel(User $user, $scope, $action)
|
||||
/**
|
||||
* Get an access level for a specific scope and action.
|
||||
*/
|
||||
public function getLevel(User $user, string $scope, string $action) : string
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return $this->getTable($user)->getHighestLevel($scope, $action);
|
||||
}
|
||||
|
||||
return $this->getTable($user)->getLevel($scope, $action);
|
||||
}
|
||||
|
||||
public function get(User $user, $permission)
|
||||
/**
|
||||
* Get a permission. E.g. 'assignment' permission.
|
||||
*/
|
||||
public function get(User $user, string $permission) : ?string
|
||||
{
|
||||
if (substr($permission, -10) !== 'Permission') {
|
||||
$permission .= 'Permission';
|
||||
}
|
||||
|
||||
return $this->getTable($user)->get($permission);
|
||||
}
|
||||
|
||||
public function checkReadNo(User $user, $scope)
|
||||
/**
|
||||
* Whether there's no 'read' access for a specific scope.
|
||||
*/
|
||||
public function checkReadNo(User $user, string $scope) : bool
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = $this->getTable($user)->getScopeData($scope);
|
||||
return $this->getImplementation($scope)->checkReadNo($user, $data);
|
||||
|
||||
return (bool) $this->getImplementation($scope)->checkReadNo($user, $data);
|
||||
}
|
||||
|
||||
public function checkReadOnlyTeam(User $user, $scope)
|
||||
/**
|
||||
* Whether 'read' access is set to 'team' for a specific scope.
|
||||
*/
|
||||
public function checkReadOnlyTeam(User $user, string $scope) : bool
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = $this->getTable($user)->getScopeData($scope);
|
||||
return $this->getImplementation($scope)->checkReadOnlyTeam($user, $data);
|
||||
|
||||
return (bool) $this->getImplementation($scope)->checkReadOnlyTeam($user, $data);
|
||||
}
|
||||
|
||||
public function checkReadOnlyOwn(User $user, $scope)
|
||||
/**
|
||||
* Whether 'read' access is set to 'own' for a specific scope.
|
||||
*/
|
||||
public function checkReadOnlyOwn(User $user, string $scope) : bool
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = $this->getTable($user)->getScopeData($scope);
|
||||
return $this->getImplementation($scope)->checkReadOnlyOwn($user, $data);
|
||||
|
||||
return (bool) $this->getImplementation($scope)->checkReadOnlyOwn($user, $data);
|
||||
}
|
||||
|
||||
public function check(User $user, $subject, $action = null)
|
||||
/**
|
||||
* Check a scope or entity. If $action is omitted, it will check whether a scope level is set to 'enabled'.
|
||||
*/
|
||||
public function check(User $user, $subject, ?string $action = null) : bool
|
||||
{
|
||||
if (is_string($subject)) {
|
||||
return $this->checkScope($user, $subject, $action);
|
||||
} else {
|
||||
$entity = $subject;
|
||||
if ($entity instanceof Entity) {
|
||||
return $this->checkEntity($user, $entity, $action);
|
||||
}
|
||||
}
|
||||
|
||||
$entity = $subject;
|
||||
|
||||
if ($entity instanceof Entity) {
|
||||
$action = $action ?? 'read';
|
||||
|
||||
return $this->checkEntity($user, $entity, $action);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkEntity(User $user, Entity $entity, $action = 'read')
|
||||
/**
|
||||
* Check access to a specific entity (record).
|
||||
*/
|
||||
public function checkEntity(User $user, Entity $entity, string $action = 'read') : bool
|
||||
{
|
||||
$scope = $entity->getEntityType();
|
||||
|
||||
@@ -197,60 +231,79 @@ class AclManager
|
||||
|
||||
if ($action) {
|
||||
$methodName = 'checkEntity' . ucfirst($action);
|
||||
|
||||
if (method_exists($impl, $methodName)) {
|
||||
return $impl->$methodName($user, $entity, $data);
|
||||
return (bool) $impl->$methodName($user, $entity, $data);
|
||||
}
|
||||
}
|
||||
|
||||
return $impl->checkEntity($user, $entity, $data, $action);
|
||||
return (bool) $impl->checkEntity($user, $entity, $data, $action);
|
||||
}
|
||||
|
||||
public function checkIsOwner(User $user, Entity $entity)
|
||||
/**
|
||||
* Whether a user is owned of an entity (record). Usually 'assignedUser' field is used for checking.
|
||||
*/
|
||||
public function checkIsOwner(User $user, Entity $entity) : bool
|
||||
{
|
||||
return $this->getImplementation($entity->getEntityType())->checkIsOwner($user, $entity);
|
||||
return (bool) $this->getImplementation($entity->getEntityType())->checkIsOwner($user, $entity);
|
||||
}
|
||||
|
||||
public function checkInTeam(User $user, Entity $entity)
|
||||
/**
|
||||
* Whether a user team list overlaps with teams set in an entity.
|
||||
*/
|
||||
public function checkInTeam(User $user, Entity $entity) : bool
|
||||
{
|
||||
return $this->getImplementation($entity->getEntityType())->checkInTeam($user, $entity);
|
||||
return (bool) $this->getImplementation($entity->getEntityType())->checkInTeam($user, $entity);
|
||||
}
|
||||
|
||||
public function checkScope(User $user, $scope, $action = null)
|
||||
/**
|
||||
* Check access to scope. If $action is omitted, it will check whether a scope level is set to 'enabled'.
|
||||
*/
|
||||
public function checkScope(User $user, string $scope, ?string $action = null) : bool
|
||||
{
|
||||
$data = $this->getTable($user)->getScopeData($scope);
|
||||
return $this->getImplementation($scope)->checkScope($user, $data, $action);
|
||||
|
||||
return (bool) $this->getImplementation($scope)->checkScope($user, $data, $action);
|
||||
}
|
||||
|
||||
public function checkUser(User $user, $permission, User $entity)
|
||||
/**
|
||||
* @deprecated Use checkUserPermission instead.
|
||||
*/
|
||||
public function checkUser(User $user, string $permission, User $target) : bool
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->get($user, $permission) === 'no') {
|
||||
if ($entity->id !== $user->id) {
|
||||
if ($target->id !== $user->id) {
|
||||
return false;
|
||||
}
|
||||
} else if ($this->get($user, $permission) === 'team') {
|
||||
if ($entity->id != $user->id) {
|
||||
if ($target->id != $user->id) {
|
||||
$teamIdList1 = $user->getTeamIdList();
|
||||
$teamIdList2 = $entity->getTeamIdList();
|
||||
$teamIdList2 = $target->getTeamIdList();
|
||||
|
||||
$inTeam = false;
|
||||
|
||||
foreach ($teamIdList1 as $id) {
|
||||
if (in_array($id, $teamIdList2)) {
|
||||
$inTeam = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$inTeam) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getGlobalRestrictionTypeList(User $user, $action = 'read')
|
||||
protected function getGlobalRestrictionTypeList(User $user, string $action = 'read') : array
|
||||
{
|
||||
$typeList = ['forbidden'];
|
||||
|
||||
@@ -264,6 +317,7 @@ class AclManager
|
||||
|
||||
if ($action === 'edit') {
|
||||
$typeList[] = 'readOnly';
|
||||
|
||||
if (!$user->isAdmin()) {
|
||||
$typeList[] = 'nonAdminReadOnly';
|
||||
}
|
||||
@@ -272,8 +326,12 @@ class AclManager
|
||||
return $typeList;
|
||||
}
|
||||
|
||||
public function getScopeForbiddenAttributeList(User $user, $scope, $action = 'read', $thresholdLevel = 'no')
|
||||
{
|
||||
/**
|
||||
* Get attributes forbidden for a user.
|
||||
*/
|
||||
public function getScopeForbiddenAttributeList(
|
||||
User $user, string $scope, string $action = 'read', string $thresholdLevel = 'no'
|
||||
) : array {
|
||||
$list = [];
|
||||
|
||||
if (!$user->isAdmin()) {
|
||||
@@ -285,14 +343,19 @@ class AclManager
|
||||
$list,
|
||||
$this->getScopeRestrictedAttributeList($scope, $this->getGlobalRestrictionTypeList($user, $action))
|
||||
);
|
||||
|
||||
$list = array_values($list);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function getScopeForbiddenFieldList(User $user, $scope, $action = 'read', $thresholdLevel = 'no')
|
||||
{
|
||||
/**
|
||||
* Get fields forbidden for a user.
|
||||
*/
|
||||
public function getScopeForbiddenFieldList(
|
||||
User $user, string $scope, string $action = 'read', string $thresholdLevel = 'no'
|
||||
) : array {
|
||||
$list = [];
|
||||
|
||||
if (!$user->isAdmin()) {
|
||||
@@ -304,15 +367,19 @@ class AclManager
|
||||
$list,
|
||||
$this->getScopeRestrictedFieldList($scope, $this->getGlobalRestrictionTypeList($user, $action))
|
||||
);
|
||||
|
||||
$list = array_values($list);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
|
||||
public function getScopeForbiddenLinkList(User $user, $scope, $action = 'read', $thresholdLevel = 'no')
|
||||
{
|
||||
/**
|
||||
* Get links forbidden for a user.
|
||||
*/
|
||||
public function getScopeForbiddenLinkList(
|
||||
User $user, string $scope, string $action = 'read', string $thresholdLevel = 'no'
|
||||
) : array {
|
||||
$list = [];
|
||||
|
||||
if ($thresholdLevel === 'no') {
|
||||
@@ -320,13 +387,19 @@ class AclManager
|
||||
$list,
|
||||
$this->getScopeRestrictedLinkList($scope, $this->getGlobalRestrictionTypeList($user, $action))
|
||||
);
|
||||
|
||||
$list = array_values($list);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function checkUserPermission(User $user, $target, $permissionType = 'userPermission')
|
||||
/**
|
||||
* Whether a user has an access to another user over a specific permission.
|
||||
*
|
||||
* @param $target User|string User entity or user ID.
|
||||
*/
|
||||
public function checkUserPermission(User $user, $target, string $permissionType = 'user') : bool
|
||||
{
|
||||
$permission = $this->get($user, $permissionType);
|
||||
|
||||
@@ -348,7 +421,8 @@ class AclManager
|
||||
|
||||
if ($permission === 'team') {
|
||||
$teamIdList = $user->getLinkMultipleIdList('teams');
|
||||
if (!$this->getContainer()->get('entityManager')->getRepository('User')->checkBelongsToAnyOfTeams($userId, $teamIdList)) {
|
||||
|
||||
if (!$this->entityManager->getRepository('User')->checkBelongsToAnyOfTeams($userId, $teamIdList)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -356,57 +430,77 @@ class AclManager
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkAssignmentPermission(User $user, $target)
|
||||
/**
|
||||
* Whether a user can assign to another user.
|
||||
*
|
||||
* @param $target User|string User entity or user ID.
|
||||
*/
|
||||
public function checkAssignmentPermission(User $user, $target) : bool
|
||||
{
|
||||
return $this->checkUserPermission($user, $target, 'assignmentPermission');
|
||||
return $this->checkUserPermission($user, $target, 'assignment');
|
||||
}
|
||||
|
||||
public function createUserAcl(User $user)
|
||||
/**
|
||||
* Create a wrapper for a specific user.
|
||||
*/
|
||||
public function createUserAcl(User $user) : UserAclWrapper
|
||||
{
|
||||
$className = $this->userAclClassName;
|
||||
$acl = new $className($this, $user);
|
||||
|
||||
return $acl;
|
||||
}
|
||||
|
||||
public function getScopeRestrictedFieldList($scope, $type)
|
||||
public function getScopeRestrictedFieldList(string $scope, $type) : array
|
||||
{
|
||||
if (is_array($type)) {
|
||||
$typeList = $type;
|
||||
$list = [];
|
||||
|
||||
foreach ($typeList as $type) {
|
||||
$list = array_merge($list, $this->globalRestricton->getScopeRestrictedFieldList($scope, $type));
|
||||
}
|
||||
|
||||
$list = array_values($list);
|
||||
|
||||
return $list;
|
||||
}
|
||||
return $this->globalRestricton->getScopeRestrictedFieldList($scope, $type);
|
||||
}
|
||||
|
||||
public function getScopeRestrictedAttributeList($scope, $type)
|
||||
public function getScopeRestrictedAttributeList(string $scope, $type) : array
|
||||
{
|
||||
if (is_array($type)) {
|
||||
$typeList = $type;
|
||||
$list = [];
|
||||
|
||||
foreach ($typeList as $type) {
|
||||
$list = array_merge($list, $this->globalRestricton->getScopeRestrictedAttributeList($scope, $type));
|
||||
}
|
||||
|
||||
$list = array_values($list);
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
return $this->globalRestricton->getScopeRestrictedAttributeList($scope, $type);
|
||||
}
|
||||
|
||||
public function getScopeRestrictedLinkList($scope, $type)
|
||||
public function getScopeRestrictedLinkList(string $scope, $type) : array
|
||||
{
|
||||
if (is_array($type)) {
|
||||
$typeList = $type;
|
||||
$list = [];
|
||||
|
||||
foreach ($typeList as $type) {
|
||||
$list = array_merge($list, $this->globalRestricton->getScopeRestrictedLinkList($scope, $type));
|
||||
}
|
||||
|
||||
$list = array_values($list);
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
return $this->globalRestricton->getScopeRestrictedLinkList($scope, $type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy 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\Core\AclPortal;
|
||||
|
||||
use Espo\Core\Acl\Acl as BaseAcl;
|
||||
|
||||
class Acl extends BaseAcl implements PortalScopeAcl
|
||||
{
|
||||
use Portal;
|
||||
}
|
||||
@@ -29,188 +29,9 @@
|
||||
|
||||
namespace Espo\Core\AclPortal;
|
||||
|
||||
use \Espo\Entities\User;
|
||||
use \Espo\ORM\Entity;
|
||||
|
||||
class Base extends \Espo\Core\Acl\Base
|
||||
/** @deprecated */
|
||||
class Base extends \Espo\Core\Acl\Base implements PortalScopeAcl
|
||||
{
|
||||
public function checkScope(User $user, $data, $action = null, Entity $entity = null, $entityAccessData = array())
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_null($data)) {
|
||||
return false;
|
||||
}
|
||||
if ($data === false) {
|
||||
return false;
|
||||
}
|
||||
if ($data === true) {
|
||||
return true;
|
||||
}
|
||||
if (is_string($data)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$isOwner = null;
|
||||
if (isset($entityAccessData['isOwner'])) {
|
||||
$isOwner = $entityAccessData['isOwner'];
|
||||
}
|
||||
$inAccount = null;
|
||||
if (isset($entityAccessData['inAccount'])) {
|
||||
$inAccount = $entityAccessData['inAccount'];
|
||||
}
|
||||
$isOwnContact = null;
|
||||
if (isset($entityAccessData['isOwnContact'])) {
|
||||
$isOwnContact = $entityAccessData['isOwnContact'];
|
||||
}
|
||||
|
||||
if (is_null($action)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isset($data->$action)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = $data->$action;
|
||||
|
||||
if ($value === 'all' || $value === 'yes' || $value === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$value || $value === 'no') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_null($isOwner)) {
|
||||
if ($entity) {
|
||||
$isOwner = $this->checkIsOwner($user, $entity);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isOwner) {
|
||||
if ($value === 'own' || $value === 'account' || $value === 'contact') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($value === 'account') {
|
||||
if (is_null($inAccount) && $entity) {
|
||||
$inAccount = $this->checkInAccount($user, $entity);
|
||||
}
|
||||
if ($inAccount) {
|
||||
return true;
|
||||
} else {
|
||||
if (is_null($isOwnContact) && $entity) {
|
||||
$isOwnContact = $this->checkIsOwnContact($user, $entity);
|
||||
}
|
||||
if ($isOwnContact) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($value === 'contact') {
|
||||
if (is_null($isOwnContact) && $entity) {
|
||||
$isOwnContact = $this->checkIsOwnContact($user, $entity);
|
||||
}
|
||||
if ($isOwnContact) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkReadOnlyAccount(User $user, $data)
|
||||
{
|
||||
if (empty($data) || !is_object($data) || !isset($data->read)) {
|
||||
return false;
|
||||
}
|
||||
return $data->read === 'account';
|
||||
}
|
||||
|
||||
public function checkReadOnlyContact(User $user, $data)
|
||||
{
|
||||
if (empty($data) || !is_object($data) || !isset($data->read)) {
|
||||
return false;
|
||||
}
|
||||
return $data->read === 'contact';
|
||||
}
|
||||
|
||||
public function checkIsOwner(User $user, Entity $entity)
|
||||
{
|
||||
if ($entity->hasAttribute('createdById')) {
|
||||
if ($entity->has('createdById')) {
|
||||
if ($user->id === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkInAccount(User $user, Entity $entity)
|
||||
{
|
||||
$accountIdList = $user->getLinkMultipleIdList('accounts');
|
||||
if (count($accountIdList)) {
|
||||
if ($entity->hasAttribute('accountId') && $entity->getRelationParam('account', 'entity') === 'Account') {
|
||||
if (in_array($entity->get('accountId'), $accountIdList)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->hasRelation('accounts') && $entity->getRelationParam('accounts', 'entity') === 'Account') {
|
||||
$repository = $this->getEntityManager()->getRepository($entity->getEntityType());
|
||||
foreach ($accountIdList as $accountId) {
|
||||
if ($repository->isRelated($entity, 'accounts', $accountId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->hasAttribute('parentId') && $entity->hasRelation('parent')) {
|
||||
if ($entity->get('parentType') === 'Account') {
|
||||
if (in_array($entity->get('parentId'), $accountIdList)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkIsOwnContact(User $user, Entity $entity)
|
||||
{
|
||||
$contactId = $user->get('contactId');
|
||||
if ($contactId) {
|
||||
if ($entity->hasAttribute('contactId') && $entity->getRelationParam('contact', 'entity') === 'Contact') {
|
||||
if ($entity->get('contactId') === $contactId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->hasRelation('contacts') && $entity->getRelationParam('contacts', 'entity') === 'Contact') {
|
||||
$repository = $this->getEntityManager()->getRepository($entity->getEntityType());
|
||||
if ($repository->isRelated($entity, 'contacts', $contactId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->hasAttribute('parentId') && $entity->hasRelation('parent')) {
|
||||
if ($entity->get('parentType') === 'Contact') {
|
||||
if ($entity->get('parentId') === $contactId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
use Portal;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2020 Yuri Kuznetsov, Taras Machyshyn, Oleksiy 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\Core\AclPortal;
|
||||
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
trait Portal
|
||||
{
|
||||
public function checkScope(User $user, $data, $action = null, Entity $entity = null, $entityAccessData = [])
|
||||
{
|
||||
if ($user->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_null($data)) {
|
||||
return false;
|
||||
}
|
||||
if ($data === false) {
|
||||
return false;
|
||||
}
|
||||
if ($data === true) {
|
||||
return true;
|
||||
}
|
||||
if (is_string($data)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$isOwner = null;
|
||||
if (isset($entityAccessData['isOwner'])) {
|
||||
$isOwner = $entityAccessData['isOwner'];
|
||||
}
|
||||
$inAccount = null;
|
||||
if (isset($entityAccessData['inAccount'])) {
|
||||
$inAccount = $entityAccessData['inAccount'];
|
||||
}
|
||||
$isOwnContact = null;
|
||||
if (isset($entityAccessData['isOwnContact'])) {
|
||||
$isOwnContact = $entityAccessData['isOwnContact'];
|
||||
}
|
||||
|
||||
if (is_null($action)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isset($data->$action)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = $data->$action;
|
||||
|
||||
if ($value === 'all' || $value === 'yes' || $value === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$value || $value === 'no') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_null($isOwner)) {
|
||||
if ($entity) {
|
||||
$isOwner = $this->checkIsOwner($user, $entity);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isOwner) {
|
||||
if ($value === 'own' || $value === 'account' || $value === 'contact') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($value === 'account') {
|
||||
if (is_null($inAccount) && $entity) {
|
||||
$inAccount = $this->checkInAccount($user, $entity);
|
||||
}
|
||||
if ($inAccount) {
|
||||
return true;
|
||||
} else {
|
||||
if (is_null($isOwnContact) && $entity) {
|
||||
$isOwnContact = $this->checkIsOwnContact($user, $entity);
|
||||
}
|
||||
if ($isOwnContact) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($value === 'contact') {
|
||||
if (is_null($isOwnContact) && $entity) {
|
||||
$isOwnContact = $this->checkIsOwnContact($user, $entity);
|
||||
}
|
||||
if ($isOwnContact) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkReadOnlyAccount(User $user, $data)
|
||||
{
|
||||
if (empty($data) || !is_object($data) || !isset($data->read)) {
|
||||
return false;
|
||||
}
|
||||
return $data->read === 'account';
|
||||
}
|
||||
|
||||
public function checkReadOnlyContact(User $user, $data)
|
||||
{
|
||||
if (empty($data) || !is_object($data) || !isset($data->read)) {
|
||||
return false;
|
||||
}
|
||||
return $data->read === 'contact';
|
||||
}
|
||||
|
||||
public function checkIsOwner(User $user, Entity $entity)
|
||||
{
|
||||
if ($entity->hasAttribute('createdById')) {
|
||||
if ($entity->has('createdById')) {
|
||||
if ($user->id === $entity->get('createdById')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkInAccount(User $user, Entity $entity)
|
||||
{
|
||||
$accountIdList = $user->getLinkMultipleIdList('accounts');
|
||||
if (count($accountIdList)) {
|
||||
if ($entity->hasAttribute('accountId') && $entity->getRelationParam('account', 'entity') === 'Account') {
|
||||
if (in_array($entity->get('accountId'), $accountIdList)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->hasRelation('accounts') && $entity->getRelationParam('accounts', 'entity') === 'Account') {
|
||||
$repository = $this->getEntityManager()->getRepository($entity->getEntityType());
|
||||
foreach ($accountIdList as $accountId) {
|
||||
if ($repository->isRelated($entity, 'accounts', $accountId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->hasAttribute('parentId') && $entity->hasRelation('parent')) {
|
||||
if ($entity->get('parentType') === 'Account') {
|
||||
if (in_array($entity->get('parentId'), $accountIdList)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkIsOwnContact(User $user, Entity $entity)
|
||||
{
|
||||
$contactId = $user->get('contactId');
|
||||
if ($contactId) {
|
||||
if ($entity->hasAttribute('contactId') && $entity->getRelationParam('contact', 'entity') === 'Contact') {
|
||||
if ($entity->get('contactId') === $contactId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->hasRelation('contacts') && $entity->getRelationParam('contacts', 'entity') === 'Contact') {
|
||||
$repository = $this->getEntityManager()->getRepository($entity->getEntityType());
|
||||
if ($repository->isRelated($entity, 'contacts', $contactId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity->hasAttribute('parentId') && $entity->hasRelation('parent')) {
|
||||
if ($entity->get('parentType') === 'Contact') {
|
||||
if ($entity->get('parentId') === $contactId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -27,10 +27,9 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Interfaces;
|
||||
namespace Espo\Core\AclPortal;
|
||||
|
||||
interface InjectableService
|
||||
interface PortalScopeAcl
|
||||
{
|
||||
public function inject(string $name, object $object);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,16 +29,24 @@
|
||||
|
||||
namespace Espo\Core\AclPortal;
|
||||
|
||||
use \Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
use \Espo\ORM\Entity;
|
||||
use \Espo\Entities\User;
|
||||
use \Espo\Entities\Portal;
|
||||
use Espo\Entities\{
|
||||
User,
|
||||
Portal,
|
||||
};
|
||||
|
||||
use \Espo\Core\Utils\Config;
|
||||
use \Espo\Core\Utils\Metadata;
|
||||
use \Espo\Core\Utils\FieldManagerUtil;
|
||||
use \Espo\Core\Utils\File\Manager as FileManager;
|
||||
use Espo\Core\{
|
||||
ORM\EntityManager,
|
||||
ORM\Entity,
|
||||
Utils\Config,
|
||||
Utils\Metadata,
|
||||
Utils\FieldUtil,
|
||||
Utils\File\Manager as FileManager,
|
||||
Utils\DataCache,
|
||||
};
|
||||
|
||||
use Traversable;
|
||||
|
||||
class Table extends \Espo\Core\Acl\Table
|
||||
{
|
||||
@@ -52,13 +60,22 @@ class Table extends \Espo\Core\Acl\Table
|
||||
|
||||
protected $isStrictModeForced = true;
|
||||
|
||||
public function __construct(User $user, Portal $portal, Config $config = null, FileManager $fileManager = null, Metadata $metadata = null, FieldManagerUtil $fieldManager = null)
|
||||
{
|
||||
public function __construct(
|
||||
EntityManager $entityManager,
|
||||
User $user,
|
||||
Portal $portal,
|
||||
Config $config = null,
|
||||
Metadata $metadata = null,
|
||||
FieldUtil $fieldUtil = null,
|
||||
DataCache $dataCache
|
||||
) {
|
||||
if (empty($portal)) {
|
||||
throw new Error("No portal was passed to AclPortal\\Table constructor.");
|
||||
}
|
||||
|
||||
$this->portal = $portal;
|
||||
parent::__construct($user, $config, $fileManager, $metadata, $fieldManager);
|
||||
|
||||
parent::__construct($entityManager, $user, $config, $metadata, $fieldUtil, $dataCache);
|
||||
}
|
||||
|
||||
protected function getPortal()
|
||||
@@ -66,27 +83,37 @@ class Table extends \Espo\Core\Acl\Table
|
||||
return $this->portal;
|
||||
}
|
||||
|
||||
protected function initCacheFilePath()
|
||||
protected function initCacheKey()
|
||||
{
|
||||
$this->cacheFilePath = 'data/cache/application/acl-portal/'.$this->getPortal()->id.'/' . $this->getUser()->id . '.php';
|
||||
$this->cacheKey = 'aclPortal/' . $this->getPortal()->id.'/' . $this->getUser()->id;
|
||||
}
|
||||
|
||||
protected function getRoleList()
|
||||
{
|
||||
$roleList = [];
|
||||
|
||||
$userRoleList = $this->getUser()->get('portalRoles');
|
||||
if (!(is_array($userRoleList) || $userRoleList instanceof \Traversable)) {
|
||||
$userRoleList = $this->entityManager
|
||||
->getRepository('User')
|
||||
->getRelation($this->getUser(), 'portalRoles')
|
||||
->find();
|
||||
|
||||
if (! $userRoleList instanceof Traversable) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
foreach ($userRoleList as $role) {
|
||||
$roleList[] = $role;
|
||||
}
|
||||
|
||||
$portalRoleList = $this->getPortal()->get('portalRoles');
|
||||
if (!(is_array($portalRoleList) || $portalRoleList instanceof \Traversable)) {
|
||||
$portalRoleList = $this->entityManager
|
||||
->getRepository('Portal')
|
||||
->getRelation($this->getPortal(), 'portalRoles')
|
||||
->find();
|
||||
|
||||
if (! $portalRoleList instanceof Traversable) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
foreach ($portalRoleList as $role) {
|
||||
$roleList[] = $role;
|
||||
}
|
||||
@@ -132,4 +159,3 @@ class Table extends \Espo\Core\Acl\Table
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user