Compare commits
997 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a325f777f | |||
| 2496ea3f9a | |||
| c2cc463678 | |||
| 7ba5567205 | |||
| 7fd11cca1d | |||
| fb4df94831 | |||
| c8722df0c0 | |||
| 9878e8e170 | |||
| b26b240790 | |||
| ee990ba3bb | |||
| 6283c33979 | |||
| 8f75fc3657 | |||
| 09bb6f19e5 | |||
| dfc8d9a23b | |||
| f91e143f1d | |||
| 578558f070 | |||
| 3f4249d198 | |||
| ddda4a8827 | |||
| 804122a7a0 | |||
| cd6c041b41 | |||
| 56add3f0f3 | |||
| a61abb5557 | |||
| 08d116cd3d | |||
| cf44cfc398 | |||
| 5f65bb2e43 | |||
| 19ad96aee3 | |||
| 7cff64fdbf | |||
| 65734f149f | |||
| f1178ebcd9 | |||
| 7ca8c34045 | |||
| 77e072ebec | |||
| 12c232df76 | |||
| 48d8989f13 | |||
| 17bed94dd7 | |||
| 817cae1ac7 | |||
| 3a4d04cdb7 | |||
| 493e0febed | |||
| 546a71cf7e | |||
| f14252ba8e | |||
| 992c414ee4 | |||
| 7823046588 | |||
| ba646064b8 | |||
| c3728be605 | |||
| c5a43c1e74 | |||
| a36700bc41 | |||
| 47f708bec6 | |||
| 6050de43d8 | |||
| 3b9ba0034c | |||
| 7cb98a969e | |||
| b098545057 | |||
| 83aec89c42 | |||
| fad4180820 | |||
| dbb540329b | |||
| 61cb6bfaf4 | |||
| 864c61ecba | |||
| fd42923e67 | |||
| 8c5be66b12 | |||
| 2b459a6e97 | |||
| 2d8d39406b | |||
| 4c142669dc | |||
| 691ed15ce2 | |||
| 45e41c4fbe | |||
| 7277f5a28e | |||
| fe8900c83e | |||
| c2681c14b7 | |||
| 0362b18553 | |||
| 3ee30709a5 | |||
| 71321b2461 | |||
| 2efa73d91e | |||
| fb290224b0 | |||
| 971602a6c2 | |||
| 582460fbb6 | |||
| 64c2c2c091 | |||
| 5566ccf52c | |||
| 942ec23dd1 | |||
| b320590668 | |||
| 665c1f7105 | |||
| 68a0906ad7 | |||
| c0f9d4014a | |||
| a9b82ea745 | |||
| df8b69a470 | |||
| fb861fd51d | |||
| fb8af88c5c | |||
| 010931d695 | |||
| d51a20234e | |||
| a65c0dc2f2 | |||
| c88bedf4dd | |||
| 8c13b827a9 | |||
| 26fa4746c9 | |||
| 16bb5d56c5 | |||
| d37c325ff6 | |||
| 3391ec00f0 | |||
| 0c15e941dd | |||
| bf54c89e8f | |||
| bd7583c7fa | |||
| befdd07ceb | |||
| b007713333 | |||
| f755308c8c | |||
| b828920455 | |||
| ff1c3e67af | |||
| 4bb31de252 | |||
| 34776dac4f | |||
| 89e0f80a84 | |||
| fdcdcba552 | |||
| 4ed6a0b3d6 | |||
| 936ef246c4 | |||
| 9b9c0ebf1a | |||
| ccd130374b | |||
| 5f46076e1e | |||
| 4dfa85c18b | |||
| 5d563e92b0 | |||
| ca46e95170 | |||
| c31327ceb0 | |||
| b60cf799e0 | |||
| 37c98b2b4f | |||
| e566327fa6 | |||
| a0b2d4e707 | |||
| 1d9eb4709d | |||
| cd58862cc8 | |||
| 716b0ac977 | |||
| 19c7f9d457 | |||
| ab029256b3 | |||
| 19cc1b1839 | |||
| 418c59f945 | |||
| 55ae536cb8 | |||
| 812a994f6f | |||
| ebd2721708 | |||
| ad0f3b0986 | |||
| a6739f12aa | |||
| e0e4779523 | |||
| 81fcf79f04 | |||
| 1542061801 | |||
| c2fbd20021 | |||
| fd3acdf024 | |||
| acbdf41d83 | |||
| b340da9420 | |||
| e945bad970 | |||
| 3ee3b0276d | |||
| 9a2c7d2f03 | |||
| 51e39264eb | |||
| f6e0465718 | |||
| 8e496bbf97 | |||
| 12621418bd | |||
| a56ffba668 | |||
| a583fd0f8d | |||
| 577030b4c2 | |||
| 0a64621644 | |||
| b6b07a3d24 | |||
| d711d02fa3 | |||
| 63ccf4da71 | |||
| 126fa4b314 | |||
| 9eec9e3eae | |||
| 2e707c274a | |||
| 7c399ad875 | |||
| 50868598fb | |||
| 718caae926 | |||
| 2f39d695c3 | |||
| 8ba76c053c | |||
| c7fa026645 | |||
| bb10739913 | |||
| 1fe476078c | |||
| 68b5527fd2 | |||
| 5a92a95e9c | |||
| 7821a81662 | |||
| 7e99fac4b3 | |||
| 259db679f0 | |||
| caeaef8c16 | |||
| c8c806eea9 | |||
| 9d00644da6 | |||
| de7b0a3be0 | |||
| 27f4084642 | |||
| b880d690d7 | |||
| 7f67cf5102 | |||
| ee598ac82a | |||
| f6057175fb | |||
| 9b8d2eda4d | |||
| ad7c52eb85 | |||
| 0cd5052f4b | |||
| 6fb37f884f | |||
| 54a669fa52 | |||
| 63ba497c29 | |||
| 529162a2c3 | |||
| 656af10fc1 | |||
| 1ad598584d | |||
| 1f77dcd5b3 | |||
| 2c3fec1406 | |||
| 78cdc5327b | |||
| e6311ee386 | |||
| 580ea641f1 | |||
| aa6ad4698a | |||
| 02bb527c56 | |||
| 5e295f8af5 | |||
| 5528d4e20f | |||
| c2df6f969e | |||
| 03ab23d34a | |||
| 373861c951 | |||
| 6f1eec32e5 | |||
| 6c5f5bd8ef | |||
| 5f68e420d0 | |||
| f3669c2a69 | |||
| 3ad7079217 | |||
| 693f5eff05 | |||
| 4e435ac25a | |||
| e735a8f7d6 | |||
| 8aa7c69eb5 | |||
| 82e8cc50eb | |||
| d44d5d0257 | |||
| 208f6dfce0 | |||
| d4b743890c | |||
| ad81b49f4a | |||
| d2d18b2abf | |||
| f0e56d7197 | |||
| e3e4358287 | |||
| 73062f6503 | |||
| cf945e8ffb | |||
| e494eb4743 | |||
| 284fd4d3ac | |||
| 2ac1086916 | |||
| 6d9b42695a | |||
| cded277648 | |||
| c84f6fd713 | |||
| 00a51457f4 | |||
| 55f93cb5f0 | |||
| f3acb82953 | |||
| 8db4327324 | |||
| 048a0996f1 | |||
| 9aed16a38f | |||
| 87b01f2599 | |||
| cd5f5147df | |||
| d7a5af3f74 | |||
| cfcef5d0e2 | |||
| 9d6ce46e15 | |||
| 2523ec4ba9 | |||
| 1f93fcfe46 | |||
| 845360bec9 | |||
| e619162d7d | |||
| 68ca374e7d | |||
| 54c92105cc | |||
| 8143c179f2 | |||
| 014eee157d | |||
| 3cad70efa0 | |||
| cbd5cc6c97 | |||
| 8ae030ea26 | |||
| 833042d716 | |||
| 7dd1a2adff | |||
| 0e1967f0ef | |||
| b3be78703e | |||
| e81c36413e | |||
| 0c9eba6722 | |||
| 550445a364 | |||
| a6174e039b | |||
| 86e12fc481 | |||
| 3876164bb9 | |||
| 9c409941ac | |||
| 3c32d705b4 | |||
| 725b10cbea | |||
| 3d7be50b95 | |||
| 4287eb3f85 | |||
| 3a1c91bbe0 | |||
| 3fb95da969 | |||
| bca5897d9d | |||
| 0df572a400 | |||
| ee64a43e1f | |||
| eaaf824878 | |||
| e914864d08 | |||
| fb289cac64 | |||
| 13aa85310e | |||
| 3153e64879 | |||
| 43c37c2a6c | |||
| 74898ce3a9 | |||
| 5a30263466 | |||
| f7265106ef | |||
| 5230bba5a5 | |||
| 7d5747f1d1 | |||
| 392dccf38b | |||
| 4addd78dfc | |||
| 8422607979 | |||
| 1283e4c1b5 | |||
| afd9a1766d | |||
| 679b9927fe | |||
| bb126a9b18 | |||
| e5cd1282a1 | |||
| 33a42e94b4 | |||
| 49e36faa06 | |||
| 67885c39ae | |||
| a12ee735fe | |||
| 71b39748eb | |||
| b17f884ee0 | |||
| 8503ae7558 | |||
| 50ee86edc8 | |||
| 6d1170ad84 | |||
| 55ef80065e | |||
| 5cf8645e95 | |||
| 26385f6e34 | |||
| b44fd9143c | |||
| e9a554e24e | |||
| c1a2d364dd | |||
| 2dd2288807 | |||
| bc9cfd8e92 | |||
| 49abb3dbd1 | |||
| 8c632bed76 | |||
| 90728c0471 | |||
| e6ad581ef1 | |||
| 5e59d05dcb | |||
| 0be4b0e256 | |||
| 68bd2b3132 | |||
| e544b6b02a | |||
| 204f6198de | |||
| 6fc0e628c2 | |||
| b5f95a5aec | |||
| e3ba5c0bf7 | |||
| 868fccdfec | |||
| 34ed3b47d1 | |||
| 49e22cf34c | |||
| 99e496e085 | |||
| c4f82182b7 | |||
| 9b0671bf64 | |||
| 8754df0a60 | |||
| 9931445ebb | |||
| 468ed9d2cf | |||
| b5c0915c78 | |||
| a9c345ff81 | |||
| 5c3cf3991a | |||
| 3576fc22c1 | |||
| 05fcce2d37 | |||
| 96a2f1bf90 | |||
| c666cd83d5 | |||
| 3f922fc16b | |||
| d97841bd6a | |||
| e198c711d6 | |||
| 13cc47d30f | |||
| 3bf7532b3a | |||
| 94990b79dd | |||
| 1f7c86cd14 | |||
| 95950c4696 | |||
| 5830edf9ec | |||
| beed73ad0f | |||
| b7d2ed3004 | |||
| f65bf24e5c | |||
| e6b37361a1 | |||
| 6e29f12837 | |||
| ee7300f6e6 | |||
| 761e4380ef | |||
| 14c9b43005 | |||
| 60aeac00a5 | |||
| 146cf59327 | |||
| 8f0336c473 | |||
| 60cab07485 | |||
| cc895e58d4 | |||
| 9a386ebbbe | |||
| a259be942b | |||
| 20b5f693a5 | |||
| a5ff17de21 | |||
| 73fede1b48 | |||
| 9fd1342692 | |||
| 343ed5b929 | |||
| f9cc721dfd | |||
| 7647c6eabe | |||
| 85dcae6808 | |||
| fa57105063 | |||
| 62f72f8ba9 | |||
| 1c496f6923 | |||
| fbfe01cbb2 | |||
| ae6b18a934 | |||
| ac470f3721 | |||
| e33ff30b44 | |||
| e6adcaf3c6 | |||
| 7fc9fe32a7 | |||
| b2f0dc9d10 | |||
| c6b86ab0c0 | |||
| 7d4a741216 | |||
| ebc0351e54 | |||
| cba5940f2e | |||
| 9cd25ae9a7 | |||
| edbfa27218 | |||
| 2edfa4a1f9 | |||
| 289bc7f9e3 | |||
| 5536fee5a5 | |||
| 5dab1b52ba | |||
| ab006d43e4 | |||
| 037e05e8b2 | |||
| 58ffa95a15 | |||
| 56c0af9224 | |||
| 30d813d44e | |||
| b7dffc34f5 | |||
| e7444eb62e | |||
| d8c9588662 | |||
| 2e3e1ae283 | |||
| 28987b3c9d | |||
| 0fce1a1a6b | |||
| a64e1f3684 | |||
| 2da85b88b9 | |||
| dec22fcdf6 | |||
| 37cec3335b | |||
| 956f281bd6 | |||
| 776f291ffd | |||
| 3e280b70e6 | |||
| cd232214c2 | |||
| 4b58bce051 | |||
| d3b8ae917a | |||
| ca36c9eecb | |||
| 0c9d44b050 | |||
| 7a43fe824c | |||
| 5b203b3edb | |||
| 9f3a76cb07 | |||
| a0c74d2ad9 | |||
| 95778c3e51 | |||
| 758e773b97 | |||
| 301bb0954a | |||
| ca8260190a | |||
| 3652b59313 | |||
| 7d98676efc | |||
| d1dd5d0c20 | |||
| c378540995 | |||
| b11c542a13 | |||
| a7b1ab1629 | |||
| 5fa0153289 | |||
| 9067f9b0d4 | |||
| 3dcdac00a1 | |||
| db50734bd6 | |||
| 9314b26c12 | |||
| b94dcc42c0 | |||
| 7964285dd5 | |||
| 18bc684a56 | |||
| 492d18b67d | |||
| 78e0a308da | |||
| 3b96fd4c4d | |||
| 3daf01d5c4 | |||
| e56cf432d7 | |||
| 121ab83eb5 | |||
| 258bd55190 | |||
| 328732592e | |||
| 4df0cdb191 | |||
| 38458cc314 | |||
| b1c395be36 | |||
| 875b5d8adf | |||
| cdf0f5c144 | |||
| f563d2066d | |||
| d7caed18da | |||
| 067ff3bdb6 | |||
| 8049148bcf | |||
| 6e9edacd2c | |||
| c1c0a3e5cd | |||
| 2a5e171e38 | |||
| ef9291481f | |||
| 4966e4ba41 | |||
| 389065d313 | |||
| c7fab83ae6 | |||
| 0a9b9f2192 | |||
| 124e381eeb | |||
| 9898944941 | |||
| 1d6945afc5 | |||
| f892e8e0ba | |||
| b929c12f9e | |||
| 3b6e267b24 | |||
| a8af89ac13 | |||
| c592c17e96 | |||
| 4a0e7a2a80 | |||
| 1eca49da48 | |||
| 0908a7c14d | |||
| 6b610880dc | |||
| 5f4980811d | |||
| fc2a25837f | |||
| ed05747ed5 | |||
| 13897daf53 | |||
| d4f8522545 | |||
| 576aa6bbda | |||
| b9705008a1 | |||
| bf76e3fd7f | |||
| fc95ad105d | |||
| 78fdc72794 | |||
| 6f1dc75492 | |||
| fcda61ba37 | |||
| 8fb6ac2cb7 | |||
| c4e1aae15e | |||
| e1c41f3c70 | |||
| eb7adebc48 | |||
| c395cb2dbb | |||
| ecdacbfc97 | |||
| 9130e94980 | |||
| 116ae934c2 | |||
| 4b1dd6e471 | |||
| bb1744fb50 | |||
| 852f1a8646 | |||
| 2b4fd22388 | |||
| 3d05b9f57a | |||
| c65835a156 | |||
| a3ef8e4744 | |||
| 2b3795a55f | |||
| fc607b307a | |||
| efa7a8a9e4 | |||
| 471d59d053 | |||
| 3f2e092c9f | |||
| c32a27e5e8 | |||
| 58c274dcb3 | |||
| 629975a563 | |||
| 8bfbebcc56 | |||
| df5222b3ac | |||
| 315939d98c | |||
| 1426599d63 | |||
| eb6cfca764 | |||
| f315095e42 | |||
| a7da0416b2 | |||
| d4f667ed1e | |||
| 654c69c08b | |||
| 7923a04c42 | |||
| 5e325f5dce | |||
| b4173ea1ad | |||
| e30c799185 | |||
| 285ca6ffbf | |||
| 14d54450e7 | |||
| 2ed920e774 | |||
| a73b0208ea | |||
| 47699db7f4 | |||
| d03817a4eb | |||
| d0741e9791 | |||
| 4dcaaed6e0 | |||
| 28268cb20e | |||
| aed2279b50 | |||
| 8c89201543 | |||
| a746101872 | |||
| 2635b929d9 | |||
| cdf311cd4f | |||
| 1a7fcb9d52 | |||
| 0dde4b7536 | |||
| 265cf9f7c7 | |||
| 7ae86a915c | |||
| a0f2d25ccd | |||
| 47b5927c10 | |||
| f5e48d21ec | |||
| e805a8afcb | |||
| d744140220 | |||
| 4aae37f7a7 | |||
| 9fe1f70c4d | |||
| 9b7c56ed0d | |||
| f799599c76 | |||
| 3bd64b35db | |||
| 2492e22a3b | |||
| 27384b2589 | |||
| b995470d68 | |||
| 9a45788698 | |||
| c1e6db4538 | |||
| a75c62d090 | |||
| 8856004b3a | |||
| f95118c1ee | |||
| 9ac618ebfe | |||
| 24c9c630cb | |||
| c237ec4c29 | |||
| 3c78c0df57 | |||
| 79f47fd1b3 | |||
| e85112f074 | |||
| 19b6e5512f | |||
| e53efac19c | |||
| b61a30c5ff | |||
| 1dd3f049e0 | |||
| f969608c68 | |||
| 4575ba6f34 | |||
| 593f2842e7 | |||
| 02bc23c784 | |||
| cba771a588 | |||
| eea7fbc292 | |||
| 33d551abbb | |||
| 4f43ea59c8 | |||
| c7007d2c20 | |||
| 09ae51738f | |||
| 35728d3595 | |||
| fd7f843022 | |||
| fb892eb383 | |||
| 894d2d2b3b | |||
| af4266eac7 | |||
| f6597fa087 | |||
| 49fa660aca | |||
| ff7896adc7 | |||
| a42d0d98fb | |||
| b26f764754 | |||
| 5e0af40734 | |||
| 0ba8e843b1 | |||
| 488ba5c1ef | |||
| b8ca7925c0 | |||
| a4209ab67a | |||
| a74ead4260 | |||
| 411a4b4082 | |||
| 1aa3ead079 | |||
| b963701081 | |||
| bdf512f2c1 | |||
| 89a762ca8c | |||
| 9241c64f97 | |||
| 4baad0fd5c | |||
| 71c6272dfe | |||
| 1e0cc67b0e | |||
| 6532dc07f5 | |||
| c7d4aa10ce | |||
| 6f91dc9497 | |||
| 0ff0722b2f | |||
| e2bbadf137 | |||
| 7daf0d32d0 | |||
| a6f919b8c8 | |||
| bd7a798d11 | |||
| d6802fd4a7 | |||
| 2e173e6a23 | |||
| 8854ba9bda | |||
| f47b39cbea | |||
| db526aa03a | |||
| 56b63c4151 | |||
| 78b0d423b1 | |||
| 9d4c7b6573 | |||
| eb644d98b5 | |||
| add21c5f20 | |||
| 4893167372 | |||
| 313bba607a | |||
| 1c548b8006 | |||
| 1fcd127797 | |||
| bee6faa8ac | |||
| 3999a761eb | |||
| d4c0adb685 | |||
| 0b91dd902a | |||
| e4e72baa5d | |||
| 67de7818ba | |||
| e5ca803a40 | |||
| 13a140400c | |||
| eb1d954cda | |||
| c39133315e | |||
| 92434b8f2b | |||
| d2d6ab4f88 | |||
| caede15d09 | |||
| 4ca8a308d6 | |||
| e92750abc2 | |||
| 0ae2f41141 | |||
| 9f970d338d | |||
| ad70c80da3 | |||
| 670344b164 | |||
| a2cefb4228 | |||
| 56b35937fa | |||
| b3b49df108 | |||
| 3718b75234 | |||
| 6504c740b6 | |||
| 6edb0474e3 | |||
| 9923f33a1a | |||
| bdf1e4e617 | |||
| 6e8ca5db5a | |||
| 6f7fc58710 | |||
| 57b6aa814e | |||
| 443d5b3aa5 | |||
| 3a68038421 | |||
| 0d8674d771 | |||
| 1fc557af41 | |||
| 1f42924fdd | |||
| e54053e712 | |||
| 1a29f44649 | |||
| 462104b7b4 | |||
| ac62233074 | |||
| 5dd4dd5e24 | |||
| 9aa6d6a434 | |||
| 28b91e26c1 | |||
| 358cd4e54a | |||
| c3bf02945a | |||
| e2b49dde9e | |||
| f4935dd9fe | |||
| 841fe2b2e8 | |||
| a3f0e47c49 | |||
| cd02b264bd | |||
| d821b4a848 | |||
| f23a44de04 | |||
| 7dd47eec3e | |||
| d1c480c72d | |||
| 0964d538fe | |||
| ca719d2df8 | |||
| cce7558a9f | |||
| 2d87c112f8 | |||
| 106fd4f300 | |||
| e6e6926103 | |||
| 52788d744e | |||
| 6fb892c16f | |||
| c5d7c66e51 | |||
| f7b362485c | |||
| 3439fa1a22 | |||
| bd103e4288 | |||
| 35b097d9fa | |||
| a457117ca8 | |||
| 54588deffa | |||
| 496955cc9f | |||
| 3d4c68aa36 | |||
| b6852df791 | |||
| b1f85cb018 | |||
| 6532e2871e | |||
| bb4bab30bd | |||
| aa7742e105 | |||
| 9d2c5fb75b | |||
| f1f4daba91 | |||
| 8621a178a1 | |||
| 7fa73576b5 | |||
| fc0103cc80 | |||
| 141ce827df | |||
| a00cff0291 | |||
| c82ce1017b | |||
| 9d5e9a3d4d | |||
| 30ce935ea8 | |||
| e842d0538d | |||
| 12b24e0893 | |||
| 82860ddf9a | |||
| 4d12cb69e4 | |||
| 3721921799 | |||
| 60b6746994 | |||
| d1c463d65e | |||
| 2f238bcf59 | |||
| 34ab3eea77 | |||
| 9908ce7f04 | |||
| 6066cb4f1d | |||
| 2d858fb001 | |||
| 5ca31b1621 | |||
| bba5f72513 | |||
| c736b82694 | |||
| 9aa4a14744 | |||
| 1a4957d59d | |||
| a47e912d14 | |||
| eed580748c | |||
| f39d3f94b8 | |||
| a09d176ea9 | |||
| f9f4fe80e6 | |||
| 25717253d6 | |||
| a3acae963d | |||
| 200ff69b41 | |||
| 5a178ce23c | |||
| cccef4ca28 | |||
| c746755c15 | |||
| 564f346e12 | |||
| 2aeb97163e | |||
| e50d52bd3a | |||
| c948f378b9 | |||
| 9ecb4e3abd | |||
| 17bb213dd3 | |||
| 3c23a2cd2e | |||
| 461f479dde | |||
| 8946171eca | |||
| 54f5401149 | |||
| 038b33f0fd | |||
| ff6fe05733 | |||
| 9ca6dcd3ba | |||
| 7d803c4c52 | |||
| 5ab9f04410 | |||
| 9b84c81dfd | |||
| 4a6ed0cf53 | |||
| c81c8a2ae8 | |||
| 4d0d11b6d6 | |||
| e6ad444ea1 | |||
| e87f4d63c3 | |||
| a809a8dcce | |||
| 6314335c49 | |||
| 3cb39c2a04 | |||
| 30e59bbc21 | |||
| e228ce6e04 | |||
| d2cb356582 | |||
| 46460a2303 | |||
| 0b715c77f2 | |||
| adb234e19d | |||
| 5656fdb9c9 | |||
| 5710353976 | |||
| 9580c08e9e | |||
| 27478ecd47 | |||
| a2f36ceef5 | |||
| d3e9d99ccb | |||
| a603cb5af4 | |||
| f9b6810d4e | |||
| 0b89c8dd85 | |||
| f521c1e769 | |||
| 4ca8ff532b | |||
| d5720db41e | |||
| b04406e697 | |||
| 064cfdff92 | |||
| dfec225a37 | |||
| b4faba939d | |||
| 5409b5a7ec | |||
| b930cd1515 | |||
| 8f683efff3 | |||
| d68806edf9 | |||
| a8646c70fa | |||
| d783a8fba7 | |||
| 147aca3043 | |||
| 532acaf5ac | |||
| bc7b926591 | |||
| b3892e62a5 | |||
| e09d38647b | |||
| 005ead1f8a | |||
| c5bc16fe8a | |||
| cdca00ca81 | |||
| b29b31dc12 | |||
| 4342a37310 | |||
| 824bbbcb3f | |||
| fd954ad01b | |||
| 5edd9315d1 | |||
| 9c4b068082 | |||
| e806e2c9f7 | |||
| ba0e10425f | |||
| 0c2db45a76 | |||
| bfebfd5b28 | |||
| 3f33350e0d | |||
| c9f8064b23 | |||
| e107f6227c | |||
| f5273c374f | |||
| 0e1a2090b8 | |||
| 1ee0876d3d | |||
| a6640dcbe5 | |||
| 73441dca38 | |||
| f8cc4ea4a1 | |||
| 9d1d7caafd | |||
| d88fa5e681 | |||
| 76ef7726e2 | |||
| 5ac3194c6f | |||
| 497e490a6b | |||
| 5b41ec52f7 | |||
| 45ced3d17d | |||
| 200e4da537 | |||
| 11189884a8 | |||
| ca587e8819 | |||
| bffd9c6ad2 | |||
| dc4e443256 | |||
| 0aa98ebda1 | |||
| 78c315db76 | |||
| 8ceecd98a8 | |||
| 775f5d6a9f | |||
| 99f4c550f2 | |||
| f102573e45 | |||
| b848eeacc8 | |||
| c74f2c3e70 | |||
| 95554b45b6 | |||
| 2bea2a1918 | |||
| f934fdf46c | |||
| 7d1d36e036 | |||
| ca4c8b1942 | |||
| d0a5d336f7 | |||
| 893d5e69a0 | |||
| f74ae05201 | |||
| 14e7f3c3b7 | |||
| 7c6d8dd8e0 | |||
| e82c2eb2b1 | |||
| 87cd84ddb7 | |||
| 531908df75 | |||
| ced7d04d07 | |||
| d16724b42b | |||
| e0a114e4f5 | |||
| 0d7f387b37 | |||
| b8e8cbf3bb | |||
| 887d0618cc | |||
| ab4665046a | |||
| 72e0a56673 | |||
| eaf0d255b4 | |||
| ebae161cdf | |||
| 691c2913bb | |||
| fce1153108 | |||
| 2817ff06ae | |||
| 61c8747a39 | |||
| 6e0401d61f | |||
| 3391ece9f8 | |||
| 6be25bc988 | |||
| 3eb9b4a316 | |||
| f872eef1e9 | |||
| 0624b774d0 | |||
| 3783dde956 | |||
| 98a8ef2777 | |||
| e3cd190100 | |||
| 9b1539c5d6 | |||
| d4990e4c94 | |||
| 99422f333b | |||
| 128a866390 | |||
| 1187ce03ec | |||
| 8f1d67ea09 | |||
| 97c9eaefa8 | |||
| ca0042ca80 | |||
| bc10960447 | |||
| 7d0bdbe264 | |||
| 4c07dea461 | |||
| b09e7b4c7d | |||
| c0be92c749 | |||
| ee4c6f78c6 | |||
| e003e65ea8 | |||
| b25bb3cf29 | |||
| 5d8cfda315 | |||
| 1f2fbac207 | |||
| 7955318e45 | |||
| 2799e8f70e | |||
| 69ece23a48 | |||
| 1eb297becf | |||
| a81d590726 | |||
| c3661ca0cc | |||
| 5be5d4d2c9 | |||
| 629f298ce7 | |||
| 8172729a07 | |||
| 78285d5c9c | |||
| 1fab00298d | |||
| e27f30b7c8 | |||
| 3af357dd2c | |||
| c5e83ccab0 | |||
| ea20d927ad | |||
| 6964dc6e73 | |||
| 80f8e00bd7 | |||
| 53f0b8ae3c | |||
| 377ec4c107 | |||
| 659c60614b | |||
| f0a7bbcd14 | |||
| 3372a99e13 | |||
| 6f7bf269b2 | |||
| a48f97d414 | |||
| 8f4a31ce65 | |||
| 4f27bea28b | |||
| caaf4113ce | |||
| 5ed79f4e97 | |||
| 1f797413d4 | |||
| 28e427c0f9 | |||
| 71b448e27d | |||
| 47596be087 | |||
| 199fbeb647 | |||
| 8389e416a4 | |||
| 3143816be1 | |||
| 5a561e90c3 | |||
| 314eb4342c | |||
| b73491b280 | |||
| d91491569c | |||
| a38b6660e4 | |||
| 18dd4e5d9b | |||
| 3d944b0454 | |||
| a8b977172a | |||
| deb125fa6d | |||
| 1cb3091780 | |||
| 3ac8f0c5e3 | |||
| 7ee737690a | |||
| e600df800c | |||
| b77a45c3a2 | |||
| 0e0e83abdf | |||
| 777f822fad | |||
| a694acd9b8 | |||
| 0676b9c186 | |||
| 5c5fb8bd8f | |||
| cdd1fcbf45 | |||
| 55cf90e9db | |||
| f59d6a6fcf | |||
| ad9131d75d | |||
| 6e54261fe8 | |||
| fdfea113b5 | |||
| 267238bac4 | |||
| 83a061c8e8 | |||
| e1cd01e60e | |||
| 32eb50d49b | |||
| c3b65cc9e9 | |||
| 544a4f57ec | |||
| 44ad175eda | |||
| 628bee355e | |||
| fcd6880e1e | |||
| 159a8fda78 | |||
| ecdadf2a18 | |||
| c1813cf5d9 | |||
| ed97ad100b | |||
| 609e3cfc0b | |||
| f2a6afba21 | |||
| 60fa8157f2 | |||
| 723f9b73eb | |||
| 4cf3969700 | |||
| 73cc1d04c9 | |||
| bd13927c47 | |||
| 198c3fb3f0 | |||
| 690725416b | |||
| 058b07958b | |||
| d5307d89e3 | |||
| d5df44623f | |||
| dfa7e964c5 | |||
| 7c964c9fac | |||
| d014bdea09 | |||
| 5c57e2ad47 | |||
| 7e41013038 | |||
| 35a0d15031 | |||
| aff87a12e2 | |||
| 954626a2b9 | |||
| 41c398aa5c | |||
| 0809c38938 | |||
| 69afba56e6 | |||
| 44be211cb2 | |||
| 3dd7be272f | |||
| ea3f6e2b75 | |||
| 22d4ded11f | |||
| 0161f4f957 | |||
| 383aa049c0 | |||
| 3257b829a8 | |||
| 38a659dc10 | |||
| 356c4ae63e | |||
| 3f87e8e54b | |||
| 859aac85c4 | |||
| 55f468ff62 | |||
| 2138e7eddc | |||
| f47d844c68 | |||
| f007447294 | |||
| 4590d1be1e | |||
| a236699367 | |||
| f461827532 | |||
| 406af5521c | |||
| a229c2fb0f | |||
| 057cf60bd7 | |||
| cd3cd9ffc3 | |||
| 5e236840b0 |
@@ -1,4 +0,0 @@
|
||||
**/yui/build/** -diff
|
||||
**/amd/build/** -diff
|
||||
theme/bootstrapbase/style/editor.css -diff
|
||||
theme/bootstrapbase/style/moodle.css -diff
|
||||
@@ -35,8 +35,7 @@
|
||||
"plusplus": false,
|
||||
"predef": [
|
||||
"M",
|
||||
"define",
|
||||
"require"
|
||||
"define"
|
||||
],
|
||||
"proto": false,
|
||||
"regexdash": false,
|
||||
|
||||
@@ -1,218 +0,0 @@
|
||||
# PLEASE NOTE: Travis is not currently utilised by the Moodle core integration
|
||||
# process (which uses our internal CI system) this file is here for the benefit
|
||||
# of community developers git clones - see MDL-51458.
|
||||
|
||||
sudo: false
|
||||
|
||||
# We currently disable Travis notifications entirely until https://github.com/travis-ci/travis-ci/issues/4976
|
||||
# is fixed.
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
language: php
|
||||
|
||||
php:
|
||||
# We only run the highest and lowest supported versions to reduce the load on travis-ci.org.
|
||||
- 7.0
|
||||
# - 5.6
|
||||
# - 5.5
|
||||
- 5.4
|
||||
|
||||
env:
|
||||
# Although we want to run these jobs and see failures as quickly as possible, we also want to get the slowest job to
|
||||
# start first so that the total run time is not too high.
|
||||
#
|
||||
# We only run MySQL on PHP 5.6, so run that first.
|
||||
# CI Tests should be second-highest in priority as these only take <= 60 seconds to run under normal circumstances.
|
||||
# Postgres is significantly is pretty reasonable in its run-time.
|
||||
|
||||
# Run unit tests on MySQL
|
||||
- DB=mysqli PHPUNIT=true INSTALL=false CITEST=false
|
||||
|
||||
# Run CI Tests without running PHPUnit.
|
||||
- DB=none PHPUNIT=false INSTALL=false CITEST=true
|
||||
|
||||
# Run unit tests on Postgres
|
||||
- DB=pgsql PHPUNIT=true INSTALL=false CITEST=false
|
||||
|
||||
# Perform an upgrade test too.
|
||||
- DB=pgsql PHPUNIT=false INSTALL=true CITEST=false UPGRADE=true
|
||||
|
||||
matrix:
|
||||
# Enable fast finish.
|
||||
# This will fail the build if a single job fails (except those in allow_failures).
|
||||
# It will not stop the jobs from running.
|
||||
fast_finish: true
|
||||
|
||||
exclude:
|
||||
# MySQL - it's just too slow.
|
||||
# Exclude it on all versions except for 7.0
|
||||
# - env: DB=mysqli PHPUNIT=true INSTALL=false CITEST=false
|
||||
# php: 5.6
|
||||
#
|
||||
# - env: DB=mysqli PHPUNIT=true INSTALL=false CITEST=false
|
||||
# php: 5.5
|
||||
|
||||
- env: DB=mysqli PHPUNIT=true INSTALL=false CITEST=false
|
||||
php: 5.4
|
||||
|
||||
# Moodle 2.7 is not compatible with PHP 7 for the upgrade test.
|
||||
- env: DB=pgsql PHPUNIT=false INSTALL=true CITEST=false UPGRADE=true
|
||||
php: 7.0
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
|
||||
install:
|
||||
# Disable xdebug. We aren't generating code coverage, and it has a huge impact upon test performance.
|
||||
- rm /home/travis/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini
|
||||
|
||||
# Set the encrypted GITHUB_TOKEN if it's available to raise the API limit.
|
||||
- if [ -n "$GITHUB_APITOKEN" ]; then composer config github-oauth.github.com $GITHUB_APITOKEN; fi
|
||||
|
||||
# Install composer dependencies.
|
||||
# We need --no-interaction in case we hit API limits for composer. This causes it to fall back to a standard clone.
|
||||
# Typically it should be able to use the Composer cache if any other job has already completed before we started here.
|
||||
- travis_retry composer install --prefer-dist --no-interaction
|
||||
|
||||
before_script:
|
||||
- >
|
||||
if [ "$INSTALL" = 'true' -o "$PHPUNIT" = 'true' ];
|
||||
then
|
||||
# Copy generic configuration in place.
|
||||
cp config-dist.php config.php ;
|
||||
|
||||
# Create the moodledata directory.
|
||||
mkdir -p "$HOME"/roots/base
|
||||
|
||||
# The database name and password.
|
||||
sed -i \
|
||||
-e "s%= 'moodle'%= 'travis_ci_test'%" \
|
||||
-e "s%= 'password'%= ''%" \
|
||||
config.php ;
|
||||
|
||||
# The wwwroot and dataroot.
|
||||
sed -i \
|
||||
-e "s%http://example.com/moodle%http://localhost%" \
|
||||
-e "s%/home/example/moodledata%/home/travis/roots/base%" \
|
||||
config.php ;
|
||||
|
||||
if [ "$DB" = 'pgsql' ];
|
||||
then
|
||||
# Postgres-specific setup.
|
||||
sed -i \
|
||||
-e "s%= 'username'%= 'postgres'%" \
|
||||
config.php ;
|
||||
|
||||
psql -c 'CREATE DATABASE travis_ci_test;' -U postgres;
|
||||
fi
|
||||
|
||||
if [ "$DB" = 'mysqli' ];
|
||||
then
|
||||
# MySQL-specific setup.
|
||||
sed -i \
|
||||
-e "s%= 'pgsql'%= 'mysqli'%" \
|
||||
-e "s%= 'username'%= 'travis'%" \
|
||||
config.php;
|
||||
|
||||
mysql -u root -e 'SET GLOBAL innodb_file_format=barracuda;' ;
|
||||
mysql -u root -e 'SET GLOBAL innodb_file_per_table=ON;' ;
|
||||
mysql -e 'CREATE DATABASE travis_ci_test DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_bin;' ;
|
||||
fi
|
||||
|
||||
if [ "$PHPUNIT" = 'true' ];
|
||||
then
|
||||
# Create a directory for the phpunit dataroot.
|
||||
mkdir -p "$HOME"/roots/phpunit
|
||||
|
||||
# The phpunit dataroot and prefix..
|
||||
sed -i \
|
||||
-e "/require_once/i \\\$CFG->phpunit_dataroot = '\/home\/travis\/roots\/phpunit';" \
|
||||
-e "/require_once/i \\\$CFG->phpunit_prefix = 'p_';" \
|
||||
config.php ;
|
||||
|
||||
# Initialise PHPUnit for Moodle.
|
||||
php admin/tool/phpunit/cli/init.php
|
||||
fi
|
||||
fi
|
||||
|
||||
script:
|
||||
########################################################################
|
||||
# PHPUnit
|
||||
########################################################################
|
||||
- >
|
||||
if [ "$PHPUNIT" = 'true' ];
|
||||
then
|
||||
vendor/bin/phpunit;
|
||||
fi
|
||||
|
||||
########################################################################
|
||||
# CI Tests
|
||||
########################################################################
|
||||
- >
|
||||
if [ "$CITEST" = 'true' ];
|
||||
then
|
||||
# Note - this is deliberately placed in the script section as we
|
||||
# should not add any code until after phpunit has run.
|
||||
|
||||
# The following repositories are required.
|
||||
# The local_ci repository does the actual checking.
|
||||
git clone https://github.com/moodlehq/moodle-local_ci.git local/ci
|
||||
|
||||
# We need the official upstream for comparison
|
||||
git remote add upstream https://github.com/moodle/moodle.git;
|
||||
|
||||
git fetch upstream master;
|
||||
export GIT_PREVIOUS_COMMIT="`git merge-base FETCH_HEAD $TRAVIS_COMMIT`";
|
||||
export GIT_COMMIT="$TRAVIS_COMMIT";
|
||||
export UPSTREAM_FETCH_HEAD=`git rev-parse FETCH_HEAD`
|
||||
|
||||
# Variables required by our linter.
|
||||
export gitcmd=`which git`;
|
||||
export gitdir="$TRAVIS_BUILD_DIR";
|
||||
export phpcmd=`which php`;
|
||||
fi
|
||||
|
||||
# Actually run the CI Tests - do this outside of the main test to make output clearer.
|
||||
- >
|
||||
if [ "$CITEST" = 'true' ];
|
||||
then
|
||||
bash local/ci/php_lint/php_lint.sh;
|
||||
fi
|
||||
|
||||
########################################################################
|
||||
# Upgrade test
|
||||
########################################################################
|
||||
- >
|
||||
if [ "$UPGRADE" = 'true' ];
|
||||
then
|
||||
# We need the official upstream.
|
||||
git remote add upstream https://github.com/moodle/moodle.git;
|
||||
|
||||
# Checkout 27 STABLE branch.
|
||||
git fetch upstream MOODLE_27_STABLE;
|
||||
git checkout MOODLE_27_STABLE;
|
||||
|
||||
# Perform the upgrade
|
||||
php admin/cli/install_database.php --agree-license --adminpass=Password --adminemail=admin@example.com --fullname="Upgrade test" --shortname=Upgrade;
|
||||
|
||||
# Return to the previous commit
|
||||
git checkout -;
|
||||
|
||||
# Perform the upgrade
|
||||
php admin/cli/upgrade.php --non-interactive --allow-unstable ;
|
||||
|
||||
# The local_ci repository can be used to check upgrade savepoints.
|
||||
git clone https://github.com/moodlehq/moodle-local_ci.git local/ci ;
|
||||
|
||||
cp local/ci/check_upgrade_savepoints/check_upgrade_savepoints.php ./check_upgrade_savepoints.php
|
||||
result=`php check_upgrade_savepoints.php`;
|
||||
# Check if there are problems
|
||||
count=`echo "$result" | grep -P "ERROR|WARN" | wc -l` ;
|
||||
if (($count > 0));
|
||||
then
|
||||
echo "$result"
|
||||
exit 1 ;
|
||||
fi
|
||||
fi
|
||||
@@ -1,56 +0,0 @@
|
||||
CONTRIBUTING TO MOODLE
|
||||
======================
|
||||
|
||||
Moodle is made by people like you. We are members of a big worldwide community
|
||||
of developers, designers, teachers, testers, translators and other users. We
|
||||
work in universities, schools, companies and other places. You are very welcome
|
||||
to join us and contribute to the project.
|
||||
|
||||
See <https://docs.moodle.org/dev/Contributing_to_Moodle> for the many ways you
|
||||
can help, not only with coding.
|
||||
|
||||
Moodle is open to community contributions to core, though all code must go
|
||||
through peer-review, automated behaviour testing, continuous integration and
|
||||
human post-integration checks.
|
||||
|
||||
Pull requests
|
||||
-------------
|
||||
|
||||
Please do not open pull requests via Github. The repository there is just a
|
||||
mirror of the official repository at <https://git.moodle.org>. Issues are
|
||||
reported and patches provided via <https://tracker.moodle.org>. See below for
|
||||
more information.
|
||||
|
||||
Moodle core bug fixes and new features
|
||||
--------------------------------------
|
||||
|
||||
During the years of intensive development, a mature process of including
|
||||
submitted patches has evolved.
|
||||
|
||||
* Every bug fix or new feature must have a tracker issue.
|
||||
* You publish the branch implementing the fix or new feature in your public
|
||||
clone of the moodle.git repository (typically on Github).
|
||||
* Your patch is peer-reviewed, discussed, integrated, tested and then released
|
||||
as a part of moodle.git.
|
||||
* New features are developed on the master branch. Bug fixes are also
|
||||
backported to currently supported maintenance (stable) branches.
|
||||
|
||||
For further details, see <https://docs.moodle.org/dev/Process>.
|
||||
|
||||
Moodle plugins
|
||||
--------------
|
||||
|
||||
Moodle has a framework for additional plugins to extend its functionality. We
|
||||
have a Moodle plugins directory <https://moodle.org/plugins/> where you can
|
||||
register and maintain your plugin. Plugins hosted in the plugins directory can
|
||||
be easily installed and updated via the Moodle administration interface.
|
||||
|
||||
* You are expected to have a public source code repository with your plugin
|
||||
code.
|
||||
* After registering your plugin in the plugins directory it is reviewed before
|
||||
being published.
|
||||
* You are expected to continuously release updated versions of the plugin via
|
||||
the plugins directory. We do not pull from your code repository; you must do
|
||||
it explicitly.
|
||||
|
||||
For further details, see <https://docs.moodle.org/dev/Plugin_contribution>.
|
||||
@@ -12,7 +12,6 @@
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
/* jshint node: true, browser: false */
|
||||
|
||||
/**
|
||||
* @copyright 2014 Andrew Nicols
|
||||
@@ -25,163 +24,100 @@
|
||||
|
||||
module.exports = function(grunt) {
|
||||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
tasks = {},
|
||||
cwd = process.env.PWD || process.cwd();
|
||||
|
||||
// Windows users can't run grunt in a subdirectory, so allow them to set
|
||||
// the root by passing --root=path/to/dir.
|
||||
if (grunt.option('root')) {
|
||||
var root = grunt.option('root');
|
||||
if (grunt.file.exists(__dirname, root)) {
|
||||
cwd = path.join(__dirname, root);
|
||||
grunt.log.ok('Setting root to '+cwd);
|
||||
} else {
|
||||
grunt.fail.fatal('Setting root to '+root+' failed - path does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
var inAMD = path.basename(cwd) == 'amd';
|
||||
|
||||
// Globbing pattern for matching all AMD JS source files.
|
||||
var amdSrc = [inAMD ? cwd + '/src/*.js' : '**/amd/src/*.js'];
|
||||
|
||||
/**
|
||||
* Function to generate the destination for the uglify task
|
||||
* (e.g. build/file.min.js). This function will be passed to
|
||||
* the rename property of files array when building dynamically:
|
||||
* http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
|
||||
*
|
||||
* @param {String} destPath the current destination
|
||||
* @param {String} srcPath the matched src path
|
||||
* @return {String} The rewritten destination path.
|
||||
*/
|
||||
var uglify_rename = function (destPath, srcPath) {
|
||||
destPath = srcPath.replace('src', 'build');
|
||||
destPath = destPath.replace('.js', '.min.js');
|
||||
destPath = path.resolve(cwd, destPath);
|
||||
return destPath;
|
||||
};
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
jshint: {
|
||||
options: {jshintrc: '.jshintrc'},
|
||||
amd: { src: amdSrc }
|
||||
files: ['**/amd/src/*.js']
|
||||
},
|
||||
uglify: {
|
||||
amd: {
|
||||
files: [{
|
||||
expand: true,
|
||||
src: amdSrc,
|
||||
rename: uglify_rename
|
||||
}]
|
||||
}
|
||||
},
|
||||
less: {
|
||||
bootstrapbase: {
|
||||
files: {
|
||||
"theme/bootstrapbase/style/moodle.css": "theme/bootstrapbase/less/moodle.less",
|
||||
"theme/bootstrapbase/style/editor.css": "theme/bootstrapbase/less/editor.less",
|
||||
},
|
||||
options: {
|
||||
compress: true
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
options: {
|
||||
nospawn: true // We need not to spawn so config can be changed dynamically.
|
||||
},
|
||||
amd: {
|
||||
files: ['**/amd/src/**/*.js'],
|
||||
tasks: ['amd']
|
||||
},
|
||||
bootstrapbase: {
|
||||
files: ["theme/bootstrapbase/less/**/*.less"],
|
||||
tasks: ["less:bootstrapbase"]
|
||||
},
|
||||
yui: {
|
||||
files: ['**/yui/src/**/*.js'],
|
||||
tasks: ['shifter']
|
||||
},
|
||||
},
|
||||
shifter: {
|
||||
options: {
|
||||
recursive: true,
|
||||
paths: [cwd]
|
||||
dynamic_mappings: {
|
||||
files: grunt.file.expandMapping(
|
||||
['**/src/*.js', '!**/node_modules/**'],
|
||||
'',
|
||||
{
|
||||
cwd: cwd,
|
||||
rename: function(destBase, destPath) {
|
||||
destPath = destPath.replace('src', 'build');
|
||||
destPath = destPath.replace('.js', '.min.js');
|
||||
destPath = path.resolve(cwd, destPath);
|
||||
return destPath;
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Shifter task. Is configured with a path to a specific file or a directory,
|
||||
* in the case of a specific file it will work out the right module to be built.
|
||||
*
|
||||
* Note that this task runs the invidiaul shifter jobs async (becase it spawns
|
||||
* so be careful to to call done().
|
||||
*/
|
||||
tasks.shifter = function() {
|
||||
var async = require('async'),
|
||||
var exec = require('child_process').spawn,
|
||||
done = this.async(),
|
||||
options = grunt.config('shifter.options');
|
||||
args = [],
|
||||
options = {
|
||||
recursive: true,
|
||||
watch: false,
|
||||
walk: false,
|
||||
module: false
|
||||
},
|
||||
shifter;
|
||||
|
||||
// Run the shifter processes one at a time to avoid confusing output.
|
||||
async.eachSeries(options.paths, function (src, filedone) {
|
||||
var args = [];
|
||||
args.push( path.normalize(__dirname + '/node_modules/shifter/bin/shifter'));
|
||||
|
||||
// Always ignore the node_modules directory.
|
||||
args.push('--excludes', 'node_modules');
|
||||
|
||||
// Determine the most appropriate options to run with based upon the current location.
|
||||
if (grunt.file.isMatch('**/yui/**/*.js', src)) {
|
||||
// When passed a JS file, build our containing module (this happen with
|
||||
// watch).
|
||||
grunt.log.debug('Shifter passed a specific JS file');
|
||||
src = path.dirname(path.dirname(src));
|
||||
options.recursive = false;
|
||||
} else if (grunt.file.isMatch('**/yui/src', src)) {
|
||||
// When in a src directory --walk all modules.
|
||||
if (path.basename(cwd) === 'src') {
|
||||
// Detect whether we're in a src directory.
|
||||
grunt.log.debug('In a src directory');
|
||||
args.push('--walk');
|
||||
options.recursive = false;
|
||||
} else if (grunt.file.isMatch('**/yui/src/*', src)) {
|
||||
// When in module, only build our module.
|
||||
options.walk = true;
|
||||
} else if (path.basename(path.dirname(cwd)) === 'src') {
|
||||
// Detect whether we're in a module directory.
|
||||
grunt.log.debug('In a module directory');
|
||||
options.recursive = false;
|
||||
} else if (grunt.file.isMatch('**/yui/src/*/js', src)) {
|
||||
// When in module src, only build our module.
|
||||
grunt.log.debug('In a source directory');
|
||||
src = path.dirname(src);
|
||||
options.recursive = false;
|
||||
options.module = true;
|
||||
}
|
||||
|
||||
if (grunt.option('watch')) {
|
||||
grunt.fail.fatal('The --watch option has been removed, please use `grunt watch` instead');
|
||||
if (!options.walk && !options.module) {
|
||||
grunt.fail.fatal('Unable to watch unless in a src or module directory');
|
||||
}
|
||||
|
||||
// It is not advisable to run with recursivity and watch - this
|
||||
// leads to building the build directory in a race-like fashion.
|
||||
grunt.log.debug('Detected a watch - disabling recursivity');
|
||||
options.recursive = false;
|
||||
args.push('--watch');
|
||||
}
|
||||
|
||||
if (options.recursive) {
|
||||
args.push('--recursive');
|
||||
}
|
||||
|
||||
// Always ignore the node_modules directory.
|
||||
args.push('--excludes', 'node_modules');
|
||||
|
||||
// Add the stderr option if appropriate
|
||||
if (grunt.option('verbose')) {
|
||||
args.push('--lint-stderr');
|
||||
}
|
||||
|
||||
if (grunt.option('no-color')) {
|
||||
args.push('--color=false');
|
||||
}
|
||||
|
||||
var execShifter = function() {
|
||||
|
||||
grunt.log.ok("Running shifter on " + src);
|
||||
grunt.util.spawn({
|
||||
cmd: "node",
|
||||
args: args,
|
||||
opts: {cwd: src, stdio: 'inherit', env: process.env}
|
||||
}, function (error, result, code) {
|
||||
shifter = exec("node", args, {
|
||||
cwd: cwd,
|
||||
stdio: 'inherit',
|
||||
env: process.env
|
||||
});
|
||||
|
||||
// Tidy up after exec.
|
||||
shifter.on('exit', function (code) {
|
||||
if (code) {
|
||||
grunt.fail.fatal('Shifter failed with code: ' + code);
|
||||
} else {
|
||||
grunt.log.ok('Shifter build complete.');
|
||||
filedone();
|
||||
done();
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -191,15 +127,79 @@ module.exports = function(grunt) {
|
||||
execShifter();
|
||||
} else {
|
||||
// Check that there are yui modules otherwise shifter ends with exit code 1.
|
||||
if (grunt.file.expand({cwd: src}, '**/yui/src/**/*.js').length > 0) {
|
||||
args.push('--recursive');
|
||||
execShifter();
|
||||
} else {
|
||||
grunt.log.ok('No YUI modules to build.');
|
||||
filedone();
|
||||
}
|
||||
var found = false;
|
||||
var hasYuiModules = function(directory, callback) {
|
||||
fs.readdir(directory, function(err, files) {
|
||||
if (err) {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
// If we already found a match there is no need to continue scanning.
|
||||
if (found === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to track the number of files to know when we return a result.
|
||||
var pending = files.length;
|
||||
|
||||
// We first check files, so if there is a match we don't need further
|
||||
// async calls and we just return a true.
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
if (files[i] === 'yui') {
|
||||
return callback(null, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate through subdirs if there were no matches.
|
||||
files.forEach(function (file) {
|
||||
|
||||
var p = path.join(directory, file);
|
||||
stat = fs.statSync(p);
|
||||
if (!stat.isDirectory()) {
|
||||
pending--;
|
||||
} else {
|
||||
|
||||
// We defer the pending-1 until we scan the whole dir and subdirs.
|
||||
hasYuiModules(p, function(err, result) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (result === true) {
|
||||
// Once we get a true we notify the caller.
|
||||
found = true;
|
||||
return callback(null, true);
|
||||
}
|
||||
|
||||
pending--;
|
||||
if (pending === 0) {
|
||||
// Notify the caller that the whole dir has been scaned and there are no matches.
|
||||
return callback(null, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// No subdirs here, otherwise the return would be deferred until all subdirs are scanned.
|
||||
if (pending === 0) {
|
||||
return callback(null, false);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
hasYuiModules(cwd, function(err, result) {
|
||||
if (err) {
|
||||
grunt.fail.fatal(err.message);
|
||||
}
|
||||
|
||||
if (result === true) {
|
||||
execShifter();
|
||||
} else {
|
||||
grunt.log.ok('No YUI modules to build.');
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
}, done);
|
||||
};
|
||||
|
||||
tasks.startup = function() {
|
||||
@@ -207,45 +207,24 @@ module.exports = function(grunt) {
|
||||
if (path.basename(path.resolve(cwd, '../../')) == 'yui') {
|
||||
grunt.task.run('shifter');
|
||||
// Are we in an AMD directory?
|
||||
} else if (inAMD) {
|
||||
grunt.task.run('amd');
|
||||
} else if (path.basename(cwd) == 'amd') {
|
||||
grunt.task.run('jshint');
|
||||
grunt.task.run('uglify');
|
||||
} else {
|
||||
// Run them all!.
|
||||
grunt.task.run('css');
|
||||
grunt.task.run('js');
|
||||
grunt.task.run('shifter');
|
||||
grunt.task.run('jshint');
|
||||
grunt.task.run('uglify');
|
||||
}
|
||||
};
|
||||
|
||||
// On watch, we dynamically modify config to build only affected files. This
|
||||
// method is slightly complicated to deal with multiple changed files at once (copied
|
||||
// from the grunt-contrib-watch readme).
|
||||
var changedFiles = Object.create(null);
|
||||
var onChange = grunt.util._.debounce(function() {
|
||||
var files = Object.keys(changedFiles);
|
||||
grunt.config('jshint.amd.src', files);
|
||||
grunt.config('uglify.amd.files', [{ expand: true, src: files, rename: uglify_rename }]);
|
||||
grunt.config('shifter.options.paths', files);
|
||||
changedFiles = Object.create(null);
|
||||
}, 200);
|
||||
|
||||
grunt.event.on('watch', function(action, filepath) {
|
||||
changedFiles[filepath] = action;
|
||||
onChange();
|
||||
});
|
||||
|
||||
// Register NPM tasks.
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-less');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
|
||||
// Register JS tasks.
|
||||
// Register the shifter task.
|
||||
grunt.registerTask('shifter', 'Run Shifter against the current directory', tasks.shifter);
|
||||
grunt.registerTask('amd', ['jshint', 'uglify']);
|
||||
grunt.registerTask('js', ['amd', 'shifter']);
|
||||
|
||||
// Register CSS taks.
|
||||
grunt.registerTask('css', ['less:bootstrapbase']);
|
||||
|
||||
// Register the startup task.
|
||||
grunt.registerTask('startup', 'Run the correct tasks for the current directory', tasks.startup);
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
MOODLE INSTALLATION
|
||||
===================
|
||||
|
||||
Here is a short summary of the installation process (which can take just a few
|
||||
minutes):
|
||||
|
||||
1. Move the Moodle files into your web directory.
|
||||
|
||||
2. Create a single database for Moodle to store all its tables in (or choose an
|
||||
existing database).
|
||||
|
||||
3. Visit your Moodle site with a browser. You should be taken to the
|
||||
install.php script, which will lead you through creating a config.php file
|
||||
and then setting up Moodle, creating an admin account etc.
|
||||
|
||||
4. Set up a cron task to call the file admin/cron.php every minute.
|
||||
|
||||
For more information, see <https://docs.moodle.org/en/Installing_Moodle>.
|
||||
|
||||
Good luck and have fun!
|
||||
@@ -1,7 +0,0 @@
|
||||
*** PLEASE DO NOT OPEN PULL REQUESTS VIA GITHUB ***
|
||||
|
||||
The moodle.git repository at Github is just a mirror of the official repository. We do not accept pull requests at Github.
|
||||
|
||||
See CONTRIBUTING.txt guidelines for how to contribute patches for Moodle. Thank you.
|
||||
|
||||
--
|
||||
@@ -1,28 +1,29 @@
|
||||
.-..-.
|
||||
_____ | || |
|
||||
/____/-.---_ .---. .---. .-.| || | .---.
|
||||
| | _ _ |/ _ \/ _ \/ _ || |/ __ \
|
||||
* | | | | | || |_| || |_| || |_| || || |___/
|
||||
|_| |_| |_|\_____/\_____/\_____||_|\_____)
|
||||
QUICK INSTALL
|
||||
=============
|
||||
|
||||
Moodle - the world's open source learning platform
|
||||
For the impatient, here is a basic outline of the
|
||||
installation process, which normally takes me only
|
||||
a few minutes:
|
||||
|
||||
Moodle <https://moodle.org> is a learning platform designed to provide
|
||||
educators, administrators and learners with a single robust, secure and
|
||||
integrated system to create personalised learning environments.
|
||||
1) Move the Moodle files into your web directory.
|
||||
|
||||
You can download Moodle <https://download.moodle.org> and run it on your own
|
||||
web server, ask one of our Moodle Partners <https://moodle.com/partners/> to
|
||||
assist you, or have a MoodleCloud site <https://moodle.com/cloud/> set up for
|
||||
you.
|
||||
2) Create a single database for Moodle to store all
|
||||
its tables in (or choose an existing database).
|
||||
|
||||
Moodle is widely used around the world by universities, schools, companies and
|
||||
all manner of organisations and individuals.
|
||||
3) Visit your Moodle site with a browser, you should
|
||||
be taken to the install.php script, which will lead
|
||||
you through creating a config.php file and then
|
||||
setting up Moodle, creating an admin account etc.
|
||||
|
||||
Moodle is provided freely as open source software, under the GNU General Public
|
||||
License <https://docs.moodle.org/dev/License>.
|
||||
4) Set up a cron task to call the file admin/cron.php
|
||||
every five minutes or so.
|
||||
|
||||
Moodle is written in PHP and JavaScript and uses an SQL database for storing
|
||||
the data.
|
||||
|
||||
See <https://docs.moodle.org> for details of Moodle's many features.
|
||||
For more information, see the INSTALL DOCUMENTATION:
|
||||
|
||||
http://docs.moodle.org/en/Installing_Moodle
|
||||
|
||||
|
||||
Good luck and have fun!
|
||||
Martin Dougiamas, Lead Developer
|
||||
|
||||
|
||||
@@ -1,48 +1,34 @@
|
||||
MOODLE TRADEMARKS POLICY
|
||||
========================
|
||||
------------------------
|
||||
Moodle Trademark License
|
||||
------------------------
|
||||
|
||||
The word "Moodle" is trademarked in many countries around the world. The word
|
||||
was originally an acronym: Modular Object-Oriented Dynamic Learning
|
||||
Environment. The trademark is owned by Martin Dougiamas, Founder and Director
|
||||
of Moodle.
|
||||
The name Moodle™ is a registered trademark of the Moodle Trust.
|
||||
|
||||
The law obligates trademark owners to police their marks and prevent the use of
|
||||
confusingly similar names by third parties. Through this policy we’d like to
|
||||
make it clear how Moodle-related projects, organisations, and people can use
|
||||
the Moodle trademark. We’d also like to be clear about how use of the word is
|
||||
restricted when used to promote commercial Moodle services. We do this to
|
||||
protect the very business model that allows us to continue developing Moodle
|
||||
for you.
|
||||
A key part of the business model that allows us to produce and
|
||||
distribute Moodle as completely Free open source software is that
|
||||
we restrict the commercial use of the Moodle trademark to those
|
||||
who have contracted to support Moodle development (Moodle Partners).
|
||||
|
||||
Allowed uses
|
||||
------------
|
||||
If you are intending to use the name (and/or logo) to advertise
|
||||
generic Moodle™ services (eg Moodle Hosting, Moodle Support,
|
||||
Moodle Certification, Moodle Training, Moodle Consulting,
|
||||
Moodle Customisation, Moodle Courseware Development, Moodle
|
||||
Theme design, Moodle Integrations, Moodle Installations, etc)
|
||||
or as the name of a software package, then you must seek
|
||||
direct permission in writing from the Moodle Trust via the
|
||||
moodle.com helpdesk, in accordance with normal trademark
|
||||
restrictions.
|
||||
|
||||
The following uses don’t require any permission at all:
|
||||
There are no restrictions on how you use the name in other
|
||||
contexts (for example, if you use Moodle just to provide
|
||||
courses then you can use the name freely to refer to it.)
|
||||
|
||||
* Referring to the software or the Moodle project.
|
||||
* Describing your own Moodle implementation (including within corporate
|
||||
settings).
|
||||
* Describing a Moodle-based community hub.
|
||||
* Describing some software you’ve made that integrates with Moodle
|
||||
(eg a Moodle integration feature on another system).
|
||||
If you aren't sure of a particular case, please ask us via
|
||||
http://moodle.com/helpdesk: we'll be happy to either provide
|
||||
you with official permission in writing or help you fix
|
||||
your wording.
|
||||
|
||||
Restricted uses
|
||||
---------------
|
||||
|
||||
The following uses are generally prohibited without explicit and direct
|
||||
permission being granted to you by Moodle Pty Ltd. We do this to protect the
|
||||
Moodle project from software and sites which could confuse people. Please
|
||||
contact us to ask for permission in writing.
|
||||
|
||||
* You can’t use "Moodle" in the name of your software (including Mobile apps)
|
||||
* You can’t use "Moodle" in your company name
|
||||
* You can’t use "Moodle" in your domain name
|
||||
* You can’t use "Moodle" in advertising-related keywords (such as Adsense)
|
||||
* You can’t use "Moodle" to describe services around Moodle (such as hosting,
|
||||
training, support, consulting, course creation services, theme development,
|
||||
customisation, installation, integration and certification). This applies
|
||||
even if you do not charge for the services. Note that usually only Moodle
|
||||
Partners have this permission.
|
||||
|
||||
For information about the Moodle Partner Certification Mark as well as for how
|
||||
to contact us, please see <https://moodle.com/trademarks/>.
|
||||
Martin Dougiamas
|
||||
Executive Director
|
||||
Moodle Trust
|
||||
http://moodle.com
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Allows admin to configure antiviruses.
|
||||
*
|
||||
* @package core_antivirus
|
||||
* @copyright 2015 Ruslan Kabalin, Lancaster University.
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once('../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/tablelib.php');
|
||||
|
||||
$action = required_param('action', PARAM_ALPHANUMEXT);
|
||||
$antivirus = required_param('antivirus', PARAM_PLUGIN);
|
||||
$confirm = optional_param('confirm', 0, PARAM_BOOL);
|
||||
|
||||
$PAGE->set_url('/admin/antiviruses.php', array('action' => $action, 'antivirus' => $antivirus));
|
||||
$PAGE->set_context(context_system::instance());
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/site:config', context_system::instance());
|
||||
|
||||
$returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageantiviruses";
|
||||
|
||||
// Get currently installed and enabled antivirus plugins.
|
||||
$availableantiviruses = \core\antivirus\manager::get_available();
|
||||
if (!empty($antivirus) and empty($availableantiviruses[$antivirus])) {
|
||||
redirect ($returnurl);
|
||||
}
|
||||
|
||||
$activeantiviruses = explode(',', $CFG->antiviruses);
|
||||
foreach ($activeantiviruses as $key => $active) {
|
||||
if (empty($availableantiviruses[$active])) {
|
||||
unset($activeantiviruses[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!confirm_sesskey()) {
|
||||
redirect($returnurl);
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
case 'disable':
|
||||
// Remove from enabled list.
|
||||
$key = array_search($antivirus, $activeantiviruses);
|
||||
unset($activeantiviruses[$key]);
|
||||
break;
|
||||
|
||||
case 'enable':
|
||||
// Add to enabled list.
|
||||
if (!in_array($antivirus, $activeantiviruses)) {
|
||||
$activeantiviruses[] = $antivirus;
|
||||
$activeantiviruses = array_unique($activeantiviruses);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'down':
|
||||
$key = array_search($antivirus, $activeantiviruses);
|
||||
// Check auth plugin is valid.
|
||||
if ($key !== false) {
|
||||
// Move down the list.
|
||||
if ($key < (count($activeantiviruses) - 1)) {
|
||||
$fsave = $activeantiviruses[$key];
|
||||
$activeantiviruses[$key] = $activeantiviruses[$key + 1];
|
||||
$activeantiviruses[$key + 1] = $fsave;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'up':
|
||||
$key = array_search($antivirus, $activeantiviruses);
|
||||
// Check auth is valid.
|
||||
if ($key !== false) {
|
||||
// Move up the list.
|
||||
if ($key >= 1) {
|
||||
$fsave = $activeantiviruses[$key];
|
||||
$activeantiviruses[$key] = $activeantiviruses[$key - 1];
|
||||
$activeantiviruses[$key - 1] = $fsave;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
set_config('antiviruses', implode(',', $activeantiviruses));
|
||||
core_plugin_manager::reset_caches();
|
||||
|
||||
redirect ($returnurl);
|
||||
@@ -148,6 +148,8 @@ function print_auth_lock_options($auth, $user_fields, $helptext, $retrieveopts,
|
||||
// If custom field then pick name from database.
|
||||
$fieldshortname = str_replace('profile_field_', '', $fieldname);
|
||||
$fieldname = $customfieldname[$fieldshortname]->name;
|
||||
} elseif ($fieldname == 'phone1') {
|
||||
$fieldname = get_string('phone');
|
||||
} elseif ($fieldname == 'url') {
|
||||
$fieldname = get_string('webpage');
|
||||
} else {
|
||||
|
||||
@@ -155,8 +155,7 @@
|
||||
} else if ($blocksettings instanceof admin_settingpage) {
|
||||
$settings = '<a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section=blocksetting'.$block->name.'">'.$strsettings.'</a>';
|
||||
} else {
|
||||
debugging('Warning: block_'.$block->name.' returns true in has_config() but does not provide a settings.php file',
|
||||
DEBUG_DEVELOPER);
|
||||
$settings = '<a href="block.php?block='.$blockid.'">'.$strsettings.'</a>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,14 +74,12 @@ Options:
|
||||
--adminpass=PASSWORD Password for the moodle admin account,
|
||||
required in non-interactive mode.
|
||||
--adminemail=STRING Email address for the moodle admin account.
|
||||
--upgradekey=STRING The upgrade key to be set in the config.php, leave empty to not set it.
|
||||
--non-interactive No interactive questions, installation fails if any
|
||||
problem encountered.
|
||||
--agree-license Indicates agreement with software license,
|
||||
required in non-interactive mode.
|
||||
--allow-unstable Install even if the version is not marked as stable yet,
|
||||
required in non-interactive mode.
|
||||
--skip-database Stop the installation before installing the database.
|
||||
-h, --help Print out this help
|
||||
|
||||
Example:
|
||||
@@ -259,11 +257,9 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'adminuser' => 'admin',
|
||||
'adminpass' => '',
|
||||
'adminemail' => '',
|
||||
'upgradekey' => '',
|
||||
'non-interactive' => false,
|
||||
'agree-license' => false,
|
||||
'allow-unstable' => false,
|
||||
'skip-database' => false,
|
||||
'help' => false
|
||||
),
|
||||
array(
|
||||
@@ -275,8 +271,7 @@ $interactive = empty($options['non-interactive']);
|
||||
|
||||
// set up language
|
||||
$lang = clean_param($options['lang'], PARAM_SAFEDIR);
|
||||
$languages = get_string_manager()->get_list_of_translations();
|
||||
if (array_key_exists($lang, $languages)) {
|
||||
if (file_exists($CFG->dirroot.'/install/lang/'.$lang)) {
|
||||
$CFG->lang = $lang;
|
||||
}
|
||||
|
||||
@@ -291,41 +286,28 @@ if ($options['help']) {
|
||||
}
|
||||
|
||||
//Print header
|
||||
cli_logo();
|
||||
echo PHP_EOL;
|
||||
echo get_string('cliinstallheader', 'install', $CFG->target_release)."\n";
|
||||
|
||||
//Fist select language
|
||||
if ($interactive) {
|
||||
cli_separator();
|
||||
$languages = get_string_manager()->get_list_of_translations();
|
||||
// Do not put the langs into columns because it is not compatible with RTL.
|
||||
$langlist = implode("\n", $languages);
|
||||
$default = $CFG->lang;
|
||||
cli_heading(get_string('chooselanguagehead', 'install'));
|
||||
if (array_key_exists($default, $languages)) {
|
||||
echo $default.' - '.$languages[$default]."\n";
|
||||
}
|
||||
if ($default !== 'en') {
|
||||
echo 'en - English (en)'."\n";
|
||||
}
|
||||
echo '? - '.get_string('availablelangs', 'install')."\n";
|
||||
cli_heading(get_string('availablelangs', 'install'));
|
||||
echo $langlist."\n";
|
||||
$prompt = get_string('clitypevaluedefault', 'admin', $CFG->lang);
|
||||
$error = '';
|
||||
do {
|
||||
echo $error;
|
||||
$input = cli_input($prompt, $default);
|
||||
$input = clean_param($input, PARAM_SAFEDIR);
|
||||
|
||||
if ($input === '?') {
|
||||
echo implode("\n", $languages)."\n";
|
||||
$error = "\n";
|
||||
|
||||
if (!file_exists($CFG->dirroot.'/install/lang/'.$input)) {
|
||||
$error = get_string('cliincorrectvalueretry', 'admin')."\n";
|
||||
} else {
|
||||
$input = clean_param($input, PARAM_SAFEDIR);
|
||||
|
||||
if (!array_key_exists($input, $languages)) {
|
||||
$error = get_string('cliincorrectvalueretry', 'admin')."\n";
|
||||
} else {
|
||||
$error = '';
|
||||
}
|
||||
$error = '';
|
||||
}
|
||||
} while ($error !== '');
|
||||
$CFG->lang = $input;
|
||||
@@ -724,24 +706,6 @@ if (!empty($options['adminemail']) && !validate_email($options['adminemail'])) {
|
||||
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
|
||||
}
|
||||
|
||||
// Ask for the upgrade key.
|
||||
if ($interactive) {
|
||||
cli_separator();
|
||||
cli_heading(get_string('upgradekeyset', 'admin'));
|
||||
if ($options['upgradekey'] !== '') {
|
||||
$prompt = get_string('clitypevaluedefault', 'admin', $options['upgradekey']);
|
||||
$options['upgradekey'] = cli_input($prompt, $options['upgradekey']);
|
||||
} else {
|
||||
$prompt = get_string('clitypevalue', 'admin');
|
||||
$options['upgradekey'] = cli_input($prompt);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the upgrade key if it was provided.
|
||||
if ($options['upgradekey'] !== '') {
|
||||
$CFG->upgradekey = $options['upgradekey'];
|
||||
}
|
||||
|
||||
if ($interactive) {
|
||||
if (!$options['agree-license']) {
|
||||
cli_separator();
|
||||
@@ -806,11 +770,7 @@ if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
|
||||
cli_error(get_string('pluginschecktodo', 'admin'));
|
||||
}
|
||||
|
||||
if (!$options['skip-database']) {
|
||||
install_cli_database($options, $interactive);
|
||||
} else {
|
||||
echo get_string('cliskipdatabase', 'install')."\n";
|
||||
}
|
||||
install_cli_database($options, $interactive);
|
||||
|
||||
echo get_string('cliinstallfinished', 'install')."\n";
|
||||
exit(0); // 0 means success
|
||||
|
||||
@@ -45,23 +45,17 @@ require_once($CFG->libdir.'/clilib.php'); // cli only functions
|
||||
require_once($CFG->libdir.'/environmentlib.php');
|
||||
|
||||
// now get cli options
|
||||
$lang = isset($SESSION->lang) ? $SESSION->lang : $CFG->lang;
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
array(
|
||||
'non-interactive' => false,
|
||||
'allow-unstable' => false,
|
||||
'help' => false,
|
||||
'lang' => $lang
|
||||
'help' => false
|
||||
),
|
||||
array(
|
||||
'h' => 'help'
|
||||
)
|
||||
);
|
||||
|
||||
if ($options['lang']) {
|
||||
$SESSION->lang = $options['lang'];
|
||||
}
|
||||
|
||||
$interactive = empty($options['non-interactive']);
|
||||
|
||||
if ($unrecognized) {
|
||||
@@ -80,10 +74,6 @@ Options:
|
||||
--non-interactive No interactive questions or confirmations
|
||||
--allow-unstable Upgrade even if the version is not marked as stable yet,
|
||||
required in non-interactive mode.
|
||||
--lang=CODE Set preferred language for CLI output. Defaults to the
|
||||
site language if not set. Defaults to 'en' if the lang
|
||||
parameter is invalid or if the language pack is not
|
||||
installed.
|
||||
-h, --help Print out this help
|
||||
|
||||
Example:
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Lets users manage data formats
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @copyright 2016 Brendan Heywood (brendan@catalyst-au.net)
|
||||
* @package core
|
||||
* @subpackage dataformat
|
||||
*/
|
||||
|
||||
require_once('../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
|
||||
$action = required_param('action', PARAM_ALPHANUMEXT);
|
||||
$name = required_param('name', PARAM_PLUGIN);
|
||||
|
||||
$syscontext = context_system::instance();
|
||||
$PAGE->set_url('/admin/dataformats.php');
|
||||
$PAGE->set_context($syscontext);
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/site:config', $syscontext);
|
||||
require_sesskey();
|
||||
|
||||
$return = new moodle_url('/admin/settings.php', array('section' => 'managedataformats'));
|
||||
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('dataformat');
|
||||
$sortorder = array_flip(array_keys($plugins));
|
||||
|
||||
if (!isset($plugins[$name])) {
|
||||
print_error('courseformatnotfound', 'error', $return, $name);
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
case 'disable':
|
||||
if ($plugins[$name]->is_enabled()) {
|
||||
set_config('disabled', 1, 'dataformat_'. $name);
|
||||
core_plugin_manager::reset_caches();
|
||||
}
|
||||
break;
|
||||
case 'enable':
|
||||
if (!$plugins[$name]->is_enabled()) {
|
||||
unset_config('disabled', 'dataformat_'. $name);
|
||||
core_plugin_manager::reset_caches();
|
||||
}
|
||||
break;
|
||||
case 'up':
|
||||
if ($sortorder[$name]) {
|
||||
$currentindex = $sortorder[$name];
|
||||
$seq = array_keys($plugins);
|
||||
$seq[$currentindex] = $seq[$currentindex - 1];
|
||||
$seq[$currentindex - 1] = $name;
|
||||
set_config('dataformat_plugins_sortorder', implode(',', $seq));
|
||||
}
|
||||
break;
|
||||
case 'down':
|
||||
if ($sortorder[$name] < count($sortorder) - 1) {
|
||||
$currentindex = $sortorder[$name];
|
||||
$seq = array_keys($plugins);
|
||||
$seq[$currentindex] = $seq[$currentindex + 1];
|
||||
$seq[$currentindex + 1] = $name;
|
||||
set_config('dataformat_plugins_sortorder', implode(',', $seq));
|
||||
}
|
||||
break;
|
||||
}
|
||||
redirect($return);
|
||||
|
||||
@@ -1434,6 +1434,7 @@
|
||||
<VENDOR name="oracle" version="10.2" />
|
||||
</DATABASE>
|
||||
<PHP version="5.4.4" level="required">
|
||||
<RESTRICT function="restrict_php_version_7" message="unsupportedphpversion7" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -1558,144 +1559,4 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="3.1" requires="2.7">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="5.5.31" />
|
||||
<VENDOR name="mysql" version="5.5.31" />
|
||||
<VENDOR name="postgres" version="9.1" />
|
||||
<VENDOR name="mssql" version="10.0" />
|
||||
<VENDOR name="oracle" version="10.2" />
|
||||
</DATABASE>
|
||||
<PHP version="5.4.4" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="mbstringrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opensslrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlrpc" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="xmlrpcrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="intlrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -54,16 +54,6 @@ if (!function_exists('json_encode') || !function_exists('json_decode')) {
|
||||
|
||||
define('NO_OUTPUT_BUFFERING', true);
|
||||
|
||||
if (isset($_POST['upgradekey'])) {
|
||||
// Before you start reporting issues about the collision attacks against
|
||||
// SHA-1, you should understand that we are not actually attempting to do
|
||||
// any cryptography here. This is hashed purely so that the key is not
|
||||
// that apparent in the address bar itself. Anyone who catches the HTTP
|
||||
// traffic can immediately use it as a valid admin key.
|
||||
header('Location: index.php?cache=0&upgradekeyhash='.sha1($_POST['upgradekey']));
|
||||
die();
|
||||
}
|
||||
|
||||
if ((isset($_GET['cache']) and $_GET['cache'] === '0')
|
||||
or (isset($_POST['cache']) and $_POST['cache'] === '0')
|
||||
or (!isset($_POST['cache']) and !isset($_GET['cache']) and empty($_GET['sesskey']) and empty($_POST['sesskey']))) {
|
||||
@@ -98,51 +88,22 @@ core_component::get_core_subsystems();
|
||||
require_once($CFG->libdir.'/adminlib.php'); // various admin-only functions
|
||||
require_once($CFG->libdir.'/upgradelib.php'); // general upgrade/install related functions
|
||||
|
||||
$confirmupgrade = optional_param('confirmupgrade', 0, PARAM_BOOL); // Core upgrade confirmed?
|
||||
$confirmrelease = optional_param('confirmrelease', 0, PARAM_BOOL); // Core release info and server checks confirmed?
|
||||
$confirmplugins = optional_param('confirmplugincheck', 0, PARAM_BOOL); // Plugins check page confirmed?
|
||||
$showallplugins = optional_param('showallplugins', 0, PARAM_BOOL); // Show all plugins on the plugins check page?
|
||||
$agreelicense = optional_param('agreelicense', 0, PARAM_BOOL); // GPL license confirmed for installation?
|
||||
$fetchupdates = optional_param('fetchupdates', 0, PARAM_BOOL); // Should check for available updates?
|
||||
$newaddonreq = optional_param('installaddonrequest', null, PARAM_RAW); // Plugin installation requested at moodle.org/plugins.
|
||||
$upgradekeyhash = optional_param('upgradekeyhash', null, PARAM_ALPHANUM); // Hash of provided upgrade key.
|
||||
$installdep = optional_param('installdep', null, PARAM_COMPONENT); // Install given missing dependency (required plugin).
|
||||
$installdepx = optional_param('installdepx', false, PARAM_BOOL); // Install all missing dependencies.
|
||||
$confirminstalldep = optional_param('confirminstalldep', false, PARAM_BOOL); // Installing dependencies confirmed.
|
||||
$abortinstall = optional_param('abortinstall', null, PARAM_COMPONENT); // Cancel installation of the given new plugin.
|
||||
$abortinstallx = optional_param('abortinstallx', null, PARAM_BOOL); // Cancel installation of all new plugins.
|
||||
$confirmabortinstall = optional_param('confirmabortinstall', false, PARAM_BOOL); // Installation cancel confirmed.
|
||||
$abortupgrade = optional_param('abortupgrade', null, PARAM_COMPONENT); // Cancel upgrade of the given existing plugin.
|
||||
$abortupgradex = optional_param('abortupgradex', null, PARAM_BOOL); // Cancel upgrade of all upgradable plugins.
|
||||
$confirmabortupgrade = optional_param('confirmabortupgrade', false, PARAM_BOOL); // Upgrade cancel confirmed.
|
||||
$installupdate = optional_param('installupdate', null, PARAM_COMPONENT); // Install given available update.
|
||||
$installupdateversion = optional_param('installupdateversion', null, PARAM_INT); // Version of the available update to install.
|
||||
$installupdatex = optional_param('installupdatex', false, PARAM_BOOL); // Install all available plugin updates.
|
||||
$confirminstallupdate = optional_param('confirminstallupdate', false, PARAM_BOOL); // Available update(s) install confirmed?
|
||||
|
||||
if (!empty($CFG->disableupdateautodeploy)) {
|
||||
// Invalidate all requests to install plugins via the admin UI.
|
||||
$newaddonreq = null;
|
||||
$installdep = null;
|
||||
$installdepx = false;
|
||||
$abortupgrade = null;
|
||||
$abortupgradex = null;
|
||||
$installupdate = null;
|
||||
$installupdateversion = null;
|
||||
$installupdatex = false;
|
||||
}
|
||||
$confirmupgrade = optional_param('confirmupgrade', 0, PARAM_BOOL);
|
||||
$confirmrelease = optional_param('confirmrelease', 0, PARAM_BOOL);
|
||||
$confirmplugins = optional_param('confirmplugincheck', 0, PARAM_BOOL);
|
||||
$showallplugins = optional_param('showallplugins', 0, PARAM_BOOL);
|
||||
$agreelicense = optional_param('agreelicense', 0, PARAM_BOOL);
|
||||
$fetchupdates = optional_param('fetchupdates', 0, PARAM_BOOL);
|
||||
$newaddonreq = optional_param('installaddonrequest', null, PARAM_RAW);
|
||||
|
||||
// Set up PAGE.
|
||||
$url = new moodle_url('/admin/index.php');
|
||||
$url->param('cache', $cache);
|
||||
if (isset($upgradekeyhash)) {
|
||||
$url->param('upgradekeyhash', $upgradekeyhash);
|
||||
}
|
||||
$PAGE->set_url($url);
|
||||
unset($url);
|
||||
|
||||
// Are we returning from an add-on installation request at moodle.org/plugins?
|
||||
if ($newaddonreq and !$cache and empty($CFG->disableupdateautodeploy)) {
|
||||
if ($newaddonreq and !$cache and empty($CFG->disableonclickaddoninstall)) {
|
||||
$target = new moodle_url('/admin/tool/installaddon/index.php', array(
|
||||
'installaddonrequest' => $newaddonreq,
|
||||
'confirm' => 0));
|
||||
@@ -213,6 +174,7 @@ if (!core_tables_exist()) {
|
||||
$PAGE->set_heading($strinstallation);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->install_licence_page();
|
||||
die();
|
||||
@@ -227,6 +189,7 @@ if (!core_tables_exist()) {
|
||||
$PAGE->set_heading($strinstallation . ' - Moodle ' . $CFG->target_release);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->install_environment_page($maturity, $envstatus, $environment_results, $release);
|
||||
die();
|
||||
@@ -240,7 +203,7 @@ if (!core_tables_exist()) {
|
||||
$PAGE->set_heading($strinstallation . ' - Moodle ' . $CFG->target_release);
|
||||
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
$url = new moodle_url($PAGE->url, array('agreelicense' => 1, 'confirmrelease' => 1, 'lang' => $CFG->lang));
|
||||
$url = new moodle_url('/admin/index.php', array('agreelicense' => 1, 'confirmrelease' => 1, 'lang' => $CFG->lang));
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, $url);
|
||||
die();
|
||||
}
|
||||
@@ -290,19 +253,11 @@ if (empty($CFG->version)) {
|
||||
// Detect config cache inconsistency, this happens when you switch branches on dev servers.
|
||||
if ($CFG->version != $DB->get_field('config', 'value', array('name'=>'version'))) {
|
||||
purge_all_caches();
|
||||
redirect(new moodle_url($PAGE->url), 'Config cache inconsistency detected, resetting caches...');
|
||||
redirect(new moodle_url('/admin/index.php'), 'Config cache inconsistency detected, resetting caches...');
|
||||
}
|
||||
|
||||
if (!$cache and $version > $CFG->version) { // upgrade
|
||||
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array(
|
||||
'confirmupgrade' => $confirmupgrade,
|
||||
'confirmrelease' => $confirmrelease,
|
||||
'confirmplugincheck' => $confirmplugins,
|
||||
)));
|
||||
|
||||
check_upgrade_key($upgradekeyhash);
|
||||
|
||||
// Warning about upgrading a test site.
|
||||
$testsite = false;
|
||||
if (defined('BEHAT_SITE_RUNNING')) {
|
||||
@@ -318,6 +273,7 @@ if (!$cache and $version > $CFG->version) { // upgrade
|
||||
// We then purge the regular caches.
|
||||
purge_all_caches();
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
if (upgrade_stale_php_files_present()) {
|
||||
@@ -362,137 +318,40 @@ if (!$cache and $version > $CFG->version) { // upgrade
|
||||
$PAGE->set_heading($strplugincheck);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
$reloadurl = new moodle_url('/admin/index.php', array('confirmupgrade' => 1, 'confirmrelease' => 1, 'cache' => 0));
|
||||
|
||||
// Check for available updates.
|
||||
if ($fetchupdates) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$updateschecker = \core\update\checker::instance();
|
||||
if ($updateschecker->enabled()) {
|
||||
$updateschecker->fetch();
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
redirect($reloadurl);
|
||||
}
|
||||
|
||||
// Cancel all plugin installations.
|
||||
if ($abortinstallx) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$abortables = $pluginman->list_cancellable_installations();
|
||||
if ($abortables) {
|
||||
if ($confirmabortinstall) {
|
||||
foreach ($abortables as $plugin) {
|
||||
$pluginman->cancel_plugin_installation($plugin->component);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstallx' => $abortinstallx, 'confirmabortinstall' => 1));
|
||||
echo $output->upgrade_confirm_abort_install_page($abortables, $continue);
|
||||
die();
|
||||
}
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
$deployer = \core\update\deployer::instance();
|
||||
if ($deployer->enabled()) {
|
||||
$deployer->initialize($reloadurl, $reloadurl);
|
||||
|
||||
// Cancel single plugin installation.
|
||||
if ($abortinstall) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
if ($confirmabortinstall) {
|
||||
$pluginman->cancel_plugin_installation($abortinstall);
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstall' => $abortinstall, 'confirmabortinstall' => 1));
|
||||
$abortable = $pluginman->get_plugin_info($abortinstall);
|
||||
if ($pluginman->can_cancel_plugin_installation($abortable)) {
|
||||
echo $output->upgrade_confirm_abort_install_page(array($abortable), $continue);
|
||||
die();
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel all plugins upgrades (that is, restore archived versions).
|
||||
if ($abortupgradex) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if ($restorable) {
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
get_string('cancelupgradehead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('abortupgradex' => 1, 'confirmabortupgrade' => 1))
|
||||
);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Cancel single plugin upgrade (that is, install the archived version).
|
||||
if ($abortupgrade) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if (isset($restorable[$abortupgrade])) {
|
||||
$restorable = array($restorable[$abortupgrade]);
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
get_string('cancelupgradehead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('abortupgrade' => $abortupgrade, 'confirmabortupgrade' => 1))
|
||||
);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Install all available missing dependencies.
|
||||
if ($installdepx) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdepx' => 1, 'confirminstalldep' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available missing dependency.
|
||||
if ($installdep) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
if (!empty($installable[$installdep])) {
|
||||
$installable = array($installable[$installdep]);
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdep' => $installdep, 'confirminstalldep' => 1))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Install all available updates.
|
||||
if ($installupdatex) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->available_updates());
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available update.
|
||||
if ($installupdate and $installupdateversion) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdate' => $installupdate,
|
||||
'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
|
||||
)
|
||||
);
|
||||
$deploydata = $deployer->submitted_data();
|
||||
if (!empty($deploydata)) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
echo $output->upgrade_plugin_confirm_deploy_page($deployer, $deploydata);
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
echo $output->upgrade_plugin_check_page(core_plugin_manager::instance(), \core\update\checker::instance(),
|
||||
$version, $showallplugins, $PAGE->url, new moodle_url($PAGE->url, array('confirmplugincheck' => 1)));
|
||||
$version, $showallplugins, $reloadurl,
|
||||
new moodle_url('/admin/index.php', array('confirmupgrade'=>1, 'confirmrelease'=>1, 'confirmplugincheck'=>1, 'cache'=>0)));
|
||||
die();
|
||||
|
||||
} else {
|
||||
// Always verify plugin dependencies!
|
||||
$failed = array();
|
||||
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, $PAGE->url);
|
||||
$reloadurl = new moodle_url('/admin/index.php', array('confirmupgrade' => 1, 'confirmrelease' => 1, 'cache' => 0));
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl);
|
||||
die();
|
||||
}
|
||||
unset($failed);
|
||||
@@ -515,17 +374,9 @@ if (!$cache and $branch <> $CFG->branch) { // Update the branch
|
||||
}
|
||||
|
||||
if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array('confirmplugincheck' => $confirmplugins)));
|
||||
|
||||
check_upgrade_key($upgradekeyhash);
|
||||
|
||||
if (!$PAGE->headerprinted) {
|
||||
// means core upgrade or installation was not already done
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
if (!$confirmplugins) {
|
||||
$strplugincheck = get_string('plugincheck');
|
||||
|
||||
@@ -534,7 +385,6 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
$PAGE->set_heading($strplugincheck);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
// Check for available updates.
|
||||
if ($fetchupdates) {
|
||||
require_sesskey();
|
||||
$updateschecker = \core\update\checker::instance();
|
||||
@@ -544,130 +394,36 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Cancel all plugin installations.
|
||||
if ($abortinstallx) {
|
||||
require_sesskey();
|
||||
$abortables = $pluginman->list_cancellable_installations();
|
||||
if ($abortables) {
|
||||
if ($confirmabortinstall) {
|
||||
foreach ($abortables as $plugin) {
|
||||
$pluginman->cancel_plugin_installation($plugin->component);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstallx' => $abortinstallx,
|
||||
'confirmabortinstall' => 1));
|
||||
echo $output->upgrade_confirm_abort_install_page($abortables, $continue);
|
||||
die();
|
||||
}
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
// Cancel single plugin installation.
|
||||
if ($abortinstall) {
|
||||
require_sesskey();
|
||||
if ($confirmabortinstall) {
|
||||
$pluginman->cancel_plugin_installation($abortinstall);
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstall' => $abortinstall, 'confirmabortinstall' => 1));
|
||||
$abortable = $pluginman->get_plugin_info($abortinstall);
|
||||
if ($pluginman->can_cancel_plugin_installation($abortable)) {
|
||||
echo $output->upgrade_confirm_abort_install_page(array($abortable), $continue);
|
||||
die();
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
}
|
||||
$deployer = \core\update\deployer::instance();
|
||||
if ($deployer->enabled()) {
|
||||
$deployer->initialize($PAGE->url, $PAGE->url);
|
||||
|
||||
// Cancel all plugins upgrades (that is, restore archived versions).
|
||||
if ($abortupgradex) {
|
||||
require_sesskey();
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if ($restorable) {
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
get_string('cancelupgradehead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('abortupgradex' => 1, 'confirmabortupgrade' => 1))
|
||||
);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Cancel single plugin upgrade (that is, install the archived version).
|
||||
if ($abortupgrade) {
|
||||
require_sesskey();
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if (isset($restorable[$abortupgrade])) {
|
||||
$restorable = array($restorable[$abortupgrade]);
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
get_string('cancelupgradehead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('abortupgrade' => $abortupgrade, 'confirmabortupgrade' => 1))
|
||||
);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Install all available missing dependencies.
|
||||
if ($installdepx) {
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdepx' => 1, 'confirminstalldep' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available missing dependency.
|
||||
if ($installdep) {
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
if (!empty($installable[$installdep])) {
|
||||
$installable = array($installable[$installdep]);
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdep' => $installdep, 'confirminstalldep' => 1))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Install all available updates.
|
||||
if ($installupdatex) {
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->available_updates());
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available update.
|
||||
if ($installupdate and $installupdateversion) {
|
||||
require_sesskey();
|
||||
if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdate' => $installupdate,
|
||||
'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
|
||||
)
|
||||
);
|
||||
$deploydata = $deployer->submitted_data();
|
||||
if (!empty($deploydata)) {
|
||||
require_sesskey();
|
||||
echo $output->upgrade_plugin_confirm_deploy_page($deployer, $deploydata);
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
// Show plugins info.
|
||||
echo $output->upgrade_plugin_check_page($pluginman, \core\update\checker::instance(),
|
||||
echo $output->upgrade_plugin_check_page(core_plugin_manager::instance(), \core\update\checker::instance(),
|
||||
$version, $showallplugins,
|
||||
new moodle_url($PAGE->url),
|
||||
new moodle_url($PAGE->url, array('confirmplugincheck' => 1, 'cache' => 0)));
|
||||
new moodle_url('/admin/index.php', array('confirmplugincheck'=>1, 'cache'=>0)));
|
||||
die();
|
||||
}
|
||||
|
||||
// Make sure plugin dependencies are always checked.
|
||||
$failed = array();
|
||||
if (!$pluginman->all_plugins_ok($version, $failed)) {
|
||||
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, $PAGE->url);
|
||||
$reloadurl = new moodle_url('/admin/index.php', array('cache' => 0));
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl);
|
||||
die();
|
||||
}
|
||||
unset($failed);
|
||||
@@ -813,7 +569,7 @@ $updateschecker = \core\update\checker::instance();
|
||||
$availableupdates = array();
|
||||
$availableupdatesfetch = null;
|
||||
|
||||
if ($updateschecker->enabled()) {
|
||||
if (empty($CFG->disableupdatenotifications)) {
|
||||
// Only compute the update information when it is going to be displayed to the user.
|
||||
$availableupdates['core'] = $updateschecker->get_update_info('core',
|
||||
array('minmaturity' => $CFG->updateminmaturity, 'notifybuilds' => $CFG->updatenotifybuilds));
|
||||
@@ -822,13 +578,14 @@ if ($updateschecker->enabled()) {
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
foreach ($pluginman->get_plugins() as $plugintype => $plugintypeinstances) {
|
||||
foreach ($plugintypeinstances as $pluginname => $plugininfo) {
|
||||
$pluginavailableupdates = $plugininfo->available_updates();
|
||||
if (!empty($pluginavailableupdates)) {
|
||||
foreach ($pluginavailableupdates as $pluginavailableupdate) {
|
||||
if (!isset($availableupdates[$plugintype.'_'.$pluginname])) {
|
||||
$availableupdates[$plugintype.'_'.$pluginname] = array();
|
||||
if (!empty($plugininfo->availableupdates)) {
|
||||
foreach ($plugininfo->availableupdates as $pluginavailableupdate) {
|
||||
if ($pluginavailableupdate->version > $plugininfo->versiondisk) {
|
||||
if (!isset($availableupdates[$plugintype.'_'.$pluginname])) {
|
||||
$availableupdates[$plugintype.'_'.$pluginname] = array();
|
||||
}
|
||||
$availableupdates[$plugintype.'_'.$pluginname][] = $pluginavailableupdate;
|
||||
}
|
||||
$availableupdates[$plugintype.'_'.$pluginname][] = $pluginavailableupdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -843,13 +600,12 @@ $buggyiconvnomb = (!function_exists('mb_convert_encoding') and @iconv('UTF-8', '
|
||||
$registered = $DB->count_records('registration_hubs', array('huburl' => HUB_MOODLEORGHUBURL, 'confirmed' => 1));
|
||||
// Check if there are any cache warnings.
|
||||
$cachewarnings = cache_helper::warnings();
|
||||
// Check if there are events 1 API handlers.
|
||||
$eventshandlers = $DB->get_records_sql('SELECT DISTINCT component FROM {events_handlers}');
|
||||
|
||||
admin_externalpage_setup('adminnotifications');
|
||||
|
||||
/* @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed, $cronoverdue, $dbproblems,
|
||||
$maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
|
||||
$registered, $cachewarnings, $eventshandlers);
|
||||
$registered, $cachewarnings);
|
||||
|
||||
@@ -18,6 +18,15 @@
|
||||
/**
|
||||
* UI for general plugins management
|
||||
*
|
||||
* Supported HTTP parameters:
|
||||
*
|
||||
* ?fetchremote=1 - check for available updates
|
||||
* ?updatesonly=1 - display plugins with available update only
|
||||
* ?contribonly=1 - display non-standard add-ons only
|
||||
* ?uninstall=foo_bar - uninstall the given plugin
|
||||
* ?delete=foo_bar - delete the plugin folder (it must not be installed)
|
||||
* &confirm=1 - confirm the uninstall or delete action
|
||||
*
|
||||
* @package core
|
||||
* @subpackage admin
|
||||
* @copyright 2011 David Mudrak <david@moodle.com>
|
||||
@@ -28,17 +37,13 @@ require_once(dirname(dirname(__FILE__)) . '/config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
$fetchupdates = optional_param('fetchupdates', false, PARAM_BOOL); // Check for available plugins updates.
|
||||
$updatesonly = optional_param('updatesonly', false, PARAM_BOOL); // Show updateable plugins only.
|
||||
$contribonly = optional_param('contribonly', false, PARAM_BOOL); // Show additional plugins only.
|
||||
$uninstall = optional_param('uninstall', '', PARAM_COMPONENT); // Uninstall the plugin.
|
||||
$delete = optional_param('delete', '', PARAM_COMPONENT); // Delete the plugin folder after it is uninstalled.
|
||||
$confirmed = optional_param('confirm', false, PARAM_BOOL); // Confirm the uninstall/delete action.
|
||||
$return = optional_param('return', 'overview', PARAM_ALPHA); // Where to return after uninstall.
|
||||
$installupdate = optional_param('installupdate', null, PARAM_COMPONENT); // Install given available update.
|
||||
$installupdateversion = optional_param('installupdateversion', null, PARAM_INT); // Version of the available update to install.
|
||||
$installupdatex = optional_param('installupdatex', false, PARAM_BOOL); // Install all available plugin updates.
|
||||
$confirminstallupdate = optional_param('confirminstallupdate', false, PARAM_BOOL); // Available update(s) install confirmed?
|
||||
$fetchremote = optional_param('fetchremote', false, PARAM_BOOL);
|
||||
$updatesonly = optional_param('updatesonly', false, PARAM_BOOL);
|
||||
$contribonly = optional_param('contribonly', false, PARAM_BOOL);
|
||||
$uninstall = optional_param('uninstall', '', PARAM_COMPONENT);
|
||||
$delete = optional_param('delete', '', PARAM_COMPONENT);
|
||||
$confirmed = optional_param('confirm', false, PARAM_BOOL);
|
||||
$return = optional_param('return', 'overview', PARAM_ALPHA);
|
||||
|
||||
// NOTE: do not use admin_externalpage_setup() here because it loads
|
||||
// full admin tree which is not possible during uninstallation.
|
||||
@@ -47,19 +52,15 @@ require_login();
|
||||
$syscontext = context_system::instance();
|
||||
require_capability('moodle/site:config', $syscontext);
|
||||
|
||||
// URL params we want to maintain on redirects.
|
||||
$pageparams = array('updatesonly' => $updatesonly, 'contribonly' => $contribonly);
|
||||
$pageurl = new moodle_url('/admin/plugins.php', $pageparams);
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
|
||||
if ($uninstall) {
|
||||
require_sesskey();
|
||||
|
||||
if (!$confirmed) {
|
||||
admin_externalpage_setup('pluginsoverview', '', $pageparams);
|
||||
admin_externalpage_setup('pluginsoverview');
|
||||
} else {
|
||||
$PAGE->set_url($pageurl);
|
||||
$PAGE->set_url('/admin/plugins.php');
|
||||
$PAGE->set_context($syscontext);
|
||||
$PAGE->set_pagelayout('maintenance');
|
||||
$PAGE->set_popup_notification_allowed(false);
|
||||
@@ -121,7 +122,7 @@ if ($uninstall) {
|
||||
if ($delete and $confirmed) {
|
||||
require_sesskey();
|
||||
|
||||
$PAGE->set_url($pageurl);
|
||||
$PAGE->set_url('/admin/plugins.php');
|
||||
$PAGE->set_context($syscontext);
|
||||
$PAGE->set_pagelayout('maintenance');
|
||||
$PAGE->set_popup_notification_allowed(false);
|
||||
@@ -148,6 +149,13 @@ if ($delete and $confirmed) {
|
||||
'core_plugin_manager::get_plugin_info() returned not-null versiondb for the plugin to be deleted');
|
||||
}
|
||||
|
||||
// Make sure the folder is removable.
|
||||
if (!$pluginman->is_plugin_folder_removable($pluginfo->component)) {
|
||||
throw new moodle_exception('err_removing_unremovable_folder', 'core_plugin', '',
|
||||
array('plugin' => $pluginfo->component, 'rootdir' => $pluginfo->rootdir),
|
||||
'plugin root folder is not removable as expected');
|
||||
}
|
||||
|
||||
// Make sure the folder is within Moodle installation tree.
|
||||
if (strpos($pluginfo->rootdir, $CFG->dirroot) !== 0) {
|
||||
throw new moodle_exception('err_unexpected_plugin_rootdir', 'core_plugin', '',
|
||||
@@ -156,61 +164,44 @@ if ($delete and $confirmed) {
|
||||
}
|
||||
|
||||
// So long, and thanks for all the bugs.
|
||||
$pluginman->remove_plugin_folder($pluginfo);
|
||||
|
||||
fulldelete($pluginfo->rootdir);
|
||||
// Reset op code caches.
|
||||
if (function_exists('opcache_reset')) {
|
||||
opcache_reset();
|
||||
}
|
||||
// We need to execute upgrade to make sure everything including caches is up to date.
|
||||
redirect(new moodle_url('/admin/index.php'));
|
||||
}
|
||||
|
||||
// Install all avilable updates.
|
||||
if ($installupdatex) {
|
||||
require_once($CFG->libdir.'/upgradelib.php');
|
||||
require_sesskey();
|
||||
|
||||
$PAGE->set_url($pageurl);
|
||||
$PAGE->set_context($syscontext);
|
||||
$PAGE->set_pagelayout('maintenance');
|
||||
$PAGE->set_popup_notification_allowed(false);
|
||||
|
||||
$installable = $pluginman->filter_installable($pluginman->available_updates());
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available update.
|
||||
if ($installupdate and $installupdateversion) {
|
||||
require_once($CFG->libdir.'/upgradelib.php');
|
||||
require_sesskey();
|
||||
|
||||
$PAGE->set_url($pageurl);
|
||||
$PAGE->set_context($syscontext);
|
||||
$PAGE->set_pagelayout('maintenance');
|
||||
$PAGE->set_popup_notification_allowed(false);
|
||||
|
||||
if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdate' => $installupdate,
|
||||
'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
admin_externalpage_setup('pluginsoverview', '', $pageparams);
|
||||
admin_externalpage_setup('pluginsoverview');
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
$checker = \core\update\checker::instance();
|
||||
|
||||
if ($fetchupdates) {
|
||||
// Filtering options.
|
||||
$options = array(
|
||||
'updatesonly' => $updatesonly,
|
||||
'contribonly' => $contribonly,
|
||||
);
|
||||
|
||||
if ($fetchremote) {
|
||||
require_sesskey();
|
||||
$checker->fetch();
|
||||
redirect($PAGE->url);
|
||||
redirect(new moodle_url($PAGE->url, $options));
|
||||
}
|
||||
|
||||
echo $output->plugin_management_page($pluginman, $checker, $pageparams);
|
||||
$deployer = \core\update\deployer::instance();
|
||||
if ($deployer->enabled()) {
|
||||
$myurl = new moodle_url($PAGE->url, array('updatesonly' => $updatesonly, 'contribonly' => $contribonly));
|
||||
$deployer->initialize($myurl, new moodle_url('/admin'));
|
||||
|
||||
$deploydata = $deployer->submitted_data();
|
||||
if (!empty($deploydata)) {
|
||||
echo $output->upgrade_plugin_confirm_deploy_page($deployer, $deploydata);
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
echo $output->plugin_management_page($pluginman, $checker, $options);
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This file processes AJAX requests and returns JSON
|
||||
*
|
||||
* This is a server part of yui permissions manager module
|
||||
*
|
||||
* @package core_role
|
||||
* @copyright 2015 Martin Mastny
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define('AJAX_SCRIPT', true);
|
||||
|
||||
require(__DIR__ . '/../../config.php');
|
||||
|
||||
$contextid = required_param('contextid', PARAM_INT);
|
||||
$getroles = optional_param('getroles', 0, PARAM_BOOL);
|
||||
|
||||
list($context, $course, $cm) = get_context_info_array($contextid);
|
||||
|
||||
require_login($course, false, $cm);
|
||||
require_capability('moodle/role:review', $context);
|
||||
require_sesskey();
|
||||
|
||||
list($overridableroles, $overridecounts, $nameswithcounts) = get_overridable_roles($context,
|
||||
ROLENAME_BOTH, true);
|
||||
|
||||
if ($getroles) {
|
||||
echo json_encode($overridableroles);
|
||||
die();
|
||||
}
|
||||
|
||||
$capability = required_param('capability', PARAM_CAPABILITY);
|
||||
$roleid = required_param('roleid', PARAM_INT);
|
||||
$action = required_param('action', PARAM_ALPHA);
|
||||
|
||||
$capability = $DB->get_record('capabilities', array('name' => $capability), '*', MUST_EXIST);
|
||||
|
||||
if (!isset($overridableroles[$roleid])) {
|
||||
throw new moodle_exception('invalidarguments');
|
||||
}
|
||||
|
||||
if (!has_capability('moodle/role:override', $context)) {
|
||||
if (!has_capability('moodle/role:safeoverride', $context) || !is_safe_capability($capability)) {
|
||||
require_capability('moodle/role:override', $context);
|
||||
}
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
case 'allow':
|
||||
role_change_permission($roleid, $context, $capability->name, CAP_ALLOW);
|
||||
break;
|
||||
case 'prevent':
|
||||
role_change_permission($roleid, $context, $capability->name, CAP_PREVENT);
|
||||
break;
|
||||
case 'prohibit':
|
||||
role_change_permission($roleid, $context, $capability->name, CAP_PROHIBIT);
|
||||
break;
|
||||
case 'unprohibit':
|
||||
role_change_permission($roleid, $context, $capability->name, CAP_INHERIT);
|
||||
break;
|
||||
default:
|
||||
throw new moodle_exception('invalidarguments');
|
||||
}
|
||||
|
||||
echo json_encode($action);
|
||||
die();
|
||||
@@ -106,22 +106,18 @@ abstract class core_role_capability_table_base {
|
||||
$component = $capability->component;
|
||||
|
||||
// Start the row.
|
||||
$rowattributes = $this->get_row_attributes($capability);
|
||||
// Handle class attributes same as other.
|
||||
$rowclasses = array_unique(array_merge(array('rolecap'), $this->get_row_classes($capability)));
|
||||
if (array_key_exists('class', $rowattributes)) {
|
||||
$rowclasses = array_unique(array_merge($rowclasses, array($rowattributes['class'])));
|
||||
}
|
||||
$rowattributes['class'] = implode(' ', $rowclasses);
|
||||
echo '<tr class="' . implode(' ', array_unique(array_merge(array('rolecap'),
|
||||
$this->get_row_classes($capability)))) . '">';
|
||||
|
||||
// Table cell for the capability name.
|
||||
$contents = '<th scope="row" class="name"><span class="cap-desc">' . get_capability_docs_link($capability) .
|
||||
echo '<th scope="row" class="name"><span class="cap-desc">' . get_capability_docs_link($capability) .
|
||||
'<span class="cap-name">' . $capability->name . '</span></span></th>';
|
||||
|
||||
// Add the cells specific to this table.
|
||||
$contents .= $this->add_row_cells($capability);
|
||||
$this->add_row_cells($capability);
|
||||
|
||||
echo html_writer::tag('tr', $contents, $rowattributes);
|
||||
// End the row.
|
||||
echo "</tr>\n";
|
||||
}
|
||||
|
||||
// End of the table.
|
||||
@@ -171,17 +167,6 @@ abstract class core_role_capability_table_base {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* For subclasses to override. Additional attributes to be added to
|
||||
* each table row for the capability
|
||||
*
|
||||
* @param stdClass $capability the capability this row relates to.
|
||||
* @return array attribute names and their values.
|
||||
*/
|
||||
protected function get_row_attributes($capability) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* For subclasses to override. Output the data cells for this capability. The
|
||||
* capability name cell will already have been output.
|
||||
@@ -189,7 +174,6 @@ abstract class core_role_capability_table_base {
|
||||
* You can rely on get_row_classes always being called before add_row_cells.
|
||||
*
|
||||
* @param stdClass $capability the capability this row relates to.
|
||||
* @return string html of row cells
|
||||
*/
|
||||
protected abstract function add_row_cells($capability);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ abstract class core_role_capability_table_with_risks extends core_role_capabilit
|
||||
protected $allpermissions; // We don't need perms ourselves, but all our subclasses do.
|
||||
protected $strperms; // Language string cache.
|
||||
protected $risksurl; // URL in moodledocs about risks.
|
||||
protected $riskicons = array(); // Cache to avoid regenerating the HTML for each risk icon.
|
||||
/** @var array The capabilities to highlight as default/inherited. */
|
||||
protected $parentpermissions;
|
||||
protected $displaypermissions;
|
||||
@@ -162,16 +163,15 @@ abstract class core_role_capability_table_with_risks extends core_role_capabilit
|
||||
protected abstract function add_permission_cells($capability);
|
||||
|
||||
protected function add_row_cells($capability) {
|
||||
$cells = $this->add_permission_cells($capability);
|
||||
$this->add_permission_cells($capability);
|
||||
// One cell for each possible risk.
|
||||
foreach ($this->allrisks as $riskname => $risk) {
|
||||
$cells .= '<td class="risk ' . str_replace('risk', '', $riskname) . '">';
|
||||
echo '<td class="risk ' . str_replace('risk', '', $riskname) . '">';
|
||||
if ($risk & (int)$capability->riskbitmask) {
|
||||
$cells .= $this->get_risk_icon($riskname);
|
||||
echo $this->get_risk_icon($riskname);
|
||||
}
|
||||
$cells .= '</td>';
|
||||
echo '</td>';
|
||||
}
|
||||
return $cells;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,12 +182,12 @@ abstract class core_role_capability_table_with_risks extends core_role_capabilit
|
||||
*/
|
||||
public function get_risk_icon($type) {
|
||||
global $OUTPUT;
|
||||
|
||||
$iconurl = $OUTPUT->pix_url('i/' . str_replace('risk', 'risk_', $type));
|
||||
$text = '<img src="' . $iconurl . '" alt="' . get_string($type . 'short', 'admin') . '" />';
|
||||
$action = new popup_action('click', $this->risksurl, 'docspopup');
|
||||
$riskicon = $OUTPUT->action_link($this->risksurl, $text, $action, array('title'=>get_string($type, 'admin')));
|
||||
|
||||
return $riskicon;
|
||||
if (!isset($this->riskicons[$type])) {
|
||||
$iconurl = $OUTPUT->pix_url('i/' . str_replace('risk', 'risk_', $type));
|
||||
$text = '<img src="' . $iconurl . '" alt="' . get_string($type . 'short', 'admin') . '" />';
|
||||
$action = new popup_action('click', $this->risksurl, 'docspopup');
|
||||
$this->riskicons[$type] = $OUTPUT->action_link($this->risksurl, $text, $action, array('title'=>get_string($type, 'admin')));
|
||||
}
|
||||
return $this->riskicons[$type];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,6 @@ class core_role_check_capability_table extends core_role_capability_table_base {
|
||||
$a->fullname = $this->fullname;
|
||||
$a->capability = $capability->name;
|
||||
$a->context = $this->contextname;
|
||||
return '<td>' . $result . '</td>';
|
||||
echo '<td>' . $result . '</td>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,7 +413,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
|
||||
}
|
||||
|
||||
public function save_changes() {
|
||||
global $DB, $CFG;
|
||||
global $DB;
|
||||
|
||||
if (!$this->roleid) {
|
||||
// Creating role.
|
||||
@@ -422,13 +422,6 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
|
||||
} else {
|
||||
// Updating role.
|
||||
$DB->update_record('role', $this->role);
|
||||
|
||||
// This will ensure the course contacts cache is purged so name changes get updated in
|
||||
// the UI. It would be better to do this only when we know that fields affected are
|
||||
// updated. But thats getting into the weeds of the coursecat cache and role edits
|
||||
// should not be that frequent, so here is the ugly brutal approach.
|
||||
require_once($CFG->libdir . '/coursecatlib.php');
|
||||
coursecat::role_assignment_changed($this->role->id, context_system::instance());
|
||||
}
|
||||
|
||||
// Assignable contexts.
|
||||
@@ -635,7 +628,6 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
|
||||
|
||||
protected function add_permission_cells($capability) {
|
||||
// One cell for each possible permission.
|
||||
$content = '';
|
||||
foreach ($this->displaypermissions as $perm => $permname) {
|
||||
$strperm = $this->strperms[$permname];
|
||||
$extraclass = '';
|
||||
@@ -646,12 +638,11 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
|
||||
if ($this->permissions[$capability->name] == $perm) {
|
||||
$checked = 'checked="checked" ';
|
||||
}
|
||||
$content .= '<td class="' . $permname . $extraclass . '">';
|
||||
$content .= '<label><input type="radio" name="' . $capability->name .
|
||||
echo '<td class="' . $permname . $extraclass . '">';
|
||||
echo '<label><input type="radio" name="' . $capability->name .
|
||||
'" value="' . $perm . '" ' . $checked . '/> ';
|
||||
$content .= '<span class="note">' . $strperm . '</span>';
|
||||
$content .= '</label></td>';
|
||||
echo '<span class="note">' . $strperm . '</span>';
|
||||
echo '</label></td>';
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,20 +45,19 @@ class core_role_define_role_table_basic extends core_role_define_role_table_adva
|
||||
$perm = $this->permissions[$capability->name];
|
||||
$permname = $this->allpermissions[$perm];
|
||||
$defaultperm = $this->allpermissions[$this->parentpermissions[$capability->name]];
|
||||
$content = '<td class="' . $permname . '">';
|
||||
echo '<td class="' . $permname . '">';
|
||||
if ($perm == CAP_ALLOW || $perm == CAP_INHERIT) {
|
||||
$checked = '';
|
||||
if ($perm == CAP_ALLOW) {
|
||||
$checked = 'checked="checked" ';
|
||||
}
|
||||
$content .= '<input type="hidden" name="' . $capability->name . '" value="' . CAP_INHERIT . '" />';
|
||||
$content .= '<label><input type="checkbox" name="' . $capability->name .
|
||||
echo '<input type="hidden" name="' . $capability->name . '" value="' . CAP_INHERIT . '" />';
|
||||
echo '<label><input type="checkbox" name="' . $capability->name .
|
||||
'" value="' . CAP_ALLOW . '" ' . $checked . '/> ' . $this->strallow . '</label>';
|
||||
} else {
|
||||
$content .= '<input type="hidden" name="' . $capability->name . '" value="' . $perm . '" />';
|
||||
$content .= $this->strperms[$permname] . '<span class="note">' . $this->stradvmessage . '</span>';
|
||||
echo '<input type="hidden" name="' . $capability->name . '" value="' . $perm . '" />';
|
||||
echo $this->strperms[$permname] . '<span class="note">' . $this->stradvmessage . '</span>';
|
||||
}
|
||||
$content .= '</td>';
|
||||
return $content;
|
||||
echo '</td>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@ class core_role_override_permissions_table_advanced extends core_role_capability
|
||||
}
|
||||
|
||||
// One cell for each possible permission.
|
||||
$content = '';
|
||||
foreach ($this->displaypermissions as $perm => $permname) {
|
||||
$strperm = $this->strperms[$permname];
|
||||
$extraclass = '';
|
||||
@@ -84,8 +83,8 @@ class core_role_override_permissions_table_advanced extends core_role_capability
|
||||
if ($this->permissions[$capability->name] == $perm) {
|
||||
$checked = 'checked="checked" ';
|
||||
}
|
||||
$content .= '<td class="' . $permname . $extraclass . '">';
|
||||
$content .= '<label><input type="radio" name="' . $capability->name .
|
||||
echo '<td class="' . $permname . $extraclass . '">';
|
||||
echo '<label><input type="radio" name="' . $capability->name .
|
||||
'" value="' . $perm . '" ' . $checked . $disabled . '/> ';
|
||||
if ($perm == CAP_INHERIT) {
|
||||
$inherited = $this->parentpermissions[$capability->name];
|
||||
@@ -96,9 +95,8 @@ class core_role_override_permissions_table_advanced extends core_role_capability
|
||||
}
|
||||
$strperm .= ' (' . $inherited . ')';
|
||||
}
|
||||
$content .= '<span class="note">' . $strperm . '</span>';
|
||||
$content .= '</label></td>';
|
||||
echo '<span class="note">' . $strperm . '</span>';
|
||||
echo '</label></td>';
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,8 +67,6 @@ class core_role_permissions_table extends core_role_capability_table_base {
|
||||
|
||||
protected function add_row_cells($capability) {
|
||||
global $OUTPUT, $PAGE;
|
||||
$renderer = $PAGE->get_renderer('core');
|
||||
$adminurl = new moodle_url("/admin/");
|
||||
|
||||
$context = $this->context;
|
||||
$contextid = $this->context->id;
|
||||
@@ -77,6 +75,7 @@ class core_role_permissions_table extends core_role_capability_table_base {
|
||||
$overridableroles = $this->overridableroles;
|
||||
$roles = $this->roles;
|
||||
|
||||
|
||||
list($needed, $forbidden) = get_roles_with_cap_in_context($context, $capability->name);
|
||||
$neededroles = array();
|
||||
$forbiddenroles = array();
|
||||
@@ -92,50 +91,40 @@ class core_role_permissions_table extends core_role_capability_table_base {
|
||||
|
||||
foreach ($roles as $id => $name) {
|
||||
if (isset($needed[$id])) {
|
||||
$templatecontext = array("rolename" => $name, "roleid" => $id, "action" => "prevent", "spanclass" => "allowed",
|
||||
"linkclass" => "preventlink", "adminurl" => $adminurl->out(), "imageurl" => "");
|
||||
$neededroles[$id] = $roles[$id];
|
||||
if (isset($overridableroles[$id]) and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) {
|
||||
$templatecontext['imageurl'] = $renderer->pix_url('t/delete');
|
||||
$preventurl = new moodle_url($PAGE->url, array('contextid'=>$contextid, 'roleid'=>$id, 'capability'=>$capability->name, 'prevent'=>1));
|
||||
$neededroles[$id] .= $OUTPUT->action_icon($preventurl, new pix_icon('t/delete', get_string('prevent', 'core_role')));
|
||||
}
|
||||
$neededroles[$id] = $renderer->render_from_template('core/permissionmanager_role', $templatecontext);
|
||||
}
|
||||
}
|
||||
$neededroles = implode(' ', $neededroles);
|
||||
$neededroles = implode(', ', $neededroles);
|
||||
foreach ($roles as $id => $name) {
|
||||
if (isset($forbidden[$id]) and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) {
|
||||
$templatecontext = array("rolename" => $name, "roleid" => $id, "action" => "unprohibit",
|
||||
"spanclass" => "forbidden", "linkclass" => "unprohibitlink", "adminurl" => $adminurl->out(),
|
||||
"imageurl" => "");
|
||||
$forbiddenroles[$id] = $roles[$id];
|
||||
if (isset($overridableroles[$id]) and prohibit_is_removable($id, $context, $capability->name)) {
|
||||
$templatecontext['imageurl'] = $renderer->pix_url('t/delete');
|
||||
$unprohibiturl = new moodle_url($PAGE->url, array('contextid'=>$contextid, 'roleid'=>$id, 'capability'=>$capability->name, 'unprohibit'=>1));
|
||||
$forbiddenroles[$id] .= $OUTPUT->action_icon($unprohibiturl, new pix_icon('t/delete', get_string('delete')));
|
||||
}
|
||||
$forbiddenroles[$id] = $renderer->render_from_template('core/permissionmanager_role', $templatecontext);
|
||||
}
|
||||
}
|
||||
$forbiddenroles = implode(' ', $forbiddenroles);
|
||||
$forbiddenroles = implode(', ', $forbiddenroles);
|
||||
|
||||
if ($allowable and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) {
|
||||
$allowurl = new moodle_url($PAGE->url, array('contextid' => $contextid,
|
||||
'capability' => $capability->name, 'allow' => 1));
|
||||
$allowicon = $OUTPUT->action_icon($allowurl, new pix_icon('t/add', get_string('allow', 'core_role')), null,
|
||||
array('class' => 'allowlink', 'data-action' => 'allow'));
|
||||
$neededroles .= html_writer::div($allowicon, 'allowmore');
|
||||
$allowurl = new moodle_url($PAGE->url, array('contextid'=>$contextid, 'capability'=>$capability->name, 'allow'=>1));
|
||||
$neededroles .= '<div class="allowmore">'.$OUTPUT->action_icon($allowurl, new pix_icon('t/add', get_string('allow', 'core_role'))).'</div>';
|
||||
}
|
||||
|
||||
if ($forbitable and ($allowoverrides or ($allowsafeoverrides and is_safe_capability($capability)))) {
|
||||
$prohibiturl = new moodle_url($PAGE->url, array('contextid' => $contextid,
|
||||
'capability' => $capability->name, 'prohibit' => 1));
|
||||
$prohibiticon = $OUTPUT->action_icon($prohibiturl, new pix_icon('t/add', get_string('prohibit', 'core_role')), null,
|
||||
array('class' => 'prohibitlink', 'data-action' => 'prohibit'));
|
||||
$forbiddenroles .= html_writer::div($prohibiticon, 'prohibitmore');
|
||||
$prohibiturl = new moodle_url($PAGE->url, array('contextid'=>$contextid, 'capability'=>$capability->name, 'prohibit'=>1));
|
||||
$forbiddenroles .= '<div class="prohibitmore">'.$OUTPUT->action_icon($prohibiturl, new pix_icon('t/add', get_string('prohibit', 'core_role'))).'</div>';
|
||||
}
|
||||
|
||||
$risks = $this->get_risks($capability);
|
||||
|
||||
$contents = html_writer::tag('td', $risks, array('class' => 'risks'));
|
||||
$contents .= html_writer::tag('td', $neededroles, array('class' => 'allowedroles'));
|
||||
$contents .= html_writer::tag('td', $forbiddenroles, array('class' => 'forbiddenroles'));
|
||||
return $contents;
|
||||
echo '<td>' . $risks . '</td>';
|
||||
echo '<td>' . $neededroles . '</td>';
|
||||
echo '<td>' . $forbiddenroles . '</td>';
|
||||
}
|
||||
|
||||
protected function get_risks($capability) {
|
||||
@@ -158,18 +147,4 @@ class core_role_permissions_table extends core_role_capability_table_base {
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional attributes to row
|
||||
*
|
||||
* @param stdClass $capability capability that this table row relates to.
|
||||
* @return array key value pairs of attribute names and values.
|
||||
*/
|
||||
protected function get_row_attributes($capability) {
|
||||
return array(
|
||||
'data-id' => $capability->id,
|
||||
'data-name' => $capability->name,
|
||||
'data-humanname' => get_capability_string($capability->name),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ class core_role_view_role_definition_table extends core_role_define_role_table_a
|
||||
} else {
|
||||
$default = " ";
|
||||
}
|
||||
return '<td class="' . $permname . '">' . $this->strperms[$permname] . '<span class="note">' .
|
||||
echo '<td class="' . $permname . '">' . $this->strperms[$permname] . '<span class="note">' .
|
||||
$default . '</span></td>';
|
||||
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey() && $de
|
||||
$event = \core\event\role_capabilities_updated::create(
|
||||
array(
|
||||
'context' => $systemcontext,
|
||||
'objectid' => $tableroleid
|
||||
'objectid' => $roleid
|
||||
)
|
||||
);
|
||||
$event->set_legacy_logdata(array(SITEID, 'role', $action, 'admin/roles/define.php?action=view&roleid=' . $tableroleid,
|
||||
|
||||
@@ -195,15 +195,6 @@ if ($capability && ($allowoverrides || ($allowsafeoverrides && is_safe_capabilit
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($title);
|
||||
|
||||
$adminurl = new moodle_url('/admin/');
|
||||
$arguments = array('contextid' => $contextid,
|
||||
'contextname' => $contextname,
|
||||
'adminurl' => $adminurl->out());
|
||||
$PAGE->requires->strings_for_js(
|
||||
array('roleprohibitinfo', 'roleprohibitheader', 'roleallowinfo', 'roleallowheader',
|
||||
'confirmunassigntitle', 'confirmroleunprohibit', 'confirmroleprevent', 'confirmunassignyes',
|
||||
'confirmunassignno'), 'core_role');
|
||||
$PAGE->requires->js_call_amd('core/permissionmanager', 'initialize', array($arguments));
|
||||
$table = new core_role_permissions_table($context, $contextname, $allowoverrides, $allowsafeoverrides, $overridableroles);
|
||||
echo $OUTPUT->box_start('generalbox capbox');
|
||||
// Print link to advanced override page.
|
||||
|
||||
@@ -20,15 +20,13 @@ $focus = '';
|
||||
// now we'll deal with the case that the admin has submitted the form with changed settings
|
||||
if ($data = data_submitted() and confirm_sesskey()) {
|
||||
if (admin_write_settings($data)) {
|
||||
redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
|
||||
$statusmsg = get_string('changessaved');
|
||||
}
|
||||
|
||||
if (!empty($adminroot->errors)) {
|
||||
$errormsg = get_string('errorwithsettings', 'admin');
|
||||
$firsterror = reset($adminroot->errors);
|
||||
$focus = $firsterror->id;
|
||||
} else {
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,11 +20,7 @@ $adminroot = admin_get_root(); // need all settings
|
||||
$settingspage = $adminroot->locate($section, true);
|
||||
|
||||
if (empty($settingspage) or !($settingspage instanceof admin_settingpage)) {
|
||||
if (moodle_needs_upgrading()) {
|
||||
redirect(new moodle_url('/admin/index.php'));
|
||||
} else {
|
||||
print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
|
||||
}
|
||||
print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
|
||||
die;
|
||||
}
|
||||
|
||||
@@ -40,7 +36,7 @@ $errormsg = '';
|
||||
|
||||
if ($data = data_submitted() and confirm_sesskey()) {
|
||||
if (admin_write_settings($data)) {
|
||||
redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
|
||||
$statusmsg = get_string('changessaved');
|
||||
}
|
||||
|
||||
if (empty($adminroot->errors)) {
|
||||
@@ -48,7 +44,6 @@ if ($data = data_submitted() and confirm_sesskey()) {
|
||||
case 'site': redirect("$CFG->wwwroot/");
|
||||
case 'admin': redirect("$CFG->wwwroot/$CFG->admin/");
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$errormsg = get_string('errorwithsettings', 'admin');
|
||||
$firsterror = reset($adminroot->errors);
|
||||
@@ -77,7 +72,7 @@ if (empty($SITE->fullname)) {
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
echo '<form action="' . $PAGE->url . '" method="post" id="adminsettings">';
|
||||
echo '<form action="settings.php" method="post" id="adminsettings">';
|
||||
echo '<div class="settingsform clearfix">';
|
||||
echo html_writer::input_hidden_params($PAGE->url);
|
||||
echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
|
||||
@@ -121,7 +116,7 @@ if (empty($SITE->fullname)) {
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
echo '<form action="' . $PAGE->url . '" method="post" id="adminsettings">';
|
||||
echo '<form action="settings.php" method="post" id="adminsettings">';
|
||||
echo '<div class="settingsform clearfix">';
|
||||
echo html_writer::input_hidden_params($PAGE->url);
|
||||
echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* File.
|
||||
*
|
||||
* @package core_competency
|
||||
* @copyright 2016 Frédéric Massart - FMCorz.net
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
// Save processing when the user will not be able to access anything.
|
||||
if (has_capability('moodle/site:config', $systemcontext)) {
|
||||
|
||||
$parentname = 'competencies';
|
||||
|
||||
// Settings page.
|
||||
$settings = new admin_settingpage('competencysettings', new lang_string('competenciessettings', 'core_competency'),
|
||||
'moodle/site:config', false);
|
||||
$ADMIN->add($parentname, $settings);
|
||||
|
||||
// Load the full tree of settings.
|
||||
if ($ADMIN->fulltree) {
|
||||
$setting = new admin_setting_configcheckbox('core_competency/enabled',
|
||||
new lang_string('enablecompetencies', 'core_competency'),
|
||||
new lang_string('enablecompetencies_desc', 'core_competency'), 1);
|
||||
$settings->add($setting);
|
||||
|
||||
$setting = new admin_setting_configcheckbox('core_competency/pushcourseratingstouserplans',
|
||||
new lang_string('pushcourseratingstouserplans', 'core_competency'),
|
||||
new lang_string('pushcourseratingstouserplans_desc', 'core_competency'), 1);
|
||||
$settings->add($setting);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -205,9 +205,6 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
// Create a page for general import configuration and defaults.
|
||||
$temp = new admin_settingpage('importgeneralsettings', new lang_string('importgeneralsettings', 'backup'), 'moodle/backup:backupcourse');
|
||||
$temp->add(new admin_setting_configtext('backup/import_general_maxresults', new lang_string('importgeneralmaxresults', 'backup'), new lang_string('importgeneralmaxresults_desc', 'backup'), 10));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/import_general_duplicate_admin_allowed',
|
||||
new lang_string('importgeneralduplicateadminallowed', 'backup'),
|
||||
new lang_string('importgeneralduplicateadminallowed_desc', 'backup'), 0));
|
||||
$ADMIN->add('backups', $temp);
|
||||
|
||||
// Create a page for automated backups configuration and defaults.
|
||||
@@ -229,8 +226,7 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
);
|
||||
$temp->add(new admin_setting_configselect('backup/backup_auto_storage', new lang_string('automatedstorage', 'backup'), new lang_string('automatedstoragehelp', 'backup'), 0, $storageoptions));
|
||||
$temp->add(new admin_setting_special_backup_auto_destination());
|
||||
|
||||
$maxkeptoptions = array(
|
||||
$keepoptoins = array(
|
||||
0 => new lang_string('all'), 1 => '1',
|
||||
2 => '2',
|
||||
5 => '5',
|
||||
@@ -244,44 +240,7 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
300 => '300',
|
||||
400 => '400',
|
||||
500 => '500');
|
||||
$temp->add(new admin_setting_configselect('backup/backup_auto_max_kept', new lang_string('automatedmaxkept', 'backup'),
|
||||
new lang_string('automatedmaxkepthelp', 'backup'), 1, $maxkeptoptions));
|
||||
|
||||
$automateddeletedaysoptions = array(
|
||||
0 => new lang_string('never'),
|
||||
1000 => new lang_string('numdays', '', 1000),
|
||||
365 => new lang_string('numdays', '', 365),
|
||||
180 => new lang_string('numdays', '', 180),
|
||||
150 => new lang_string('numdays', '', 150),
|
||||
120 => new lang_string('numdays', '', 120),
|
||||
90 => new lang_string('numdays', '', 90),
|
||||
60 => new lang_string('numdays', '', 60),
|
||||
35 => new lang_string('numdays', '', 35),
|
||||
10 => new lang_string('numdays', '', 10),
|
||||
5 => new lang_string('numdays', '', 5),
|
||||
2 => new lang_string('numdays', '', 2)
|
||||
);
|
||||
$temp->add(new admin_setting_configselect('backup/backup_auto_delete_days', new lang_string('automateddeletedays', 'backup'),
|
||||
'', 0, $automateddeletedaysoptions));
|
||||
|
||||
$minkeptoptions = array(
|
||||
0 => new lang_string('none'),
|
||||
1 => '1',
|
||||
2 => '2',
|
||||
5 => '5',
|
||||
10 => '10',
|
||||
20 => '20',
|
||||
30 => '30',
|
||||
40 => '40',
|
||||
50 => '50',
|
||||
100 => '100',
|
||||
200 => '200',
|
||||
300 => '300',
|
||||
400 => '400'
|
||||
);
|
||||
$temp->add(new admin_setting_configselect('backup/backup_auto_min_kept', new lang_string('automatedminkept', 'backup'),
|
||||
new lang_string('automatedminkepthelp', 'backup'), 0, $minkeptoptions));
|
||||
|
||||
$temp->add(new admin_setting_configselect('backup/backup_auto_keep', new lang_string('keep'), new lang_string('backupkeephelp'), 1, $keepoptoins));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_shortname', new lang_string('backup_shortname', 'admin'), new lang_string('backup_shortnamehelp', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_skip_hidden', new lang_string('skiphidden', 'backup'), new lang_string('skiphiddenhelp', 'backup'), 1));
|
||||
$temp->add(new admin_setting_configselect('backup/backup_auto_skip_modif_days', new lang_string('skipmodifdays', 'backup'), new lang_string('skipmodifdayshelp', 'backup'), 30, array(
|
||||
|
||||
@@ -33,13 +33,13 @@ if ($hassiteconfig) {
|
||||
// activity modules
|
||||
$ADMIN->add('modules', new admin_category('modsettings', new lang_string('activitymodules')));
|
||||
|
||||
$ADMIN->add('modsettings', new admin_page_managemods());
|
||||
$temp = new admin_settingpage('managemodulescommon', new lang_string('commonsettings', 'admin'));
|
||||
|
||||
$temp = new admin_settingpage('managemodulescommon', new lang_string('commonactivitysettings', 'admin'));
|
||||
$temp->add(new admin_setting_configcheckbox('requiremodintro',
|
||||
get_string('requiremodintro', 'admin'), get_string('requiremodintro_desc', 'admin'), 0));
|
||||
$ADMIN->add('modsettings', $temp);
|
||||
|
||||
$ADMIN->add('modsettings', new admin_page_managemods());
|
||||
foreach (core_plugin_manager::instance()->get_plugins_of_type('mod') as $plugin) {
|
||||
/** @var \core\plugininfo\mod $plugin */
|
||||
$plugin->load_settings($ADMIN, 'modsettings', $hassiteconfig);
|
||||
@@ -80,9 +80,6 @@ if ($hassiteconfig) {
|
||||
$temp->add(new admin_setting_heading('manageauthscommonheading', new lang_string('commonsettings', 'admin'), ''));
|
||||
$temp->add(new admin_setting_special_registerauth());
|
||||
$temp->add(new admin_setting_configcheckbox('authloginviaemail', new lang_string('authloginviaemail', 'core_auth'), new lang_string('authloginviaemail_desc', 'core_auth'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('allowaccountssameemail',
|
||||
new lang_string('allowaccountssameemail', 'core_auth'),
|
||||
new lang_string('allowaccountssameemail_desc', 'core_auth'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('authpreventaccountcreation', new lang_string('authpreventaccountcreation', 'admin'), new lang_string('authpreventaccountcreation_help', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('loginpageautofocus', new lang_string('loginpageautofocus', 'admin'), new lang_string('loginpageautofocus_help', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configselect('guestloginbutton', new lang_string('guestloginbutton', 'auth'),
|
||||
@@ -138,16 +135,6 @@ if ($hassiteconfig) {
|
||||
$plugin->load_settings($ADMIN, 'editorsettings', $hassiteconfig);
|
||||
}
|
||||
|
||||
// Antivirus plugins.
|
||||
$ADMIN->add('modules', new admin_category('antivirussettings', new lang_string('antiviruses', 'antivirus')));
|
||||
$temp = new admin_settingpage('manageantiviruses', new lang_string('antivirussettings', 'antivirus'));
|
||||
$temp->add(new admin_setting_manageantiviruses());
|
||||
$ADMIN->add('antivirussettings', $temp);
|
||||
foreach (core_plugin_manager::instance()->get_plugins_of_type('antivirus') as $plugin) {
|
||||
/* @var \core\plugininfo\antivirus $plugin */
|
||||
$plugin->load_settings($ADMIN, 'antivirussettings', $hassiteconfig);
|
||||
}
|
||||
|
||||
/// License types
|
||||
$ADMIN->add('modules', new admin_category('licensesettings', new lang_string('licenses')));
|
||||
$temp = new admin_settingpage('managelicenses', new lang_string('managelicenses', 'admin'));
|
||||
@@ -187,11 +174,6 @@ if ($hassiteconfig) {
|
||||
$plugin->load_settings($ADMIN, 'filtersettings', $hassiteconfig);
|
||||
}
|
||||
|
||||
// Data format settings.
|
||||
$ADMIN->add('modules', new admin_category('dataformatsettings', new lang_string('dataformats')));
|
||||
$temp = new admin_settingpage('managedataformats', new lang_string('managedataformats'));
|
||||
$temp->add(new admin_setting_managedataformats());
|
||||
$ADMIN->add('dataformatsettings', $temp);
|
||||
|
||||
//== Portfolio settings ==
|
||||
require_once($CFG->libdir. '/portfoliolib.php');
|
||||
@@ -292,18 +274,11 @@ if ($hassiteconfig) {
|
||||
$ADMIN->add('modules', new admin_category('webservicesettings', new lang_string('webservices', 'webservice')));
|
||||
// Mobile
|
||||
$temp = new admin_settingpage('mobile', new lang_string('mobile','admin'), 'moodle/site:config', false);
|
||||
|
||||
// We should wait to the installation to finish since we depend on some configuration values that are set once
|
||||
// the admin user profile is configured.
|
||||
if (!during_initial_install()) {
|
||||
$enablemobiledocurl = new moodle_url(get_docs_url('Enable_mobile_web_services'));
|
||||
$enablemobiledoclink = html_writer::link($enablemobiledocurl, new lang_string('documentation'));
|
||||
$default = is_https() ? 1 : 0;
|
||||
$temp->add(new admin_setting_enablemobileservice('enablemobilewebservice',
|
||||
new lang_string('enablemobilewebservice', 'admin'),
|
||||
new lang_string('configenablemobilewebservice', 'admin', $enablemobiledoclink), $default));
|
||||
}
|
||||
|
||||
$enablemobiledocurl = new moodle_url(get_docs_url('Enable_mobile_web_services'));
|
||||
$enablemobiledoclink = html_writer::link($enablemobiledocurl, new lang_string('documentation'));
|
||||
$temp->add(new admin_setting_enablemobileservice('enablemobilewebservice',
|
||||
new lang_string('enablemobilewebservice', 'admin'),
|
||||
new lang_string('configenablemobilewebservice', 'admin', $enablemobiledoclink), 0));
|
||||
$temp->add(new admin_setting_configtext('mobilecssurl', new lang_string('mobilecssurl', 'admin'), new lang_string('configmobilecssurl','admin'), '', PARAM_URL));
|
||||
$ADMIN->add('webservicesettings', $temp);
|
||||
/// overview page
|
||||
@@ -472,49 +447,6 @@ foreach ($pages as $page) {
|
||||
$ADMIN->add('reportplugins', $page);
|
||||
}
|
||||
|
||||
if ($hassiteconfig) {
|
||||
// Global Search engine plugins.
|
||||
$ADMIN->add('modules', new admin_category('searchplugins', new lang_string('search', 'admin')));
|
||||
$temp = new admin_settingpage('manageglobalsearch', new lang_string('globalsearchmanage', 'admin'));
|
||||
|
||||
$pages = array();
|
||||
$engines = array();
|
||||
foreach (core_component::get_plugin_list('search') as $engine => $plugindir) {
|
||||
$engines[$engine] = new lang_string('pluginname', 'search_' . $engine);
|
||||
$settingspath = "$plugindir/settings.php";
|
||||
if (file_exists($settingspath)) {
|
||||
$settings = new admin_settingpage('search' . $engine,
|
||||
new lang_string('pluginname', 'search_' . $engine), 'moodle/site:config');
|
||||
include($settingspath);
|
||||
if ($settings) {
|
||||
$pages[] = $settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup status.
|
||||
$temp->add(new admin_setting_searchsetupinfo());
|
||||
|
||||
// Search engine selection.
|
||||
$temp->add(new admin_setting_heading('searchengineheading', new lang_string('searchengine', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configselect('searchengine',
|
||||
new lang_string('selectsearchengine', 'admin'), '', 'solr', $engines));
|
||||
|
||||
// Enable search areas.
|
||||
$temp->add(new admin_setting_heading('searchareasheading', new lang_string('availablesearchareas', 'admin'), ''));
|
||||
$searchareas = \core_search\manager::get_search_areas_list();
|
||||
foreach ($searchareas as $areaid => $searcharea) {
|
||||
list($componentname, $varname) = $searcharea->get_config_var_name();
|
||||
$temp->add(new admin_setting_configcheckbox($componentname . '/' . $varname . '_enabled', $searcharea->get_visible_name(true),
|
||||
'', 1, 1, 0));
|
||||
}
|
||||
$ADMIN->add('searchplugins', $temp);
|
||||
|
||||
foreach ($pages as $page) {
|
||||
$ADMIN->add('searchplugins', $page);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add all admin tools
|
||||
if ($hassiteconfig) {
|
||||
$ADMIN->add('modules', new admin_category('tools', new lang_string('tools', 'admin')));
|
||||
@@ -547,9 +479,10 @@ if ($hassiteconfig) {
|
||||
// Add Calendar type settings.
|
||||
if ($hassiteconfig) {
|
||||
$ADMIN->add('modules', new admin_category('calendartype', new lang_string('calendartypes', 'calendar')));
|
||||
foreach (core_plugin_manager::instance()->get_plugins_of_type('calendartype') as $plugin) {
|
||||
/** @var \core\plugininfo\calendartype $plugin */
|
||||
$plugin->load_settings($ADMIN, 'calendartype', $hassiteconfig);
|
||||
foreach (core_component::get_plugin_list_with_file('calendartype', 'settings.php') as $plugin => $settingspath) {
|
||||
$settings = new admin_settingpage('calendartype_' . $plugin . '_settings', new lang_string('pluginname', 'calendartype_' . $plugin), 'moodle/site:config');
|
||||
include($settingspath);
|
||||
$ADMIN->add('calendartype', $settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -127,4 +127,19 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
}
|
||||
$temp->add(new admin_setting_configselect('notifyloginthreshold', new lang_string('notifyloginthreshold', 'admin'), new lang_string('confignotifyloginthreshold', 'admin'), '10', $options));
|
||||
$ADMIN->add('security', $temp);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// "antivirus" settingpage
|
||||
$temp = new admin_settingpage('antivirus', new lang_string('antivirus', 'admin'));
|
||||
$temp->add(new admin_setting_configcheckbox('runclamonupload', new lang_string('runclamavonupload', 'admin'), new lang_string('configrunclamavonupload', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configexecutable('pathtoclam', new lang_string('pathtoclam', 'admin'), new lang_string('configpathtoclam', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configdirectory('quarantinedir', new lang_string('quarantinedir', 'admin'), new lang_string('configquarantinedir', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configselect('clamfailureonupload', new lang_string('clamfailureonupload', 'admin'), new lang_string('configclamfailureonupload', 'admin'), 'donothing', array('donothing' => new lang_string('configclamdonothing', 'admin'),
|
||||
'actlikevirus' => new lang_string('configclamactlikevirus', 'admin'))));
|
||||
$ADMIN->add('security', $temp);
|
||||
|
||||
} // end of speedup
|
||||
|
||||
@@ -12,17 +12,17 @@ $temp->add(new admin_setting_configexecutable('pathtodu', new lang_string('patht
|
||||
$temp->add(new admin_setting_configexecutable('aspellpath', new lang_string('aspellpath', 'admin'), new lang_string('edhelpaspellpath'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('pathtodot', new lang_string('pathtodot', 'admin'), new lang_string('pathtodot_help', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('pathtogs', new lang_string('pathtogs', 'admin'), new lang_string('pathtogs_help', 'admin'), '/usr/bin/gs'));
|
||||
$temp->add(new admin_setting_configexecutable('pathtounoconv', new lang_string('pathtounoconv', 'admin'), new lang_string('pathtounoconv_help', 'admin'), '/usr/bin/unoconv'));
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
|
||||
|
||||
// "supportcontact" settingpage
|
||||
$temp = new admin_settingpage('supportcontact', new lang_string('supportcontact','admin'));
|
||||
$primaryadmin = get_admin();
|
||||
if ($primaryadmin) {
|
||||
$primaryadminemail = $primaryadmin->email;
|
||||
$primaryadminname = fullname($primaryadmin, true);
|
||||
if (isloggedin()) {
|
||||
global $USER;
|
||||
$primaryadminemail = $USER->email;
|
||||
$primaryadminname = fullname($USER, true);
|
||||
|
||||
} else {
|
||||
// no defaults during installation - admin user must be created first
|
||||
$primaryadminemail = NULL;
|
||||
@@ -215,6 +215,10 @@ if (empty($CFG->disableupdatenotifications)) {
|
||||
$temp = new admin_settingpage('updatenotifications', new lang_string('updatenotifications', 'core_admin'));
|
||||
$temp->add(new admin_setting_configcheckbox('updateautocheck', new lang_string('updateautocheck', 'core_admin'),
|
||||
new lang_string('updateautocheck_desc', 'core_admin'), 1));
|
||||
if (empty($CFG->disableupdateautodeploy)) {
|
||||
$temp->add(new admin_setting_configcheckbox('updateautodeploy', new lang_string('updateautodeploy', 'core_admin'),
|
||||
new lang_string('updateautodeploy_desc', 'core_admin'), 0));
|
||||
}
|
||||
$temp->add(new admin_setting_configselect('updateminmaturity', new lang_string('updateminmaturity', 'core_admin'),
|
||||
new lang_string('updateminmaturity_desc', 'core_admin'), MATURITY_STABLE,
|
||||
array(
|
||||
|
||||
@@ -34,7 +34,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
// Conditional activities: completion and availability
|
||||
$optionalsubsystems->add(new admin_setting_configcheckbox('enablecompletion',
|
||||
new lang_string('enablecompletion','completion'),
|
||||
new lang_string('configenablecompletion', 'completion'), 1));
|
||||
new lang_string('configenablecompletion','completion'), 0));
|
||||
|
||||
$options = array(
|
||||
1 => get_string('completionactivitydefault', 'completion'),
|
||||
@@ -45,13 +45,10 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
|
||||
$optionalsubsystems->add($checkbox = new admin_setting_configcheckbox('enableavailability',
|
||||
new lang_string('enableavailability', 'availability'),
|
||||
new lang_string('enableavailability_desc', 'availability'), 1));
|
||||
new lang_string('enableavailability_desc', 'availability'), 0));
|
||||
$checkbox->set_affects_modinfo(true);
|
||||
|
||||
$optionalsubsystems->add(new admin_setting_configcheckbox('enableplagiarism', new lang_string('enableplagiarism','plagiarism'), new lang_string('configenableplagiarism','plagiarism'), 0));
|
||||
|
||||
$optionalsubsystems->add(new admin_setting_configcheckbox('enablebadges', new lang_string('enablebadges', 'badges'), new lang_string('configenablebadges', 'badges'), 1));
|
||||
|
||||
$optionalsubsystems->add(new admin_setting_configcheckbox('enableglobalsearch', new lang_string('enableglobalsearch', 'admin'),
|
||||
new lang_string('enableglobalsearch_desc', 'admin'), 0, 1, 0));
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ if ($hassiteconfig) {
|
||||
$ADMIN->add('root', new admin_category('users', new lang_string('users','admin')));
|
||||
$ADMIN->add('root', new admin_category('courses', new lang_string('courses','admin')));
|
||||
$ADMIN->add('root', new admin_category('grades', new lang_string('grades')));
|
||||
$ADMIN->add('root', new admin_category('competencies', new lang_string('competencies', 'core_competency')));
|
||||
$ADMIN->add('root', new admin_category('badges', new lang_string('badges'), empty($CFG->enablebadges)));
|
||||
$ADMIN->add('root', new admin_category('location', new lang_string('location','admin')));
|
||||
$ADMIN->add('root', new admin_category('language', new lang_string('language')));
|
||||
|
||||
@@ -185,7 +185,7 @@ if ($hassiteconfig
|
||||
new lang_string('showuseridentity_desc', 'admin'), array('email' => 1), array(
|
||||
'idnumber' => new lang_string('idnumber'),
|
||||
'email' => new lang_string('email'),
|
||||
'phone1' => new lang_string('phone1'),
|
||||
'phone1' => new lang_string('phone'),
|
||||
'phone2' => new lang_string('phone2'),
|
||||
'department' => new lang_string('department'),
|
||||
'institution' => new lang_string('institution'),
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
require_once(__DIR__ . '/../../../lib/behat/behat_base.php');
|
||||
require_once(__DIR__ . '/../../../lib/behat/behat_field_manager.php');
|
||||
|
||||
use Behat\Gherkin\Node\TableNode as TableNode,
|
||||
use Behat\Behat\Context\Step\Given as Given,
|
||||
Behat\Gherkin\Node\TableNode as TableNode,
|
||||
Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException;
|
||||
|
||||
/**
|
||||
@@ -74,7 +75,7 @@ class behat_admin extends behat_base {
|
||||
$exception = new ElementNotFoundException($this->getSession(), '"' . $label . '" administration setting ');
|
||||
|
||||
// The argument should be converted to an xpath literal.
|
||||
$label = behat_context_helper::escape($label);
|
||||
$label = $this->getSession()->getSelectorsHandler()->xpathLiteral($label);
|
||||
|
||||
// Single element settings.
|
||||
try {
|
||||
|
||||
@@ -27,6 +27,7 @@ Feature: An administrator can filter user accounts by role, cohort and other pro
|
||||
And I add "User Three (three@example.com)" user to "CH1" cohort members
|
||||
And I follow "Browse list of users"
|
||||
|
||||
@javascript
|
||||
Scenario: Filter user accounts by role and cohort
|
||||
When I set the following fields to these values:
|
||||
| courserole_rl | Student |
|
||||
@@ -50,6 +51,7 @@ Feature: An administrator can filter user accounts by role, cohort and other pro
|
||||
And I should see "User Three"
|
||||
And I should see "User Four"
|
||||
|
||||
@javascript
|
||||
Scenario: Filter user accounts by confirm and authentication method
|
||||
When I set the following fields to these values:
|
||||
| Confirmed | No |
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
@core @core_admin @_file_upload
|
||||
Feature: Upload users
|
||||
In order to add users to the system
|
||||
As an admin
|
||||
I need to upload files containing the users data
|
||||
|
||||
@javascript
|
||||
Scenario: Upload users enrolling them on courses and groups
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Maths | math102 | 0 |
|
||||
And the following "groups" exist:
|
||||
| name | course | idnumber |
|
||||
| Section 1 | math102 | S1 |
|
||||
| Section 3 | math102 | S3 |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Upload users" node in "Site administration > Users > Accounts"
|
||||
When I upload "lib/tests/fixtures/upload_users.csv" file to "File" filemanager
|
||||
And I press "Upload users"
|
||||
Then I should see "Upload users preview"
|
||||
And I should see "Tom"
|
||||
And I should see "Jones"
|
||||
And I should see "verysecret"
|
||||
And I should see "jonest@example.com"
|
||||
And I should see "Reznor"
|
||||
And I should see "course1"
|
||||
And I should see "math102"
|
||||
And I should see "group1"
|
||||
And I should see "Section 1"
|
||||
And I press "Upload users"
|
||||
And I press "Continue"
|
||||
And I follow "Browse list of users"
|
||||
And I should see "Tom Jones"
|
||||
And I should see "Trent Reznor"
|
||||
And I should see "reznor@example.com"
|
||||
And I am on site homepage
|
||||
And I follow "Maths"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I set the field "groups" to "Section 1 (1)"
|
||||
And the "members" select box should contain "Tom Jones"
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111600;
|
||||
$plugin->requires = 2015111000;
|
||||
$plugin->version = 2015051100;
|
||||
$plugin->requires = 2015050500;
|
||||
$plugin->component = 'tool_assignmentupgrade';
|
||||
$plugin->dependencies = array('mod_assign' => 2015111000);
|
||||
$plugin->dependencies = array('mod_assign' => 2015050500);
|
||||
|
||||
@@ -8,8 +8,6 @@ Feature: Manage availability conditions
|
||||
Scenario: Display list of availability conditions
|
||||
# Check the report doesn't show when not enabled.
|
||||
Given I log in as "admin"
|
||||
And the following config values are set as admin:
|
||||
| enableavailability | 0 |
|
||||
And I expand "Site administration" node
|
||||
When I expand "Plugins" node
|
||||
Then I should not see "Availability restrictions"
|
||||
@@ -30,6 +28,8 @@ Feature: Manage availability conditions
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | topics |
|
||||
And the following config values are set as admin:
|
||||
| enableavailability | 1 |
|
||||
And I log in as "admin"
|
||||
And I am on site homepage
|
||||
When I navigate to "Manage restrictions" node in "Site administration > Plugins > Availability restrictions"
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111600;
|
||||
$plugin->requires = 2015111000;
|
||||
$plugin->version = 2015051100;
|
||||
$plugin->requires = 2015050500;
|
||||
$plugin->component = 'tool_availabilityconditions';
|
||||
|
||||
@@ -120,14 +120,10 @@ $tags = '';
|
||||
|
||||
if ($options['profile']) {
|
||||
$profile = $options['profile'];
|
||||
|
||||
// If profile passed is not set, then exit.
|
||||
if (!isset($CFG->behat_config[$profile]) && !isset($CFG->behat_profiles[$profile]) &&
|
||||
!(isset($options['replace']) && (strpos($options['profile'], $options['replace']) >= 0 ))) {
|
||||
echo "Invalid profile passed: " . $profile . PHP_EOL;
|
||||
if (!isset($CFG->behat_config[$profile])) {
|
||||
echo "Invalid profile passed: " . $profile;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$extraopts[] = '--profile="' . $profile . '"';
|
||||
// By default, profile tags will be used.
|
||||
if (!empty($CFG->behat_config[$profile]['filters']['tags'])) {
|
||||
@@ -230,27 +226,22 @@ $exitcodes = print_combined_run_output($processes, $stoponfail);
|
||||
$time = round(microtime(true) - $time, 1);
|
||||
echo "Finished in " . gmdate("G\h i\m s\s", $time) . PHP_EOL . PHP_EOL;
|
||||
|
||||
ksort($exitcodes);
|
||||
|
||||
// Print exit info from each run.
|
||||
// Status bits contains pass/fail status of parallel runs.
|
||||
$status = 0;
|
||||
$processcounter = 0;
|
||||
$status = false;
|
||||
foreach ($exitcodes as $exitcode) {
|
||||
if ($exitcode) {
|
||||
$status |= (1 << $processcounter);
|
||||
}
|
||||
$processcounter++;
|
||||
$status = (bool)$status || (bool)$exitcode;
|
||||
}
|
||||
|
||||
// Run finished. Show exit code and output from individual process.
|
||||
$verbose = empty($options['verbose']) ? false : true;
|
||||
$verbose = $verbose || !empty($status);
|
||||
$verbose = $verbose || $status;
|
||||
|
||||
// Show exit code from each process, if any process failed.
|
||||
if ($verbose) {
|
||||
// Echo exit codes.
|
||||
echo "Exit codes for each behat run: " . PHP_EOL;
|
||||
ksort($exitcodes);
|
||||
foreach ($exitcodes as $run => $exitcode) {
|
||||
echo $run . ": " . $exitcode . PHP_EOL;
|
||||
}
|
||||
@@ -272,7 +263,7 @@ print_each_process_info($processes, $verbose);
|
||||
// Remove site symlink if necessary.
|
||||
behat_config_manager::drop_parallel_site_links();
|
||||
|
||||
exit($status);
|
||||
exit((int) $status);
|
||||
|
||||
/**
|
||||
* Signal handler for terminal exit.
|
||||
|
||||
@@ -173,11 +173,6 @@ if ($options['install']) {
|
||||
|
||||
// This is only displayed once for parallel install.
|
||||
if (empty($options['run'])) {
|
||||
// Notify user that 2.5 profile has been converted to 3.5.
|
||||
if (behat_config_manager::$autoprofileconversion) {
|
||||
mtrace("2.5 behat profile detected, automatically converted to current 3.x format");
|
||||
}
|
||||
|
||||
$runtestscommand = behat_command::get_behat_command(true, !empty($options['run']));
|
||||
|
||||
$runtestscommand .= ' --config ' . behat_config_manager::get_behat_cli_config_filepath();
|
||||
|
||||
@@ -351,7 +351,7 @@ Feature: Set up contextual data for tests
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I expand "Setup" node
|
||||
And I follow "Gradebook setup"
|
||||
And I follow "Categories and items"
|
||||
Then I should see "Test Grade Item 1"
|
||||
And I follow "Edit Test Grade Item 1"
|
||||
And I expand all fieldsets
|
||||
@@ -424,9 +424,9 @@ Feature: Set up contextual data for tests
|
||||
And the following "grade categories" exist:
|
||||
| fullname | course |
|
||||
| Grade category 1 | C1 |
|
||||
And the following "grade items" exist:
|
||||
| itemname | course | outcome | gradecategory |
|
||||
| Test Outcome Grade Item 1 | C1 | OT1 | Grade category 1 |
|
||||
And the following "grade items" exist:
|
||||
| itemname | course | outcome | gradecategory |
|
||||
| Test Outcome Grade Item 1 | C1 | OT1 | Grade category 1 |
|
||||
And the following config values are set as admin:
|
||||
| enableoutcomes | 1 |
|
||||
When I log in as "admin"
|
||||
@@ -434,22 +434,10 @@ Feature: Set up contextual data for tests
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I expand "Setup" node
|
||||
And I follow "Gradebook setup"
|
||||
And I follow "Categories and items"
|
||||
Then I should see "Test Outcome Grade Item 1"
|
||||
And I follow "Edit Test Outcome Grade Item 1"
|
||||
And the field "Outcome" matches value "Grade outcome 1"
|
||||
And I expand all fieldsets
|
||||
And "//div[contains(@class, 'fitem')]/div[contains(@class, 'fitemtitle')]/div[contains(@class, fstaticlabel) and contains(., 'Grade category')]/../../div[contains(@class, 'felement') and contains(., 'Grade category 1')]" "xpath_element" should exist
|
||||
And I press "Cancel"
|
||||
|
||||
Scenario: Add a block
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| online_users | Course | C1 | course-view-* | site-pre |
|
||||
When I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
Then I should see "Online users"
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Display environment used for running behat.
|
||||
*
|
||||
* This file is used for behat testing to ensure cli and apache
|
||||
* version of environment is same.
|
||||
*
|
||||
* @package tool_behat
|
||||
* @copyright 2016 onwards Rajesh Taneja
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__.'/../../../../../../config.php');
|
||||
|
||||
// Only continue for behat site.
|
||||
defined('BEHAT_SITE_RUNNING') || die();
|
||||
|
||||
require_once($CFG->libdir.'/behat/classes/util.php');
|
||||
echo json_encode(behat_util::get_environment(), true);
|
||||
@@ -35,33 +35,53 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I log in as "admin"
|
||||
And I expand "Site administration" node
|
||||
And I expand "Appearance" node
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
And I follow "Reset"
|
||||
# Select (multi-select) - Checking "the select box should contain".
|
||||
And I expand all fieldsets
|
||||
And the "Unenrol users" select box should contain "No roles"
|
||||
And the "Unenrol users" select box should contain "Student"
|
||||
And the "Unenrol users" select box should contain "Non-editing teacher"
|
||||
And the "Unenrol users" select box should contain "Teacher"
|
||||
And the "Unenrol users" select box should contain "Manager"
|
||||
And the "Unenrol users" select box should contain "No roles, Student, Non-editing teacher, Teacher, Manager"
|
||||
And the "Unenrol users" select box should contain "Manager, Teacher, Non-editing teacher, Student, No roles"
|
||||
And the "Unenrol users" select box should not contain "President"
|
||||
And the "Unenrol users" select box should not contain "Baker"
|
||||
And the "Unenrol users" select box should not contain "President, Baker"
|
||||
And I follow "Manage tags"
|
||||
# Select (multi-select) - We will check "I set the field...".
|
||||
And I set the field "otagsadd" to "OT1, OT2, OT3, OT4, OT5"
|
||||
And I press "Add official tags"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I follow "Test this one"
|
||||
And I press "Create page"
|
||||
# Select (multi-select) - Checking "the select box should contain".
|
||||
And the "tags[officialtags][]" select box should contain "OT1"
|
||||
And the "tags[officialtags][]" select box should contain "OT2"
|
||||
And the "tags[officialtags][]" select box should contain "OT3"
|
||||
And the "tags[officialtags][]" select box should contain "OT4"
|
||||
And the "tags[officialtags][]" select box should contain "OT5"
|
||||
And the "tags[officialtags][]" select box should contain "OT1, OT2, OT3, OT4, OT5"
|
||||
And the "tags[officialtags][]" select box should contain "OT5, OT4, OT3, OT2, OT1"
|
||||
And the "tags[officialtags][]" select box should not contain "OT6"
|
||||
And the "tags[officialtags][]" select box should not contain "OT7"
|
||||
And the "tags[officialtags][]" select box should not contain "OT6, OT7"
|
||||
# Text (textarea & editor) & Select (multi-select) - Checking "I set the following fields to these values".
|
||||
When I set the following fields to these values:
|
||||
| HTML format | Student page contents |
|
||||
| HTML format | Student page contents to be tagged |
|
||||
| tags[officialtags][] | OT1, OT3, OT5 |
|
||||
And I press "Save"
|
||||
Then I should see "Student page contents" in the "region-main" "region"
|
||||
Then I should see "Student page contents to be tagged" in the "region-main" "region"
|
||||
And I should see "OT1" in the ".wiki-tags" "css_element"
|
||||
And I should see "OT3" in the ".wiki-tags" "css_element"
|
||||
And I should see "OT5" in the ".wiki-tags" "css_element"
|
||||
And I should not see "OT2" in the ".wiki-tags" "css_element"
|
||||
And I should not see "OT4" in the ".wiki-tags" "css_element"
|
||||
And I follow "Edit"
|
||||
# Select (multi-select) - Checking "I set the field".
|
||||
And I set the field "tags[officialtags][]" to "OT2, OT4"
|
||||
And I press "Save"
|
||||
And I should see "OT2" in the ".wiki-tags" "css_element"
|
||||
And I should see "OT4" in the ".wiki-tags" "css_element"
|
||||
And I should not see "OT1" in the ".wiki-tags" "css_element"
|
||||
And I should not see "OT3" in the ".wiki-tags" "css_element"
|
||||
And I should not see "OT5" in the ".wiki-tags" "css_element"
|
||||
And I follow "Edit"
|
||||
# Select (multi-select) - Checking "the field matches value" and "the field does not match value".
|
||||
And the field "tags[officialtags][]" matches value "OT2, OT4"
|
||||
And the field "tags[officialtags][]" does not match value "OT4"
|
||||
And the field "tags[officialtags][]" does not match value "OT2"
|
||||
And the field "tags[officialtags][]" does not match value "OT1, OT3, OT5"
|
||||
And I press "Cancel"
|
||||
And I follow "Edit settings"
|
||||
And I expand all fieldsets
|
||||
# Checkbox - Checking "I set the field".
|
||||
|
||||
@@ -12,6 +12,7 @@ Feature: Forms manipulation
|
||||
When I set the field "First name" to "Field value"
|
||||
And I set the field "Select a country" to "Japan"
|
||||
And I set the field "Unmask" to "1"
|
||||
And I expand all fieldsets
|
||||
Then the field "First name" matches value "Field value"
|
||||
And the "Select a country" select box should contain "Japan"
|
||||
And the field "Unmask" matches value "1"
|
||||
|
||||
@@ -142,10 +142,11 @@ class tool_behat_manager_testcase extends advanced_testcase {
|
||||
// YAML decides when is is necessary to wrap strings between single quotes, so not controlled
|
||||
// values like paths should not be asserted including the key name as they would depend on the
|
||||
// directories values.
|
||||
$this->assertContains($CFG->dirroot, $contents);
|
||||
$this->assertContains($CFG->dirroot . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'behat' . DIRECTORY_SEPARATOR . 'features', $contents);
|
||||
|
||||
// Not quoted strings.
|
||||
$this->assertContains('micarro: /me/lo/robaron', $contents);
|
||||
$this->assertContains('class: behat_init_context', $contents);
|
||||
|
||||
// YAML uses single quotes to wrap URL strings.
|
||||
$this->assertContains("base_url: '" . $CFG->behat_wwwroot . "'", $contents);
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111600; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2015111000; // Requires this Moodle version
|
||||
$plugin->version = 2015051100; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2015050500; // Requires this Moodle version
|
||||
$plugin->component = 'tool_behat'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
.path-admin-tool-capability .comparisontable tbody th span {display:block;color:#666;font-size:80%;}
|
||||
.path-admin-tool-capability .comparisontable tbody td {border:1px solid #DFDFDF;}
|
||||
|
||||
.path-admin-tool-capability .comparisontable .inherit {color:#666}
|
||||
.path-admin-tool-capability .comparisontable .allow {background-color:#006600;font-weight:bold;color:white;}
|
||||
.path-admin-tool-capability .comparisontable .prevent {background-color:#ad6704;font-weight:bold;color:white;}
|
||||
.path-admin-tool-capability .comparisontable .prohibit {background-color:#880000;font-weight:bold;color:white;}
|
||||
.path-admin-tool-capability .comparisontable .inherit {color:#666;}
|
||||
.path-admin-tool-capability .comparisontable .allow {color:#006600;font-weight:bold;}
|
||||
.path-admin-tool-capability .comparisontable .prevent {color:#ad6704;font-weight:bold;}
|
||||
.path-admin-tool-capability .comparisontable .prohibit {color:#880000;font-weight:bold;}
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111600; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2015111000; // Requires this Moodle version.
|
||||
$plugin->version = 2015051100; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2015050500; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_capability'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class exposing the api for the cohortroles tool.
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_cohortroles;
|
||||
|
||||
use stdClass;
|
||||
use context_system;
|
||||
use core_competency\invalid_persistent_exception;
|
||||
|
||||
/**
|
||||
* Class for doing things with cohort roles.
|
||||
*
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class api {
|
||||
|
||||
/**
|
||||
* Create a cohort role assignment from a record containing all the data for the class.
|
||||
*
|
||||
* Requires moodle/role:manage capability at the system context.
|
||||
*
|
||||
* @param stdClass $record Record containing all the data for an instance of the class.
|
||||
* @return competency
|
||||
*/
|
||||
public static function create_cohort_role_assignment(stdClass $record) {
|
||||
$cohortroleassignment = new cohort_role_assignment(0, $record);
|
||||
$context = context_system::instance();
|
||||
|
||||
// First we do a permissions check.
|
||||
require_capability('moodle/role:manage', $context);
|
||||
|
||||
// Validate before we check for existing records.
|
||||
if (!$cohortroleassignment->is_valid()) {
|
||||
throw new invalid_persistent_exception($cohortroleassignment->get_errors());
|
||||
}
|
||||
|
||||
$existing = cohort_role_assignment::get_record((array) $record);
|
||||
if (!empty($existing)) {
|
||||
return false;
|
||||
} else {
|
||||
// OK - all set.
|
||||
$cohortroleassignment->create();
|
||||
}
|
||||
return $cohortroleassignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cohort role assignment by id.
|
||||
*
|
||||
* Requires moodle/role:manage capability at the system context.
|
||||
*
|
||||
* @param int $id The record to delete. This will also remove this role from the user for all users in the system.
|
||||
* @return boolean
|
||||
*/
|
||||
public static function delete_cohort_role_assignment($id) {
|
||||
$cohortroleassignment = new cohort_role_assignment($id);
|
||||
$context = context_system::instance();
|
||||
|
||||
// First we do a permissions check.
|
||||
require_capability('moodle/role:manage', $context);
|
||||
|
||||
// OK - all set.
|
||||
return $cohortroleassignment->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a search based on the provided filters and return a paginated list of records.
|
||||
*
|
||||
* Requires moodle/role:manage capability at the system context.
|
||||
*
|
||||
* @param string $sort The column to sort on
|
||||
* @param string $order ('ASC' or 'DESC')
|
||||
* @param int $skip Number of records to skip (pagination)
|
||||
* @param int $limit Max of records to return (pagination)
|
||||
* @return array of cohort_role_assignment
|
||||
*/
|
||||
public static function list_cohort_role_assignments($sort = '', $order = 'ASC', $skip = 0, $limit = 0) {
|
||||
$context = context_system::instance();
|
||||
|
||||
// First we do a permissions check.
|
||||
require_capability('moodle/role:manage', $context);
|
||||
|
||||
// OK - all set.
|
||||
return cohort_role_assignment::get_records(array(), $sort, $order, $skip, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a search based on the provided filters and return a paginated list of records.
|
||||
*
|
||||
* Requires moodle/role:manage capability at system context.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function count_cohort_role_assignments() {
|
||||
$context = context_system::instance();
|
||||
|
||||
// First we do a permissions check.
|
||||
require_capability('moodle/role:manage', $context);
|
||||
|
||||
// OK - all set.
|
||||
return cohort_role_assignment::count_records();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync all roles - adding and deleting role assignments as required.
|
||||
*
|
||||
* Slow. Should only be called from a background task.
|
||||
*
|
||||
* Requires moodle/role:manage capability at the system context.
|
||||
*
|
||||
* @return array('rolesadded' => array of (useridassignedto, useridassignedover, roleid),
|
||||
* 'rolesremoved' => array of (useridassignedto, useridassignedover, roleid))
|
||||
*/
|
||||
public static function sync_all_cohort_roles() {
|
||||
global $DB;
|
||||
|
||||
$context = context_system::instance();
|
||||
|
||||
// First we do a permissions check.
|
||||
require_capability('moodle/role:manage', $context);
|
||||
|
||||
// Ok ready to go.
|
||||
$rolesadded = array();
|
||||
$rolesremoved = array();
|
||||
|
||||
// Get all cohort role assignments and group them by user and role.
|
||||
$all = cohort_role_assignment::get_records(array(), 'userid, roleid');
|
||||
// We build an better structure to loop on.
|
||||
$info = array();
|
||||
foreach ($all as $cra) {
|
||||
if (!isset($info[$cra->get_userid()])) {
|
||||
$info[$cra->get_userid()] = array();
|
||||
}
|
||||
if (!isset($info[$cra->get_userid()][$cra->get_roleid()])) {
|
||||
$info[$cra->get_userid()][$cra->get_roleid()] = array();
|
||||
}
|
||||
array_push($info[$cra->get_userid()][$cra->get_roleid()], $cra->get_cohortid());
|
||||
}
|
||||
// Then for each user+role combo - find user context in the cohort without a role assigned.
|
||||
|
||||
foreach ($info as $userid => $roles) {
|
||||
foreach ($roles as $roleid => $cohorts) {
|
||||
list($cohortsql, $params) = $DB->get_in_or_equal($cohorts, SQL_PARAMS_NAMED);
|
||||
|
||||
$params['usercontext'] = CONTEXT_USER;
|
||||
$params['roleid'] = $roleid;
|
||||
$params['userid'] = $userid;
|
||||
|
||||
$sql = 'SELECT u.id AS userid, ra.id, ctx.id AS contextid
|
||||
FROM {user} u
|
||||
JOIN {cohort_members} cm ON u.id = cm.userid
|
||||
JOIN {context} ctx ON u.id = ctx.instanceid AND ctx.contextlevel = :usercontext
|
||||
LEFT JOIN {role_assignments} ra ON ra.contextid = ctx.id
|
||||
AND ra.roleid = :roleid
|
||||
AND ra.userid = :userid
|
||||
WHERE cm.cohortid ' . $cohortsql . '
|
||||
AND ra.id IS NULL';
|
||||
|
||||
$toadd = $DB->get_records_sql($sql, $params);
|
||||
|
||||
foreach ($toadd as $add) {
|
||||
role_assign($roleid, $userid, $add->contextid, 'tool_cohortroles');
|
||||
$rolesadded[] = array(
|
||||
'useridassignedto' => $userid,
|
||||
'useridassignedover' => $add->userid,
|
||||
'roleid' => $roleid
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// And for each user+role combo - find user context not in the cohort with a role assigned.
|
||||
// If the role was assigned by this component, unassign the role.
|
||||
foreach ($info as $userid => $roles) {
|
||||
foreach ($roles as $roleid => $cohorts) {
|
||||
// Now we are looking for entries NOT in the cohort.
|
||||
list($cohortsql, $params) = $DB->get_in_or_equal($cohorts, SQL_PARAMS_NAMED);
|
||||
|
||||
$params['usercontext'] = CONTEXT_USER;
|
||||
$params['roleid'] = $roleid;
|
||||
$params['userid'] = $userid;
|
||||
$params['component'] = 'tool_cohortroles';
|
||||
|
||||
$sql = 'SELECT u.id as userid, ra.id, ctx.id AS contextid
|
||||
FROM {user} u
|
||||
JOIN {context} ctx ON u.id = ctx.instanceid AND ctx.contextlevel = :usercontext
|
||||
JOIN {role_assignments} ra ON ra.contextid = ctx.id AND ra.roleid = :roleid AND ra.userid = :userid
|
||||
LEFT JOIN {cohort_members} cm ON u.id = cm.userid
|
||||
AND cm.cohortid ' . $cohortsql . '
|
||||
WHERE ra.component = :component AND cm.cohortid IS NULL';
|
||||
|
||||
$toremove = $DB->get_records_sql($sql, $params);
|
||||
foreach ($toremove as $remove) {
|
||||
role_unassign($roleid, $userid, $remove->contextid, 'tool_cohortroles');
|
||||
$rolesremoved[] = array(
|
||||
'useridassignedto' => $userid,
|
||||
'useridassignedover' => $remove->userid,
|
||||
'roleid' => $roleid
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array('rolesadded' => $rolesadded, 'rolesremoved' => $rolesremoved);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class for cohort_role_assignment persistence.
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_cohortroles;
|
||||
|
||||
use lang_string;
|
||||
use core_competency\persistent;
|
||||
|
||||
/**
|
||||
* Class for loading/storing cohort_role_assignments from the DB.
|
||||
*
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cohort_role_assignment extends persistent {
|
||||
|
||||
/** Table name for user_competency persistency */
|
||||
const TABLE = 'tool_cohortroles';
|
||||
|
||||
/**
|
||||
* Return the definition of the properties of this model.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_properties() {
|
||||
return array(
|
||||
'userid' => array(
|
||||
'type' => PARAM_INT,
|
||||
),
|
||||
'roleid' => array(
|
||||
'type' => PARAM_INT,
|
||||
),
|
||||
'cohortid' => array(
|
||||
'type' => PARAM_INT,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the user ID.
|
||||
*
|
||||
* @param int $value The value.
|
||||
* @return true|lang_string
|
||||
*/
|
||||
protected function validate_userid($value) {
|
||||
global $DB;
|
||||
|
||||
if (!$DB->record_exists('user', array('id' => $value))) {
|
||||
return new lang_string('invaliduserid', 'error');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the role ID.
|
||||
*
|
||||
* @param int $value The value.
|
||||
* @return true|lang_string
|
||||
*/
|
||||
protected function validate_roleid($value) {
|
||||
global $DB;
|
||||
|
||||
if (!$DB->record_exists('role', array('id' => $value))) {
|
||||
return new lang_string('invalidroleid', 'error');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the cohort ID.
|
||||
*
|
||||
* @param int $value The value.
|
||||
* @return true|lang_string
|
||||
*/
|
||||
protected function validate_cohortid($value) {
|
||||
global $DB;
|
||||
|
||||
if (!$DB->record_exists('cohort', array('id' => $value))) {
|
||||
return new lang_string('invalidcohortid', 'error');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Assign role to cohort form.
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_cohortroles\form;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use moodleform;
|
||||
use context_system;
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
|
||||
/**
|
||||
* Assign role to cohort form.
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class assign_role_cohort extends moodleform {
|
||||
|
||||
/**
|
||||
* Form definition.
|
||||
*/
|
||||
public function definition() {
|
||||
global $PAGE;
|
||||
|
||||
$mform = $this->_form;
|
||||
$roles = get_roles_for_contextlevels(CONTEXT_USER);
|
||||
|
||||
if (empty($roles)) {
|
||||
$output = $PAGE->get_renderer('tool_cohortroles');
|
||||
$warning = $output->notify_problem(get_string('noassignableroles', 'tool_cohortroles'));
|
||||
$mform->addElement('html', $warning);
|
||||
return;
|
||||
}
|
||||
|
||||
$options = array(
|
||||
'ajax' => 'tool_lp/form-user-selector',
|
||||
'multiple' => true
|
||||
);
|
||||
$mform->addElement('autocomplete', 'userids', get_string('selectusers', 'tool_cohortroles'), array(), $options);
|
||||
$mform->addRule('userids', null, 'required');
|
||||
|
||||
$names = role_get_names();
|
||||
$options = array();
|
||||
foreach ($roles as $idx => $roleid) {
|
||||
$options[$roleid] = $names[$roleid]->localname;
|
||||
}
|
||||
|
||||
$mform->addElement('select', 'roleid', get_string('selectrole', 'tool_cohortroles'), $options);
|
||||
$mform->addRule('roleid', null, 'required');
|
||||
|
||||
$context = context_system::instance();
|
||||
$options = array(
|
||||
'ajax' => 'tool_lp/form-cohort-selector',
|
||||
'multiple' => true,
|
||||
'data-contextid' => $context->id,
|
||||
'data-includes' => 'all'
|
||||
);
|
||||
$mform->addElement('autocomplete', 'cohortids', get_string('selectcohorts', 'tool_cohortroles'), array(), $options);
|
||||
$mform->addRule('cohortids', null, 'required');
|
||||
$mform->addElement('submit', 'submit', get_string('assign', 'tool_cohortroles'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cohort role assignments table
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_cohortroles\output;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
|
||||
use context_helper;
|
||||
use context_system;
|
||||
use html_writer;
|
||||
use moodle_url;
|
||||
use table_sql;
|
||||
|
||||
/**
|
||||
* Cohort role assignments table.
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cohort_role_assignments_table extends table_sql {
|
||||
|
||||
/**
|
||||
* Sets up the table.
|
||||
*
|
||||
* @param string $uniqueid Unique id of table.
|
||||
* @param moodle_url $url The base URL.
|
||||
*/
|
||||
public function __construct($uniqueid, $url) {
|
||||
global $CFG;
|
||||
parent::__construct($uniqueid);
|
||||
$context = context_system::instance();
|
||||
|
||||
$this->context = $context;
|
||||
|
||||
$this->rolenames = role_get_names();
|
||||
|
||||
// This object should not be used without the right permissions.
|
||||
require_capability('moodle/role:manage', $context);
|
||||
|
||||
$this->useridfield = 'userid';
|
||||
|
||||
// Define columns in the table.
|
||||
$this->define_table_columns();
|
||||
|
||||
$this->define_baseurl($url);
|
||||
// Define configs.
|
||||
$this->define_table_configs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Role name column.
|
||||
*
|
||||
* @param array $data Row data.
|
||||
* @return string
|
||||
*/
|
||||
protected function col_rolename($data) {
|
||||
return $this->rolenames[$data->roleid]->localname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cohort name column.
|
||||
*
|
||||
* @param array $data Row data.
|
||||
* @return string
|
||||
*/
|
||||
protected function col_cohortname($data) {
|
||||
global $OUTPUT;
|
||||
|
||||
$record = (object) array(
|
||||
'id' => $data->cohortid,
|
||||
'idnumber' => $data->cohortidnumber,
|
||||
'description' => $data->cohortdescription,
|
||||
'visible' => $data->cohortvisible,
|
||||
'name' => $data->cohortname
|
||||
);
|
||||
$context = context_helper::instance_by_id($data->cohortcontextid);
|
||||
|
||||
$exporter = new \tool_lp\external\cohort_summary_exporter($record, array('context' => $context));
|
||||
$cohort = $exporter->export($OUTPUT);
|
||||
|
||||
$html = $OUTPUT->render_from_template('tool_cohortroles/cohort-in-list', $cohort);
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions column.
|
||||
*
|
||||
* @param array $data Row data.
|
||||
* @return string
|
||||
*/
|
||||
protected function col_actions($data) {
|
||||
global $OUTPUT;
|
||||
|
||||
$action = new \confirm_action(get_string('removecohortroleassignmentconfirm', 'tool_cohortroles'));
|
||||
$url = new moodle_url($this->baseurl);
|
||||
$url->params(array('removecohortroleassignment' => $data->id, 'sesskey' => sesskey()));
|
||||
$pix = new \pix_icon('t/delete', get_string('removecohortroleassignment', 'tool_cohortroles'));
|
||||
return $OUTPUT->action_link($url, '', $action, null, $pix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the headers for the table.
|
||||
*/
|
||||
protected function define_table_columns() {
|
||||
$extrafields = get_extra_user_fields($this->context);
|
||||
|
||||
// Define headers and columns.
|
||||
$cols = array(
|
||||
'cohortname' => get_string('cohort', 'cohort'),
|
||||
'rolename' => get_string('role'),
|
||||
'fullname' => get_string('name'),
|
||||
);
|
||||
|
||||
// Add headers for extra user fields.
|
||||
foreach ($extrafields as $field) {
|
||||
if (get_string_manager()->string_exists($field, 'moodle')) {
|
||||
$cols[$field] = get_string($field);
|
||||
} else {
|
||||
$cols[$field] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
// Add remaining headers.
|
||||
$cols = array_merge($cols, array('actions' => get_string('actions')));
|
||||
|
||||
$this->define_columns(array_keys($cols));
|
||||
$this->define_headers(array_values($cols));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define table configs.
|
||||
*/
|
||||
protected function define_table_configs() {
|
||||
$this->collapsible(false);
|
||||
$this->sortable(true, 'lastname', SORT_ASC);
|
||||
$this->pageable(true);
|
||||
$this->no_sorting('actions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the SQL query.
|
||||
*
|
||||
* @param bool $count When true, return the count SQL.
|
||||
* @return array containing sql to use and an array of params.
|
||||
*/
|
||||
protected function get_sql_and_params($count = false) {
|
||||
$fields = 'uca.id, uca.cohortid, uca.userid, uca.roleid, ';
|
||||
$fields .= 'c.name as cohortname, c.idnumber as cohortidnumber, c.contextid as cohortcontextid, ';
|
||||
$fields .= 'c.visible as cohortvisible, c.description as cohortdescription, ';
|
||||
|
||||
// Add extra user fields that we need for the graded user.
|
||||
$extrafields = get_extra_user_fields($this->context);
|
||||
foreach ($extrafields as $field) {
|
||||
$fields .= 'u.' . $field . ', ';
|
||||
}
|
||||
$fields .= get_all_user_name_fields(true, 'u');
|
||||
|
||||
if ($count) {
|
||||
$select = "COUNT(1)";
|
||||
} else {
|
||||
$select = "$fields";
|
||||
}
|
||||
|
||||
$sql = "SELECT $select
|
||||
FROM {tool_cohortroles} uca
|
||||
JOIN {user} u ON u.id = uca.userid
|
||||
JOIN {cohort} c ON c.id = uca.cohortid";
|
||||
$params = array();
|
||||
|
||||
// Add order by if needed.
|
||||
if (!$count && $sqlsort = $this->get_sql_sort()) {
|
||||
$sql .= " ORDER BY " . $sqlsort;
|
||||
}
|
||||
|
||||
return array($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default implementation to set a decent heading level.
|
||||
*/
|
||||
public function print_nothing_to_display() {
|
||||
global $OUTPUT;
|
||||
echo $this->render_reset_button();
|
||||
$this->print_initials_bar();
|
||||
echo $OUTPUT->heading(get_string('nothingtodisplay'), 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the DB.
|
||||
*
|
||||
* @param int $pagesize size of page for paginated displayed table.
|
||||
* @param bool $useinitialsbar do you want to use the initials bar.
|
||||
*/
|
||||
public function query_db($pagesize, $useinitialsbar = true) {
|
||||
global $DB;
|
||||
|
||||
list($countsql, $countparams) = $this->get_sql_and_params(true);
|
||||
list($sql, $params) = $this->get_sql_and_params();
|
||||
$total = $DB->count_records_sql($countsql, $countparams);
|
||||
$this->pagesize($pagesize, $total);
|
||||
$this->rawdata = $DB->get_records_sql($sql, $params, $this->get_page_start(), $this->get_page_size());
|
||||
|
||||
// Set initial bars.
|
||||
if ($useinitialsbar) {
|
||||
$this->initialbars($total > $pagesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Renderer class for cohort roles
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2016 Issam Taboubi <issam.taboubi@umontreal.ca>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_cohortroles\output;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use plugin_renderer_base;
|
||||
use renderable;
|
||||
|
||||
/**
|
||||
* Renderer class for cohort roles
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2016 Issam Taboubi <issam.taboubi@umontreal.ca>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class renderer extends plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Output a nofication.
|
||||
*
|
||||
* @param string $message the message to print out
|
||||
* @return string HTML fragment.
|
||||
* @see \core\output\notification
|
||||
*/
|
||||
public function notify_message($message) {
|
||||
$n = new \core\output\notification($message, \core\output\notification::NOTIFY_INFO);
|
||||
return $this->render($n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output an error notification.
|
||||
*
|
||||
* @param string $message the message to print out
|
||||
* @return string HTML fragment.
|
||||
* @see \core\output\notification
|
||||
*/
|
||||
public function notify_problem($message) {
|
||||
$n = new \core\output\notification($message, \core\output\notification::NOTIFY_ERROR);
|
||||
return $this->render($n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a success notification.
|
||||
*
|
||||
* @param string $message the message to print out
|
||||
* @return string HTML fragment.
|
||||
* @see \core\output\notification
|
||||
*/
|
||||
public function notify_success($message) {
|
||||
$n = new \core\output\notification($message, \core\output\notification::NOTIFY_SUCCESS);
|
||||
return $this->render($n);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Scheduled task for syncing cohort roles.
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_cohortroles\task;
|
||||
|
||||
use core\task\scheduled_task;
|
||||
use tool_cohortroles\api;
|
||||
|
||||
/**
|
||||
* Scheduled task for syncing cohort roles.
|
||||
*
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cohort_role_sync extends scheduled_task {
|
||||
|
||||
/**
|
||||
* Get name.
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
// Shown in admin screens.
|
||||
return get_string('taskname', 'tool_cohortroles');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute.
|
||||
*/
|
||||
public function execute() {
|
||||
mtrace('Sync cohort roles...');
|
||||
$result = api::sync_all_cohort_roles();
|
||||
|
||||
mtrace('Added ' . count($result['rolesadded']));
|
||||
mtrace('Removed ' . count($result['rolesremoved']));
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="admin/tool/cohortroles/db" VERSION="20151201" COMMENT="XMLDB file for Moodle admin/tool/cohortroles"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
<TABLES>
|
||||
<TABLE NAME="tool_cohortroles" COMMENT="Mapping of users to cohort role assignments.">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="cohortid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The cohort to sync"/>
|
||||
<FIELD NAME="roleid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The role to assign"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The user to sync"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The time this record was created"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The time this record was modified."/>
|
||||
<FIELD NAME="usermodified" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Who last modified this record?"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="cohortuserrole" UNIQUE="true" FIELDS="cohortid, roleid, userid"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
</TABLES>
|
||||
</XMLDB>
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tasks definitions.
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$tasks = array(
|
||||
array(
|
||||
'classname' => 'tool_cohortroles\task\cohort_role_sync',
|
||||
'blocking' => 0,
|
||||
'minute' => 'R',
|
||||
'hour' => '*',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
),
|
||||
);
|
||||
@@ -1,98 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Assign roles for a user.
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/tablelib.php');
|
||||
|
||||
$removeid = optional_param('removecohortroleassignment', 0, PARAM_INT);
|
||||
|
||||
admin_externalpage_setup('toolcohortroles');
|
||||
$context = context_system::instance();
|
||||
|
||||
$pageurl = new moodle_url('/admin/tool/cohortroles/index.php');
|
||||
|
||||
$output = $PAGE->get_renderer('tool_cohortroles');
|
||||
|
||||
echo $output->header();
|
||||
$title = get_string('assignroletocohort', 'tool_cohortroles');
|
||||
echo $output->heading($title);
|
||||
|
||||
$form = new tool_cohortroles\form\assign_role_cohort();
|
||||
|
||||
if ($removeid) {
|
||||
require_sesskey();
|
||||
|
||||
$result = \tool_cohortroles\api::delete_cohort_role_assignment($removeid);
|
||||
if ($result) {
|
||||
$notification = get_string('cohortroleassignmentremoved', 'tool_cohortroles');
|
||||
echo $output->notify_success($notification);
|
||||
} else {
|
||||
$notification = get_string('cohortroleassignmentnotremoved', 'tool_cohortroles');
|
||||
echo $output->notify_problem($notification);
|
||||
}
|
||||
echo $output->continue_button(new moodle_url($pageurl));
|
||||
} else if ($data = $form->get_data()) {
|
||||
require_sesskey();
|
||||
// We must create them all or none.
|
||||
$saved = 0;
|
||||
// Loop through userids and cohortids only if both of them are not empty.
|
||||
if (!empty($data->userids) && !empty($data->cohortids)) {
|
||||
foreach ($data->userids as $userid) {
|
||||
foreach ($data->cohortids as $cohortid) {
|
||||
$params = (object) array('userid' => $userid, 'cohortid' => $cohortid, 'roleid' => $data->roleid);
|
||||
$result = \tool_cohortroles\api::create_cohort_role_assignment($params);
|
||||
if ($result) {
|
||||
$saved++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($saved == 0) {
|
||||
$notification = get_string('nocohortroleassignmentssaved', 'tool_cohortroles');
|
||||
echo $output->notify_problem($notification);
|
||||
} else if ($saved == 1) {
|
||||
$notification = get_string('onecohortroleassignmentsaved', 'tool_cohortroles');
|
||||
echo $output->notify_success($notification);
|
||||
} else {
|
||||
$notification = get_string('acohortroleassignmentssaved', 'tool_cohortroles', $saved);
|
||||
echo $output->notify_success($notification);
|
||||
}
|
||||
|
||||
echo $output->continue_button(new moodle_url($pageurl));
|
||||
} else {
|
||||
$form->display();
|
||||
|
||||
$title = get_string('existingcohortroles', 'tool_cohortroles');
|
||||
echo $output->heading($title);
|
||||
$url = new moodle_url('/admin/tool/cohortroles/index.php');
|
||||
$table = new tool_cohortroles\output\cohort_role_assignments_table(uniqid(), $url);
|
||||
echo $table->out(50, true);
|
||||
|
||||
echo $output->spacer();
|
||||
echo $output->notify_message(get_string('backgroundsync', 'tool_cohortroles'));
|
||||
}
|
||||
|
||||
echo $output->footer();
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'tool_userroles', language 'en'
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['acohortroleassignmentssaved'] = '{$a} cohort role assignments were saved.';
|
||||
$string['assign'] = 'Assign';
|
||||
$string['assignroletocohort'] = 'Assign role to users in the context of all members of these cohorts';
|
||||
$string['backgroundsync'] = 'Note: Roles assigned on this page will not take affect immediately, the changes to role assignments will be made by a background task.';
|
||||
$string['cohortroleassignmentremoved'] = 'The cohort role assignment was removed.';
|
||||
$string['cohortroleassignmentnotremoved'] = 'The cohort role assignment was not removed.';
|
||||
$string['cohortroles'] = 'Cohort roles';
|
||||
$string['existingcohortroles'] = 'Existing cohort role assignments';
|
||||
$string['managecohortroles'] = 'Assign user roles for entire cohort';
|
||||
$string['noassignableroles'] = 'No roles can be assigned at a user context level. <a href="../../roles/manage.php">Manage roles</a>';
|
||||
$string['nocohortroleassignmentssaved'] = 'No cohort role assignments were saved.';
|
||||
$string['onecohortroleassignmentsaved'] = 'One cohort role assignment was saved.';
|
||||
$string['pluginname'] = 'Cohort roles management';
|
||||
$string['removecohortroleassignment'] = 'Remove cohort role assignment';
|
||||
$string['removecohortroleassignmentconfirm'] = 'Are you sure you want to remove this cohort role assignment? This role will be removed for this user in all other user contexts.';
|
||||
$string['selectcohorts'] = 'Select cohorts';
|
||||
$string['selectrole'] = 'Select role';
|
||||
$string['selectusers'] = 'Select users to assign role';
|
||||
$string['taskname'] = 'Sync cohort role assignments';
|
||||
$string['thisuserroles'] = 'Roles assigned relative to this user';
|
||||
@@ -1,42 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Link to user roles management.
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
// This tool's required capabilities.
|
||||
$capabilities = [
|
||||
'moodle/cohort:view',
|
||||
'moodle/role:manage'
|
||||
];
|
||||
|
||||
// Check if the user has all of the required capabilities.
|
||||
$context = context_system::instance();
|
||||
$hasaccess = has_all_capabilities($capabilities, $context);
|
||||
|
||||
// Add this admin page only if the user has all of the required capabilities.
|
||||
if ($hasaccess) {
|
||||
$str = get_string('managecohortroles', 'tool_cohortroles');
|
||||
$url = new moodle_url('/admin/tool/cohortroles/index.php');
|
||||
$ADMIN->add('roles', new admin_externalpage('toolcohortroles', $str, $url, $capabilities));
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle 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.
|
||||
|
||||
Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template tool_cohortroles/cohort-in-list
|
||||
|
||||
Moodle template for displaying a cohort in a list.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* id cohort id field
|
||||
* name cohort name field
|
||||
* idnumber cohort idnumber field
|
||||
* description cohort description field
|
||||
* visible cohort visible field
|
||||
|
||||
Example context (json):
|
||||
{ "id": "1",
|
||||
"name": "Cohort 1",
|
||||
"visible": true,
|
||||
"idnumber": "014",
|
||||
"description": "Some users"
|
||||
}
|
||||
}}
|
||||
{{> tool_lp/form-cohort-selector-suggestion }}
|
||||
@@ -1,243 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* API tests.
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use tool_cohortroles\api;
|
||||
|
||||
/**
|
||||
* API tests.
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_cohortroles_api_testcase extends advanced_testcase {
|
||||
/** @var stdClass $cohort */
|
||||
protected $cohort = null;
|
||||
|
||||
/** @var stdClass $userassignto */
|
||||
protected $userassignto = null;
|
||||
|
||||
/** @var stdClass $userassignover */
|
||||
protected $userassignover = null;
|
||||
|
||||
/** @var stdClass $role */
|
||||
protected $role = null;
|
||||
|
||||
/**
|
||||
* Setup function- we will create a course and add an assign instance to it.
|
||||
*/
|
||||
protected function setUp() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Create some users.
|
||||
$this->cohort = $this->getDataGenerator()->create_cohort();
|
||||
$this->userassignto = $this->getDataGenerator()->create_user();
|
||||
$this->userassignover = $this->getDataGenerator()->create_user();
|
||||
$this->roleid = create_role('Sausage Roll', 'sausageroll', 'mmmm');
|
||||
cohort_add_member($this->cohort->id, $this->userassignover->id);
|
||||
}
|
||||
|
||||
|
||||
public function test_create_cohort_role_assignment_without_permission() {
|
||||
$this->setExpectedException('required_capability_exception');
|
||||
$this->setUser($this->userassignto);
|
||||
$params = (object) array(
|
||||
'userid' => $this->userassignto->id,
|
||||
'roleid' => $this->roleid,
|
||||
'cohortid' => $this->cohort->id
|
||||
);
|
||||
api::create_cohort_role_assignment($params);
|
||||
}
|
||||
|
||||
public function test_create_cohort_role_assignment_with_invalid_data() {
|
||||
$this->setExpectedException('core_competency\invalid_persistent_exception');
|
||||
$this->setAdminUser();
|
||||
$params = (object) array(
|
||||
'userid' => $this->userassignto->id,
|
||||
'roleid' => -8,
|
||||
'cohortid' => $this->cohort->id
|
||||
);
|
||||
api::create_cohort_role_assignment($params);
|
||||
}
|
||||
|
||||
public function test_create_cohort_role_assignment() {
|
||||
$this->setAdminUser();
|
||||
$params = (object) array(
|
||||
'userid' => $this->userassignto->id,
|
||||
'roleid' => $this->roleid,
|
||||
'cohortid' => $this->cohort->id
|
||||
);
|
||||
$result = api::create_cohort_role_assignment($params);
|
||||
$this->assertNotEmpty($result->get_id());
|
||||
$this->assertEquals($result->get_userid(), $this->userassignto->id);
|
||||
$this->assertEquals($result->get_roleid(), $this->roleid);
|
||||
$this->assertEquals($result->get_cohortid(), $this->cohort->id);
|
||||
}
|
||||
|
||||
public function test_delete_cohort_role_assignment_without_permission() {
|
||||
$this->setAdminUser();
|
||||
$params = (object) array(
|
||||
'userid' => $this->userassignto->id,
|
||||
'roleid' => $this->roleid,
|
||||
'cohortid' => $this->cohort->id
|
||||
);
|
||||
$result = api::create_cohort_role_assignment($params);
|
||||
$this->setExpectedException('required_capability_exception');
|
||||
$this->setUser($this->userassignto);
|
||||
api::delete_cohort_role_assignment($result->get_id());
|
||||
}
|
||||
|
||||
public function test_delete_cohort_role_assignment_with_invalid_data() {
|
||||
$this->setAdminUser();
|
||||
$params = (object) array(
|
||||
'userid' => $this->userassignto->id,
|
||||
'roleid' => $this->roleid,
|
||||
'cohortid' => $this->cohort->id
|
||||
);
|
||||
$result = api::create_cohort_role_assignment($params);
|
||||
$this->setExpectedException('dml_missing_record_exception');
|
||||
api::delete_cohort_role_assignment($result->get_id() + 1);
|
||||
}
|
||||
|
||||
public function test_delete_cohort_role_assignment() {
|
||||
$this->setAdminUser();
|
||||
$params = (object) array(
|
||||
'userid' => $this->userassignto->id,
|
||||
'roleid' => $this->roleid,
|
||||
'cohortid' => $this->cohort->id
|
||||
);
|
||||
$result = api::create_cohort_role_assignment($params);
|
||||
$worked = api::delete_cohort_role_assignment($result->get_id());
|
||||
$this->assertTrue($worked);
|
||||
}
|
||||
|
||||
public function test_list_cohort_role_assignments() {
|
||||
$this->setAdminUser();
|
||||
$params = (object) array(
|
||||
'userid' => $this->userassignto->id,
|
||||
'roleid' => $this->roleid,
|
||||
'cohortid' => $this->cohort->id
|
||||
);
|
||||
$result = api::create_cohort_role_assignment($params);
|
||||
|
||||
$list = api::list_cohort_role_assignments();
|
||||
$list[0]->is_valid();
|
||||
$this->assertEquals($list[0], $result);
|
||||
}
|
||||
|
||||
public function test_count_cohort_role_assignments() {
|
||||
$this->setAdminUser();
|
||||
$params = (object) array(
|
||||
'userid' => $this->userassignto->id,
|
||||
'roleid' => $this->roleid,
|
||||
'cohortid' => $this->cohort->id
|
||||
);
|
||||
$result = api::create_cohort_role_assignment($params);
|
||||
|
||||
$count = api::count_cohort_role_assignments();
|
||||
$this->assertEquals($count, 1);
|
||||
}
|
||||
|
||||
public function test_sync_all_cohort_roles() {
|
||||
$this->setAdminUser();
|
||||
$params = (object) array(
|
||||
'userid' => $this->userassignto->id,
|
||||
'roleid' => $this->roleid,
|
||||
'cohortid' => $this->cohort->id
|
||||
);
|
||||
$result = api::create_cohort_role_assignment($params);
|
||||
|
||||
// Verify roles are assigned when users enter the cohort.
|
||||
$sync = api::sync_all_cohort_roles();
|
||||
|
||||
$rolesadded = array(array(
|
||||
'useridassignedto' => $this->userassignto->id,
|
||||
'useridassignedover' => $this->userassignover->id,
|
||||
'roleid' => $this->roleid
|
||||
));
|
||||
$rolesremoved = array();
|
||||
$expected = array('rolesadded' => $rolesadded,
|
||||
'rolesremoved' => $rolesremoved);
|
||||
$this->assertEquals($sync, $expected);
|
||||
|
||||
// Verify roles are removed when users leave the cohort.
|
||||
cohort_remove_member($this->cohort->id, $this->userassignover->id);
|
||||
$sync = api::sync_all_cohort_roles();
|
||||
|
||||
$rolesadded = array();
|
||||
$rolesremoved = array(array(
|
||||
'useridassignedto' => $this->userassignto->id,
|
||||
'useridassignedover' => $this->userassignover->id,
|
||||
'roleid' => $this->roleid
|
||||
));
|
||||
$expected = array('rolesadded' => $rolesadded,
|
||||
'rolesremoved' => $rolesremoved);
|
||||
$this->assertEquals($sync, $expected);
|
||||
|
||||
// Verify roles assigned by any other component are not removed.
|
||||
$usercontext = context_user::instance($this->userassignover->id);
|
||||
role_assign($this->roleid, $this->userassignto->id, $usercontext->id);
|
||||
$sync = api::sync_all_cohort_roles();
|
||||
|
||||
$rolesadded = array();
|
||||
$rolesremoved = array();
|
||||
$expected = array('rolesadded' => $rolesadded,
|
||||
'rolesremoved' => $rolesremoved);
|
||||
$this->assertEquals($sync, $expected);
|
||||
|
||||
// Remove manual role assignment.
|
||||
role_unassign($this->roleid, $this->userassignto->id, $usercontext->id);
|
||||
// Add someone to the cohort again...
|
||||
cohort_add_member($this->cohort->id, $this->userassignover->id);
|
||||
$sync = api::sync_all_cohort_roles();
|
||||
$rolesadded = array(array(
|
||||
'useridassignedto' => $this->userassignto->id,
|
||||
'useridassignedover' => $this->userassignover->id,
|
||||
'roleid' => $this->roleid
|
||||
));
|
||||
$rolesremoved = array();
|
||||
$expected = array('rolesadded' => $rolesadded,
|
||||
'rolesremoved' => $rolesremoved);
|
||||
$this->assertEquals($sync, $expected);
|
||||
|
||||
// Verify no fatal errors when a cohort is deleted.
|
||||
cohort_delete_cohort($this->cohort);
|
||||
$sync = api::sync_all_cohort_roles();
|
||||
|
||||
$rolesadded = array();
|
||||
$rolesremoved = array(array(
|
||||
'useridassignedto' => $this->userassignto->id,
|
||||
'useridassignedover' => $this->userassignover->id,
|
||||
'roleid' => $this->roleid
|
||||
));
|
||||
$expected = array('rolesadded' => $rolesadded,
|
||||
'rolesremoved' => $rolesremoved);
|
||||
$this->assertEquals($sync, $expected);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Plugin version info
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2015 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
$plugin->version = 2015111018; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_cohortroles'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
$plugin->dependencies = array(
|
||||
'tool_lp' => ANY_VERSION
|
||||
);
|
||||
@@ -24,10 +24,29 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
function xmldb_tool_customlang_upgrade($oldversion) {
|
||||
global $CFG;
|
||||
global $CFG, $DB, $OUTPUT;
|
||||
|
||||
$dbman = $DB->get_manager();
|
||||
|
||||
|
||||
// Moodle v2.3.0 release upgrade line
|
||||
// Put any upgrade step following this
|
||||
|
||||
|
||||
// Moodle v2.4.0 release upgrade line
|
||||
// Put any upgrade step following this
|
||||
|
||||
|
||||
// Moodle v2.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
|
||||
// Moodle v2.6.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
@@ -35,8 +54,5 @@ function xmldb_tool_customlang_upgrade($oldversion) {
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v3.0.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111600;
|
||||
$plugin->requires = 2015111000;
|
||||
$plugin->version = 2015051100;
|
||||
$plugin->requires = 2015050500;
|
||||
$plugin->component = 'tool_customlang'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111600; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2015111000; // Requires this Moodle version.
|
||||
$plugin->version = 2015051100; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2015050500; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_dbtransfer'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
|
Before Width: | Height: | Size: 67 B After Width: | Height: | Size: 67 B |
|
Before Width: | Height: | Size: 67 B After Width: | Height: | Size: 67 B |
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111600;
|
||||
$plugin->requires = 2015111000;
|
||||
$plugin->version = 2015051100;
|
||||
$plugin->requires = 2015050500;
|
||||
$plugin->component = 'tool_filetypes';
|
||||
|
||||
@@ -113,7 +113,3 @@ $backend = new tool_generator_course_backend(
|
||||
FORMAT_HTML
|
||||
);
|
||||
$id = $backend->make();
|
||||
|
||||
if (empty($options['quiet'])) {
|
||||
echo PHP_EOL.'Generated course: '.course_get_url($id).PHP_EOL;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ function tool_generator_pluginfile($course, $cm, $context, $filearea, $args, $fo
|
||||
$file = $fs->get_file($context->id, 'tool_generator', $filearea, $args[0], '/', $args[1]);
|
||||
|
||||
// Send the file, always forcing download, we don't want options.
|
||||
\core\session\manager::write_close();
|
||||
session_get_instance()->write_close();
|
||||
send_stored_file($file, 0, 0, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111600;
|
||||
$plugin->requires = 2015111000;
|
||||
$plugin->version = 2015051100;
|
||||
$plugin->requires = 2015050500;
|
||||
$plugin->component = 'tool_generator';
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111600; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2015111000; // Requires this Moodle version
|
||||
$plugin->version = 2015051100; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2015050500; // Requires this Moodle version
|
||||
$plugin->component = 'tool_health'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
$plugin->maturity = MATURITY_ALPHA; // this version's maturity level
|
||||
|
||||
@@ -25,6 +25,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111600; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2015111000; // Requires this Moodle version
|
||||
$plugin->version = 2015051100; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2015050500; // Requires this Moodle version
|
||||
$plugin->component = 'tool_innodb'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Provides tool_installaddon_installer class.
|
||||
* Provides tool_installaddon_installer related classes
|
||||
*
|
||||
* @package tool_installaddon
|
||||
* @subpackage classes
|
||||
@@ -103,16 +103,69 @@ class tool_installaddon_installer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a unique writable storage for uploaded ZIP packages.
|
||||
* Saves the ZIP file from the {@link tool_installaddon_installfromzip_form} form
|
||||
*
|
||||
* We need the saved ZIP to survive across multiple requests so that it can
|
||||
* be used by the plugin manager after the installation is confirmed. In
|
||||
* other words, we cannot use make_request_directory() here.
|
||||
* The file is saved into the given temporary location for inspection and eventual
|
||||
* deployment. The form is expected to be submitted and validated.
|
||||
*
|
||||
* @return string full path to the directory
|
||||
* @param tool_installaddon_installfromzip_form $form
|
||||
* @param string $targetdir full path to the directory where the ZIP should be stored to
|
||||
* @return string filename of the saved file relative to the given target
|
||||
*/
|
||||
public function make_installfromzip_storage() {
|
||||
return make_unique_writable_directory(make_temp_directory('tool_installaddon'));
|
||||
public function save_installfromzip_file(tool_installaddon_installfromzip_form $form, $targetdir) {
|
||||
|
||||
$filename = clean_param($form->get_new_filename('zipfile'), PARAM_FILE);
|
||||
$form->save_file('zipfile', $targetdir.'/'.$filename);
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the saved file previously saved by {self::save_installfromzip_file()}
|
||||
*
|
||||
* The list of files found in the ZIP is returned via $zipcontentfiles parameter
|
||||
* by reference. The format of that list is array of (string)filerelpath => (bool|string)
|
||||
* where the array value is either true or a string describing the problematic file.
|
||||
*
|
||||
* @see zip_packer::extract_to_pathname()
|
||||
* @param string $zipfilepath full path to the saved ZIP file
|
||||
* @param string $targetdir full path to the directory to extract the ZIP file to
|
||||
* @param string $rootdir explicitly rename the root directory of the ZIP into this non-empty value
|
||||
* @param array list of extracted files as returned by {@link zip_packer::extract_to_pathname()}
|
||||
*/
|
||||
public function extract_installfromzip_file($zipfilepath, $targetdir, $rootdir = '') {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
|
||||
$fp = get_file_packer('application/zip');
|
||||
$files = $fp->extract_to_pathname($zipfilepath, $targetdir);
|
||||
|
||||
if (!$files) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if (!empty($rootdir)) {
|
||||
$files = $this->rename_extracted_rootdir($targetdir, $rootdir, $files);
|
||||
}
|
||||
|
||||
// Sometimes zip may not contain all parent directories, add them to make it consistent.
|
||||
foreach ($files as $path => $status) {
|
||||
if ($status !== true) {
|
||||
continue;
|
||||
}
|
||||
$parts = explode('/', trim($path, '/'));
|
||||
while (array_pop($parts)) {
|
||||
if (empty($parts)) {
|
||||
break;
|
||||
}
|
||||
$dir = implode('/', $parts).'/';
|
||||
if (!isset($files[$dir])) {
|
||||
$files[$dir] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,6 +186,57 @@ class tool_installaddon_installer {
|
||||
return $menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path of the root of the given plugin type
|
||||
*
|
||||
* Null is returned if the plugin type is not known. False is returned if the plugin type
|
||||
* root is expected but not found. Otherwise, string is returned.
|
||||
*
|
||||
* @param string $plugintype
|
||||
* @return string|bool|null
|
||||
*/
|
||||
public function get_plugintype_root($plugintype) {
|
||||
|
||||
$plugintypepath = null;
|
||||
foreach (core_component::get_plugin_types() as $type => $fullpath) {
|
||||
if ($type === $plugintype) {
|
||||
$plugintypepath = $fullpath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_null($plugintypepath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!is_dir($plugintypepath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $plugintypepath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is it possible to create a new plugin directory for the given plugin type?
|
||||
*
|
||||
* @throws coding_exception for invalid plugin types or non-existing plugin type locations
|
||||
* @param string $plugintype
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_plugintype_writable($plugintype) {
|
||||
|
||||
$plugintypepath = $this->get_plugintype_root($plugintype);
|
||||
|
||||
if (is_null($plugintypepath)) {
|
||||
throw new coding_exception('Unknown plugin type!');
|
||||
}
|
||||
|
||||
if ($plugintypepath === false) {
|
||||
throw new coding_exception('Plugin type location does not exist!');
|
||||
}
|
||||
|
||||
return is_writable($plugintypepath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook method to handle the remote request to install an add-on
|
||||
*
|
||||
@@ -141,12 +245,15 @@ class tool_installaddon_installer {
|
||||
* it.
|
||||
*
|
||||
* This hook is called early from admin/tool/installaddon/index.php page so that
|
||||
* it has opportunity to take over the UI and display the first confirmation screen.
|
||||
* it has opportunity to take over the UI.
|
||||
*
|
||||
* @param tool_installaddon_renderer $output
|
||||
* @param string|null $request
|
||||
* @param bool $confirmed
|
||||
*/
|
||||
public function handle_remote_request(tool_installaddon_renderer $output, $request) {
|
||||
public function handle_remote_request(tool_installaddon_renderer $output, $request, $confirmed = false) {
|
||||
global $CFG;
|
||||
require_once(dirname(__FILE__).'/pluginfo_client.php');
|
||||
|
||||
if (is_null($request)) {
|
||||
return;
|
||||
@@ -160,34 +267,196 @@ class tool_installaddon_installer {
|
||||
}
|
||||
|
||||
list($plugintype, $pluginname) = core_component::normalize_component($data->component);
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
|
||||
$plugintypepath = $pluginman->get_plugintype_root($plugintype);
|
||||
$plugintypepath = $this->get_plugintype_root($plugintype);
|
||||
|
||||
if (file_exists($plugintypepath.'/'.$pluginname)) {
|
||||
echo $output->remote_request_alreadyinstalled_page($data, $this->index_url());
|
||||
exit();
|
||||
}
|
||||
|
||||
if (!$pluginman->is_plugintype_writable($plugintype)) {
|
||||
if (!$this->is_plugintype_writable($plugintype)) {
|
||||
$continueurl = $this->index_url(array('installaddonrequest' => $request));
|
||||
echo $output->remote_request_permcheck_page($data, $plugintypepath, $continueurl, $this->index_url());
|
||||
exit();
|
||||
}
|
||||
|
||||
if (!$pluginman->is_remote_plugin_installable($data->component, $data->version, $reason)) {
|
||||
$data->reason = $reason;
|
||||
echo $output->remote_request_non_installable_page($data, $this->index_url());
|
||||
$continueurl = $this->index_url(array(
|
||||
'installaddonrequest' => $request,
|
||||
'confirm' => 1,
|
||||
'sesskey' => sesskey()));
|
||||
|
||||
if (!$confirmed) {
|
||||
echo $output->remote_request_confirm_page($data, $continueurl, $this->index_url());
|
||||
exit();
|
||||
}
|
||||
|
||||
$continueurl = $this->index_url(array(
|
||||
'installremote' => $data->component,
|
||||
'installremoteversion' => $data->version
|
||||
));
|
||||
// The admin has confirmed their intention to install the add-on.
|
||||
require_sesskey();
|
||||
|
||||
echo $output->remote_request_confirm_page($data, $continueurl, $this->index_url());
|
||||
exit();
|
||||
// Fetch the plugin info. The essential information is the URL to download the ZIP
|
||||
// and the MD5 hash of the ZIP, obtained via HTTPS.
|
||||
$client = tool_installaddon_pluginfo_client::instance();
|
||||
|
||||
try {
|
||||
$pluginfo = $client->get_pluginfo($data->component, $data->version);
|
||||
|
||||
} catch (tool_installaddon_pluginfo_exception $e) {
|
||||
if (debugging()) {
|
||||
throw $e;
|
||||
} else {
|
||||
echo $output->remote_request_pluginfo_exception($data, $e, $this->index_url());
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch the ZIP with the plugin version
|
||||
$jobid = md5(rand().uniqid('', true));
|
||||
$sourcedir = make_temp_directory('tool_installaddon/'.$jobid.'/source');
|
||||
$zipfilename = 'downloaded.zip';
|
||||
|
||||
try {
|
||||
$this->download_file($pluginfo->downloadurl, $sourcedir.'/'.$zipfilename);
|
||||
|
||||
} catch (tool_installaddon_installer_exception $e) {
|
||||
if (debugging()) {
|
||||
throw $e;
|
||||
} else {
|
||||
echo $output->installer_exception($e, $this->index_url());
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Check the MD5 checksum
|
||||
$md5expected = $pluginfo->downloadmd5;
|
||||
$md5actual = md5_file($sourcedir.'/'.$zipfilename);
|
||||
if ($md5expected !== $md5actual) {
|
||||
$e = new tool_installaddon_installer_exception('err_zip_md5', array('expected' => $md5expected, 'actual' => $md5actual));
|
||||
if (debugging()) {
|
||||
throw $e;
|
||||
} else {
|
||||
echo $output->installer_exception($e, $this->index_url());
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect to the validation page.
|
||||
$nexturl = new moodle_url('/admin/tool/installaddon/validate.php', array(
|
||||
'sesskey' => sesskey(),
|
||||
'jobid' => $jobid,
|
||||
'zip' => $zipfilename,
|
||||
'type' => $plugintype));
|
||||
redirect($nexturl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the given file into the given destination.
|
||||
*
|
||||
* This is basically a simplified version of {@link download_file_content()} from
|
||||
* Moodle itself, tuned for fetching files from moodle.org servers. Same code is used
|
||||
* in mdeploy.php for fetching available updates.
|
||||
*
|
||||
* @param string $source file url starting with http(s)://
|
||||
* @param string $target store the downloaded content to this file (full path)
|
||||
* @throws tool_installaddon_installer_exception
|
||||
*/
|
||||
public function download_file($source, $target) {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
|
||||
$targetfile = fopen($target, 'w');
|
||||
|
||||
if (!$targetfile) {
|
||||
throw new tool_installaddon_installer_exception('err_download_write_file', $target);
|
||||
}
|
||||
|
||||
$options = array(
|
||||
'file' => $targetfile,
|
||||
'timeout' => 300,
|
||||
'followlocation' => true,
|
||||
'maxredirs' => 3,
|
||||
'ssl_verifypeer' => true,
|
||||
'ssl_verifyhost' => 2,
|
||||
);
|
||||
|
||||
$curl = new curl(array('proxy' => true));
|
||||
|
||||
$result = $curl->download_one($source, null, $options);
|
||||
|
||||
$curlinfo = $curl->get_info();
|
||||
|
||||
fclose($targetfile);
|
||||
|
||||
if ($result !== true) {
|
||||
throw new tool_installaddon_installer_exception('err_curl_exec', array(
|
||||
'url' => $source, 'errorno' => $curl->get_errno(), 'error' => $result));
|
||||
|
||||
} else if (empty($curlinfo['http_code']) or $curlinfo['http_code'] != 200) {
|
||||
throw new tool_installaddon_installer_exception('err_curl_http_code', array(
|
||||
'url' => $source, 'http_code' => $curlinfo['http_code']));
|
||||
|
||||
} else if (isset($curlinfo['ssl_verify_result']) and $curlinfo['ssl_verify_result'] != 0) {
|
||||
throw new tool_installaddon_installer_exception('err_curl_ssl_verify', array(
|
||||
'url' => $source, 'ssl_verify_result' => $curlinfo['ssl_verify_result']));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the given source into a new location recursively
|
||||
*
|
||||
* This is cross-device safe implementation to be used instead of the native rename() function.
|
||||
* See https://bugs.php.net/bug.php?id=54097 for more details.
|
||||
*
|
||||
* @param string $source full path to the existing directory
|
||||
* @param string $target full path to the new location of the directory
|
||||
* @param int $dirpermissions
|
||||
* @param int $filepermissions
|
||||
*/
|
||||
public function move_directory($source, $target, $dirpermissions, $filepermissions) {
|
||||
|
||||
if (file_exists($target)) {
|
||||
throw new tool_installaddon_installer_exception('err_folder_already_exists', array('path' => $target));
|
||||
}
|
||||
|
||||
if (is_dir($source)) {
|
||||
$handle = opendir($source);
|
||||
} else {
|
||||
throw new tool_installaddon_installer_exception('err_no_such_folder', array('path' => $source));
|
||||
}
|
||||
|
||||
if (!file_exists($target)) {
|
||||
// Do not use make_writable_directory() here - it is intended for dataroot only.
|
||||
mkdir($target, true);
|
||||
@chmod($target, $dirpermissions);
|
||||
}
|
||||
|
||||
if (!is_writable($target)) {
|
||||
closedir($handle);
|
||||
throw new tool_installaddon_installer_exception('err_folder_not_writable', array('path' => $target));
|
||||
}
|
||||
|
||||
while ($filename = readdir($handle)) {
|
||||
$sourcepath = $source.'/'.$filename;
|
||||
$targetpath = $target.'/'.$filename;
|
||||
|
||||
if ($filename === '.' or $filename === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_dir($sourcepath)) {
|
||||
$this->move_directory($sourcepath, $targetpath, $dirpermissions, $filepermissions);
|
||||
|
||||
} else {
|
||||
rename($sourcepath, $targetpath);
|
||||
@chmod($targetpath, $filepermissions);
|
||||
}
|
||||
}
|
||||
|
||||
closedir($handle);
|
||||
|
||||
rmdir($source);
|
||||
|
||||
clearstatcache();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,11 +466,11 @@ class tool_installaddon_installer {
|
||||
* are supported.
|
||||
*
|
||||
* @param string $zipfilepath full path to the saved ZIP file
|
||||
* @param string $workdir full path to the directory we can use for extracting required bits from the archive
|
||||
* @return string|bool declared component name or false if unable to detect
|
||||
*/
|
||||
public function detect_plugin_component($zipfilepath) {
|
||||
public function detect_plugin_component($zipfilepath, $workdir) {
|
||||
|
||||
$workdir = make_request_directory();
|
||||
$versionphp = $this->extract_versionphp_file($zipfilepath, $workdir);
|
||||
|
||||
if (empty($versionphp)) {
|
||||
@@ -270,6 +539,58 @@ class tool_installaddon_installer {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the root directory of the extracted ZIP package.
|
||||
*
|
||||
* This method does not validate the presence of the single root directory
|
||||
* (the validator does it later). It just searches for the first directory
|
||||
* under the given location and renames it.
|
||||
*
|
||||
* The method will not rename the root if the requested location already
|
||||
* exists.
|
||||
*
|
||||
* @param string $dirname the location of the extracted ZIP package
|
||||
* @param string $rootdir the requested name of the root directory
|
||||
* @param array $files list of extracted files
|
||||
* @return array eventually amended list of extracted files
|
||||
*/
|
||||
protected function rename_extracted_rootdir($dirname, $rootdir, array $files) {
|
||||
|
||||
if (!is_dir($dirname)) {
|
||||
debugging('Unable to rename rootdir of non-existing content', DEBUG_DEVELOPER);
|
||||
return $files;
|
||||
}
|
||||
|
||||
if (file_exists($dirname.'/'.$rootdir)) {
|
||||
debugging('Unable to rename rootdir to already existing folder', DEBUG_DEVELOPER);
|
||||
return $files;
|
||||
}
|
||||
|
||||
$found = null; // The name of the first subdirectory under the $dirname.
|
||||
foreach (scandir($dirname) as $item) {
|
||||
if (substr($item, 0, 1) === '.') {
|
||||
continue;
|
||||
}
|
||||
if (is_dir($dirname.'/'.$item)) {
|
||||
$found = $item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($found)) {
|
||||
if (rename($dirname.'/'.$found, $dirname.'/'.$rootdir)) {
|
||||
$newfiles = array();
|
||||
foreach ($files as $filepath => $status) {
|
||||
$newpath = preg_replace('~^'.preg_quote($found.'/').'~', preg_quote($rootdir.'/'), $filepath);
|
||||
$newfiles[$newpath] = $status;
|
||||
}
|
||||
return $newfiles;
|
||||
}
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the request from the Moodle Plugins directory
|
||||
*
|
||||
@@ -407,3 +728,21 @@ class tool_installaddon_installer {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* General exception thrown by {@link tool_installaddon_installer} class
|
||||
*
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_installaddon_installer_exception extends moodle_exception {
|
||||
|
||||
/**
|
||||
* @param string $errorcode exception description identifier
|
||||
* @param mixed $debuginfo debugging data to display
|
||||
*/
|
||||
public function __construct($errorcode, $a=null, $debuginfo=null) {
|
||||
parent::__construct($errorcode, 'tool_installaddon', '', $a, print_r($debuginfo, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,21 +86,6 @@ class tool_installaddon_installfromzip_form extends moodleform {
|
||||
$mform->insertElementBefore($typedetectionfailed, 'permcheck');
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn that the selected plugin type does not match the detected one.
|
||||
*
|
||||
* @param string $detected detected plugin type
|
||||
*/
|
||||
public function selected_plugintype_mismatch($detected) {
|
||||
|
||||
$mform = $this->_form;
|
||||
$mform->addRule('plugintype', get_string('required'), 'required', null, 'client');
|
||||
$mform->setAdvanced('plugintype', false);
|
||||
$mform->setAdvanced('permcheck', false);
|
||||
$mform->insertElementBefore($mform->createElement('static', 'selectedplugintypemismatch', '',
|
||||
html_writer::span(get_string('typedetectionmismatch', 'tool_installaddon', $detected), 'error')), 'permcheck');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the form fields
|
||||
*
|
||||
@@ -110,12 +95,12 @@ class tool_installaddon_installfromzip_form extends moodleform {
|
||||
*/
|
||||
public function validation($data, $files) {
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
$installer = $this->_customdata['installer'];
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
if (!empty($data['plugintype'])) {
|
||||
if (!$pluginman->is_plugintype_writable($data['plugintype'])) {
|
||||
$path = $pluginman->get_plugintype_root($data['plugintype']);
|
||||
if (!$installer->is_plugintype_writable($data['plugintype'])) {
|
||||
$path = $installer->get_plugintype_root($data['plugintype']);
|
||||
$errors['plugintype'] = get_string('permcheckresultno', 'tool_installaddon', array('path' => $path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Provides tool_installaddon_pluginfo_client and related classes
|
||||
*
|
||||
* @package tool_installaddon
|
||||
* @subpackage classes
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Implements a client for https://download.moodle.org/api/x.y/pluginfo.php service
|
||||
*
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_installaddon_pluginfo_client {
|
||||
|
||||
/**
|
||||
* Factory method returning an instance of this class.
|
||||
*
|
||||
* @return tool_installaddon_pluginfo_client
|
||||
*/
|
||||
public static function instance() {
|
||||
return new static();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the information about the plugin
|
||||
*
|
||||
* @throws tool_installaddon_pluginfo_exception
|
||||
* @param string $component
|
||||
* @param string $version
|
||||
* @return stdClass the pluginfo structure
|
||||
*/
|
||||
public function get_pluginfo($component, $version) {
|
||||
|
||||
$response = $this->call_service($component, $version);
|
||||
$response = $this->decode_response($response);
|
||||
$this->validate_response($response);
|
||||
|
||||
return $response->pluginfo;
|
||||
}
|
||||
|
||||
// End of external API /////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @see self::instance()
|
||||
*/
|
||||
protected function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the pluginfo.php service and returns the raw response
|
||||
*
|
||||
* @param string $component
|
||||
* @param string $version
|
||||
* @return string
|
||||
*/
|
||||
protected function call_service($component, $version) {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
|
||||
$curl = new curl(array('proxy' => true));
|
||||
|
||||
$response = $curl->get(
|
||||
$this->service_request_url(),
|
||||
$this->service_request_params($component, $version),
|
||||
$this->service_request_options());
|
||||
|
||||
$curlerrno = $curl->get_errno();
|
||||
$curlinfo = $curl->get_info();
|
||||
|
||||
if (!empty($curlerrno)) {
|
||||
throw new tool_installaddon_pluginfo_exception('err_curl_exec', array(
|
||||
'url' => $curlinfo['url'], 'errno' => $curlerrno, 'error' => $curl->error));
|
||||
|
||||
} else if ($curlinfo['http_code'] != 200) {
|
||||
throw new tool_installaddon_pluginfo_exception('err_curl_http_code', array(
|
||||
'url' => $curlinfo['url'], 'http_code' => $curlinfo['http_code']));
|
||||
|
||||
} else if (isset($curlinfo['ssl_verify_result']) and $curlinfo['ssl_verify_result'] != 0) {
|
||||
throw new tool_installaddon_pluginfo_exception('err_curl_ssl_verify', array(
|
||||
'url' => $curlinfo['url'], 'ssl_verify_result' => $curlinfo['ssl_verify_result']));
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return URL to the pluginfo.php service
|
||||
*
|
||||
* @return moodle_url
|
||||
*/
|
||||
protected function service_request_url() {
|
||||
global $CFG;
|
||||
|
||||
if (!empty($CFG->config_php_settings['alternativepluginfoserviceurl'])) {
|
||||
$url = $CFG->config_php_settings['alternativepluginfoserviceurl'];
|
||||
} else {
|
||||
$url = 'https://download.moodle.org/api/1.2/pluginfo.php';
|
||||
}
|
||||
|
||||
return new moodle_url($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of pluginfo service parameters
|
||||
*
|
||||
* @param string $component
|
||||
* @param string $version
|
||||
* @return array
|
||||
*/
|
||||
protected function service_request_params($component, $version) {
|
||||
|
||||
$params = array();
|
||||
$params['format'] = 'json';
|
||||
$params['plugin'] = $component.'@'.$version;
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return cURL options for the service request
|
||||
*
|
||||
* @return array of (string)param => (string)value
|
||||
*/
|
||||
protected function service_request_options() {
|
||||
global $CFG;
|
||||
|
||||
$options = array(
|
||||
'CURLOPT_SSL_VERIFYHOST' => 2, // this is the default in {@link curl} class but just in case
|
||||
'CURLOPT_SSL_VERIFYPEER' => true,
|
||||
);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the raw service response
|
||||
*
|
||||
* @param string $raw
|
||||
* @return stdClass
|
||||
*/
|
||||
protected function decode_response($raw) {
|
||||
return json_decode($raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate decoded service response
|
||||
*
|
||||
* @param stdClass $response
|
||||
*/
|
||||
protected function validate_response($response) {
|
||||
|
||||
if (empty($response)) {
|
||||
throw new tool_installaddon_pluginfo_exception('err_response_empty');
|
||||
}
|
||||
|
||||
if (empty($response->status) or $response->status !== 'OK') {
|
||||
throw new tool_installaddon_pluginfo_exception('err_response_status', $response->status);
|
||||
}
|
||||
|
||||
if (empty($response->apiver) or $response->apiver !== '1.2') {
|
||||
throw new tool_installaddon_pluginfo_exception('err_response_api_version', $response->apiver);
|
||||
}
|
||||
|
||||
if (empty($response->pluginfo->component) or empty($response->pluginfo->downloadurl)
|
||||
or empty($response->pluginfo->downloadmd5)) {
|
||||
throw new tool_installaddon_pluginfo_exception('err_response_pluginfo');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* General exception thrown by {@link tool_installaddon_pluginfo_client} class
|
||||
*
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_installaddon_pluginfo_exception extends moodle_exception {
|
||||
|
||||
/**
|
||||
* @param string $errorcode exception description identifier
|
||||
* @param mixed $debuginfo debugging data to display
|
||||
*/
|
||||
public function __construct($errorcode, $a=null, $debuginfo=null) {
|
||||
parent::__construct($errorcode, 'tool_installaddon', '', $a, print_r($debuginfo, true));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,575 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Provides validation class to check the plugin ZIP contents
|
||||
*
|
||||
* Uses fragments of the local_plugins_archive_validator class copyrighted by
|
||||
* Marina Glancy that is part of the local_plugins plugin.
|
||||
*
|
||||
* @package tool_installaddon
|
||||
* @subpackage classes
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
if (!defined('T_ML_COMMENT')) {
|
||||
define('T_ML_COMMENT', T_COMMENT);
|
||||
} else {
|
||||
define('T_DOC_COMMENT', T_ML_COMMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the contents of extracted plugin ZIP file
|
||||
*
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_installaddon_validator {
|
||||
|
||||
/** Critical error message level, causes the validation fail. */
|
||||
const ERROR = 'error';
|
||||
|
||||
/** Warning message level, validation does not fail but the admin should be always informed. */
|
||||
const WARNING = 'warning';
|
||||
|
||||
/** Information message level that the admin should be aware of. */
|
||||
const INFO = 'info';
|
||||
|
||||
/** Debugging message level, should be displayed in debugging mode only. */
|
||||
const DEBUG = 'debug';
|
||||
|
||||
/** @var string full path to the extracted ZIP contents */
|
||||
protected $extractdir = null;
|
||||
|
||||
/** @var array as returned by {@link zip_packer::extract_to_pathname()} */
|
||||
protected $extractfiles = null;
|
||||
|
||||
/** @var bool overall result of validation */
|
||||
protected $result = null;
|
||||
|
||||
/** @var string the name of the plugin root directory */
|
||||
protected $rootdir = null;
|
||||
|
||||
/** @var array explicit list of expected/required characteristics of the ZIP */
|
||||
protected $assertions = null;
|
||||
|
||||
/** @var array of validation log messages */
|
||||
protected $messages = array();
|
||||
|
||||
/** @var array|null array of relevant data obtained from version.php */
|
||||
protected $versionphp = null;
|
||||
|
||||
/** @var string|null the name of found English language file without the .php extension */
|
||||
protected $langfilename = null;
|
||||
|
||||
/** @var moodle_url|null URL to continue with the installation of validated add-on */
|
||||
protected $continueurl = null;
|
||||
|
||||
/**
|
||||
* Factory method returning instance of the validator
|
||||
*
|
||||
* @param string $zipcontentpath full path to the extracted ZIP contents
|
||||
* @param array $zipcontentfiles (string)filerelpath => (bool|string)true or error
|
||||
* @return tool_installaddon_validator
|
||||
*/
|
||||
public static function instance($zipcontentpath, array $zipcontentfiles) {
|
||||
return new static($zipcontentpath, $zipcontentfiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expected plugin type, fail the validation otherwise
|
||||
*
|
||||
* @param string $required plugin type
|
||||
*/
|
||||
public function assert_plugin_type($required) {
|
||||
$this->assertions['plugintype'] = $required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expectation that the plugin can be installed into the given Moodle version
|
||||
*
|
||||
* @param string $required Moodle version we are about to install to
|
||||
*/
|
||||
public function assert_moodle_version($required) {
|
||||
$this->assertions['moodleversion'] = $required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the validation process against all explicit and implicit requirements
|
||||
*
|
||||
* Returns true if the validation passes (all explicit and implicit requirements
|
||||
* pass) and the plugin can be installed. Returns false if the validation fails
|
||||
* (some explicit or implicit requirement fails) and the plugin must not be
|
||||
* installed.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function execute() {
|
||||
|
||||
$this->result = (
|
||||
$this->validate_files_layout()
|
||||
and $this->validate_version_php()
|
||||
and $this->validate_language_pack()
|
||||
and $this->validate_target_location()
|
||||
);
|
||||
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns overall result of the validation.
|
||||
*
|
||||
* Null is returned if the validation has not been executed yet. Otherwise
|
||||
* this method returns true (the installation can continue) or false (it is not
|
||||
* safe to continue with the installation).
|
||||
*
|
||||
* @return bool|null
|
||||
*/
|
||||
public function get_result() {
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of validation log messages
|
||||
*
|
||||
* Each validation message is a plain object with properties level, msgcode
|
||||
* and addinfo.
|
||||
*
|
||||
* @return array of (int)index => (stdClass) validation message
|
||||
*/
|
||||
public function get_messages() {
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the information provided by the the plugin's version.php
|
||||
*
|
||||
* If version.php was not found in the plugin (which is tolerated for
|
||||
* themes only at the moment), null is returned. Otherwise the array
|
||||
* is returned. It may be empty if no information was parsed (which
|
||||
* should not happen).
|
||||
*
|
||||
* @return null|array
|
||||
*/
|
||||
public function get_versionphp_info() {
|
||||
return $this->versionphp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the English language file without the .php extension
|
||||
*
|
||||
* This can be used as a suggestion for fixing the plugin root directory in the
|
||||
* ZIP file during the upload. If no file was found, or multiple PHP files are
|
||||
* located in lang/en/ folder, then null is returned.
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_language_file_name() {
|
||||
return $this->langfilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rootdir of the extracted package (after eventual renaming)
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_rootdir() {
|
||||
return $this->rootdir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the URL to continue to after successful validation
|
||||
*
|
||||
* @param moodle_url $url
|
||||
*/
|
||||
public function set_continue_url(moodle_url $url) {
|
||||
$this->continueurl = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL to continue to after successful validation
|
||||
*
|
||||
* Null is returned if the URL has not been explicitly set by the caller.
|
||||
*
|
||||
* @return moodle_url|null
|
||||
*/
|
||||
public function get_continue_url() {
|
||||
return $this->continueurl;
|
||||
}
|
||||
|
||||
// End of external API /////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @param string $zipcontentpath full path to the extracted ZIP contents
|
||||
* @param array $zipcontentfiles (string)filerelpath => (bool|string)true or error
|
||||
*/
|
||||
protected function __construct($zipcontentpath, array $zipcontentfiles) {
|
||||
$this->extractdir = $zipcontentpath;
|
||||
$this->extractfiles = $zipcontentfiles;
|
||||
}
|
||||
|
||||
// Validation methods //////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @return bool false if files in the ZIP do not have required layout
|
||||
*/
|
||||
protected function validate_files_layout() {
|
||||
|
||||
if (!is_array($this->extractfiles) or count($this->extractfiles) < 4) {
|
||||
// We need the English language pack with the name of the plugin at least
|
||||
$this->add_message(self::ERROR, 'filesnumber');
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->extractfiles as $filerelname => $filestatus) {
|
||||
if ($filestatus !== true) {
|
||||
$this->add_message(self::ERROR, 'filestatus', array('file' => $filerelname, 'status' => $filestatus));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array_keys($this->extractfiles) as $filerelname) {
|
||||
if (!file_exists($this->extractdir.'/'.$filerelname)) {
|
||||
$this->add_message(self::ERROR, 'filenotexists', array('file' => $filerelname));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array_keys($this->extractfiles) as $filerelname) {
|
||||
$matches = array();
|
||||
if (!preg_match("#^([^/]+)/#", $filerelname, $matches) or (!is_null($this->rootdir) and $this->rootdir !== $matches[1])) {
|
||||
$this->add_message(self::ERROR, 'onedir');
|
||||
return false;
|
||||
}
|
||||
$this->rootdir = $matches[1];
|
||||
}
|
||||
|
||||
if ($this->rootdir !== clean_param($this->rootdir, PARAM_PLUGIN)) {
|
||||
$this->add_message(self::ERROR, 'rootdirinvalid', $this->rootdir);
|
||||
return false;
|
||||
} else {
|
||||
$this->add_message(self::INFO, 'rootdir', $this->rootdir);
|
||||
}
|
||||
|
||||
return is_dir($this->extractdir.'/'.$this->rootdir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool false if the version.php file does not declare required information
|
||||
*/
|
||||
protected function validate_version_php() {
|
||||
|
||||
if (!isset($this->assertions['plugintype'])) {
|
||||
throw new coding_exception('Required plugin type must be set before calling this');
|
||||
}
|
||||
|
||||
if (!isset($this->assertions['moodleversion'])) {
|
||||
throw new coding_exception('Required Moodle version must be set before calling this');
|
||||
}
|
||||
|
||||
$fullpath = $this->extractdir.'/'.$this->rootdir.'/version.php';
|
||||
|
||||
if (!file_exists($fullpath)) {
|
||||
// This is tolerated for themes only.
|
||||
if ($this->assertions['plugintype'] === 'theme') {
|
||||
$this->add_message(self::DEBUG, 'missingversionphp');
|
||||
return true;
|
||||
} else {
|
||||
$this->add_message(self::ERROR, 'missingversionphp');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->versionphp = array();
|
||||
$info = $this->parse_version_php($fullpath);
|
||||
|
||||
if ($this->assertions['plugintype'] === 'mod') {
|
||||
$type = 'module';
|
||||
} else {
|
||||
$type = 'plugin';
|
||||
}
|
||||
|
||||
if (!isset($info[$type.'->version'])) {
|
||||
if ($type === 'module' and isset($info['plugin->version'])) {
|
||||
// Expect the activity module using $plugin in version.php instead of $module.
|
||||
$type = 'plugin';
|
||||
$this->versionphp['version'] = $info[$type.'->version'];
|
||||
$this->add_message(self::INFO, 'pluginversion', $this->versionphp['version']);
|
||||
} else {
|
||||
$this->add_message(self::ERROR, 'missingversion');
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->versionphp['version'] = $info[$type.'->version'];
|
||||
$this->add_message(self::INFO, 'pluginversion', $this->versionphp['version']);
|
||||
}
|
||||
|
||||
if (isset($info[$type.'->requires'])) {
|
||||
$this->versionphp['requires'] = $info[$type.'->requires'];
|
||||
if ($this->versionphp['requires'] > $this->assertions['moodleversion']) {
|
||||
$this->add_message(self::ERROR, 'requiresmoodle', $this->versionphp['requires']);
|
||||
return false;
|
||||
}
|
||||
$this->add_message(self::INFO, 'requiresmoodle', $this->versionphp['requires']);
|
||||
}
|
||||
|
||||
if (isset($info[$type.'->component'])) {
|
||||
$this->versionphp['component'] = $info[$type.'->component'];
|
||||
list($reqtype, $reqname) = core_component::normalize_component($this->versionphp['component']);
|
||||
if ($reqtype !== $this->assertions['plugintype']) {
|
||||
$this->add_message(self::ERROR, 'componentmismatchtype', array(
|
||||
'expected' => $this->assertions['plugintype'],
|
||||
'found' => $reqtype));
|
||||
return false;
|
||||
}
|
||||
if ($reqname !== $this->rootdir) {
|
||||
$this->add_message(self::ERROR, 'componentmismatchname', $reqname);
|
||||
return false;
|
||||
}
|
||||
$this->add_message(self::INFO, 'componentmatch', $this->versionphp['component']);
|
||||
}
|
||||
|
||||
if (isset($info[$type.'->maturity'])) {
|
||||
$this->versionphp['maturity'] = $info[$type.'->maturity'];
|
||||
if ($this->versionphp['maturity'] === 'MATURITY_STABLE') {
|
||||
$this->add_message(self::INFO, 'maturity', $this->versionphp['maturity']);
|
||||
} else {
|
||||
$this->add_message(self::WARNING, 'maturity', $this->versionphp['maturity']);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($info[$type.'->release'])) {
|
||||
$this->versionphp['release'] = $info[$type.'->release'];
|
||||
$this->add_message(self::INFO, 'release', $this->versionphp['release']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool false if the English language pack is not provided correctly
|
||||
*/
|
||||
protected function validate_language_pack() {
|
||||
|
||||
if (!isset($this->assertions['plugintype'])) {
|
||||
throw new coding_exception('Required plugin type must be set before calling this');
|
||||
}
|
||||
|
||||
if (!isset($this->extractfiles[$this->rootdir.'/lang/en/'])
|
||||
or $this->extractfiles[$this->rootdir.'/lang/en/'] !== true
|
||||
or !is_dir($this->extractdir.'/'.$this->rootdir.'/lang/en')) {
|
||||
$this->add_message(self::ERROR, 'missinglangenfolder');
|
||||
return false;
|
||||
}
|
||||
|
||||
$langfiles = array();
|
||||
foreach (array_keys($this->extractfiles) as $extractfile) {
|
||||
$matches = array();
|
||||
if (preg_match('#^'.preg_quote($this->rootdir).'/lang/en/([^/]+).php?$#i', $extractfile, $matches)) {
|
||||
$langfiles[] = $matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($langfiles)) {
|
||||
$this->add_message(self::ERROR, 'missinglangenfile');
|
||||
return false;
|
||||
} else if (count($langfiles) > 1) {
|
||||
$this->add_message(self::WARNING, 'multiplelangenfiles');
|
||||
} else {
|
||||
$this->langfilename = $langfiles[0];
|
||||
$this->add_message(self::DEBUG, 'foundlangfile', $this->langfilename);
|
||||
}
|
||||
|
||||
if ($this->assertions['plugintype'] === 'mod') {
|
||||
$expected = $this->rootdir.'.php';
|
||||
} else {
|
||||
$expected = $this->assertions['plugintype'].'_'.$this->rootdir.'.php';
|
||||
}
|
||||
|
||||
if (!isset($this->extractfiles[$this->rootdir.'/lang/en/'.$expected])
|
||||
or $this->extractfiles[$this->rootdir.'/lang/en/'.$expected] !== true
|
||||
or !is_file($this->extractdir.'/'.$this->rootdir.'/lang/en/'.$expected)) {
|
||||
$this->add_message(self::ERROR, 'missingexpectedlangenfile', $expected);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool false of the given add-on can't be installed into its location
|
||||
*/
|
||||
public function validate_target_location() {
|
||||
|
||||
if (!isset($this->assertions['plugintype'])) {
|
||||
throw new coding_exception('Required plugin type must be set before calling this');
|
||||
}
|
||||
|
||||
$plugintypepath = $this->get_plugintype_location($this->assertions['plugintype']);
|
||||
|
||||
if (is_null($plugintypepath)) {
|
||||
$this->add_message(self::ERROR, 'unknowntype', $this->assertions['plugintype']);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_dir($plugintypepath)) {
|
||||
throw new coding_exception('Plugin type location does not exist!');
|
||||
}
|
||||
|
||||
$target = $plugintypepath.'/'.$this->rootdir;
|
||||
|
||||
if (file_exists($target)) {
|
||||
$this->add_message(self::ERROR, 'targetexists', $target);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_writable($plugintypepath)) {
|
||||
$this->add_message(self::INFO, 'pathwritable', $plugintypepath);
|
||||
} else {
|
||||
$this->add_message(self::ERROR, 'pathwritable', $plugintypepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper methods //////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Get as much information from existing version.php as possible
|
||||
*
|
||||
* @param string full path to the version.php file
|
||||
* @return array of found meta-info declarations
|
||||
*/
|
||||
protected function parse_version_php($fullpath) {
|
||||
|
||||
$content = $this->get_stripped_file_contents($fullpath);
|
||||
|
||||
preg_match_all('#\$((plugin|module)\->(version|maturity|release|requires))=()(\d+(\.\d+)?);#m', $content, $matches1);
|
||||
preg_match_all('#\$((plugin|module)\->(maturity))=()(MATURITY_\w+);#m', $content, $matches2);
|
||||
preg_match_all('#\$((plugin|module)\->(release))=([\'"])(.*?)\4;#m', $content, $matches3);
|
||||
preg_match_all('#\$((plugin|module)\->(component))=([\'"])(.+?_.+?)\4;#m', $content, $matches4);
|
||||
|
||||
if (count($matches1[1]) + count($matches2[1]) + count($matches3[1]) + count($matches4[1])) {
|
||||
$info = array_combine(
|
||||
array_merge($matches1[1], $matches2[1], $matches3[1], $matches4[1]),
|
||||
array_merge($matches1[5], $matches2[5], $matches3[5], $matches4[5])
|
||||
);
|
||||
|
||||
} else {
|
||||
$info = array();
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the given message to the messages log
|
||||
*
|
||||
* @param string $level e.g. self::ERROR
|
||||
* @param string $msgcode may form a string
|
||||
* @param string|array|object $a optional additional info suitable for {@link get_string()}
|
||||
*/
|
||||
protected function add_message($level, $msgcode, $a = null) {
|
||||
$msg = (object)array(
|
||||
'level' => $level,
|
||||
'msgcode' => $msgcode,
|
||||
'addinfo' => $a,
|
||||
);
|
||||
$this->messages[] = $msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns bare PHP code from the given file
|
||||
*
|
||||
* Returns contents without PHP opening and closing tags, text outside php code,
|
||||
* comments and extra whitespaces.
|
||||
*
|
||||
* @param string $fullpath full path to the file
|
||||
* @return string
|
||||
*/
|
||||
protected function get_stripped_file_contents($fullpath) {
|
||||
|
||||
$source = file_get_contents($fullpath);
|
||||
$tokens = token_get_all($source);
|
||||
$output = '';
|
||||
$doprocess = false;
|
||||
foreach ($tokens as $token) {
|
||||
if (is_string($token)) {
|
||||
// Simple one character token.
|
||||
$id = -1;
|
||||
$text = $token;
|
||||
} else {
|
||||
// Token array.
|
||||
list($id, $text) = $token;
|
||||
}
|
||||
switch ($id) {
|
||||
case T_WHITESPACE:
|
||||
case T_COMMENT:
|
||||
case T_ML_COMMENT:
|
||||
case T_DOC_COMMENT:
|
||||
// Ignore whitespaces, inline comments, multiline comments and docblocks.
|
||||
break;
|
||||
case T_OPEN_TAG:
|
||||
// Start processing.
|
||||
$doprocess = true;
|
||||
break;
|
||||
case T_CLOSE_TAG:
|
||||
// Stop processing.
|
||||
$doprocess = false;
|
||||
break;
|
||||
default:
|
||||
// Anything else is within PHP tags, return it as is.
|
||||
if ($doprocess) {
|
||||
$output .= $text;
|
||||
if ($text === 'function') {
|
||||
// Explicitly keep the whitespace that would be ignored.
|
||||
$output .= ' ';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the full path to the root directory of the given plugin type
|
||||
*
|
||||
* @param string $plugintype
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_plugintype_location($plugintype) {
|
||||
|
||||
$plugintypepath = null;
|
||||
|
||||
foreach (core_component::get_plugin_types() as $type => $fullpath) {
|
||||
if ($type === $plugintype) {
|
||||
$plugintypepath = $fullpath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $plugintypepath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle 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.
|
||||
//
|
||||
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Deploy the validated contents of the ZIP package to the $CFG->dirroot
|
||||
*
|
||||
* @package tool_installaddon
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require(dirname(__FILE__) . '/../../../config.php');
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/site:config', context_system::instance());
|
||||
|
||||
if (!empty($CFG->disableonclickaddoninstall)) {
|
||||
notice(get_string('featuredisabled', 'tool_installaddon'));
|
||||
}
|
||||
|
||||
require_sesskey();
|
||||
|
||||
$jobid = required_param('jobid', PARAM_ALPHANUM);
|
||||
$plugintype = required_param('type', PARAM_ALPHANUMEXT);
|
||||
$pluginname = required_param('name', PARAM_PLUGIN);
|
||||
|
||||
$zipcontentpath = $CFG->tempdir.'/tool_installaddon/'.$jobid.'/contents';
|
||||
|
||||
if (!is_dir($zipcontentpath)) {
|
||||
debugging('Invalid location of the extracted ZIP package: '.s($zipcontentpath), DEBUG_DEVELOPER);
|
||||
redirect(new moodle_url('/admin/tool/installaddon/index.php'),
|
||||
get_string('invaliddata', 'core_error'));
|
||||
}
|
||||
|
||||
if (!is_dir($zipcontentpath.'/'.$pluginname)) {
|
||||
debugging('Invalid location of the plugin root directory: '.$zipcontentpath.'/'.$pluginname, DEBUG_DEVELOPER);
|
||||
redirect(new moodle_url('/admin/tool/installaddon/index.php'),
|
||||
get_string('invaliddata', 'core_error'));
|
||||
}
|
||||
|
||||
$installer = tool_installaddon_installer::instance();
|
||||
|
||||
if (!$installer->is_plugintype_writable($plugintype)) {
|
||||
debugging('Plugin type location not writable', DEBUG_DEVELOPER);
|
||||
redirect(new moodle_url('/admin/tool/installaddon/index.php'),
|
||||
get_string('invaliddata', 'core_error'));
|
||||
}
|
||||
|
||||
$plugintypepath = $installer->get_plugintype_root($plugintype);
|
||||
|
||||
if (file_exists($plugintypepath.'/'.$pluginname)) {
|
||||
debugging('Target location already exists', DEBUG_DEVELOPER);
|
||||
redirect(new moodle_url('/admin/tool/installaddon/index.php'),
|
||||
get_string('invaliddata', 'core_error'));
|
||||
}
|
||||
|
||||
// Copy permissions form the plugin type directory.
|
||||
$dirpermissions = fileperms($plugintypepath);
|
||||
$filepermissions = ($dirpermissions & 0666); // Strip execute flags.
|
||||
|
||||
$installer->move_directory($zipcontentpath.'/'.$pluginname, $plugintypepath.'/'.$pluginname, $dirpermissions, $filepermissions);
|
||||
fulldelete($CFG->tempdir.'/tool_installaddon/'.$jobid);
|
||||
redirect(new moodle_url('/admin'));
|
||||
@@ -28,11 +28,10 @@ require_once($CFG->libdir.'/adminlib.php');
|
||||
|
||||
admin_externalpage_setup('tool_installaddon_index');
|
||||
|
||||
if (!empty($CFG->disableupdateautodeploy)) {
|
||||
if (!empty($CFG->disableonclickaddoninstall)) {
|
||||
notice(get_string('featuredisabled', 'tool_installaddon'));
|
||||
}
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
$installer = tool_installaddon_installer::instance();
|
||||
|
||||
$output = $PAGE->get_renderer('tool_installaddon');
|
||||
@@ -40,55 +39,8 @@ $output->set_installer_instance($installer);
|
||||
|
||||
// Handle the eventual request for installing from remote repository.
|
||||
$remoterequest = optional_param('installaddonrequest', null, PARAM_RAW);
|
||||
$installer->handle_remote_request($output, $remoterequest);
|
||||
|
||||
// Handle the confirmed installation request.
|
||||
$installremote = optional_param('installremote', null, PARAM_COMPONENT);
|
||||
$installremoteversion = optional_param('installremoteversion', null, PARAM_INT);
|
||||
$installremoteconfirm = optional_param('installremoteconfirm', false, PARAM_BOOL);
|
||||
|
||||
if ($installremote and $installremoteversion) {
|
||||
require_sesskey();
|
||||
require_once($CFG->libdir.'/upgradelib.php');
|
||||
|
||||
$PAGE->set_pagelayout('maintenance');
|
||||
$PAGE->set_popup_notification_allowed(false);
|
||||
|
||||
if ($pluginman->is_remote_plugin_installable($installremote, $installremoteversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installremote, $installremoteversion, true));
|
||||
upgrade_install_plugins($installable, $installremoteconfirm,
|
||||
get_string('installfromrepo', 'tool_installaddon'),
|
||||
new moodle_url($PAGE->url, array('installremote' => $installremote,
|
||||
'installremoteversion' => $installremoteversion, 'installremoteconfirm' => 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
// We should never get here.
|
||||
throw new moodle_exception('installing_non_installable_component', 'tool_installaddon');
|
||||
}
|
||||
|
||||
// Handle installation of a plugin from the ZIP file.
|
||||
$installzipcomponent = optional_param('installzipcomponent', null, PARAM_COMPONENT);
|
||||
$installzipstorage = optional_param('installzipstorage', null, PARAM_FILE);
|
||||
$installzipconfirm = optional_param('installzipconfirm', false, PARAM_BOOL);
|
||||
|
||||
if ($installzipcomponent and $installzipstorage) {
|
||||
require_sesskey();
|
||||
require_once($CFG->libdir.'/upgradelib.php');
|
||||
|
||||
$PAGE->set_pagelayout('maintenance');
|
||||
$PAGE->set_popup_notification_allowed(false);
|
||||
|
||||
$installable = array((object)array(
|
||||
'component' => $installzipcomponent,
|
||||
'zipfilepath' => make_temp_directory('tool_installaddon').'/'.$installzipstorage.'/plugin.zip',
|
||||
));
|
||||
upgrade_install_plugins($installable, $installzipconfirm, get_string('installfromzip', 'tool_installaddon'),
|
||||
new moodle_url($installer->index_url(), array('installzipcomponent' => $installzipcomponent,
|
||||
'installzipstorage' => $installzipstorage, 'installzipconfirm' => 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
$confirmed = optional_param('confirm', false, PARAM_BOOL);
|
||||
$installer->handle_remote_request($output, $remoterequest, $confirmed);
|
||||
|
||||
$form = $installer->get_installfromzip_form();
|
||||
|
||||
@@ -96,47 +48,35 @@ if ($form->is_cancelled()) {
|
||||
redirect($PAGE->url);
|
||||
|
||||
} else if ($data = $form->get_data()) {
|
||||
$storage = $installer->make_installfromzip_storage();
|
||||
$form->save_file('zipfile', $storage.'/plugin.zip');
|
||||
|
||||
$ziprootdir = $pluginman->get_plugin_zip_root_dir($storage.'/plugin.zip');
|
||||
if (empty($ziprootdir)) {
|
||||
echo $output->zip_not_valid_plugin_package_page($installer->index_url());
|
||||
die();
|
||||
}
|
||||
|
||||
$component = $installer->detect_plugin_component($storage.'/plugin.zip');
|
||||
if (!empty($component) and !empty($data->plugintype)) {
|
||||
// If the plugin type was explicitly set, make sure it matches the detected one.
|
||||
list($detectedtype, $detectedname) = core_component::normalize_component($component);
|
||||
if ($detectedtype !== $data->plugintype) {
|
||||
$form->selected_plugintype_mismatch($detectedtype);
|
||||
echo $output->index_page();
|
||||
die();
|
||||
}
|
||||
}
|
||||
if (empty($component)) {
|
||||
// This should not happen as all plugins are supposed to declare their
|
||||
// component. Still, let admins upload legacy packages if they want/need.
|
||||
if (empty($data->plugintype)) {
|
||||
// Save the ZIP file into a temporary location.
|
||||
$jobid = md5(rand().uniqid('', true));
|
||||
$sourcedir = make_temp_directory('tool_installaddon/'.$jobid.'/source');
|
||||
$zipfilename = $installer->save_installfromzip_file($form, $sourcedir);
|
||||
if (empty($data->plugintype)) {
|
||||
$versiondir = make_temp_directory('tool_installaddon/'.$jobid.'/version');
|
||||
$detected = $installer->detect_plugin_component($sourcedir.'/'.$zipfilename, $versiondir);
|
||||
if (empty($detected)) {
|
||||
$form->require_explicit_plugintype();
|
||||
echo $output->index_page();
|
||||
die();
|
||||
}
|
||||
if (!empty($data->rootdir)) {
|
||||
$usepluginname = $data->rootdir;
|
||||
} else {
|
||||
$usepluginname = $ziprootdir;
|
||||
list($detectedtype, $detectedname) = core_component::normalize_component($detected);
|
||||
if ($detectedtype and $detectedname and $detectedtype !== 'core') {
|
||||
$data->plugintype = $detectedtype;
|
||||
} else {
|
||||
$form->require_explicit_plugintype();
|
||||
}
|
||||
}
|
||||
$component = $data->plugintype.'_'.$usepluginname;
|
||||
}
|
||||
|
||||
redirect($installer->index_url(array(
|
||||
'installzipcomponent' => $component,
|
||||
'installzipstorage' => basename($storage),
|
||||
'sesskey' => sesskey(),
|
||||
)));
|
||||
// Redirect to the validation page.
|
||||
if (!empty($data->plugintype)) {
|
||||
$nexturl = new moodle_url('/admin/tool/installaddon/validate.php', array(
|
||||
'sesskey' => sesskey(),
|
||||
'jobid' => $jobid,
|
||||
'zip' => $zipfilename,
|
||||
'type' => $data->plugintype,
|
||||
'rootdir' => $data->rootdir));
|
||||
redirect($nexturl);
|
||||
}
|
||||
}
|
||||
|
||||
// Display the tool main page.
|
||||
// Output starts here.
|
||||
echo $output->index_page();
|
||||
|
||||
@@ -31,13 +31,13 @@ $string['acknowledgementtext'] = 'I understand that it is my responsibility to h
|
||||
$string['featuredisabled'] = 'The plugin installer is disabled on this site.';
|
||||
$string['installaddon'] = 'Install plugin!';
|
||||
$string['installaddons'] = 'Install plugins';
|
||||
$string['installexception'] = 'Oops... An error occurred while trying to install the plugin. Turn debugging mode on to see details of the error.';
|
||||
$string['installfromrepo'] = 'Install plugins from the Moodle plugins directory';
|
||||
$string['installfromrepo_help'] = 'You will be redirected to the Moodle plugins directory to search for and install a plugin. Note that your site full name, URL and Moodle version will be sent as well, to make the installation process easier for you.';
|
||||
$string['installfromzip'] = 'Install plugin from ZIP file';
|
||||
$string['installfromzip_help'] = 'An alternative to installing a plugin directly from the Moodle plugins directory is to upload a ZIP package of the plugin. The ZIP package should have the same structure as a package downloaded from the Moodle plugins directory.';
|
||||
$string['installfromzipfile'] = 'ZIP package';
|
||||
$string['installfromzipfile_help'] = 'The plugin ZIP package must contain just one directory, named to match the plugin name. The ZIP will be extracted into an appropriate location for the plugin type. If the package has been downloaded from the Moodle plugins directory then it will have this structure.';
|
||||
$string['installfromzipinvalid'] = 'The plugin ZIP package must contain just one directory, named to match the plugin name. The file provided is not a valid plugin ZIP package.';
|
||||
$string['installfromzipfile_help'] = 'The plugin ZIP package must contain just one directory, named to match the plugin. The ZIP will be extracted into an appropriate location for the plugin type. If the package has been downloaded from the Moodle plugins directory then it will have this structure.';
|
||||
$string['installfromziprootdir'] = 'Rename the root directory';
|
||||
$string['installfromziprootdir_help'] = 'Some ZIP packages, such as those generated by Github, may contain an incorrect root directory name. If so, the correct name may be entered here.';
|
||||
$string['installfromzipsubmit'] = 'Install plugin from the ZIP file';
|
||||
@@ -56,6 +56,50 @@ $string['remoterequestconfirm'] = 'There is a request to install plugin <strong>
|
||||
$string['remoterequestinvalid'] = 'There is a request to install a plugin from the Moodle plugins directory on this site. Unfortunately the request is not valid and so the plugin cannot be installed.';
|
||||
$string['remoterequestpermcheck'] = 'There is a request to install plugin {$a->name} ({$a->component}) version {$a->version} from the Moodle plugins directory on this site. However, the location <strong>{$a->typepath}</strong> is <strong>not writable</strong>. You need to give write access for the web server user to the location, then press the continue button to repeat the check.';
|
||||
$string['remoterequestpluginfoexception'] = 'Oops... An error occurred while trying to obtain information about the plugin {$a->name} ({$a->component}) version {$a->version}. The plugin cannot be installed. Turn debugging mode on to see details of the error.';
|
||||
$string['remoterequestnoninstallable'] = 'There is a request to install plugin {$a->name} ({$a->component}) version {$a->version} from the Moodle plugins directory on this site. However, the plugin installation pre-check failed (reason code: {$a->reason}).';
|
||||
$string['typedetectionfailed'] = 'Unable to detect the plugin type. Please choose the plugin type manually.';
|
||||
$string['typedetectionmismatch'] = 'The selected plugin type does not match the one declared by the plugin: {$a}';
|
||||
$string['validation'] = 'Plugin package validation';
|
||||
$string['validationmsg_componentmatch'] = 'Full component name';
|
||||
$string['validationmsg_componentmismatchname'] = 'Plugin name mismatch';
|
||||
$string['validationmsg_componentmismatchname_help'] = 'Some ZIP packages, such as those generated by Github, may contain an incorrect root directory name. You need to fix the name of the root directory to match the declared plugin name.';
|
||||
$string['validationmsg_componentmismatchname_info'] = 'The plugin declares its name is \'{$a}\' but that does not match the name of the root directory.';
|
||||
$string['validationmsg_componentmismatchtype'] = 'Plugin type mismatch';
|
||||
$string['validationmsg_componentmismatchtype_info'] = 'Expected type \'{$a->expected}\' but the plugin declares its type is \'{$a->found}\'.';
|
||||
$string['validationmsg_filenotexists'] = 'Extracted file not found';
|
||||
$string['validationmsg_filesnumber'] = 'Not enough files found in the package';
|
||||
$string['validationmsg_filestatus'] = 'Unable to extract all files';
|
||||
$string['validationmsg_filestatus_info'] = 'Attempting to extract file {$a->file} resulted in error \'{$a->status}\'.';
|
||||
$string['validationmsg_foundlangfile'] = 'Found language file';
|
||||
$string['validationmsg_maturity'] = 'Declared maturity level';
|
||||
$string['validationmsg_maturity_help'] = 'The plugin can declare its maturity level. If the maintainer considers the plugin stable, the declared maturity level will read MATURITY_STABLE. All other maturity levels (such as alpha or beta) should be considered unstable and a warning is raised.';
|
||||
$string['validationmsg_missingexpectedlangenfile'] = 'English language file name mismatch';
|
||||
$string['validationmsg_missingexpectedlangenfile_info'] = 'The given plugin type is missing the expected English language file {$a}.';
|
||||
$string['validationmsg_missinglangenfile'] = 'No English language file found';
|
||||
$string['validationmsg_missinglangenfolder'] = 'Missing English language folder';
|
||||
$string['validationmsg_missingversion'] = 'Plugin does not declare its version';
|
||||
$string['validationmsg_missingversionphp'] = 'File version.php not found';
|
||||
$string['validationmsg_multiplelangenfiles'] = 'Multiple English language files found';
|
||||
$string['validationmsg_onedir'] = 'Invalid structure of the ZIP package.';
|
||||
$string['validationmsg_onedir_help'] = 'The ZIP package must contain just one root directory that holds the plugin code. The name of that root directory must match the name of the plugin.';
|
||||
$string['validationmsg_pathwritable'] = 'Write access check';
|
||||
$string['validationmsg_pluginversion'] = 'Plugin version';
|
||||
$string['validationmsg_release'] = 'Plugin release';
|
||||
$string['validationmsg_requiresmoodle'] = 'Required Moodle version';
|
||||
$string['validationmsg_rootdir'] = 'Name of the plugin to be installed';
|
||||
$string['validationmsg_rootdir_help'] = 'The name of the root directory in the ZIP package forms the name of the plugin to be installed. If the name is not correct, you may wish to rename the root directory in the ZIP prior to installing the plugin.';
|
||||
$string['validationmsg_rootdirinvalid'] = 'Invalid plugin name';
|
||||
$string['validationmsg_rootdirinvalid_help'] = 'The name of the root directory in the ZIP package violates formal syntax requirements. Some ZIP packages, such as those generated by Github, may contain an incorrect root directory name. You need to fix the name of the root directory to match the plugin name.';
|
||||
$string['validationmsg_targetexists'] = 'Target location already exists';
|
||||
$string['validationmsg_targetexists_help'] = 'The directory that the plugin is to be installed to must not yet exist.';
|
||||
$string['validationmsg_unknowntype'] = 'Unknown plugin type';
|
||||
$string['validationmsglevel_debug'] = 'Debug';
|
||||
$string['validationmsglevel_error'] = 'Error';
|
||||
$string['validationmsglevel_info'] = 'OK';
|
||||
$string['validationmsglevel_warning'] = 'Warning';
|
||||
$string['validationresult0'] = 'Validation failed!';
|
||||
$string['validationresult0_help'] = 'A serious problem was detected and so it is not safe to install the plugin. See the validation log messages for details.';
|
||||
$string['validationresult1'] = 'Validation passed!';
|
||||
$string['validationresult2_help'] = 'No serious problems were detected. You can continue with the plugin installation. See the validation log messages for more details and eventual warnings.';
|
||||
$string['validationresult1_help'] = 'The plugin package has been validated and no serious problems were detected.';
|
||||
$string['validationresultinfo'] = 'Info';
|
||||
$string['validationresultmsg'] = 'Message';
|
||||
$string['validationresultstatus'] = 'Status';
|
||||
|
||||
@@ -36,7 +36,7 @@ if (!has_capability('moodle/site:config', context_system::instance())) {
|
||||
die();
|
||||
}
|
||||
|
||||
if (!empty($CFG->disableupdateautodeploy)) {
|
||||
if (!empty($CFG->disableonclickaddoninstall)) {
|
||||
header('HTTP/1.1 403 Forbidden');
|
||||
die();
|
||||
}
|
||||
@@ -52,9 +52,9 @@ if (is_null($plugintype)) {
|
||||
die();
|
||||
}
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
$installer = tool_installaddon_installer::instance();
|
||||
|
||||
$plugintypepath = $pluginman->get_plugintype_root($plugintype);
|
||||
$plugintypepath = $installer->get_plugintype_root($plugintype);
|
||||
|
||||
if (empty($plugintypepath)) {
|
||||
header('HTTP/1.1 400 Bad Request');
|
||||
@@ -63,7 +63,7 @@ if (empty($plugintypepath)) {
|
||||
|
||||
$response = array('path' => $plugintypepath);
|
||||
|
||||
if ($pluginman->is_plugintype_writable($plugintype)) {
|
||||
if ($installer->is_plugintype_writable($plugintype)) {
|
||||
$response['writable'] = 1;
|
||||
} else {
|
||||
$response['writable'] = 0;
|
||||
|
||||
|
Before Width: | Height: | Size: 207 B After Width: | Height: | Size: 266 B |
@@ -1,3 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
|
||||
]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M16 9v6c0 .5-.5 1-1 1H1c-.5 0-1-.5-1-1V9c0-.5.5-1 1-1h1c.5 0 1 .5 1 1v4h10V9c0-.5.5-1 1-1h1c.5 0 1 .5 1 1zm-3.6-3.9l-.7-.7c-.4-.4-1-.4-1.4 0l-.8.8V1c0-.5-.4-1-1-1h-1c-.5 0-1 .5-1 1v4.2l-.8-.8c-.4-.4-1-.4-1.4 0l-.7.7c-.4.4-.4 1 0 1.4l3.7 3.7c.2.2.5.3.7.3.3 0 .5-.1.7-.3l3.7-3.7c.4-.3.4-1 0-1.4z" fill="#999"/></svg>
|
||||
]>
|
||||
<svg version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
|
||||
x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" style="overflow:visible;enable-background:new 0 0 16 16;"
|
||||
xml:space="preserve" preserveAspectRatio="xMinYMid meet">
|
||||
<defs>
|
||||
</defs>
|
||||
<path style="fill:#999999;" d="M16,9v6c0,0.5-0.5,1-1,1h-1H2H1c-0.5,0-1-0.5-1-1V9c0-0.5,0.5-1,1-1h1c0.5,0,1,0.5,1,1v4h10V9
|
||||
c0-0.5,0.5-1,1-1h1C15.5,8,16,8.5,16,9z M12.4,5.1l-0.7-0.7c-0.4-0.4-1-0.4-1.4,0L9.5,5.2V1c0-0.5-0.4-1-1-1h-1c-0.5,0-1,0.5-1,1
|
||||
v4.2L5.7,4.4C5.3,4,4.7,4,4.3,4.4L3.6,5.1c-0.4,0.4-0.4,1,0,1.4l3.7,3.7c0.2,0.2,0.5,0.3,0.7,0.3c0.3,0,0.5-0.1,0.7-0.3l3.7-3.7
|
||||
C12.8,6.2,12.8,5.5,12.4,5.1z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 618 B After Width: | Height: | Size: 1.0 KiB |
@@ -37,6 +37,9 @@ class tool_installaddon_renderer extends plugin_renderer_base {
|
||||
/** @var tool_installaddon_installer */
|
||||
protected $installer = null;
|
||||
|
||||
/** @var tool_installaddon_validator */
|
||||
protected $validator = null;
|
||||
|
||||
/**
|
||||
* Sets the tool_installaddon_installer instance being used.
|
||||
*
|
||||
@@ -51,6 +54,20 @@ class tool_installaddon_renderer extends plugin_renderer_base {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tool_installaddon_validator instance being used.
|
||||
*
|
||||
* @throws coding_exception if the validator has been already set
|
||||
* @param tool_installaddon_validator $validator
|
||||
*/
|
||||
public function set_validator_instance(tool_installaddon_validator $validator) {
|
||||
if (is_null($this->validator)) {
|
||||
$this->validator = $validator;
|
||||
} else {
|
||||
throw new coding_exception('Attempting to reset the validator instance.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the index page layout
|
||||
*
|
||||
@@ -79,17 +96,24 @@ class tool_installaddon_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the user that the ZIP is not a valid plugin package file.
|
||||
* Defines the validation results page layout
|
||||
*
|
||||
* @param moodle_url $continueurl
|
||||
* @return string
|
||||
*/
|
||||
public function zip_not_valid_plugin_package_page(moodle_url $continueurl) {
|
||||
public function validation_page() {
|
||||
|
||||
if (is_null($this->installer)) {
|
||||
throw new coding_exception('Installer instance has not been set.');
|
||||
}
|
||||
|
||||
if (is_null($this->validator)) {
|
||||
throw new coding_exception('Validator instance has not been set.');
|
||||
}
|
||||
|
||||
$out = $this->output->header();
|
||||
$out .= $this->output->heading(get_string('installfromzip', 'tool_installaddon'));
|
||||
$out .= $this->output->box(get_string('installfromzipinvalid', 'tool_installaddon'), 'generalbox', 'notice');
|
||||
$out .= $this->output->continue_button($continueurl, 'get');
|
||||
$out .= $this->validation_page_heading();
|
||||
$out .= $this->validation_page_messages();
|
||||
$out .= $this->validation_page_continue();
|
||||
$out .= $this->output->footer();
|
||||
|
||||
return $out;
|
||||
@@ -170,17 +194,44 @@ class tool_installaddon_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the user that the requested remote plugin is not installable.
|
||||
* Inform the user about pluginfo service call exception
|
||||
*
|
||||
* @param stdClass $data decoded request data with ->reason property added
|
||||
* This implementation does not actually use the passed exception. Custom renderers might want to
|
||||
* display additional data obtained via {@link get_exception_info()}. Also note, this method is called
|
||||
* in non-debugging mode only. If debugging is allowed at the site, default exception handler is triggered.
|
||||
*
|
||||
* @param stdClass $data decoded request data
|
||||
* @param tool_installaddon_pluginfo_exception $e thrown exception
|
||||
* @param moodle_url $continueurl
|
||||
* @return string
|
||||
*/
|
||||
public function remote_request_non_installable_page(stdClass $data, moodle_url $continueurl) {
|
||||
public function remote_request_pluginfo_exception(stdClass $data, tool_installaddon_pluginfo_exception $e, moodle_url $continueurl) {
|
||||
|
||||
$out = $this->output->header();
|
||||
$out .= $this->output->heading(get_string('installfromrepo', 'tool_installaddon'));
|
||||
$out .= $this->output->box(get_string('remoterequestnoninstallable', 'tool_installaddon', $data), 'generalbox', 'notice');
|
||||
$out .= $this->output->box(get_string('remoterequestpluginfoexception', 'tool_installaddon', $data), 'generalbox', 'notice');
|
||||
$out .= $this->output->continue_button($continueurl, 'get');
|
||||
$out .= $this->output->footer();
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the user about the installer exception
|
||||
*
|
||||
* This implementation does not actually use the passed exception. Custom renderers might want to
|
||||
* display additional data obtained via {@link get_exception_info()}. Also note, this method is called
|
||||
* in non-debugging mode only. If debugging is allowed at the site, default exception handler is triggered.
|
||||
*
|
||||
* @param tool_installaddon_installer_exception $e thrown exception
|
||||
* @param moodle_url $continueurl
|
||||
* @return string
|
||||
*/
|
||||
public function installer_exception(tool_installaddon_installer_exception $e, moodle_url $continueurl) {
|
||||
|
||||
$out = $this->output->header();
|
||||
$out .= $this->output->heading(get_string('installfromrepo', 'tool_installaddon'));
|
||||
$out .= $this->output->box(get_string('installexception', 'tool_installaddon'), 'generalbox', 'notice');
|
||||
$out .= $this->output->continue_button($continueurl, 'get');
|
||||
$out .= $this->output->footer();
|
||||
|
||||
@@ -233,4 +284,123 @@ class tool_installaddon_renderer extends plugin_renderer_base {
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the page title and the overall validation verdict
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function validation_page_heading() {
|
||||
|
||||
$heading = $this->output->heading(get_string('validation', 'tool_installaddon'));
|
||||
|
||||
if ($this->validator->get_result()) {
|
||||
$status = $this->output->container(
|
||||
html_writer::span(get_string('validationresult1', 'tool_installaddon'), 'verdict').
|
||||
$this->output->help_icon('validationresult1', 'tool_installaddon'),
|
||||
array('validationresult', 'success')
|
||||
);
|
||||
} else {
|
||||
$status = $this->output->container(
|
||||
html_writer::span(get_string('validationresult0', 'tool_installaddon'), 'verdict').
|
||||
$this->output->help_icon('validationresult0', 'tool_installaddon'),
|
||||
array('validationresult', 'failure')
|
||||
);
|
||||
}
|
||||
|
||||
return $heading . $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders validation log messages.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function validation_page_messages() {
|
||||
|
||||
$validator = $this->validator; // We need this to be able to use their constants.
|
||||
$messages = $validator->get_messages();
|
||||
|
||||
if (empty($messages)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$table = new html_table();
|
||||
$table->attributes['class'] = 'validationmessages generaltable';
|
||||
$table->head = array(
|
||||
get_string('validationresultstatus', 'tool_installaddon'),
|
||||
get_string('validationresultmsg', 'tool_installaddon'),
|
||||
get_string('validationresultinfo', 'tool_installaddon')
|
||||
);
|
||||
$table->colclasses = array('msgstatus', 'msgtext', 'msginfo');
|
||||
|
||||
$stringman = get_string_manager();
|
||||
|
||||
foreach ($messages as $message) {
|
||||
|
||||
if ($message->level === $validator::DEBUG and !debugging()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$msgstatus = get_string('validationmsglevel_'.$message->level, 'tool_installaddon');
|
||||
$msgtext = $msgtext = s($message->msgcode);
|
||||
if (is_null($message->addinfo)) {
|
||||
$msginfo = '';
|
||||
} else {
|
||||
$msginfo = html_writer::tag('pre', s(print_r($message->addinfo, true)));
|
||||
}
|
||||
$msghelp = '';
|
||||
|
||||
// Replace the message code with the string if it is defined.
|
||||
if ($stringman->string_exists('validationmsg_'.$message->msgcode, 'tool_installaddon')) {
|
||||
$msgtext = get_string('validationmsg_'.$message->msgcode, 'tool_installaddon');
|
||||
// And check for the eventual help, too.
|
||||
if ($stringman->string_exists('validationmsg_'.$message->msgcode.'_help', 'tool_installaddon')) {
|
||||
$msghelp = $this->output->help_icon('validationmsg_'.$message->msgcode, 'tool_installaddon');
|
||||
}
|
||||
}
|
||||
|
||||
// Re-format the message info using a string if it is define.
|
||||
if (!is_null($message->addinfo) and $stringman->string_exists('validationmsg_'.$message->msgcode.'_info', 'tool_installaddon')) {
|
||||
$msginfo = get_string('validationmsg_'.$message->msgcode.'_info', 'tool_installaddon', $message->addinfo);
|
||||
}
|
||||
|
||||
$row = new html_table_row(array($msgstatus, $msgtext.$msghelp, $msginfo));
|
||||
$row->attributes['class'] = 'level-'.$message->level.' '.$message->msgcode;
|
||||
|
||||
$table->data[] = $row;
|
||||
}
|
||||
|
||||
return html_writer::table($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders widgets to continue from the validation results page
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function validation_page_continue() {
|
||||
|
||||
$output = '';
|
||||
$conturl = $this->validator->get_continue_url();
|
||||
|
||||
if (is_null($conturl)) {
|
||||
$contbutton = '';
|
||||
|
||||
} else {
|
||||
$contbutton = $this->output->single_button(
|
||||
$conturl, get_string('installaddon', 'tool_installaddon'), 'post',
|
||||
array('class' => 'singlebutton continuebutton'));
|
||||
$output .= $this->output->heading(get_string('acknowledgement', 'tool_installaddon'), 3);
|
||||
$output .= $this->output->container(get_string('acknowledgementtext', 'tool_installaddon'));
|
||||
}
|
||||
|
||||
$cancelbutton = $this->output->single_button(
|
||||
new moodle_url('/admin/tool/installaddon/index.php'), get_string('cancel', 'core'), 'get',
|
||||
array('class' => 'singlebutton cancelbutton'));
|
||||
|
||||
$output .= $this->output->container($cancelbutton.$contbutton, 'postvalidationbuttons');
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,15 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
if ($hassiteconfig and empty($CFG->disableupdateautodeploy)) {
|
||||
if ($hassiteconfig and empty($CFG->disableonclickaddoninstall)) {
|
||||
|
||||
$ADMIN->add('modules', new admin_externalpage('tool_installaddon_index',
|
||||
get_string('installaddons', 'tool_installaddon'),
|
||||
"$CFG->wwwroot/$CFG->admin/tool/installaddon/index.php"), 'modsettings');
|
||||
|
||||
$ADMIN->add('modules', new admin_externalpage('tool_installaddon_validate',
|
||||
get_string('validation', 'tool_installaddon'),
|
||||
"$CFG->wwwroot/$CFG->admin/tool/installaddon/validate.php",
|
||||
'moodle/site:config',
|
||||
true), 'modsettings');
|
||||
}
|
||||
|
||||
@@ -11,3 +11,58 @@
|
||||
#page-admin-tool-installaddon-index #installfromrepobox .singlebutton input[type=submit] {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
#page-admin-tool-installaddon-validate .validationresult {
|
||||
margin: 2em auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#page-admin-tool-installaddon-validate .validationresult .verdict {
|
||||
margin: 0em 0.5em;
|
||||
padding: 0.5em;
|
||||
border: 2px solid;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#page-admin-tool-installaddon-validate .validationresult.success .verdict {
|
||||
background-color: #e7f1c3;
|
||||
border-color: #aaeeaa;
|
||||
}
|
||||
|
||||
#page-admin-tool-installaddon-validate .validationresult.failure .verdict {
|
||||
background-color: #ffd3d9;
|
||||
border-color: #eeaaaa;
|
||||
}
|
||||
|
||||
#page-admin-tool-installaddon-validate .validationmessages {
|
||||
margin: 0px auto;
|
||||
}
|
||||
|
||||
#page-admin-tool-installaddon-validate .validationmessages .level-error .msgstatus {
|
||||
background-color: #ffd3d9;
|
||||
}
|
||||
|
||||
#page-admin-tool-installaddon-validate .validationmessages .level-warning .msgstatus {
|
||||
background-color: #f3f2aa;
|
||||
}
|
||||
|
||||
#page-admin-tool-installaddon-validate .validationmessages .level-info .msgstatus {
|
||||
background-color: #e7f1c3;
|
||||
}
|
||||
|
||||
#page-admin-tool-installaddon-validate .validationmessages .level-debug .msgstatus {
|
||||
background-color: #d2ebff;
|
||||
}
|
||||
|
||||
#page-admin-tool-installaddon-validate .postvalidationbuttons {
|
||||
text-align: center;
|
||||
margin: 1em auto;
|
||||
}
|
||||
|
||||
#page-admin-tool-installaddon-validate .postvalidationbuttons .singlebutton {
|
||||
display: inline-block;
|
||||
margin: 1em 1em;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
|
||||
$plugin->component = 'repository_mahara';
|
||||
$plugin->version = 2014010100;
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
echo 'One, my little hobbit, never installs malicisous add-ons';
|
||||
@@ -1,2 +1,3 @@
|
||||
<?php
|
||||
|
||||
$string['pluginname'] = 'Foo bar!';
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
|
||||
$plugin->version = 2013031900;
|
||||
$plugin->component = 'local_greenbar';
|
||||