Compare commits
636 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b7d2ed3004 | |||
| 14c9b43005 | |||
| 60aeac00a5 | |||
| 60cab07485 | |||
| 9a386ebbbe | |||
| a259be942b | |||
| 20b5f693a5 | |||
| a5ff17de21 | |||
| 73fede1b48 | |||
| 9fd1342692 | |||
| 343ed5b929 | |||
| f9cc721dfd | |||
| 7647c6eabe | |||
| fa57105063 | |||
| 62f72f8ba9 | |||
| fbfe01cbb2 | |||
| ae6b18a934 | |||
| ac470f3721 | |||
| e33ff30b44 | |||
| e6adcaf3c6 | |||
| 7fc9fe32a7 | |||
| b2f0dc9d10 | |||
| 7d4a741216 | |||
| cba5940f2e | |||
| 9cd25ae9a7 | |||
| edbfa27218 | |||
| 2edfa4a1f9 | |||
| 289bc7f9e3 | |||
| 5536fee5a5 | |||
| ab006d43e4 | |||
| 037e05e8b2 | |||
| 58ffa95a15 | |||
| e7444eb62e | |||
| d8c9588662 | |||
| 28987b3c9d | |||
| 0fce1a1a6b | |||
| a64e1f3684 | |||
| 2da85b88b9 | |||
| dec22fcdf6 | |||
| 37cec3335b | |||
| 956f281bd6 | |||
| 3e280b70e6 | |||
| cd232214c2 | |||
| 4b58bce051 | |||
| d3b8ae917a | |||
| ca36c9eecb | |||
| 0c9d44b050 | |||
| 7a43fe824c | |||
| 5b203b3edb | |||
| 9f3a76cb07 | |||
| 758e773b97 | |||
| 301bb0954a | |||
| ca8260190a | |||
| 3652b59313 | |||
| 7d98676efc | |||
| d1dd5d0c20 | |||
| c378540995 | |||
| b11c542a13 | |||
| a7b1ab1629 | |||
| 5fa0153289 | |||
| 9067f9b0d4 | |||
| 3dcdac00a1 | |||
| db50734bd6 | |||
| 9314b26c12 | |||
| b94dcc42c0 | |||
| 7964285dd5 | |||
| 18bc684a56 | |||
| 492d18b67d | |||
| 78e0a308da | |||
| 3b96fd4c4d | |||
| 3daf01d5c4 | |||
| e56cf432d7 | |||
| 121ab83eb5 | |||
| 258bd55190 | |||
| 4df0cdb191 | |||
| 38458cc314 | |||
| b1c395be36 | |||
| 875b5d8adf | |||
| f563d2066d | |||
| d7caed18da | |||
| 067ff3bdb6 | |||
| 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 | |||
| 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,
|
||||
|
||||
-175
@@ -1,175 +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
|
||||
|
||||
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
|
||||
|
||||
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 MOODLE_30_STABLE;
|
||||
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
|
||||
+66
-169
@@ -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
|
||||
@@ -28,178 +27,97 @@ module.exports = function(grunt) {
|
||||
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) {
|
||||
if (code) {
|
||||
grunt.fail.fatal('Shifter failed with code: ' + code);
|
||||
} else {
|
||||
grunt.log.ok('Shifter build complete.');
|
||||
filedone();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Actually run shifter.
|
||||
if (!options.recursive) {
|
||||
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();
|
||||
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('No YUI modules to build.');
|
||||
filedone();
|
||||
grunt.log.ok('Shifter build complete.');
|
||||
done();
|
||||
}
|
||||
}
|
||||
}, done);
|
||||
});
|
||||
};
|
||||
|
||||
tasks.startup = function() {
|
||||
@@ -207,45 +125,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);
|
||||
|
||||
@@ -64,8 +64,6 @@ echo "<form id=\"authmenu\" method=\"post\" action=\"auth_config.php\">\n";
|
||||
echo "<div>\n";
|
||||
echo "<input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />\n";
|
||||
echo "<input type=\"hidden\" name=\"auth\" value=\"".$auth."\" />\n";
|
||||
// HACK to prevent browsers from automatically inserting the user's password into the wrong fields.
|
||||
echo prevent_form_autofill_password();
|
||||
|
||||
// auth plugin description
|
||||
echo $OUTPUT->box_start();
|
||||
@@ -148,6 +146,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 (preg_match('/^(.+?)(\d+)$/', $fieldname, $matches)) {
|
||||
$fieldname = get_string($matches[1]) . ' ' . $matches[2];
|
||||
} elseif ($fieldname == 'url') {
|
||||
$fieldname = get_string('webpage');
|
||||
} else {
|
||||
|
||||
+1
-2
@@ -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>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-50
@@ -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
|
||||
|
||||
@@ -1420,282 +1420,4 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="3.0" requires="2.2">
|
||||
<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="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>
|
||||
<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>
|
||||
|
||||
+52
-294
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -846,6 +603,7 @@ $cachewarnings = cache_helper::warnings();
|
||||
|
||||
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,
|
||||
|
||||
+53
-62
@@ -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);
|
||||
|
||||
@@ -39,8 +39,6 @@ require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/forms.php');
|
||||
require_once($CFG->dirroot . '/webservice/lib.php');
|
||||
require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
|
||||
|
||||
require_sesskey();
|
||||
|
||||
$huburl = required_param('huburl', PARAM_URL);
|
||||
$huburl = rtrim($huburl, "/");
|
||||
|
||||
|
||||
+280
-644
File diff suppressed because it is too large
Load Diff
+2
-6
@@ -50,8 +50,7 @@ $table->set_attribute('class', 'admintable generaltable');
|
||||
$table->setup();
|
||||
|
||||
$plugins = array();
|
||||
$availableplugins = core_component::get_plugin_list('report');
|
||||
foreach ($availableplugins as $plugin => $plugindir) {
|
||||
foreach (core_component::get_plugin_list('report') as $plugin => $plugindir) {
|
||||
if (get_string_manager()->string_exists('pluginname', 'report_' . $plugin)) {
|
||||
$strpluginname = get_string('pluginname', 'report_' . $plugin);
|
||||
} else {
|
||||
@@ -81,10 +80,7 @@ foreach ($plugins as $plugin => $name) {
|
||||
$uninstall = html_writer::link($uninstallurl, $struninstall);
|
||||
}
|
||||
|
||||
$stores = array();
|
||||
if (isset($availableplugins[$plugin])) {
|
||||
$stores = $logmanager->get_supported_logstores('report_' . $plugin);
|
||||
}
|
||||
$stores = $logmanager->get_supported_logstores('report_' . $plugin);
|
||||
if ($stores === false) {
|
||||
$supportedstores = get_string('logstorenotrequired', 'admin');
|
||||
} else if (!empty($stores)) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -163,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
+1
-5
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,8 +64,7 @@ preferences,moodle|/user/preferences.php|preferences',
|
||||
array('0' => new lang_string('default', 'calendar'),
|
||||
'%I:%M %p' => new lang_string('timeformat_12', 'calendar'),
|
||||
'%H:%M' => new lang_string('timeformat_24', 'calendar'))));
|
||||
$temp->add(new admin_setting_configselect('calendar_startwday', new lang_string('configstartwday', 'admin'),
|
||||
new lang_string('helpstartofweek', 'admin'), get_string('firstdayofweek', 'langconfig'),
|
||||
$temp->add(new admin_setting_configselect('calendar_startwday', new lang_string('configstartwday', 'admin'), new lang_string('helpstartofweek', 'admin'), 0,
|
||||
array(
|
||||
0 => new lang_string('sunday', 'calendar'),
|
||||
1 => new lang_string('monday', 'calendar'),
|
||||
|
||||
@@ -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'),
|
||||
@@ -277,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
|
||||
|
||||
@@ -35,8 +35,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$params = new stdClass();
|
||||
$params->bytes = $defaultuserquota;
|
||||
$params->displaysize = display_size($defaultuserquota);
|
||||
$temp->add(new admin_setting_configtext('userquota', new lang_string('userquota', 'admin'),
|
||||
new lang_string('configuserquota', 'admin', $params), $defaultuserquota, PARAM_INT, 30));
|
||||
$temp->add(new admin_setting_configtext('userquota', new lang_string('userquota', 'admin'), new lang_string('configuserquota', 'admin', $params), $defaultuserquota));
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('allowobjectembed', new lang_string('allowobjectembed', 'admin'), new lang_string('configallowobjectembed', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('enabletrusttext', new lang_string('enabletrusttext', 'admin'), new lang_string('configenabletrusttext', 'admin'), 0));
|
||||
|
||||
@@ -18,10 +18,11 @@ $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;
|
||||
@@ -214,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(
|
||||
|
||||
@@ -11,7 +11,7 @@ $hassiteconfig = has_capability('moodle/site:config', $systemcontext);
|
||||
$ADMIN->add('root', new admin_externalpage('adminnotifications', new lang_string('notifications'), "$CFG->wwwroot/$CFG->admin/index.php"));
|
||||
|
||||
$ADMIN->add('root', new admin_externalpage('registrationmoodleorg', new lang_string('registration', 'admin'),
|
||||
"$CFG->wwwroot/$CFG->admin/registration/register.php?huburl=" . HUB_MOODLEORGHUBURL . "&hubname=Moodle.org&sesskey=" . sesskey()));
|
||||
"$CFG->wwwroot/$CFG->admin/registration/register.php?huburl=" . HUB_MOODLEORGHUBURL . "&hubname=Moodle.org"));
|
||||
$ADMIN->add('root', new admin_externalpage('registrationhub', new lang_string('registerwith', 'hub'),
|
||||
"$CFG->wwwroot/$CFG->admin/registration/register.php", 'moodle/site:config', true));
|
||||
$ADMIN->add('root', new admin_externalpage('registrationhubs', new lang_string('hubs', 'admin'),
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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 |
|
||||
|
||||
+1
-23
@@ -1,4 +1,4 @@
|
||||
@tool @tool_uploaduser @_file_upload
|
||||
@core @core_admin @_file_upload
|
||||
Feature: Upload users
|
||||
In order to add users to the system
|
||||
As an admin
|
||||
@@ -39,25 +39,3 @@ Feature: Upload users
|
||||
And I follow "Groups"
|
||||
And I set the field "groups" to "Section 1 (1)"
|
||||
And the "members" select box should contain "Tom Jones"
|
||||
|
||||
@javascript
|
||||
Scenario: Upload users with custom profile fields
|
||||
# Create user profile field.
|
||||
Given I log in as "admin"
|
||||
And I navigate to "User profile fields" node in "Site administration > Users > Accounts"
|
||||
And I set the field "datatype" to "Text area"
|
||||
And I set the following fields to these values:
|
||||
| Short name | superfield |
|
||||
| Name | Super field |
|
||||
And I click on "Save changes" "button"
|
||||
# Upload users.
|
||||
When I navigate to "Upload users" node in "Site administration > Users > Accounts"
|
||||
And I upload "lib/tests/fixtures/upload_users_profile.csv" file to "File" filemanager
|
||||
And I press "Upload users"
|
||||
And I press "Upload users"
|
||||
# Check that users were created and the superfield is filled.
|
||||
And I navigate to "Browse list of users" node in "Site administration > Users > Accounts"
|
||||
And I follow "Tom Jones"
|
||||
And I should see "Super field"
|
||||
And I should see "The big guy"
|
||||
And I log out
|
||||
@@ -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);
|
||||
|
||||
@@ -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,8 +120,8 @@ $tags = '';
|
||||
|
||||
if ($options['profile']) {
|
||||
$profile = $options['profile'];
|
||||
if (!isset($CFG->behat_config[$profile]) && !isset($CFG->behat_profiles[$profile])) {
|
||||
echo "Invalid profile passed: " . $profile . PHP_EOL;
|
||||
if (!isset($CFG->behat_config[$profile])) {
|
||||
echo "Invalid profile passed: " . $profile;
|
||||
exit(1);
|
||||
}
|
||||
$extraopts[] = '--profile="' . $profile . '"';
|
||||
@@ -226,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;
|
||||
}
|
||||
@@ -268,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,7 +173,6 @@ if ($options['install']) {
|
||||
|
||||
// This is only displayed once for parallel install.
|
||||
if (empty($options['run'])) {
|
||||
|
||||
$runtestscommand = behat_command::get_behat_command(true, !empty($options['run']));
|
||||
|
||||
$runtestscommand .= ' --config ' . behat_config_manager::get_behat_cli_config_filepath();
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
@tool @tool_behat
|
||||
Feature: Page contents assertions
|
||||
In order to write good tests
|
||||
As a tests writer
|
||||
I need to check the page contents
|
||||
|
||||
@javascript
|
||||
Scenario: Basic contents assertions
|
||||
Given I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I press "Create group"
|
||||
And I set the following fields to these values:
|
||||
| Group name | I'm the name |
|
||||
| Group description | I'm the description |
|
||||
And I press "Save changes"
|
||||
When I follow "Overview"
|
||||
And I wait until the page is ready
|
||||
And I wait "2" seconds
|
||||
And I hover "#region-main .generaltable td span" "css_element"
|
||||
Then I should see "I'm the description"
|
||||
And "Grouping" "select" in the "region-main" "region" should be visible
|
||||
And "Group" "select" should be visible
|
||||
And "Activity report" "link" in the "Administration" "block" should not be visible
|
||||
And "Event monitoring rules" "link" should not be visible
|
||||
And I should see "Filter groups by"
|
||||
And I should not see "Filter groupssss by"
|
||||
And I should see "Group members" in the "#region-main table th.c1" "css_element"
|
||||
And I should not see "Group membersssss" in the "#region-main table th.c1" "css_element"
|
||||
And I follow "Groups"
|
||||
And the "#groupeditform #showcreateorphangroupform" "css_element" should be enabled
|
||||
And the "#groupeditform #showeditgroupsettingsform" "css_element" should be disabled
|
||||
|
||||
@javascript
|
||||
Scenario: Locators inside specific DOM nodes using CSS selectors
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
When I dock "Administration" block
|
||||
Then I should not see "Question bank" in the ".block-region" "css_element"
|
||||
And I click on "//div[@id='dock']/descendant::h2[normalize-space(.)='Administration']" "xpath_element"
|
||||
|
||||
@javascript
|
||||
Scenario: Locators inside specific DOM nodes using XPath
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And I log in as "admin"
|
||||
When I dock "Administration" block
|
||||
Then I should not see "Turn editing on" in the ".block-region" "css_element"
|
||||
@@ -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".
|
||||
@@ -117,17 +137,6 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I press "Save my choice"
|
||||
And the field "one" matches value "1"
|
||||
And the field "two" matches value ""
|
||||
# Check if field xpath set/match works.
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Edit settings" node in "Course administration"
|
||||
And I set the field with xpath "//input[@id='id_idnumber']" to "Course id number"
|
||||
And the field with xpath "//input[@name='idnumber']" matches value "Course id number"
|
||||
And the field with xpath "//input[@name='idnumber']" does not match value ""
|
||||
And I press "Save and display"
|
||||
And I navigate to "Edit settings" node in "Course administration"
|
||||
And the field "Course ID number" matches value "Course id number"
|
||||
|
||||
|
||||
Scenario: with JS disabled all form fields getters and setters works as expected
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -54,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).
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111600;
|
||||
$plugin->requires = 2015111000;
|
||||
$plugin->version = 2015051100;
|
||||
$plugin->requires = 2015050500;
|
||||
$plugin->component = 'tool_filetypes';
|
||||
|
||||
@@ -253,8 +253,7 @@ class tool_generator_course_backend extends tool_generator_backend {
|
||||
$courserecord = array(
|
||||
'shortname' => $this->shortname,
|
||||
'fullname' => $this->fullname,
|
||||
'numsections' => self::$paramsections[$this->size],
|
||||
'startdate' => usergetmidnight(time())
|
||||
'numsections' => self::$paramsections[$this->size]
|
||||
);
|
||||
if (strlen($this->summary) > 0) {
|
||||
$courserecord['summary'] = $this->summary;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
+128
-190
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@@ -20,34 +21,27 @@
|
||||
* Uses fragments of the local_plugins_archive_validator class copyrighted by
|
||||
* Marina Glancy that is part of the local_plugins plugin.
|
||||
*
|
||||
* @package core_plugin
|
||||
* @subpackage validation
|
||||
* @copyright 2013, 2015 David Mudrak <david@moodle.com>
|
||||
* @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
|
||||
*/
|
||||
|
||||
namespace core\update;
|
||||
|
||||
use core_component;
|
||||
use core_plugin_manager;
|
||||
use help_icon;
|
||||
use coding_exception;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
if (!defined('T_ML_COMMENT')) {
|
||||
define('T_ML_COMMENT', T_COMMENT);
|
||||
define('T_ML_COMMENT', T_COMMENT);
|
||||
} else {
|
||||
define('T_DOC_COMMENT', T_ML_COMMENT);
|
||||
define('T_DOC_COMMENT', T_ML_COMMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the contents of extracted plugin ZIP file
|
||||
*
|
||||
* @copyright 2013, 2015 David Mudrak <david@moodle.com>
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class validator {
|
||||
class tool_installaddon_validator {
|
||||
|
||||
/** Critical error message level, causes the validation fail. */
|
||||
const ERROR = 'error';
|
||||
@@ -85,12 +79,15 @@ class validator {
|
||||
/** @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 \core\update\validator
|
||||
* @return tool_installaddon_validator
|
||||
*/
|
||||
public static function instance($zipcontentpath, array $zipcontentfiles) {
|
||||
return new static($zipcontentpath, $zipcontentfiles);
|
||||
@@ -161,76 +158,13 @@ class validator {
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns human readable localised name of the given log level.
|
||||
*
|
||||
* @param string $level e.g. self::INFO
|
||||
* @return string
|
||||
*/
|
||||
public function message_level_name($level) {
|
||||
return get_string('validationmsglevel_'.$level, 'core_plugin');
|
||||
}
|
||||
|
||||
/**
|
||||
* If defined, returns human readable validation code.
|
||||
*
|
||||
* Otherwise, it simply returns the code itself as a fallback.
|
||||
*
|
||||
* @param string $msgcode
|
||||
* @return string
|
||||
*/
|
||||
public function message_code_name($msgcode) {
|
||||
|
||||
$stringman = get_string_manager();
|
||||
|
||||
if ($stringman->string_exists('validationmsg_'.$msgcode, 'core_plugin')) {
|
||||
return get_string('validationmsg_'.$msgcode, 'core_plugin');
|
||||
}
|
||||
|
||||
return $msgcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns help icon for the message code if defined.
|
||||
*
|
||||
* @param string $msgcode
|
||||
* @return \help_icon|false
|
||||
*/
|
||||
public function message_help_icon($msgcode) {
|
||||
|
||||
$stringman = get_string_manager();
|
||||
|
||||
if ($stringman->string_exists('validationmsg_'.$msgcode.'_help', 'core_plugin')) {
|
||||
return new help_icon('validationmsg_'.$msgcode, 'core_plugin');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Localizes the message additional info if it exists.
|
||||
*
|
||||
* @param string $msgcode
|
||||
* @param array|string|null $addinfo value for the $a placeholder in the string
|
||||
* @return string
|
||||
*/
|
||||
public function message_code_info($msgcode, $addinfo) {
|
||||
|
||||
$stringman = get_string_manager();
|
||||
|
||||
if ($addinfo !== null and $stringman->string_exists('validationmsg_'.$msgcode.'_info', 'core_plugin')) {
|
||||
return get_string('validationmsg_'.$msgcode.'_info', 'core_plugin', $addinfo);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the information provided by the the plugin's version.php
|
||||
*
|
||||
* If version.php was not found in the plugin, null is returned. Otherwise
|
||||
* the array is returned. It may be empty if no information was parsed
|
||||
* (which should not happen).
|
||||
* 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
|
||||
*/
|
||||
@@ -260,11 +194,29 @@ class validator {
|
||||
return $this->rootdir;
|
||||
}
|
||||
|
||||
// End of external API.
|
||||
/**
|
||||
* Sets the URL to continue to after successful validation
|
||||
*
|
||||
* @param moodle_url $url
|
||||
*/
|
||||
public function set_continue_url(moodle_url $url) {
|
||||
$this->continueurl = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* No public constructor, use {@link self::instance()} instead.
|
||||
* 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
|
||||
*/
|
||||
@@ -273,17 +225,15 @@ class validator {
|
||||
$this->extractfiles = $zipcontentfiles;
|
||||
}
|
||||
|
||||
// Validation methods.
|
||||
// Validation methods //////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Returns false if files in the ZIP do not have required layout.
|
||||
*
|
||||
* @return bool
|
||||
* @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.
|
||||
// We need the English language pack with the name of the plugin at least
|
||||
$this->add_message(self::ERROR, 'filesnumber');
|
||||
return false;
|
||||
}
|
||||
@@ -304,8 +254,7 @@ class validator {
|
||||
|
||||
foreach (array_keys($this->extractfiles) as $filerelname) {
|
||||
$matches = array();
|
||||
if (!preg_match("#^([^/]+)/#", $filerelname, $matches)
|
||||
or (!is_null($this->rootdir) and $this->rootdir !== $matches[1])) {
|
||||
if (!preg_match("#^([^/]+)/#", $filerelname, $matches) or (!is_null($this->rootdir) and $this->rootdir !== $matches[1])) {
|
||||
$this->add_message(self::ERROR, 'onedir');
|
||||
return false;
|
||||
}
|
||||
@@ -323,9 +272,7 @@ class validator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if the version.php file does not declare required information.
|
||||
*
|
||||
* @return bool
|
||||
* @return bool false if the version.php file does not declare required information
|
||||
*/
|
||||
protected function validate_version_php() {
|
||||
|
||||
@@ -353,21 +300,29 @@ class validator {
|
||||
$this->versionphp = array();
|
||||
$info = $this->parse_version_php($fullpath);
|
||||
|
||||
if (isset($info['module->version'])) {
|
||||
$this->add_message(self::ERROR, 'versionphpsyntax', '$module');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($info['plugin->version'])) {
|
||||
$this->versionphp['version'] = $info['plugin->version'];
|
||||
$this->add_message(self::INFO, 'pluginversion', $this->versionphp['version']);
|
||||
if ($this->assertions['plugintype'] === 'mod') {
|
||||
$type = 'module';
|
||||
} else {
|
||||
$this->add_message(self::ERROR, 'missingversion');
|
||||
return false;
|
||||
$type = 'plugin';
|
||||
}
|
||||
|
||||
if (isset($info['plugin->requires'])) {
|
||||
$this->versionphp['requires'] = $info['plugin->requires'];
|
||||
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;
|
||||
@@ -375,27 +330,24 @@ class validator {
|
||||
$this->add_message(self::INFO, 'requiresmoodle', $this->versionphp['requires']);
|
||||
}
|
||||
|
||||
if (!isset($info['plugin->component'])) {
|
||||
$this->add_message(self::ERROR, 'missingcomponent');
|
||||
return false;
|
||||
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']);
|
||||
}
|
||||
|
||||
$this->versionphp['component'] = $info['plugin->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['plugin->maturity'])) {
|
||||
$this->versionphp['maturity'] = $info['plugin->maturity'];
|
||||
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 {
|
||||
@@ -403,8 +355,8 @@ class validator {
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($info['plugin->release'])) {
|
||||
$this->versionphp['release'] = $info['plugin->release'];
|
||||
if (isset($info[$type.'->release'])) {
|
||||
$this->versionphp['release'] = $info[$type.'->release'];
|
||||
$this->add_message(self::INFO, 'release', $this->versionphp['release']);
|
||||
}
|
||||
|
||||
@@ -412,9 +364,7 @@ class validator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if the English language pack is not provided correctly.
|
||||
*
|
||||
* @return bool
|
||||
* @return bool false if the English language pack is not provided correctly
|
||||
*/
|
||||
protected function validate_language_pack() {
|
||||
|
||||
@@ -463,10 +413,9 @@ class validator {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns false of the given add-on can't be installed into its location.
|
||||
*
|
||||
* @return bool
|
||||
* @return bool false of the given add-on can't be installed into its location
|
||||
*/
|
||||
public function validate_target_location() {
|
||||
|
||||
@@ -485,42 +434,29 @@ class validator {
|
||||
throw new coding_exception('Plugin type location does not exist!');
|
||||
}
|
||||
|
||||
// Always check that the plugintype root is writable.
|
||||
if (!is_writable($plugintypepath)) {
|
||||
$this->add_message(self::ERROR, 'pathwritable', $plugintypepath);
|
||||
$target = $plugintypepath.'/'.$this->rootdir;
|
||||
|
||||
if (file_exists($target)) {
|
||||
$this->add_message(self::ERROR, 'targetexists', $target);
|
||||
return false;
|
||||
} else {
|
||||
$this->add_message(self::INFO, 'pathwritable', $plugintypepath);
|
||||
}
|
||||
|
||||
// The target location itself may or may not exist. Even if installing an
|
||||
// available update, the code could have been removed by accident (and
|
||||
// be reported as missing) etc. So we just make sure that the code
|
||||
// can be replaced if it already exists.
|
||||
$target = $plugintypepath.'/'.$this->rootdir;
|
||||
if (file_exists($target)) {
|
||||
if (!is_dir($target)) {
|
||||
$this->add_message(self::ERROR, 'targetnotdir', $target);
|
||||
return false;
|
||||
}
|
||||
$this->add_message(self::WARNING, 'targetexists', $target);
|
||||
if ($this->get_plugin_manager()->is_directory_removable($target)) {
|
||||
$this->add_message(self::INFO, 'pathwritable', $target);
|
||||
} else {
|
||||
$this->add_message(self::ERROR, 'pathwritable', $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.
|
||||
// Helper methods //////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Get as much information from existing version.php as possible
|
||||
*
|
||||
* @param string $fullpath full path to the version.php file
|
||||
* @param string full path to the version.php file
|
||||
* @return array of found meta-info declarations
|
||||
*/
|
||||
protected function parse_version_php($fullpath) {
|
||||
@@ -586,52 +522,54 @@ class validator {
|
||||
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 .= ' ';
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the full path to the root directory of the given plugin type.
|
||||
* 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) {
|
||||
return $this->get_plugin_manager()->get_plugintype_root($plugintype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns plugin manager to use.
|
||||
*
|
||||
* @return core_plugin_manager
|
||||
*/
|
||||
protected function get_plugin_manager() {
|
||||
return core_plugin_manager::instance();
|
||||
$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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
<?php
|
||||
|
||||
$plugin->component = 'repository_mahara';
|
||||
$plugin->version = 2014010100;
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
<?php
|
||||
|
||||
echo 'One, my little hobbit, never installs malicisous add-ons';
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
<?php
|
||||
|
||||
$string['pluginname'] = 'Foo bar!';
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
<?php
|
||||
|
||||
$plugin->version = 2013031900;
|
||||
$plugin->component = 'local_greenbar';
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
<?php
|
||||
|
||||
$plugin->component = 'local_one';
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
<?php
|
||||
|
||||
$string['pluginnname'] = 'Root directory mismatch';
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
<?php
|
||||
|
||||
$module->version = 2014122455;
|
||||
$plugin->version = 2014122455;
|
||||
$plugin->component = 'mod_bah';
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
<?php
|
||||
|
||||
echo 'Do not use hardcoded strings, provide the language pack';
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
<?php
|
||||
|
||||
$string['pluginversion'] = 'Activity module with no version.php';
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
<?php
|
||||
|
||||
$string['pluginversion'] = 'A theme with no version.php';
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
// index.php
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
<?php
|
||||
|
||||
$string['pluginname'] = 'Foo!';
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
<?php // $Id$
|
||||
|
||||
// I don't miss CVS, do you?
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
<?php
|
||||
|
||||
echo 'One, my little hobbit, never installs malicisous add-ons';
|
||||
+1
@@ -1,2 +1,3 @@
|
||||
<?php
|
||||
|
||||
$string['pluginname'] = 'Foo bar!';
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
$module->version = 10; // Ignored, this should use $plugin
|
||||
$plugin->version = 2013031900;
|
||||
$plugin->component = 'local_foobar';
|
||||
$plugin->requires = 2013031200;
|
||||
$module->release = 'We are not an activity module!';
|
||||
$plugin->maturity = MATURITY_ALPHA;
|
||||
//$plugin->release = 'And this is commented';
|
||||
@@ -1,60 +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/>.
|
||||
|
||||
/**
|
||||
* Provides {@link testable_tool_installaddon_installer} class.
|
||||
*
|
||||
* @package tool_installaddon
|
||||
* @subpackage fixtures
|
||||
* @category test
|
||||
* @copyright 2013, 2015 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Testable subclass of the tested class
|
||||
*
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class testable_tool_installaddon_installer extends tool_installaddon_installer {
|
||||
|
||||
public function get_site_fullname() {
|
||||
return strip_tags('<h1 onmouseover="alert(\'Hello Moodle.org!\');">Nasty site</h1>');
|
||||
}
|
||||
|
||||
public function get_site_url() {
|
||||
return 'file:///etc/passwd';
|
||||
}
|
||||
|
||||
public function get_site_major_version() {
|
||||
return "2.5'; DROP TABLE mdl_user; --";
|
||||
}
|
||||
|
||||
public function testable_decode_remote_request($request) {
|
||||
return parent::decode_remote_request($request);
|
||||
}
|
||||
|
||||
protected function should_send_site_info() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function testable_detect_plugin_component_from_versionphp($code) {
|
||||
return parent::detect_plugin_component_from_versionphp($code);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -23,9 +23,9 @@ Replace $plugin with $module for activity modules, as in
|
||||
$plugin->component
|
||||
= 'old_foobar';//$plugin->component='commented';
|
||||
|
||||
$plugin->component =
|
||||
$plugin->component =
|
||||
'block_foobar';
|
||||
|
||||
|
||||
$plugin->version = 2013010100;
|
||||
////////$plugin->version = 0;
|
||||
/* for activity
|
||||
@@ -26,8 +26,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once(__DIR__.'/fixtures/testable_installer.php');
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link tool_installaddon_installer} class
|
||||
@@ -51,6 +49,29 @@ class tool_installaddon_installer_testcase extends advanced_testcase {
|
||||
$this->assertSame("2.5'; DROP TABLE mdl_user; --", $site['majorversion']);
|
||||
}
|
||||
|
||||
public function test_extract_installfromzip_file() {
|
||||
$jobid = md5(rand().uniqid('test_', true));
|
||||
$sourcedir = make_temp_directory('tool_installaddon/'.$jobid.'/source');
|
||||
$contentsdir = make_temp_directory('tool_installaddon/'.$jobid.'/contents');
|
||||
copy(dirname(__FILE__).'/fixtures/zips/invalidroot.zip', $sourcedir.'/testinvalidroot.zip');
|
||||
|
||||
$installer = tool_installaddon_installer::instance();
|
||||
$files = $installer->extract_installfromzip_file($sourcedir.'/testinvalidroot.zip', $contentsdir, 'fixed_root');
|
||||
$this->assertInternalType('array', $files);
|
||||
$this->assertCount(4, $files);
|
||||
$this->assertSame(true, $files['fixed_root/']);
|
||||
$this->assertSame(true, $files['fixed_root/lang/']);
|
||||
$this->assertSame(true, $files['fixed_root/lang/en/']);
|
||||
$this->assertSame(true, $files['fixed_root/lang/en/fixed_root.php']);
|
||||
foreach ($files as $file => $status) {
|
||||
if (substr($file, -1) === '/') {
|
||||
$this->assertTrue(is_dir($contentsdir.'/'.$file));
|
||||
} else {
|
||||
$this->assertTrue(is_file($contentsdir.'/'.$file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function test_decode_remote_request() {
|
||||
$installer = testable_tool_installaddon_installer::instance();
|
||||
|
||||
@@ -109,51 +130,66 @@ class tool_installaddon_installer_testcase extends advanced_testcase {
|
||||
$this->assertSame(false, $installer->testable_decode_remote_request($request));
|
||||
}
|
||||
|
||||
public function test_detect_plugin_component() {
|
||||
global $CFG;
|
||||
public function test_move_directory() {
|
||||
$jobid = md5(rand().uniqid('test_', true));
|
||||
$jobroot = make_temp_directory('tool_installaddon/'.$jobid);
|
||||
$contentsdir = make_temp_directory('tool_installaddon/'.$jobid.'/contents/sub/folder');
|
||||
file_put_contents($contentsdir.'/readme.txt', 'Hello world!');
|
||||
|
||||
$installer = tool_installaddon_installer::instance();
|
||||
$installer->move_directory($jobroot.'/contents', $jobroot.'/moved', 0777, 0666);
|
||||
|
||||
$zipfile = $CFG->libdir.'/tests/fixtures/update_validator/zips/bar.zip';
|
||||
$this->assertEquals('foo_bar', $installer->detect_plugin_component($zipfile));
|
||||
$this->assertFalse(is_dir($jobroot.'/contents'));
|
||||
$this->assertTrue(is_file($jobroot.'/moved/sub/folder/readme.txt'));
|
||||
$this->assertSame('Hello world!', file_get_contents($jobroot.'/moved/sub/folder/readme.txt'));
|
||||
}
|
||||
|
||||
$zipfile = $CFG->libdir.'/tests/fixtures/update_validator/zips/invalidroot.zip';
|
||||
$this->assertFalse($installer->detect_plugin_component($zipfile));
|
||||
public function test_detect_plugin_component() {
|
||||
$jobid = md5(rand().uniqid('test_', true));
|
||||
$workdir = make_temp_directory('tool_installaddon/'.$jobid.'/version');
|
||||
$zipfile = __DIR__.'/fixtures/zips/bar.zip';
|
||||
$installer = tool_installaddon_installer::instance();
|
||||
$this->assertEquals('foo_bar', $installer->detect_plugin_component($zipfile, $workdir));
|
||||
}
|
||||
|
||||
public function test_detect_plugin_component_from_versionphp() {
|
||||
global $CFG;
|
||||
|
||||
$installer = testable_tool_installaddon_installer::instance();
|
||||
$fixtures = $CFG->libdir.'/tests/fixtures/update_validator/';
|
||||
|
||||
$this->assertEquals('bar_bar_conan', $installer->testable_detect_plugin_component_from_versionphp('
|
||||
$this->assertEquals('bar_bar_conan', $installer->detect_plugin_component_from_versionphp('
|
||||
$plugin->version = 2014121300;
|
||||
$plugin->component= "bar_bar_conan" ; // Go Arnie go!'));
|
||||
|
||||
$versionphp = file_get_contents($fixtures.'/github/moodle-repository_mahara-master/version.php');
|
||||
$this->assertEquals('repository_mahara', $installer->testable_detect_plugin_component_from_versionphp($versionphp));
|
||||
|
||||
$versionphp = file_get_contents($fixtures.'/nocomponent/baz/version.php');
|
||||
$this->assertFalse($installer->testable_detect_plugin_component_from_versionphp($versionphp));
|
||||
}
|
||||
|
||||
public function test_make_installfromzip_storage() {
|
||||
$installer = testable_tool_installaddon_installer::instance();
|
||||
|
||||
// Check we get writable directory.
|
||||
$storage1 = $installer->make_installfromzip_storage();
|
||||
$this->assertTrue(is_dir($storage1));
|
||||
$this->assertTrue(is_writable($storage1));
|
||||
file_put_contents($storage1.'/hello.txt', 'Find me if you can!');
|
||||
|
||||
// Check we get unique directory on each call.
|
||||
$storage2 = $installer->make_installfromzip_storage();
|
||||
$this->assertTrue(is_dir($storage2));
|
||||
$this->assertTrue(is_writable($storage2));
|
||||
$this->assertFalse(file_exists($storage2.'/hello.txt'));
|
||||
|
||||
// Check both are in the same parent directory.
|
||||
$this->assertEquals(dirname($storage1), dirname($storage2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Testable subclass of the tested class
|
||||
*
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class testable_tool_installaddon_installer extends tool_installaddon_installer {
|
||||
|
||||
public function get_site_fullname() {
|
||||
return strip_tags('<h1 onmouseover="alert(\'Hello Moodle.org!\');">Nasty site</h1>');
|
||||
}
|
||||
|
||||
public function get_site_url() {
|
||||
return 'file:///etc/passwd';
|
||||
}
|
||||
|
||||
public function get_site_major_version() {
|
||||
return "2.5'; DROP TABLE mdl_user; --";
|
||||
}
|
||||
|
||||
public function testable_decode_remote_request($request) {
|
||||
return parent::decode_remote_request($request);
|
||||
}
|
||||
|
||||
protected function should_send_site_info() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function detect_plugin_component_from_versionphp($code) {
|
||||
return parent::detect_plugin_component_from_versionphp($code);
|
||||
}
|
||||
}
|
||||
|
||||
+78
-119
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@@ -17,40 +18,39 @@
|
||||
/**
|
||||
* Provides the unit tests class and some helper classes
|
||||
*
|
||||
* @package core_plugin
|
||||
* @package tool_installaddon
|
||||
* @category test
|
||||
* @copyright 2013, 2015 David Mudrak <david@moodle.com>
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__.'/fixtures/testable_update_validator.php');
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link \core\update\validator} class
|
||||
* Unit tests for the {@link tool_installaddon_installer} class
|
||||
*
|
||||
* @copyright 2013, 2015 David Mudrak <david@moodle.com>
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_update_validator_testcase extends advanced_testcase {
|
||||
class tool_installaddon_validator_testcase extends basic_testcase {
|
||||
|
||||
public function test_validate_files_layout() {
|
||||
$fixtures = __DIR__.'/fixtures/update_validator';
|
||||
$fixtures = dirname(__FILE__).'/fixtures';
|
||||
|
||||
// Non-existing directory.
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/nulldir', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/nulldir', array(
|
||||
'null/' => true,
|
||||
'null/lang/' => true,
|
||||
'null/lang/en/' => true,
|
||||
'null/lang/en/null.php' => true));
|
||||
$this->assertEquals('testable_core_update_validator', get_class($validator));
|
||||
$this->assertEquals('testable_tool_installaddon_validator', get_class($validator));
|
||||
$this->assertFalse($validator->execute());
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR,
|
||||
'filenotexists', array('file' => 'null/')));
|
||||
|
||||
// Missing expected file.
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/plugindir', array(
|
||||
// Missing expected file
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/plugindir', array(
|
||||
'foobar/' => true,
|
||||
'foobar/version.php' => true,
|
||||
'foobar/index.php' => true,
|
||||
@@ -62,8 +62,8 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR,
|
||||
'filenotexists', array('file' => 'foobar/NOTEXISTS.txt')));
|
||||
|
||||
// Errors during ZIP extraction.
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/multidir', array(
|
||||
// Errors during ZIP extraction
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/multidir', array(
|
||||
'one/' => true,
|
||||
'one/version.php' => 'Can not write target file',
|
||||
'two/' => true,
|
||||
@@ -72,15 +72,15 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'filestatus',
|
||||
array('file' => 'one/version.php', 'status' => 'Can not write target file')));
|
||||
|
||||
// Insufficient number of extracted files.
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/emptydir', array(
|
||||
// Insufficient number of extracted files
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/emptydir', array(
|
||||
'emptydir/' => true,
|
||||
'emptydir/README.txt' => true));
|
||||
$this->assertFalse($validator->execute());
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'filesnumber'));
|
||||
|
||||
// No wrapping directory.
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/nowrapdir', array(
|
||||
// No wrapping directory
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/nowrapdir', array(
|
||||
'version.php' => true,
|
||||
'index.php' => true,
|
||||
'lang/' => true,
|
||||
@@ -89,8 +89,8 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
$this->assertFalse($validator->execute());
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'onedir'));
|
||||
|
||||
// Multiple directories.
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/multidir', array(
|
||||
// Multiple directories
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/multidir', array(
|
||||
'one/' => true,
|
||||
'one/version.php' => true,
|
||||
'two/' => true,
|
||||
@@ -98,8 +98,8 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
$this->assertFalse($validator->execute());
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'onedir'));
|
||||
|
||||
// Invalid root directory name.
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/github', array(
|
||||
// Invalid root directory name
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/github', array(
|
||||
'moodle-repository_mahara-master/' => true,
|
||||
'moodle-repository_mahara-master/lang/' => true,
|
||||
'moodle-repository_mahara-master/lang/en/' => true,
|
||||
@@ -111,9 +111,9 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
}
|
||||
|
||||
public function test_validate_version_php() {
|
||||
$fixtures = __DIR__.'/fixtures/update_validator';
|
||||
$fixtures = dirname(__FILE__).'/fixtures';
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/noversiontheme', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/noversiontheme', array(
|
||||
'noversion/' => true,
|
||||
'noversion/lang/' => true,
|
||||
'noversion/lang/en/' => true,
|
||||
@@ -124,7 +124,7 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::DEBUG, 'missingversionphp'));
|
||||
$this->assertTrue(is_null($validator->get_versionphp_info()));
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/noversionmod', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/noversionmod', array(
|
||||
'noversion/' => true,
|
||||
'noversion/lang/' => true,
|
||||
'noversion/lang/en/' => true,
|
||||
@@ -134,29 +134,7 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
$this->assertFalse($validator->execute());
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'missingversionphp'));
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/plugindir', array(
|
||||
'legacymod/' => true,
|
||||
'legacymod/version.php' => true,
|
||||
'legacymod/lang/' => true,
|
||||
'legacymod/lang/en/' => true,
|
||||
'legacymod/lang/en/legacymod.php' => true));
|
||||
$validator->assert_plugin_type('mod');
|
||||
$validator->assert_moodle_version(0);
|
||||
$this->assertFalse($validator->execute());
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'versionphpsyntax', '$module'));
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/nocomponent', array(
|
||||
'baz/' => true,
|
||||
'baz/version.php' => true,
|
||||
'baz/lang/' => true,
|
||||
'baz/lang/en/' => true,
|
||||
'baz/lang/en/auth_baz.php' => true));
|
||||
$validator->assert_plugin_type('auth');
|
||||
$validator->assert_moodle_version(0);
|
||||
$this->assertFalse($validator->execute());
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'missingcomponent'));
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/plugindir', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/plugindir', array(
|
||||
'foobar/' => true,
|
||||
'foobar/version.php' => true,
|
||||
'foobar/index.php' => true,
|
||||
@@ -167,7 +145,7 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'componentmismatchtype',
|
||||
array('expected' => 'block', 'found' => 'local')));
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/plugindir', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/plugindir', array(
|
||||
'foobar/' => true,
|
||||
'foobar/version.php' => true,
|
||||
'foobar/index.php' => true,
|
||||
@@ -192,9 +170,9 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
}
|
||||
|
||||
public function test_validate_language_pack() {
|
||||
$fixtures = __DIR__.'/fixtures/update_validator';
|
||||
$fixtures = dirname(__FILE__).'/fixtures';
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/nolang', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/nolang', array(
|
||||
'bah/' => true,
|
||||
'bah/index.php' => true,
|
||||
'bah/view.php' => true,
|
||||
@@ -204,7 +182,7 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
$this->assertFalse($validator->execute());
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'missinglangenfolder'));
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/nolang', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/nolang', array(
|
||||
'bah/' => true,
|
||||
'bah/version.php' => true,
|
||||
'bah/lang/' => true,
|
||||
@@ -214,7 +192,7 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
$this->assertFalse($validator->execute());
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'missinglangenfile'));
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/nolang', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/nolang', array(
|
||||
'bah/' => true,
|
||||
'bah/version.php' => true,
|
||||
'bah/lang/' => true,
|
||||
@@ -227,7 +205,7 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::WARNING, 'multiplelangenfiles'));
|
||||
$this->assertTrue(is_null($validator->get_language_file_name()));
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/wronglang', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/nolang', array(
|
||||
'bah/' => true,
|
||||
'bah/version.php' => true,
|
||||
'bah/lang/' => true,
|
||||
@@ -236,11 +214,10 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
$validator->assert_plugin_type('block');
|
||||
$validator->assert_moodle_version(0);
|
||||
$this->assertFalse($validator->execute());
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'missingexpectedlangenfile',
|
||||
'block_bah.php'));
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'missingexpectedlangenfile', 'block_bah.php'));
|
||||
$this->assertEquals('bah', $validator->get_language_file_name());
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/noversiontheme', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/noversiontheme', array(
|
||||
'noversion/' => true,
|
||||
'noversion/lang/' => true,
|
||||
'noversion/lang/en/' => true,
|
||||
@@ -251,7 +228,7 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::DEBUG, 'foundlangfile', 'theme_noversion'));
|
||||
$this->assertEquals('theme_noversion', $validator->get_language_file_name());
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/plugindir', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/plugindir', array(
|
||||
'foobar/' => true,
|
||||
'foobar/version.php' => true,
|
||||
'foobar/index.php' => true,
|
||||
@@ -266,9 +243,9 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
}
|
||||
|
||||
public function test_validate_target_location() {
|
||||
$fixtures = __DIR__.'/fixtures/update_validator';
|
||||
$fixtures = dirname(__FILE__).'/fixtures';
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/installed', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/installed', array(
|
||||
'greenbar/' => true,
|
||||
'greenbar/version.php' => true,
|
||||
'greenbar/index.php' => true,
|
||||
@@ -277,27 +254,11 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
'greenbar/lang/en/local_greenbar.php' => true));
|
||||
$validator->assert_plugin_type('local');
|
||||
$validator->assert_moodle_version('2013031400.00');
|
||||
|
||||
$this->assertTrue($validator->execute());
|
||||
$this->assertFalse($this->has_message($validator->get_messages(), $validator::WARNING, 'targetexists',
|
||||
$validator->get_plugintype_location('local').'/greenbar'));
|
||||
|
||||
$typeroot = $validator->get_plugintype_location('local');
|
||||
make_writable_directory($typeroot.'/greenbar');
|
||||
$this->assertTrue($validator->execute());
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::WARNING, 'targetexists',
|
||||
$validator->get_plugintype_location('local').'/greenbar'));
|
||||
|
||||
remove_dir($typeroot.'/greenbar');
|
||||
file_put_contents($typeroot.'/greenbar', 'This file occupies a place where a plugin should land.');
|
||||
$this->assertFalse($validator->execute());
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'targetnotdir',
|
||||
$this->assertTrue($this->has_message($validator->get_messages(), $validator::ERROR, 'targetexists',
|
||||
$validator->get_plugintype_location('local').'/greenbar'));
|
||||
|
||||
unlink($typeroot.'/greenbar');
|
||||
$this->assertTrue($validator->execute());
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures.'/plugindir', array(
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures.'/plugindir', array(
|
||||
'foobar/' => true,
|
||||
'foobar/version.php' => true,
|
||||
'foobar/index.php' => true,
|
||||
@@ -312,56 +273,25 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
}
|
||||
|
||||
public function test_parse_version_php() {
|
||||
$fixtures = __DIR__.'/fixtures/update_validator/versionphp';
|
||||
$fixtures = dirname(__FILE__).'/fixtures/versionphp';
|
||||
|
||||
$validator = testable_core_update_validator::instance($fixtures, array());
|
||||
$this->assertEquals('testable_core_update_validator', get_class($validator));
|
||||
$validator = testable_tool_installaddon_validator::instance($fixtures, array());
|
||||
$this->assertEquals('testable_tool_installaddon_validator', get_class($validator));
|
||||
|
||||
$info = $validator->testable_parse_version_php($fixtures.'/version1.php');
|
||||
$this->assertInternalType('array', $info);
|
||||
$this->assertCount(7, $info);
|
||||
$this->assertEquals('block_foobar', $info['plugin->component']); // Later in the file.
|
||||
$this->assertEquals('2013010100', $info['plugin->version']); // Numeric wins over strings.
|
||||
$this->assertEquals('2012122401', $info['plugin->requires']); // Commented.
|
||||
$this->assertEquals('MATURITY_STABLE', $info['module->maturity']);// Constant wins regardless the order (non-PHP behaviour).
|
||||
$this->assertEquals('MATURITY_ALPHA', $info['plugin->maturity']); // Constant wins regardless the order (non-PHP behaviour).
|
||||
$this->assertEquals('v2.3', $info['module->release']); // String wins over numeric (non-PHP behaviour).
|
||||
$this->assertEquals('v2.4', $info['plugin->release']); // String wins over numeric (non-PHP behaviour).
|
||||
$this->assertEquals('block_foobar', $info['plugin->component']); // Later in the file.
|
||||
$this->assertEquals('2013010100', $info['plugin->version']); // Numeric wins over strings.
|
||||
$this->assertEquals('2012122401', $info['plugin->requires']); // Commented.
|
||||
$this->assertEquals('MATURITY_STABLE', $info['module->maturity']); // Constant wins regardless the order (non-PHP behaviour).
|
||||
$this->assertEquals('MATURITY_ALPHA', $info['plugin->maturity']); // Constant wins regardless the order (non-PHP behaviour).
|
||||
$this->assertEquals('v2.3', $info['module->release']); // String wins over numeric (non-PHP behaviour).
|
||||
$this->assertEquals('v2.4', $info['plugin->release']); // String wins over numeric (non-PHP behaviour).
|
||||
}
|
||||
|
||||
public function test_messages_output() {
|
||||
$fixtures = __DIR__.'/fixtures/update_validator';
|
||||
$validator = testable_core_update_validator::instance($fixtures, array());
|
||||
// Helper methods //////////////////////////////////////////////////////////
|
||||
|
||||
$this->assertDebuggingNotCalled();
|
||||
$this->assertNotEmpty($validator->message_level_name($validator::ERROR));
|
||||
$this->assertNotEmpty($validator->message_level_name($validator::WARNING));
|
||||
$this->assertNotEmpty($validator->message_level_name($validator::INFO));
|
||||
$this->assertNotEmpty($validator->message_level_name($validator::DEBUG));
|
||||
|
||||
$this->assertNotEmpty($validator->message_code_name('missingversion'));
|
||||
$this->assertSame(
|
||||
'some_really_crazy_message_code_that_is_not_localised',
|
||||
$validator->message_code_name('some_really_crazy_message_code_that_is_not_localised')
|
||||
);
|
||||
|
||||
$this->assertInstanceOf('help_icon', $validator->message_help_icon('onedir'));
|
||||
$this->assertFalse($validator->message_help_icon('some_really_crazy_message_code_that_is_not_localised'));
|
||||
|
||||
$this->assertNotEmpty($validator->message_code_info('missingexpectedlangenfile', 'something'));
|
||||
$this->assertSame('', $validator->message_code_info('missingexpectedlangenfile', null));
|
||||
$this->assertSame('', $validator->message_code_info('some_really_crazy_message_code_that_is_not_localised', 'something'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for checking if the given message has been raised by the validator.
|
||||
*
|
||||
* @param array $messages list of returned messages
|
||||
* @param string $level expected message severity level
|
||||
* @param string $msgcode expected message code
|
||||
* @param string|array $addinfo expected additional info
|
||||
* @return bool
|
||||
*/
|
||||
protected function has_message(array $messages, $level, $msgcode, $addinfo = null) {
|
||||
foreach ($messages as $message) {
|
||||
if ($message->level === $level and $message->msgcode === $msgcode and $message->addinfo === $addinfo) {
|
||||
@@ -371,3 +301,32 @@ class core_update_validator_testcase extends advanced_testcase {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provides access to protected methods we want to explicitly test
|
||||
*
|
||||
* @copyright 2013 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class testable_tool_installaddon_validator extends tool_installaddon_validator {
|
||||
|
||||
public function testable_parse_version_php($fullpath) {
|
||||
return parent::parse_version_php($fullpath);
|
||||
}
|
||||
|
||||
public function get_plugintype_location($plugintype) {
|
||||
|
||||
$testableroot = make_temp_directory('testable_tool_installaddon_validator/plugintypes');
|
||||
if (!is_dir($testableroot.'/'.$plugintype)) {
|
||||
make_temp_directory('testable_tool_installaddon_validator/plugintypes/'.$plugintype);
|
||||
}
|
||||
|
||||
if ($plugintype === 'local') {
|
||||
// We need the following for the test_validate_target_location() method
|
||||
make_temp_directory('testable_tool_installaddon_validator/plugintypes/local/greenbar');
|
||||
}
|
||||
|
||||
return $testableroot.'/'.$plugintype;
|
||||
}
|
||||
}
|
||||
@@ -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/>.
|
||||
|
||||
/**
|
||||
* The ZIP package validation.
|
||||
*
|
||||
* @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.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
|
||||
navigation_node::override_active_url(new moodle_url('/admin/tool/installaddon/index.php'));
|
||||
admin_externalpage_setup('tool_installaddon_validate');
|
||||
|
||||
if (!empty($CFG->disableonclickaddoninstall)) {
|
||||
notice(get_string('featuredisabled', 'tool_installaddon'));
|
||||
}
|
||||
|
||||
require_sesskey();
|
||||
|
||||
$jobid = required_param('jobid', PARAM_ALPHANUM);
|
||||
$zipfilename = required_param('zip', PARAM_FILE);
|
||||
$plugintype = required_param('type', PARAM_ALPHANUMEXT);
|
||||
$rootdir = optional_param('rootdir', '', PARAM_PLUGIN);
|
||||
|
||||
$zipfilepath = $CFG->tempdir.'/tool_installaddon/'.$jobid.'/source/'.$zipfilename;
|
||||
if (!file_exists($zipfilepath)) {
|
||||
redirect(new moodle_url('/admin/tool/installaddon/index.php'),
|
||||
get_string('invaliddata', 'core_error'));
|
||||
}
|
||||
|
||||
$installer = tool_installaddon_installer::instance();
|
||||
|
||||
// Extract the ZIP contents.
|
||||
fulldelete($CFG->tempdir.'/tool_installaddon/'.$jobid.'/contents');
|
||||
$zipcontentpath = make_temp_directory('tool_installaddon/'.$jobid.'/contents');
|
||||
$zipcontentfiles = $installer->extract_installfromzip_file($zipfilepath, $zipcontentpath, $rootdir);
|
||||
|
||||
// Validate the contents of the plugin ZIP file.
|
||||
$validator = tool_installaddon_validator::instance($zipcontentpath, $zipcontentfiles);
|
||||
$validator->assert_plugin_type($plugintype);
|
||||
$validator->assert_moodle_version($CFG->version);
|
||||
$result = $validator->execute();
|
||||
|
||||
if ($result) {
|
||||
$validator->set_continue_url(new moodle_url('/admin/tool/installaddon/deploy.php', array(
|
||||
'sesskey' => sesskey(),
|
||||
'jobid' => $jobid,
|
||||
'type' => $plugintype,
|
||||
'name' => $validator->get_rootdir())));
|
||||
|
||||
} else {
|
||||
fulldelete($CFG->tempdir.'/tool_installaddon/'.$jobid);
|
||||
}
|
||||
|
||||
// Display the validation results.
|
||||
$output = $PAGE->get_renderer('tool_installaddon');
|
||||
$output->set_installer_instance($installer);
|
||||
$output->set_validator_instance($validator);
|
||||
echo $output->validation_page();
|
||||
@@ -24,6 +24,6 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'tool_installaddon';
|
||||
$plugin->version = 2015111600;
|
||||
$plugin->requires = 2015111000;
|
||||
$plugin->version = 2015051100;
|
||||
$plugin->requires = 2015050500;
|
||||
$plugin->maturity = MATURITY_STABLE;
|
||||
|
||||
@@ -128,7 +128,7 @@ class controller {
|
||||
event\langpack_removed::event_with_langcode($lang)->trigger();
|
||||
return true;
|
||||
} else { // Nothing deleted, possibly due to permission error.
|
||||
$this->errors[] = get_string('langpacknotremoved', 'tool_langimport', $lang);
|
||||
$this->errors[] = 'An error has occurred, language pack is not completely uninstalled, please check file permissions';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,9 +112,4 @@ class langpack_imported extends \core\event\base {
|
||||
throw new \coding_exception('The \'langcode\' value must be set to a valid language code');
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_other_mapping() {
|
||||
// No mapping required for this event because this event is not backed up.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,9 +113,4 @@ class langpack_removed extends \core\event\base {
|
||||
throw new \coding_exception('The \'langcode\' value must be set to a valid language code');
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_other_mapping() {
|
||||
// No mapping required for this event because this event is not backed up.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,9 +112,4 @@ class langpack_updated extends \core\event\base {
|
||||
throw new \coding_exception('The \'langcode\' value must be set to a valid language code');
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_other_mapping() {
|
||||
// No mapping required for this event because this event is not backed up.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,11 +37,11 @@ if (empty($CFG->langotherroot)) {
|
||||
throw new moodle_exception('missingcfglangotherroot', 'tool_langimport');
|
||||
}
|
||||
|
||||
$mode = optional_param('mode', 0, PARAM_INT); // action
|
||||
$pack = optional_param_array('pack', array(), PARAM_SAFEDIR); // pack to install
|
||||
$uninstalllang = optional_param_array('uninstalllang', array(), PARAM_LANG);// installed pack to uninstall
|
||||
$confirmtounistall = optional_param('confirmtouninstall', '', PARAM_ALPHAEXT); // uninstallation confirmation
|
||||
$purgecaches = optional_param('purgecaches', false, PARAM_BOOL); // explicit caches reset
|
||||
$mode = optional_param('mode', 0, PARAM_INT); // action
|
||||
$pack = optional_param_array('pack', array(), PARAM_SAFEDIR); // pack to install
|
||||
$uninstalllang = optional_param('uninstalllang', '', PARAM_LANG); // installed pack to uninstall
|
||||
$confirm = optional_param('confirm', 0, PARAM_BOOL); // uninstallation confirmation
|
||||
$purgecaches = optional_param('purgecaches', false, PARAM_BOOL); // explicit caches reset
|
||||
|
||||
if ($purgecaches) {
|
||||
require_sesskey();
|
||||
@@ -70,30 +70,21 @@ if (($mode == INSTALLATION_OF_SELECTED_LANG) and confirm_sesskey() and !empty($p
|
||||
$controller->install_languagepacks($pack);
|
||||
}
|
||||
|
||||
if ($mode == DELETION_OF_SELECTED_LANG and (!empty($uninstalllang) or !empty($confirmtounistall))) {
|
||||
// Actually deleting languages, languages to delete are passed as GET parameter as string
|
||||
// ...need to populate them to array.
|
||||
if (empty($uninstalllang)) {
|
||||
$uninstalllang = explode('-', $confirmtounistall);
|
||||
}
|
||||
|
||||
if (in_array('en', $uninstalllang)) {
|
||||
if ($mode == DELETION_OF_SELECTED_LANG and !empty($uninstalllang)) {
|
||||
if ($uninstalllang == 'en') {
|
||||
// TODO.
|
||||
$controller->errors[] = get_string('noenglishuninstall', 'tool_langimport');
|
||||
$controller->errors[] = 'English language pack can not be uninstalled';
|
||||
|
||||
} else if (empty($confirmtounistall) and confirm_sesskey()) { // User chose langs to be deleted, show confirmation.
|
||||
} else if (!$confirm and confirm_sesskey()) {
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->confirm(get_string('uninstallconfirm', 'tool_langimport', implode(', ', $uninstalllang)),
|
||||
'index.php?mode='.DELETION_OF_SELECTED_LANG.'&confirmtouninstall='.implode('-', $uninstalllang),
|
||||
echo $OUTPUT->confirm(get_string('uninstallconfirm', 'tool_langimport', $uninstalllang),
|
||||
'index.php?mode='.DELETION_OF_SELECTED_LANG.'&uninstalllang='.$uninstalllang.'&confirm=1',
|
||||
'index.php');
|
||||
echo $OUTPUT->footer();
|
||||
die;
|
||||
|
||||
} else if (confirm_sesskey()) { // Deleting languages.
|
||||
foreach ($uninstalllang as $ulang) {
|
||||
$controller->uninstall_language($ulang);
|
||||
}
|
||||
|
||||
} else if (confirm_sesskey()) {
|
||||
$controller->uninstall_language($uninstalllang);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,13 +158,10 @@ echo html_writer::start_tag('form', array('id' => 'uninstallform', 'action' => $
|
||||
echo html_writer::start_tag('fieldset');
|
||||
echo html_writer::label(get_string('installedlangs', 'tool_langimport'), 'menuuninstalllang');
|
||||
echo html_writer::empty_tag('br');
|
||||
echo html_writer::select($installedlangs, 'uninstalllang[]', '', false, array('size' => 15, 'multiple' => 'multiple'));
|
||||
echo html_writer::select($installedlangs, 'uninstalllang', '', false, array('size' => 15));
|
||||
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
|
||||
echo html_writer::empty_tag('br');
|
||||
echo html_writer::empty_tag('input', array('id' => 'languninstallbutton',
|
||||
'type' => 'submit',
|
||||
'value' => get_string('uninstall', 'tool_langimport'))
|
||||
);
|
||||
echo html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('uninstall', 'tool_langimport')));
|
||||
echo html_writer::end_tag('fieldset');
|
||||
echo html_writer::end_tag('form');
|
||||
if ($remote) {
|
||||
@@ -188,7 +176,7 @@ echo html_writer::end_tag('td');
|
||||
$options = array();
|
||||
foreach ($availablelangs as $alang) {
|
||||
if (!empty($alang[0]) and trim($alang[0]) !== 'en' and !$controller->is_installed_lang($alang[0], $alang[1])) {
|
||||
$options[$alang[0]] = $alang[2].' ‎('.$alang[0].')‎';
|
||||
$options[$alang[0]] = $alang[2].' ('.$alang[0].')';
|
||||
}
|
||||
}
|
||||
if (!empty($options)) {
|
||||
@@ -210,13 +198,5 @@ if (!empty($options)) {
|
||||
echo html_writer::end_tag('tr');
|
||||
echo html_writer::end_tag('table');
|
||||
echo $OUTPUT->box_end();
|
||||
|
||||
$uninstallurl = new moodle_url('/admin/tool/langimport/index.php');
|
||||
$PAGE->requires->strings_for_js(array('uninstallconfirm', 'uninstall', 'selectlangs', 'noenglishuninstall'),
|
||||
'tool_langimport');
|
||||
$PAGE->requires->yui_module('moodle-core-languninstallconfirm',
|
||||
'Y.M.core.languninstallconfirm.init',
|
||||
array(array('uninstallUrl' => $uninstallurl->out()))
|
||||
);
|
||||
echo $OUTPUT->footer();
|
||||
die();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user