Compare commits
749 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c1d466b911 | |||
| 13561f5881 | |||
| a31041ef7b | |||
| 098013a01d | |||
| ec63b8f289 | |||
| b3cea552a2 | |||
| 9777b29452 | |||
| 081dc58c6f | |||
| a650045e23 | |||
| 1396072aa3 | |||
| 8864cfdcb8 | |||
| 727cedf0be | |||
| d45bc875af | |||
| d09d4730d9 | |||
| 57fcc42a49 | |||
| be680afe3e | |||
| e1d69f2347 | |||
| c0a69e036e | |||
| aca6d79b91 | |||
| a2c405ba5f | |||
| f200548361 | |||
| 1ff829a4f0 | |||
| 607cf7fff1 | |||
| f714dbee87 | |||
| 72ba0759fc | |||
| 0ada05c99f | |||
| a5c0090669 | |||
| 31d7689f7f | |||
| 86a5027502 | |||
| 36002cf5e7 | |||
| 778a1c3546 | |||
| 19666984de | |||
| 268b9dadfd | |||
| e3b1909b2b | |||
| da1346752d | |||
| 50bbd580ac | |||
| 6367ed9300 | |||
| 8684982cfe | |||
| 59a80f598b | |||
| 181f00f36e | |||
| 38aaac7af6 | |||
| fb7ef63350 | |||
| 2d51edb610 | |||
| 24e196b63d | |||
| 944e9d5fdc | |||
| b28424638c | |||
| d580889967 | |||
| d559cde424 | |||
| fafeeda7e1 | |||
| ef70a58aed | |||
| d82ea0f211 | |||
| 96cf22c819 | |||
| 833b48fc75 | |||
| a1b390bd4f | |||
| cc9b202deb | |||
| f2e657fc42 | |||
| d94e170007 | |||
| d430695693 | |||
| 36030e92d7 | |||
| 0d0cdaeecf | |||
| dc9b44f531 | |||
| 2243d1b395 | |||
| c0a2c4bfd8 | |||
| 49a95e4cef | |||
| d1d01d2cdb | |||
| cef371bcac | |||
| 60dafdf7c1 | |||
| 9e351777b1 | |||
| 0620ca406c | |||
| cc2edf3b8c | |||
| 7376b6deca | |||
| 7052d36f7c | |||
| 04479a6a3c | |||
| 3521b24e51 | |||
| bdfa441f00 | |||
| 6728d1ccc0 | |||
| 40d1da51bb | |||
| c52869afbe | |||
| 18d4531ad4 | |||
| 62aab40860 | |||
| b4525ba984 | |||
| 7b16b52ffe | |||
| ff93557b40 | |||
| 48e8e6f434 | |||
| ecc5f367ef | |||
| 850b4a5f56 | |||
| 91eae783fc | |||
| 912817f097 | |||
| 36412a5fea | |||
| a7f19c9072 | |||
| 4bc773ad03 | |||
| cb05767ce1 | |||
| 4973da2768 | |||
| aa145e2669 | |||
| bdc4367460 | |||
| fc467246b4 | |||
| ee502bf6b5 | |||
| ee6e605770 | |||
| 2d953eb291 | |||
| 6e7faf5854 | |||
| 50569e6f4a | |||
| 23a61db0f0 | |||
| d3d580671a | |||
| 8304649791 | |||
| c8c3b17cd2 | |||
| 3e5569a61a | |||
| 80782f8907 | |||
| 51af50ade5 | |||
| b683a38423 | |||
| 54dc1112cb | |||
| 421c0608e8 | |||
| 7678c3f41c | |||
| a3573087d1 | |||
| f809e209e3 | |||
| 59a377abbe | |||
| ac7cecfb37 | |||
| 83a24b0e9f | |||
| 7ffbd04d35 | |||
| 19284518d1 | |||
| cb8578e93f | |||
| 217f5d8f8d | |||
| dec2143d73 | |||
| abd4203547 | |||
| 28922ba889 | |||
| b67fb190b9 | |||
| 1e0f46a125 | |||
| 1abeac9ba4 | |||
| 84c134f7c0 | |||
| aa8f7a6a39 | |||
| 2937e90bc7 | |||
| 01971bc9a4 | |||
| 09fae09cd5 | |||
| e0381615aa | |||
| 349916ae5f | |||
| 5168d9c97b | |||
| fc38c5c7e7 | |||
| 3ab8986eb0 | |||
| be4d15a856 | |||
| 495f38ff3f | |||
| 0fe19ee1dc | |||
| ef3d7a9d18 | |||
| 1970d836c6 | |||
| 96f76208d1 | |||
| 2fb409a999 | |||
| 86afac09e9 | |||
| 45fbccf625 | |||
| 2c2cda1660 | |||
| e6176d6dba | |||
| 0be064b328 | |||
| 5b68c82eb2 | |||
| 94bcaa0d4f | |||
| 971b7b6eb7 | |||
| ad698059ae | |||
| 1114ab3822 | |||
| adf336cbf2 | |||
| b150085bb1 | |||
| f0dd2ae1f5 | |||
| fd63451ecc | |||
| 3d40c9bc47 | |||
| b540ab944c | |||
| d34d87f45a | |||
| abd665d545 | |||
| 5bcdefb516 | |||
| d69212b895 | |||
| 0223b0fefb | |||
| 3452312c8c | |||
| e884c04350 | |||
| a1dcb85347 | |||
| ed179a8d7f | |||
| 30bae49637 | |||
| 0ae247b51f | |||
| d8a1a67fd7 | |||
| acbfa5e1a3 | |||
| 408154a1b6 | |||
| f91d479407 | |||
| 09b9c2a5b9 | |||
| 8d12c2a15e | |||
| a358040701 | |||
| a03674de6f | |||
| b3dbeeecf7 | |||
| e18333d842 | |||
| 67b21bbc99 | |||
| d81770cdbe | |||
| 688ee9e9d1 | |||
| 42cc612a5e | |||
| fa8b74b5eb | |||
| ffc32f80a5 | |||
| 3da6a04461 | |||
| eac19ef151 | |||
| 37a95f12e7 | |||
| 727c4c5a6e | |||
| a52f92a82c | |||
| 067818c2e6 | |||
| d7d19fe136 | |||
| 28a7d39b2a | |||
| da95f8d083 | |||
| b1297a80df | |||
| cbafc55078 | |||
| b7bd55bc82 | |||
| aafb937adf | |||
| 95d011dcf1 | |||
| c930111e17 | |||
| f0c5d668e9 | |||
| a061f1b4c2 | |||
| 2299b73307 | |||
| 85c7dcaf05 | |||
| 8d30ff7575 | |||
| 2e8bf841c6 | |||
| d5b719f6a0 | |||
| d7cb2a66cd | |||
| e96db7beec | |||
| 44801c448c | |||
| 904222b6f2 | |||
| f1bc96a8ab | |||
| d0ce8e8d62 | |||
| c2f3e98cea | |||
| 266c8b73b0 | |||
| 00ce502c67 | |||
| 38ab94e04b | |||
| dc6db54e99 | |||
| d45422ccbf | |||
| c1b4d24095 | |||
| e05fa63684 | |||
| 03f840b4f2 | |||
| fbd674e81b | |||
| 1291503846 | |||
| 21fc6a3016 | |||
| 23f0ec2766 | |||
| b99a81af8e | |||
| 908488e472 | |||
| 7fdb644bd1 | |||
| 70204fd73c | |||
| 389e4fc011 | |||
| ed4a47302e | |||
| 0f0710a249 | |||
| 42511349ae | |||
| 32f1542b5e | |||
| 78bcf355c6 | |||
| 31e0fd81a7 | |||
| 7a21be49f9 | |||
| 43b3bda115 | |||
| 088c523df0 | |||
| 4af5185587 | |||
| b2018b2fbc | |||
| 25f4874743 | |||
| 3ff165b4c5 | |||
| 1d51af0f8e | |||
| aa550ddea6 | |||
| 978ada1047 | |||
| 8b7270f9b1 | |||
| 8741181a5b | |||
| e7065ad471 | |||
| d36cf65ef3 | |||
| 39d46917bb | |||
| 6b3d8fd889 | |||
| b15b73848a | |||
| 6cd08cc382 | |||
| b1a6791aa2 | |||
| 384300011c | |||
| 57fc94747d | |||
| 9956e9ff31 | |||
| 8601c56964 | |||
| 9f1ab61160 | |||
| 4197e50fec | |||
| 23ba4d1792 | |||
| 17e5aaa5be | |||
| dd998e8d88 | |||
| 1bfd61c0fd | |||
| 95274afe55 | |||
| 8d1bf9d92d | |||
| 799e5c9ecc | |||
| 1d20be4c3d | |||
| ed5fde9c1f | |||
| 45d839a7c8 | |||
| 0ebbf88990 | |||
| 2196813e1e | |||
| 562b9775b2 | |||
| cbe78bb3a6 | |||
| 8cfc9387f2 | |||
| 0ea950e710 | |||
| 077f535912 | |||
| e1816e9af1 | |||
| 5ca387bef3 | |||
| 27cd5596e7 | |||
| a10c074f54 | |||
| ba80f884f7 | |||
| 54ec6416b4 | |||
| 83bec3bdb5 | |||
| 8a325684d0 | |||
| 8704a69aed | |||
| d6fbf5661a | |||
| 6a33cb3e08 | |||
| cd2d47dafc | |||
| 1be7820208 | |||
| f297094295 | |||
| 0aeff04c0a | |||
| 959963e1e4 | |||
| 7acefc469c | |||
| 3ae349b86e | |||
| 3413c90bd2 | |||
| 41a5833327 | |||
| 9557a52569 | |||
| f41181c894 | |||
| ff3fb00a96 | |||
| 7f45da44ed | |||
| d9a761f6ee | |||
| 771694018e | |||
| eafd1bcb17 | |||
| 7065a3dca0 | |||
| 5bc2479793 | |||
| 70d257fc5b | |||
| 3423dd2245 | |||
| a0a2015027 | |||
| 96f2686d47 | |||
| 5bbd628f49 | |||
| aad75c1072 | |||
| c35610502f | |||
| f35b8e6651 | |||
| 5be8cf7ba8 | |||
| b3b8f520e9 | |||
| a25eb4cb95 | |||
| f4f7f83ce5 | |||
| f312621f0d | |||
| 6ad723885c | |||
| 2119c703d2 | |||
| 42938d2dd4 | |||
| 462357ebf0 | |||
| a79853672e | |||
| 75b3607fc3 | |||
| f142770c37 | |||
| cf92d64a57 | |||
| 6771eb805b | |||
| 6c7121254d | |||
| f523a01673 | |||
| 75791eabea | |||
| 2c804c3ab2 | |||
| 044e924d8a | |||
| 6b01e331e6 | |||
| 87d7ac1f81 | |||
| 09c7a41d7f | |||
| 219d5bfb44 | |||
| 32d08ee47f | |||
| ef45ffc444 | |||
| 52cbcdbca7 | |||
| 97c21add9e | |||
| 15d331c058 | |||
| 2ac781b76d | |||
| 6d4ea3f3c2 | |||
| b0b17142c7 | |||
| 306b5289a7 | |||
| 99ae088704 | |||
| 7605966155 | |||
| 0f7d291b9c | |||
| ff2164fd3d | |||
| b1072fc937 | |||
| 81900583fe | |||
| 9dde27f0bb | |||
| 40ffccc33b | |||
| 1975be2909 | |||
| 160617d2d5 | |||
| 2b42e986e3 | |||
| e9683d416f | |||
| 85c8395e52 | |||
| fa80a0b8a5 | |||
| 10eead2473 | |||
| f341c774de | |||
| 731bf1cb78 | |||
| 18bf9704e7 | |||
| cd781ab1b7 | |||
| 7ec026173e | |||
| ce6b2f77c9 | |||
| d3078a3f53 | |||
| d5be1b502f | |||
| a74b702a23 | |||
| 4246ca2fbf | |||
| 931f11899a | |||
| f3ade2b67a | |||
| a1334d14d7 | |||
| c2cd21be15 | |||
| 3fb33d314e | |||
| e075cb4c1d | |||
| 7cb072b11e | |||
| d84efee3e2 | |||
| 5fbdb37d60 | |||
| f8eecf37d9 | |||
| 4bdf820437 | |||
| d59f7a04f0 | |||
| 1d753e37af | |||
| 77c9660195 | |||
| 877e585704 | |||
| f64d94dd62 | |||
| f6f6475b8e | |||
| e877329be1 | |||
| 26824c239e | |||
| 6aa18b9c05 | |||
| d348237022 | |||
| 114ddf489e | |||
| f78c93e325 | |||
| 941c866216 | |||
| d9ba8ea3f3 | |||
| 6e41020e44 | |||
| 2be9aaf311 | |||
| ac65869391 | |||
| f7184f748f | |||
| 40995c1030 | |||
| 202c58888a | |||
| 6d35be2af2 | |||
| 754768bad3 | |||
| fbed8034eb | |||
| 73713bd675 | |||
| 347ade6e68 | |||
| ece31e87a6 | |||
| 7b3d547f4a | |||
| 89d93d2632 | |||
| d1f4ca4505 | |||
| f5a2ddef9f | |||
| 533deb42af | |||
| 15b422f3a7 | |||
| 17f080683d | |||
| 9874249ad1 | |||
| 7fae6efbd8 | |||
| e4a8fd37f0 | |||
| c8bdae260b | |||
| 200eb30225 | |||
| d3890caed1 | |||
| 3f1f6192ea | |||
| bf51502049 | |||
| 0d1cbfb3b7 | |||
| 6d717d9c8a | |||
| 4d4efaa72c | |||
| b2ce12db1d | |||
| 96c159f032 | |||
| c260c622b9 | |||
| 71f5eee793 | |||
| 2a86638a15 | |||
| 091b458c52 | |||
| 1093256560 | |||
| 7b6070003a | |||
| d376d8cdbf | |||
| 5541cd1af9 | |||
| dd345ab8ee | |||
| 90c5adee7c | |||
| d5395c4f47 | |||
| 84a3e73aa0 | |||
| c0a966d944 | |||
| 844247aecf | |||
| 90f138fced | |||
| 6a46e9524b | |||
| 21b4aac782 | |||
| 83b9f0e29d | |||
| 6d4a0cbcb2 | |||
| 06b9cbdefd | |||
| 2b4769bb73 | |||
| e858c2e747 | |||
| 222fb603c0 | |||
| f2dbbfe66e | |||
| 821f2a390c | |||
| ac692ebbf6 | |||
| 40960e49bc | |||
| db07c09afc | |||
| 70c8bfa038 | |||
| ccca8adbc1 | |||
| 7e01d53de3 | |||
| 3317a05ec9 | |||
| b0dddbb02a | |||
| 322dae8b9c | |||
| f6be7e2a3e | |||
| aca5d1d5c6 | |||
| 07367f22f1 | |||
| 0c47aa6a92 | |||
| e23f603c41 | |||
| 9af9711c0a | |||
| 30fadc3686 | |||
| 756090ed79 | |||
| 2630591338 | |||
| e00e4487a4 | |||
| 64f1fd7d7b | |||
| 09b06bdb28 | |||
| 9e1723f4b8 | |||
| 3b4e2ae357 | |||
| d35b9dc7bb | |||
| 500cec5757 | |||
| 891e9994b4 | |||
| 1bff691a64 | |||
| 1913cdb088 | |||
| 83b3ee6212 | |||
| 253c16b64d | |||
| 2ed6a57f36 | |||
| af96d4eebe | |||
| 4e6de24f31 | |||
| 7d1563333b | |||
| f7988538b2 | |||
| 6ba71820b1 | |||
| 61c5863b1a | |||
| 0091b1a153 | |||
| b12afc89e4 | |||
| 844aef124c | |||
| 476a8fcb72 | |||
| fe22fe1c83 | |||
| cb9527cd4f | |||
| e71fc4ff3b | |||
| 89fae608a6 | |||
| 2692097272 | |||
| 11ca67f853 | |||
| 34bcb7e70e | |||
| 608f7d6aa0 | |||
| c43d07d0cf | |||
| ad46a97f53 | |||
| da4e626ffa | |||
| cb4904ea25 | |||
| 4d5289e599 | |||
| 0efd3066a2 | |||
| 002b1aed6a | |||
| c73c1bafc1 | |||
| e56c732209 | |||
| cff22cd5ab | |||
| 2ec3b297d7 | |||
| 1e480e2851 | |||
| a22d64816d | |||
| 89d9032e4d | |||
| f540fab1dc | |||
| a49c099ae5 | |||
| 1291869f90 | |||
| 7a420b6a34 | |||
| ff963d9feb | |||
| ad693b830a | |||
| c2b0463539 | |||
| f0445d5cac | |||
| 2debc731ef | |||
| 56aaf7a998 | |||
| 86cb89c5fc | |||
| 9a75b24e1c | |||
| b19ce46723 | |||
| 370843c967 | |||
| da15787ed0 | |||
| 801a2b9497 | |||
| 7a5bdf76b6 | |||
| 63f7c6cc6a | |||
| b35b012e9e | |||
| 0204fbb810 | |||
| 5cf7efb761 | |||
| 2016d4c6dd | |||
| aae18f59aa | |||
| 4d23fe8a58 | |||
| fcfcdd6508 | |||
| 45808a99b4 | |||
| e4acde27c9 | |||
| 5182b60391 | |||
| 23ab7d4973 | |||
| af8f13bac5 | |||
| e5b2b5e0ba | |||
| 9a6b07f0de | |||
| 11e53bf4b0 | |||
| 176caab765 | |||
| bd03886512 | |||
| 6f6d2d9a0f | |||
| e6af0ea94e | |||
| 86b45212e8 | |||
| b2a485e244 | |||
| 80f521eed0 | |||
| f14fdf23e3 | |||
| 25724ebfbb | |||
| c73623506d | |||
| 7450f0e33f | |||
| 55163a6ba9 | |||
| 4e04339cbd | |||
| bf3562d13e | |||
| aca3ad2008 | |||
| f34e050e9b | |||
| c2eb42fc7b | |||
| 625e015ff8 | |||
| 9d74cebd74 | |||
| 64ad970e5e | |||
| f0fb54d907 | |||
| 5da8226f72 | |||
| 2fcd7f93b9 | |||
| 9b30118456 | |||
| dd87304fcf | |||
| b08fbf99db | |||
| b3f708d4d1 | |||
| 4572a114a9 | |||
| c889381be2 | |||
| 1e07a5eef6 | |||
| 2c40c8554b | |||
| 955f4f3bb7 | |||
| 1dca48371d | |||
| c0b9a52430 | |||
| 462b8f9861 | |||
| 242ab5d5aa | |||
| bf8a28b220 | |||
| 20d6ffb9ee | |||
| a76a1e3f5c | |||
| fbd18d8ead | |||
| 78b3369ca0 | |||
| 2f0513b91c | |||
| b25405fd56 | |||
| 5565f47e9b | |||
| 2848c7d6be | |||
| 4e151ddf30 | |||
| 4b9de301c3 | |||
| dbffeb334b | |||
| 165709ff7d | |||
| 0a75d57b13 | |||
| 3182c71093 | |||
| 56fb55683a | |||
| 78229db6a1 | |||
| d04044bb0a | |||
| c1b4ccc4c6 | |||
| 5db3c95e29 | |||
| bcae2164ac | |||
| 207eed1190 | |||
| c948d9e40e | |||
| 9ccdee7687 | |||
| 1a3e68a956 | |||
| dfde819c8b | |||
| ffe67fc6df | |||
| 8a60437bea | |||
| c62143a5df | |||
| 691f2c8950 | |||
| 6ae2c78e9f | |||
| 7a4ea4dd65 | |||
| 217a7af933 | |||
| df176b292a | |||
| fa5a564a17 | |||
| dd1d91486d | |||
| f9ab045794 | |||
| 32bf836fec | |||
| e205d5accc | |||
| 9febdf9b0f | |||
| ce8695ff1f | |||
| 3e80d6ee79 | |||
| 513bafbcfd | |||
| 7fc818ebb8 | |||
| 0219831af4 | |||
| 477aa7c750 | |||
| 47e844d0f4 | |||
| c44c1b5345 | |||
| 28e9e58577 | |||
| 6a628bcd3a | |||
| 10e44e40d9 | |||
| a625583b11 | |||
| 810ab99d7d | |||
| 82a76a1b69 | |||
| ddca055e0d | |||
| b0a11d12ca | |||
| 996564f803 | |||
| 2512e6b09e | |||
| d5d6b0f7f9 | |||
| 52b4f3bb1d | |||
| ad9d4bb4af | |||
| 569d9dfe39 | |||
| 1c2f5dc1df | |||
| 75d95bc4b8 | |||
| a6c17af4c7 | |||
| 7ac2d7f598 | |||
| c4533967d1 | |||
| 5bd4a81e09 | |||
| 72f0a11f0d | |||
| 7b873db958 | |||
| b83cd14d25 | |||
| 4b0ca64617 | |||
| 7741ae3094 | |||
| aa1dc46bc8 | |||
| 27dd2e751f | |||
| f88dbfcafc | |||
| aaf45097b7 | |||
| adb0352ef4 | |||
| da4486b202 | |||
| 778470818a | |||
| 4625eeb998 | |||
| 4e7d555c18 | |||
| 8b7f262aca | |||
| d33dd13fd5 | |||
| a548bccf18 | |||
| 9977c07a69 | |||
| eedb5fde7a | |||
| eabc15f983 | |||
| 18ac43934a | |||
| 35914200b5 | |||
| 48c064505e | |||
| 417fbe1534 | |||
| c70ceb5f7b | |||
| c4735904e5 | |||
| 0792e7bdd9 | |||
| eaf09ebbc4 | |||
| d620ee8cdf | |||
| f7124a4a95 | |||
| 34f1f22b00 | |||
| a95ac513bf | |||
| a829242d47 | |||
| 2479bc2042 | |||
| 67376511ac | |||
| b65b4892ae | |||
| be159037d4 | |||
| eccadb67b7 | |||
| 94d8b7f040 | |||
| c6bf1efac6 | |||
| 50c7842d73 | |||
| 48597285cd | |||
| e13fe01c7b | |||
| 1542a9f9e1 | |||
| 310b932482 | |||
| edf923e38e | |||
| 95a5cb8038 | |||
| 771786ad4d | |||
| 5f6b32c4cb | |||
| 8ee732f391 | |||
| 21e6eea20e | |||
| 1dbc78253c | |||
| c9d48f6f25 | |||
| 894ee17f53 | |||
| cbdfc83b69 | |||
| 6c484f9fc8 | |||
| 6de35b2623 | |||
| f0c1a3789d | |||
| 8f0f474882 | |||
| 452cf5c72d | |||
| dd88b540c2 | |||
| 6a04c121af | |||
| 83eb2a624c | |||
| 1d6bee488d | |||
| 14574fdb56 | |||
| aa213563e7 | |||
| 1d01c74390 | |||
| 0e70a88d03 | |||
| 49b666b670 | |||
| 4c1beb921f | |||
| dcb43cf3b0 | |||
| aa71fcfb7f | |||
| 53557c3be1 | |||
| 16f7008c68 | |||
| 291a5449eb | |||
| 42d52002ee | |||
| c9b7b67fad | |||
| 8a2929c1a9 | |||
| 8f53f30e02 | |||
| 9ea7607613 | |||
| 26a607e8a3 | |||
| 4378d1dadc | |||
| 582eb88404 | |||
| ec0e1d74a0 | |||
| 82eacb2e48 | |||
| 8b976e77ce | |||
| cab8184fcb | |||
| 7b18faed92 | |||
| 4adb2a7695 | |||
| 410b333e47 | |||
| a8908c1a50 | |||
| b0fec7d82b |
+1
-3
@@ -1,5 +1,3 @@
|
||||
**/yui/build/** -diff
|
||||
**/amd/build/** -diff
|
||||
**.js.map -diff
|
||||
**-min.js -diff
|
||||
**.min.js -diff
|
||||
lib/dml/oci_native_moodle_package.sql text eol=lf
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
# Primary donations pages.
|
||||
custom: ["https://moodle.com/donations/", "https://fund.moodle.org"]
|
||||
custom: ["https://moodle.com/donations/", moodle.org]
|
||||
|
||||
@@ -45,7 +45,7 @@ $CFG->admin = 'admin';
|
||||
$CFG->directorypermissions = 0777;
|
||||
|
||||
// Debug options - possible to be controlled by flag in future.
|
||||
$CFG->debug = (E_ALL); // DEBUG_DEVELOPER.
|
||||
$CFG->debug = (E_ALL | E_STRICT); // DEBUG_DEVELOPER.
|
||||
$CFG->debugdisplay = 1;
|
||||
$CFG->debugstringids = 1; // Add strings=1 to url to get string ids.
|
||||
$CFG->perfdebug = 15;
|
||||
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
- name: Setting up DB pgsql
|
||||
uses: m4nu56/postgresql-action@v1
|
||||
with:
|
||||
postgresql version: 14
|
||||
postgresql version: 13
|
||||
postgresql db: test
|
||||
postgresql user: test
|
||||
postgresql password: test
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
- name: Setting up PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 8.4
|
||||
php-version: 8.3
|
||||
ini-values: max_input_vars=5000
|
||||
coverage: none
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@ on:
|
||||
default: ''
|
||||
|
||||
env:
|
||||
php: 8.4
|
||||
php: 8.3
|
||||
|
||||
jobs:
|
||||
Grunt:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checking out code
|
||||
@@ -61,13 +61,13 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
# MySQL builds always run with the lowest PHP supported version.
|
||||
- os: ubuntu-24.04
|
||||
php: 8.2
|
||||
- os: ubuntu-22.04
|
||||
php: 8.1
|
||||
extensions:
|
||||
db: mysqli
|
||||
# PostgreSQL builds always run with the highest PHP supported version.
|
||||
- os: ubuntu-24.04
|
||||
php: 8.4
|
||||
- os: ubuntu-22.04
|
||||
php: 8.3
|
||||
db: pgsql
|
||||
|
||||
steps:
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
uses: moodlehq/mysql-action@v1
|
||||
with:
|
||||
collation server: utf8mb4_bin
|
||||
mysql version: 8.4
|
||||
mysql version: 8.0
|
||||
mysql database: test
|
||||
mysql user: test
|
||||
mysql password: test
|
||||
@@ -88,7 +88,7 @@ jobs:
|
||||
if: ${{ matrix.db == 'pgsql' }}
|
||||
uses: m4nu56/postgresql-action@v1
|
||||
with:
|
||||
postgresql version: 14
|
||||
postgresql version: 13
|
||||
postgresql db: test
|
||||
postgresql user: test
|
||||
postgresql password: test
|
||||
@@ -122,6 +122,3 @@ jobs:
|
||||
dbtype: ${{ matrix.db }}
|
||||
phpunit_options: ${{ secrets.phpunit_options }}
|
||||
run: vendor/bin/phpunit $phpunit_options ${{ inputs.phpunit_extra_options }}
|
||||
|
||||
- name: Git status
|
||||
run: git status
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
php: [8.2, 8.4]
|
||||
php: [8.1, 8.3]
|
||||
steps:
|
||||
- name: Construct repository URL
|
||||
run: echo "REPOSITORY_URL=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" >> $GITHUB_ENV
|
||||
|
||||
@@ -8,7 +8,7 @@ on:
|
||||
required: false
|
||||
default: ''
|
||||
env:
|
||||
php: 8.4
|
||||
php: 8.3
|
||||
|
||||
jobs:
|
||||
Grunt:
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-latest
|
||||
php: 8.4
|
||||
php: 8.3
|
||||
# Ideally we should use mysql/mariadb, but they are 4x slower without tweaks and configuration
|
||||
# so let's run only postgres (1.5h vs 6h) only, If some day we want to improve the mysql runs,
|
||||
# this is the place to enable them.
|
||||
@@ -59,16 +59,16 @@ jobs:
|
||||
db: pgsql
|
||||
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium, zip
|
||||
- os: windows-latest
|
||||
php: 8.2
|
||||
php: 8.1
|
||||
db: pgsql
|
||||
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium, zip
|
||||
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium
|
||||
|
||||
steps:
|
||||
- name: Setting up DB mysql
|
||||
if: ${{ matrix.db == 'mysqli' }}
|
||||
uses: shogo82148/actions-setup-mysql@v1
|
||||
with:
|
||||
mysql-version: 8.4
|
||||
mysql-version: 8.0
|
||||
user: test
|
||||
password: test
|
||||
|
||||
@@ -128,7 +128,7 @@ jobs:
|
||||
|
||||
- name: Setting up redis service
|
||||
run: |
|
||||
choco install redis --version 5.0.7 --no-progress
|
||||
choco install redis-64 --version 3.0.503 --no-progress
|
||||
nssm install redis redis-server
|
||||
nssm start redis
|
||||
|
||||
|
||||
@@ -58,5 +58,3 @@ moodle-plugin-ci.phar
|
||||
.hugo_build.lock
|
||||
phpcs.xml
|
||||
jsconfig.json
|
||||
UPGRADING-CURRENT.md
|
||||
.phpunit.cache
|
||||
|
||||
+11
-49
@@ -40,20 +40,9 @@ const fetchComponentData = () => {
|
||||
if (!Object.entries(componentData).length) {
|
||||
componentData.subsystems = {};
|
||||
componentData.pathList = [];
|
||||
componentData.components = {};
|
||||
componentData.standardComponents = {};
|
||||
|
||||
// Fetch the component definiitions from the distributed JSON file.
|
||||
const components = JSON.parse(fs.readFileSync(`${gruntFilePath}/lib/components.json`));
|
||||
const pluginData = JSON.parse(fs.readFileSync(`${gruntFilePath}/lib/plugins.json`));
|
||||
|
||||
componentData.pluginTypes = components.plugintypes;
|
||||
|
||||
const standardPlugins = Object.entries(pluginData.standard).map(
|
||||
([pluginType, pluginNames]) => {
|
||||
return pluginNames.map(pluginName => `${pluginType}_${pluginName}`);
|
||||
}
|
||||
).reduce((acc, val) => acc.concat(val), []);
|
||||
|
||||
// Build the list of moodle subsystems.
|
||||
componentData.subsystems.lib = 'core';
|
||||
@@ -66,19 +55,8 @@ const fetchComponentData = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// The list of components includes the list of subsystems.
|
||||
componentData.components = {...componentData.subsystems};
|
||||
|
||||
const subpluginAdder = (subpluginType, subpluginTypePath) => {
|
||||
glob.sync(`${subpluginTypePath}/*/version.php`).forEach(versionPath => {
|
||||
const componentPath = fs.realpathSync(path.dirname(versionPath));
|
||||
const componentName = path.basename(componentPath);
|
||||
const frankenstyleName = `${subpluginType}_${componentName}`;
|
||||
|
||||
componentData.components[`${subpluginTypePath}/${componentName}`] = frankenstyleName;
|
||||
componentData.pathList.push(componentPath);
|
||||
});
|
||||
};
|
||||
// The list of components incldues the list of subsystems.
|
||||
componentData.components = componentData.subsystems;
|
||||
|
||||
// Go through each of the plugintypes.
|
||||
Object.entries(components.plugintypes).forEach(([pluginType, pluginTypePath]) => {
|
||||
@@ -95,36 +73,20 @@ const fetchComponentData = () => {
|
||||
if (fs.existsSync(subPluginConfigurationFile)) {
|
||||
const subpluginList = JSON.parse(fs.readFileSync(fs.realpathSync(subPluginConfigurationFile)));
|
||||
|
||||
if (subpluginList.subplugintypes) {
|
||||
Object.entries(subpluginList.subplugintypes).forEach(([subpluginType, subpluginTypePath]) => {
|
||||
subpluginAdder(
|
||||
subpluginType,
|
||||
`${pluginTypePath}/${componentName}/${subpluginTypePath}`
|
||||
);
|
||||
Object.entries(subpluginList.plugintypes).forEach(([subpluginType, subpluginTypePath]) => {
|
||||
glob.sync(`${subpluginTypePath}/*/version.php`).forEach(versionPath => {
|
||||
const componentPath = fs.realpathSync(path.dirname(versionPath));
|
||||
const componentName = path.basename(componentPath);
|
||||
const frankenstyleName = `${subpluginType}_${componentName}`;
|
||||
|
||||
componentData.components[`${subpluginTypePath}/${componentName}`] = frankenstyleName;
|
||||
componentData.pathList.push(componentPath);
|
||||
});
|
||||
} else if (subpluginList.plugintypes) {
|
||||
Object.entries(subpluginList.plugintypes).forEach(([subpluginType, subpluginTypePath]) => {
|
||||
subpluginAdder(subpluginType, subpluginTypePath);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Create a list of the standard subsystem and plugins.
|
||||
componentData.standardComponents = Object.fromEntries(
|
||||
Object.entries(componentData.components).filter(([, name]) => {
|
||||
if (name === 'core' || name.startsWith('core_')) {
|
||||
return true;
|
||||
}
|
||||
return standardPlugins.indexOf(name) !== -1;
|
||||
})
|
||||
);
|
||||
|
||||
componentData.componentMapping = Object.fromEntries(
|
||||
Object.entries(componentData.components).map(([path, name]) => [name, path])
|
||||
);
|
||||
}
|
||||
|
||||
return componentData;
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import * as Components from '../../components.js';
|
||||
|
||||
const componentData = Components.fetchComponentData();
|
||||
|
||||
/**
|
||||
* The standard components shipped with core Moodle.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
export const standardComponents = componentData.standardComponents;
|
||||
|
||||
/**
|
||||
* All components of the current Moodle instance.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
export const allComponents = componentData.components;
|
||||
|
||||
/**
|
||||
* Get all components of the current Moodle instance.
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const getAllComponents = () => {
|
||||
let components = new Map(Object.entries(componentData.pluginTypes).map(([value, path]) => ([path,{
|
||||
path,
|
||||
value,
|
||||
name: `${value} (plugin type)`,
|
||||
}])));
|
||||
|
||||
Object
|
||||
.entries(componentData.components)
|
||||
.filter(([path, value]) => Object.values(componentData.standardComponents).includes(value))
|
||||
.forEach(([path, value]) => {
|
||||
const entry = {
|
||||
path,
|
||||
value,
|
||||
name: value,
|
||||
};
|
||||
if (Object.values(componentData.subsystems).includes(value)) {
|
||||
if (components.has(path)) {
|
||||
entry.name = `${value} (subsystem / plugintype)`;
|
||||
} else {
|
||||
entry.name = `${value} (subsystem)`;
|
||||
}
|
||||
}
|
||||
|
||||
components.set(path, entry);
|
||||
});
|
||||
|
||||
return Array.from(components.values());
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether the specified component is a standard component shipped with core Moodle.
|
||||
*
|
||||
* @param {string} componentName
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isStandardComponent = (componentName) => {
|
||||
if (Object.values(componentData.standardComponents).includes(componentName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Object.keys(componentData.pluginTypes).includes(componentName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
export const rewritePlugintypeAsSubsystem = (componentName) => {
|
||||
if (Object.keys(componentData.pluginTypes).includes(componentName)) {
|
||||
const pluginTypePath = componentData.pluginTypes[componentName];
|
||||
if (Object.keys(componentData.subsystems).includes(pluginTypePath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether the specified component is a community component.
|
||||
*
|
||||
* @param {string} componentName
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isCommunityComponent = (componentName) => {
|
||||
if (isStandardComponent(componentName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Object.values(componentData.components).indexOf(componentName) !== -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sort method for components.
|
||||
*
|
||||
* This method sorts components putting `core` first, followed by core subsystems, then everything else.
|
||||
*
|
||||
* @param {String} a
|
||||
* @param {String} b
|
||||
* @returns {Number}
|
||||
*/
|
||||
export const sortComponents = (a, b) => {
|
||||
// Always put 'core' first.
|
||||
if (a === 'core') {
|
||||
return -1;
|
||||
} else if (b === 'core') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Put core subsystems next.
|
||||
if (a.startsWith('core_') && !b.startsWith('core_')) {
|
||||
return -1;
|
||||
} else if (b.startsWith('core_') && !a.startsWith('core_')) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Sort alphabetically for everything else.
|
||||
return a.localeCompare(b);
|
||||
};
|
||||
@@ -1,85 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
// 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/>.
|
||||
|
||||
import inquirer from 'inquirer';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { createNote } from './note.mjs';
|
||||
import { getInitialValues } from './helpers.mjs';
|
||||
import * as Prompts from './prompts.mjs';
|
||||
import logger from './logger.mjs';
|
||||
|
||||
export default async (options) => {
|
||||
// Processs the initial values.
|
||||
const initialValues = getInitialValues(options);
|
||||
|
||||
// Fetch information.
|
||||
const messages = [];
|
||||
const { issueNumber } = await inquirer.prompt([
|
||||
Prompts.getIssuePrompt(),
|
||||
], initialValues);
|
||||
|
||||
let selection = {};
|
||||
let notePath;
|
||||
do {
|
||||
selection = {};
|
||||
selection = await inquirer.prompt([
|
||||
Prompts.getComponentsPrompt(),
|
||||
Prompts.getTypePrompt(),
|
||||
Prompts.getMessagePromptInput(),
|
||||
], initialValues);
|
||||
if (selection.message === '') {
|
||||
selection = Object.assign(
|
||||
selection,
|
||||
await inquirer.prompt([
|
||||
Prompts.getMessagePromptEditor(),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
logger.info(`
|
||||
Creating upgrade note with the following options:
|
||||
|
||||
- Issue: ${chalk.bold(issueNumber)}
|
||||
- Component: ${chalk.bold(selection.components)}
|
||||
- Type: ${chalk.bold(selection.type)}
|
||||
- Message:
|
||||
${chalk.bold(selection.message)}
|
||||
`);
|
||||
|
||||
messages.push({
|
||||
components: [selection.components],
|
||||
type: selection.type,
|
||||
message: selection.message,
|
||||
});
|
||||
|
||||
// Save the note so far.
|
||||
if (notePath) {
|
||||
await createNote(issueNumber, messages, notePath);
|
||||
logger.info(`Updated note at: ${chalk.underline(chalk.bold(notePath))}`);
|
||||
} else {
|
||||
notePath = await createNote(issueNumber, messages);
|
||||
logger.info(`Note created at: ${chalk.underline(chalk.bold(notePath))}`);
|
||||
}
|
||||
|
||||
selection = Object.assign(
|
||||
selection,
|
||||
await inquirer.prompt([
|
||||
Prompts.getAddAnotherPrompt(),
|
||||
], initialValues),
|
||||
);
|
||||
} while (selection.addAnother);
|
||||
};
|
||||
@@ -1,357 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
// 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/>.
|
||||
|
||||
import chalk from 'chalk';
|
||||
import { getAllComponents } from './components.mjs';
|
||||
import { getCombinedNotesByComponent, deleteAllNotes } from './note.mjs';
|
||||
import { getNoteName } from './noteTypes.mjs';
|
||||
import { writeFile, readFile, unlink } from 'fs/promises';
|
||||
import { join as joinPath } from 'path';
|
||||
import logger from './logger.mjs';
|
||||
import { getCurrentVersion } from './helpers.mjs';
|
||||
|
||||
/**
|
||||
* Helper to fetch the current notes from a file.
|
||||
*
|
||||
* @param {string} file
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
const getCurrentNotes = async (file) => {
|
||||
try {
|
||||
return await readFile(file, 'utf8');
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the UPGRADING.md file.
|
||||
*
|
||||
* @param {string} upgradeNotes
|
||||
* @param {Object} options
|
||||
* @param {boolean} options.deleteNotes
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const updateUpgradeNotes = async (upgradeNotes, options) => {
|
||||
const fileName = 'UPGRADING.md';
|
||||
// Write the notes to a file.
|
||||
logger.info(`Writing notes to ${chalk.underline(chalk.bold(fileName))}`);
|
||||
// Prepend to the existing file.
|
||||
const existingContent = await getCurrentNotes(fileName);
|
||||
if (existingContent) {
|
||||
await writeFile(fileName, getUpdatedNotes(existingContent, upgradeNotes));
|
||||
} else {
|
||||
// This should not normally happen.
|
||||
await writeFile(fileName, upgradeNotes);
|
||||
}
|
||||
|
||||
if (options.deleteNotes) {
|
||||
logger.warn(`>>> Deleting all notes <<<`)
|
||||
// Delete the notes.
|
||||
deleteAllNotes();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the current summary notes.
|
||||
*
|
||||
* @param {string} upgradeNotes
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const createCurrentSummary = async (upgradeNotes) => {
|
||||
const fileName = 'UPGRADING-CURRENT.md';
|
||||
const notes = `# Moodle upgrade notes\n\n${upgradeNotes}`;
|
||||
await writeFile(fileName, notes);
|
||||
|
||||
logger.info(`Running upgrade notes written to ${chalk.underline(chalk.bold(fileName))}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the indexes of the lines that contain the version headings.
|
||||
*
|
||||
* @param {array<string>} lines
|
||||
* @returns {array<object>}
|
||||
*/
|
||||
const getVersionLineIndexes = (lines) => {
|
||||
const h2Indexes = [];
|
||||
lines.forEach((line, index) => {
|
||||
const matches = line.match(/^##\s(?<version>.*)$/);
|
||||
if (matches) {
|
||||
h2Indexes.push({
|
||||
index,
|
||||
line,
|
||||
version: matches.groups.version,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return h2Indexes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the index of the Unreleased heading.
|
||||
*
|
||||
* @param {array<object>} versionHeadings
|
||||
* @returns {number}
|
||||
*/
|
||||
const findUnreleasedHeadingIndex = (versionHeadings) => versionHeadings.findIndex((heading) => {
|
||||
if (heading.version === 'Unreleased') {
|
||||
// Used if version cannot be guessed.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (heading.version.endsWith('+')) {
|
||||
// Weekly release for a stable branch.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (heading.version.match(/beta|rc\d/)) {
|
||||
// Beta and RC rolls are treated as weeklies.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (heading.version.endsWith('dev')) {
|
||||
// Development version.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the before and after content, to facilitate replacing any existing Unreleased notes.
|
||||
*
|
||||
* @param {array<string>} lines
|
||||
* @returns {Object} {beforeContent: string, afterContent: string}
|
||||
*/
|
||||
const getBeforeAndAfterContent = (lines) => {
|
||||
const existingLines = lines.split('\n');
|
||||
const versionHeadings = getVersionLineIndexes(existingLines);
|
||||
|
||||
if (versionHeadings.length > 0) {
|
||||
const unreleasedHeadingIndex = findUnreleasedHeadingIndex(versionHeadings);
|
||||
if (unreleasedHeadingIndex !== -1) {
|
||||
const beforeContent = existingLines.slice(0, versionHeadings[unreleasedHeadingIndex].index).join('\n');
|
||||
if (versionHeadings.length > unreleasedHeadingIndex + 1) {
|
||||
const afterContent = existingLines.slice(versionHeadings[unreleasedHeadingIndex + 1].index).join('\n');
|
||||
return {
|
||||
beforeContent,
|
||||
afterContent,
|
||||
};
|
||||
}
|
||||
return {
|
||||
beforeContent,
|
||||
afterContent: '',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
beforeContent: existingLines.slice(0, versionHeadings[0].index).join('\n'),
|
||||
afterContent: existingLines.slice(versionHeadings[0].index).join('\n'),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
beforeContent: existingLines.join('\n'),
|
||||
afterContent: '',
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the notes for the component.
|
||||
*
|
||||
* @param {string} types
|
||||
* @param {Number} headingLevel
|
||||
* @returns {string}
|
||||
*/
|
||||
const getNotesForComponent = (types, headingLevel) => {
|
||||
let upgradeNotes = '';
|
||||
Object.entries(types).forEach(([type, notes]) => {
|
||||
upgradeNotes += '#'.repeat(headingLevel);
|
||||
upgradeNotes += ` ${getNoteName(type)}\n\n`;
|
||||
notes.forEach(({ message, issueNumber }) => {
|
||||
// Split the message into lines, removing empty lines.
|
||||
const messageLines = message
|
||||
.split('\n')
|
||||
// Remove empty lines between tables, and list entries, but not after lists.
|
||||
.filter((line, index, lines) => {
|
||||
if (line.trim().length === 0) {
|
||||
// This line is empty.
|
||||
|
||||
// If it's the first line in the file, remove it.
|
||||
if (index === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is the last line in the file, remove it.
|
||||
if (index === lines.length - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the previous line relates to a table, remove this line.
|
||||
if (lines[index - 1].match(/^\s*\|/)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the next line is also empty, do not remove this line.
|
||||
if (lines[index + 1].trim().length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do not remove the line if the previous line was a list item.
|
||||
if (lines[index - 1].match(/^\s*[-*]\s/)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (lines[index - 1].match(/^\s*\d+\.\s/)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Preserve all other empty lines by default.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Keep any line which has content.
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
const firstLine = messageLines.shift().trim();
|
||||
upgradeNotes += `- ${firstLine}\n`;
|
||||
|
||||
messageLines
|
||||
.forEach((line) => {
|
||||
upgradeNotes += ` ${line}`.trimEnd() + `\n`;
|
||||
});
|
||||
upgradeNotes += `\n For more information see [${issueNumber}](https://tracker.moodle.org/browse/${issueNumber})\n`;
|
||||
});
|
||||
upgradeNotes += '\n';
|
||||
});
|
||||
|
||||
return upgradeNotes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the updated notes mixed with existing content.
|
||||
*
|
||||
* @param {string} existingContent
|
||||
* @param {string} upgradeNotes
|
||||
*/
|
||||
const getUpdatedNotes = (existingContent, upgradeNotes) => {
|
||||
const { beforeContent, afterContent } = getBeforeAndAfterContent(existingContent);
|
||||
const newContent = `${beforeContent}\n${upgradeNotes}\n${afterContent}`
|
||||
.split('\n')
|
||||
.filter((line, index, lines) => {
|
||||
if (line === '' && lines[index - 1] === '') {
|
||||
// Remove multiple consecutive empty lines.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
return newContent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the notes for each component.
|
||||
*/
|
||||
const updateComponentNotes = (
|
||||
notes,
|
||||
version,
|
||||
notesFileName = 'UPGRADING.md',
|
||||
removeEmpty = false,
|
||||
) => {
|
||||
return getAllComponents().map(async (component) => {
|
||||
logger.verbose(`Updating notes for ${component.name} into ${component.path}`);
|
||||
const fileName = joinPath(component.path, notesFileName);
|
||||
|
||||
const existingContent = await getCurrentNotes(fileName);
|
||||
|
||||
if (!existingContent) {
|
||||
if (!notes[component.value]) {
|
||||
// No existing notes, and no new notes to add.
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!notes[component.value]) {
|
||||
// There is existing content, but nothing to add.
|
||||
if (removeEmpty) {
|
||||
logger.verbose(`Removing empty notes file ${fileName}`);
|
||||
await unlink(fileName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const componentNotes = notes[component.value];
|
||||
let upgradeNotes = `## ${version}\n\n`;
|
||||
upgradeNotes += getNotesForComponent(componentNotes, 3);
|
||||
|
||||
if (existingContent) {
|
||||
await writeFile(fileName, getUpdatedNotes(existingContent, upgradeNotes));
|
||||
} else {
|
||||
await writeFile(
|
||||
fileName,
|
||||
`# ${component.name} Upgrade notes\n\n${upgradeNotes}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the upgrade notes for a new release.
|
||||
*
|
||||
* @param {string|undefined} version
|
||||
* @param {Object} options
|
||||
* @param {boolean} options.generateUpgradeNotes
|
||||
* @param {boolean} options.deleteNotes
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export default async (version, options = {}) => {
|
||||
const notes = await getCombinedNotesByComponent();
|
||||
|
||||
if (Object.keys(notes).length === 0) {
|
||||
logger.warn('No notes to generate');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!version) {
|
||||
version = await getCurrentVersion();
|
||||
}
|
||||
|
||||
// Generate the upgrade notes for this release.
|
||||
// We have
|
||||
// - a title with the release name
|
||||
// - the change types
|
||||
// - which contain the components
|
||||
// - which document each change
|
||||
let upgradeNotes = `## ${version}\n\n`;
|
||||
|
||||
Object.entries(notes).forEach(([component, types]) => {
|
||||
upgradeNotes += `### ${component}\n\n`;
|
||||
upgradeNotes += getNotesForComponent(types, 4);
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
createCurrentSummary(upgradeNotes),
|
||||
...updateComponentNotes(notes, version, 'UPGRADING-CURRENT.md', true),
|
||||
]);
|
||||
if (options.generateUpgradeNotes) {
|
||||
await Promise.all(updateComponentNotes(notes, version));
|
||||
await updateUpgradeNotes(upgradeNotes, options);
|
||||
}
|
||||
};
|
||||
@@ -1,230 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import chalk from 'chalk';
|
||||
import { isStandardComponent, isCommunityComponent, rewritePlugintypeAsSubsystem } from './components.mjs';
|
||||
import { isValidNoteName } from './noteTypes.mjs';
|
||||
import logger from './logger.mjs';
|
||||
import { readFile } from 'fs/promises';
|
||||
|
||||
/**
|
||||
* Validate an issue number input
|
||||
*
|
||||
* @param {string} input
|
||||
* @returns {string|boolean}
|
||||
*/
|
||||
export const validateIssueNumber = (input) => {
|
||||
if (!input) {
|
||||
return 'You must provide a tracker issue number';
|
||||
}
|
||||
|
||||
if (input.match(/^[a-zA-Z]*-\d+$/)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (input.match(/^\d+$/)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return 'The issue number was not recognised as a valid issue number';
|
||||
};
|
||||
|
||||
/**
|
||||
* Format an issue number input.
|
||||
*
|
||||
* @param {string} input
|
||||
* @returns {string}
|
||||
*/
|
||||
export const formatIssueNumber = (input) => {
|
||||
if (input.match(/^[a-zA-Z]*-\d+$/)) {
|
||||
return input;
|
||||
}
|
||||
|
||||
if (input.match(/^\d+$/)) {
|
||||
return `MDL-${input}`;
|
||||
}
|
||||
|
||||
return input;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate a component.
|
||||
*
|
||||
* @param {string} input
|
||||
* @returns {string|boolean}
|
||||
*/
|
||||
export const validateComponent = (input) => {
|
||||
if (isStandardComponent(input)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isCommunityComponent(input)) {
|
||||
return 'Currently only core plugins are supported.';
|
||||
}
|
||||
|
||||
return 'The component was not recognised as a standard component';
|
||||
};
|
||||
|
||||
export const formatComponent = (input) => {
|
||||
if (rewritePlugintypeAsSubsystem(input)) {
|
||||
return `core_${input}`;
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the initial values from the options.
|
||||
*
|
||||
* @param {object} options
|
||||
* @returns {object}
|
||||
*/
|
||||
export const getInitialValues = (options) => {
|
||||
const initialValues = {};
|
||||
|
||||
const type = getInitialTypeValue(options);
|
||||
if (type) {
|
||||
initialValues.type = type;
|
||||
}
|
||||
|
||||
const issueNumber = getInitialIssueValue(options);
|
||||
if (issueNumber) {
|
||||
initialValues.issueNumber = issueNumber;
|
||||
}
|
||||
|
||||
const component = getInitialComponentValue(options);
|
||||
if (component) {
|
||||
initialValues.components = component;
|
||||
}
|
||||
|
||||
const message = getInitialMessageValue(options);
|
||||
if (message) {
|
||||
initialValues.message = message
|
||||
initialValues.addAnother = false;
|
||||
}
|
||||
|
||||
return initialValues;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the initial type value.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
const getInitialTypeValue = (options) => {
|
||||
if (!options.type) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.type = options.type.trim().toLowerCase();
|
||||
|
||||
if (isValidNoteName(options.type)) {
|
||||
return options.type;
|
||||
}
|
||||
|
||||
logger.warn(`Note type "${chalk.underline(chalk.red(options.type))}" is not valid.`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the initial issue number value.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
|
||||
const getInitialIssueValue = (options) => {
|
||||
if (!options.issue) {
|
||||
return;
|
||||
}
|
||||
options.issue = options.issue.trim().toUpperCase();
|
||||
|
||||
const issueNumberValidated = validateIssueNumber(options.issue);
|
||||
if (issueNumberValidated === true) {
|
||||
const issueNumber = formatIssueNumber(options.issue);
|
||||
if (issueNumber !== options.issue) {
|
||||
logger.warn(
|
||||
`Issue number "${chalk.underline(chalk.red(options.issue))}" was updated to ` +
|
||||
`"${chalk.underline(chalk.green(issueNumber))}"`
|
||||
);
|
||||
}
|
||||
|
||||
return issueNumber;
|
||||
} else {
|
||||
logger.warn(`Issue number "${chalk.underline(chalk.red(options.issue))}" is not valid: ${issueNumberValidated}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the initial component value.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
const getInitialComponentValue = (options) => {
|
||||
if (!options.component) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.component = options.component.trim().toLowerCase();
|
||||
const componentValidated = validateComponent(options.component);
|
||||
if (componentValidated === true) {
|
||||
const component = formatComponent(options.component);
|
||||
if (component !== options.component) {
|
||||
logger.warn(
|
||||
`Component "${chalk.underline(chalk.red(options.component))}" was updated to ` +
|
||||
`"${chalk.underline(chalk.green(component))}"`
|
||||
);
|
||||
}
|
||||
|
||||
return component;
|
||||
} else {
|
||||
logger.warn(`Component "${chalk.underline(chalk.red(options.component))}" is not valid: ${componentValidated}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the initial message value.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
|
||||
const getInitialMessageValue = (options) => {
|
||||
if (!options.message) {
|
||||
return;
|
||||
}
|
||||
|
||||
return options.message.trim();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current version from the project /version.php file.
|
||||
*
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
export const getCurrentVersion = async () => {
|
||||
const versionRegex = new RegExp(/^ *\$release *= *['\"](?<release>[^ \+]+\+?) *\(Build:.*/m);
|
||||
try {
|
||||
const versionFile = await readFile('version.php', 'utf8');
|
||||
const match = versionFile.match(versionRegex);
|
||||
if (match) {
|
||||
return match.groups.release;
|
||||
}
|
||||
} catch(error) {
|
||||
logger.error('Unable to read the version file');
|
||||
}
|
||||
|
||||
return "Unreleased";
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
// 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/>.
|
||||
|
||||
import winston from 'winston';
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.simple()
|
||||
),
|
||||
transports: [
|
||||
new winston.transports.Console(),
|
||||
],
|
||||
});
|
||||
|
||||
export default logger;
|
||||
@@ -1,194 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import yaml from 'js-yaml';
|
||||
import path from 'path';
|
||||
import { writeFile, mkdir, readdir, readFile, unlink } from 'fs/promises';
|
||||
import { isValidNoteName, sortNoteTypes } from './noteTypes.mjs';
|
||||
import { sortComponents } from './components.mjs';
|
||||
|
||||
const unreleasedPath = path.resolve('.upgradenotes');
|
||||
|
||||
/**
|
||||
* Get the filename for the note.
|
||||
*
|
||||
* @param {string} issueNumnber The issue number
|
||||
* @returns {string}
|
||||
*/
|
||||
const getFilename = (issueNumber) => {
|
||||
const dateTimeFormat = new Intl.DateTimeFormat(undefined, {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
fractionalSecondDigits: 2,
|
||||
timeZone: 'UTC',
|
||||
});
|
||||
|
||||
const date = Object.fromEntries(
|
||||
dateTimeFormat.formatToParts(new Date())
|
||||
.filter((p) => p.type !== 'literal')
|
||||
.map((p) => ([p.type, p.value]))
|
||||
);
|
||||
|
||||
const dateString = [
|
||||
date.year,
|
||||
date.month,
|
||||
date.day,
|
||||
date.hour,
|
||||
date.minute,
|
||||
date.second,
|
||||
date.fractionalSecond,
|
||||
].join('');
|
||||
|
||||
return `${issueNumber}-${dateString}.yml`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new note.
|
||||
*
|
||||
* @param {string} issueNumber
|
||||
* @param {[type: string]: {message: string}} messages
|
||||
* @returns {string} The path to the note on disk
|
||||
*/
|
||||
export const createNote = async (
|
||||
issueNumber,
|
||||
messages,
|
||||
notePath,
|
||||
) => {
|
||||
const note = {
|
||||
issueNumber,
|
||||
notes: {},
|
||||
};
|
||||
|
||||
messages.forEach(({components, type, message}) => {
|
||||
note.notes[components] = note.notes[components] || [];
|
||||
note.notes[components].push({message, type});
|
||||
});
|
||||
|
||||
if (!notePath) {
|
||||
notePath = path.resolve(unreleasedPath, getFilename(issueNumber));
|
||||
}
|
||||
const noteContent = yaml.dump(note);
|
||||
|
||||
await mkdir(unreleasedPath, {recursive: true});
|
||||
await writeFile(notePath, noteContent);
|
||||
|
||||
return notePath;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all unreleased notes.
|
||||
*
|
||||
* @returns {Promise<{issueNumber: string, components: string[], types: {[type: string]: {message: string}[]}}[]>
|
||||
*/
|
||||
export const getAllNotes = async () => {
|
||||
const files = await readdir(unreleasedPath);
|
||||
const notes = files
|
||||
.filter((file) => file.endsWith('.yml'))
|
||||
.map(async (file) => {
|
||||
const filePath = path.resolve(unreleasedPath, file);
|
||||
const fileContent = await readFile(filePath, 'utf8');
|
||||
|
||||
return {
|
||||
...yaml.load(fileContent),
|
||||
filePath,
|
||||
};
|
||||
});
|
||||
|
||||
return Promise.all(notes);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the list of notes, grouped by note type, then component.
|
||||
*
|
||||
* @returns {Promise<{[type: string]: {[components: string]: {message: string, issueNumber: string}[]}}>}
|
||||
*/
|
||||
export const getCombinedNotes = async () => {
|
||||
const notes = await getAllNotes();
|
||||
const combinedNotes = {};
|
||||
|
||||
notes.forEach((note) => {
|
||||
Object.entries(note.notes).forEach(([components, data]) => {
|
||||
data.forEach((entry) => {
|
||||
if (!isValidNoteName(entry.type)) {
|
||||
throw new Error(`Invalid note type: "${entry.type}" in file ${note.filePath}`);
|
||||
}
|
||||
combinedNotes[entry.type] = combinedNotes[entry.type] || {};
|
||||
combinedNotes[entry.type][components] = combinedNotes[entry.type][components] || [];
|
||||
combinedNotes[entry.type][components].push({message: entry.message, issueNumber: note.issueNumber});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return combinedNotes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the list of notes, grouped by component, then by note type.
|
||||
*
|
||||
* @returns {Promise<{[component: string]: {[type: string]: {message: string, issueNumber: string}[]}}>}
|
||||
*/
|
||||
export const getCombinedNotesByComponent = async () => {
|
||||
const notes = await getAllNotes();
|
||||
const combinedNotes = {};
|
||||
|
||||
notes.forEach((note) => {
|
||||
Object.entries(note.notes).forEach(([component, data]) => {
|
||||
combinedNotes[component] = combinedNotes[component] || {};
|
||||
data.forEach((entry) => {
|
||||
if (!isValidNoteName(entry.type)) {
|
||||
throw new Error(`Invalid note type: "${entry.type}" in file ${note.filePath}`);
|
||||
}
|
||||
combinedNotes[component][entry.type] = combinedNotes[component][entry.type] || [];
|
||||
combinedNotes[component][entry.type].push({
|
||||
component,
|
||||
message: entry.message,
|
||||
issueNumber: note.issueNumber,
|
||||
type: entry.type,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Sort notes by note type.
|
||||
Object.entries(combinedNotes).forEach(([component, types]) => {
|
||||
combinedNotes[component] = Object.fromEntries(
|
||||
Object.entries(types).sort(([a], [b]) => sortNoteTypes(a, b))
|
||||
);
|
||||
});
|
||||
|
||||
// Sort components.
|
||||
return Object.fromEntries(
|
||||
Object.entries(combinedNotes).sort(([a], [b]) => sortComponents(a, b))
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete all unreleased notes.
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export const deleteAllNotes = async () => {
|
||||
const files = await readdir(unreleasedPath);
|
||||
return Promise.all(
|
||||
files
|
||||
.filter((item, index) => files.indexOf(item) === index)
|
||||
.filter((file) => file.endsWith('.yml'))
|
||||
.map((file) => unlink(`${unreleasedPath}/${file}`))
|
||||
);
|
||||
};
|
||||
@@ -1,80 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The note types.
|
||||
*
|
||||
* Matches the suggested order in https://keepachangelog.com/en/1.1.0/.
|
||||
* @type {Object<string, string>}
|
||||
*/
|
||||
const noteTypes = {
|
||||
'improved': 'Added',
|
||||
'changed': 'Changed',
|
||||
'deprecated': 'Deprecated',
|
||||
'removed': 'Removed',
|
||||
'fixed': 'Fixed',
|
||||
};
|
||||
|
||||
/**
|
||||
* The preferred order of note types.
|
||||
*
|
||||
* @type {string[]}
|
||||
*/
|
||||
const preferredOrder = Object.keys(noteTypes);
|
||||
|
||||
/**
|
||||
* Comparison method to sort note types.
|
||||
*
|
||||
* @param {String} a
|
||||
* @param {String} b
|
||||
* @returns {Number}
|
||||
*/
|
||||
export const sortNoteTypes = (a, b) => {
|
||||
const aIndex = preferredOrder.indexOf(a);
|
||||
const bIndex = preferredOrder.indexOf(b);
|
||||
|
||||
if (aIndex === -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bIndex === -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return aIndex - bIndex;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the note names.
|
||||
*
|
||||
* @returns {string[]}
|
||||
*/
|
||||
export const getNoteNames = () => Object.keys(noteTypes);
|
||||
|
||||
/**
|
||||
* Get the human-readable note name.
|
||||
*
|
||||
* @param {string} type
|
||||
* @returns {string}
|
||||
*/
|
||||
export const getNoteName = (type) => noteTypes[type];
|
||||
|
||||
/**
|
||||
* Whether the note name is valid.
|
||||
*
|
||||
* @param {string} type
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isValidNoteName = (type) => noteTypes[type] !== undefined;
|
||||
@@ -1,153 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import inquirer from 'inquirer';
|
||||
import SearchList from 'inquirer-search-list';
|
||||
|
||||
import { getNoteNames } from './noteTypes.mjs';
|
||||
import { getAllComponents } from './components.mjs';
|
||||
import {
|
||||
formatComponent,
|
||||
formatIssueNumber,
|
||||
validateComponent,
|
||||
validateIssueNumber,
|
||||
} from './helpers.mjs';
|
||||
|
||||
/**
|
||||
* A Search List which accepts an initial value.
|
||||
*/
|
||||
class SearchListWithInitialValue extends SearchList {
|
||||
constructor(options, ...args) {
|
||||
super(options, ...args);
|
||||
|
||||
if (options.default) {
|
||||
const pointer = this.filterList.findIndex((item) => {
|
||||
return item.value === options.default;
|
||||
});
|
||||
if (pointer > -1) {
|
||||
this.pointer = pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inquirer.registerPrompt('search-list', SearchListWithInitialValue);
|
||||
|
||||
/**
|
||||
* Get the issue type prompt.
|
||||
*
|
||||
* @param {string} defaultData The initially selected value
|
||||
* @returns {Object}
|
||||
*/
|
||||
export const getTypePrompt = (defaultData) => ({
|
||||
default: defaultData,
|
||||
type: 'search-list',
|
||||
message: 'Type of change',
|
||||
name: 'type',
|
||||
choices: getNoteNames(),
|
||||
validate: (selection) => {
|
||||
if (selection.length < 1) {
|
||||
return 'You must select at least one type of change';
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the component prompt.
|
||||
*
|
||||
* @param {string} [defaultValue='core'] The initally selected value.
|
||||
* @returns
|
||||
*/
|
||||
export const getComponentsPrompt = (defaultValue) => {
|
||||
if (!defaultValue ) {
|
||||
defaultValue = 'core';
|
||||
}
|
||||
|
||||
return {
|
||||
choices: getAllComponents(),
|
||||
default: defaultValue,
|
||||
type: 'search-list',
|
||||
message: 'Component',
|
||||
name: 'components',
|
||||
validate: validateComponent,
|
||||
filter: formatComponent,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the issue number prompt as an inline input.
|
||||
*
|
||||
* @param {string} defaultData
|
||||
* @returns {object}
|
||||
*/
|
||||
export const getIssuePrompt = (defaultData) => ({
|
||||
default: defaultData,
|
||||
type: 'input',
|
||||
message: 'Tracker issue number',
|
||||
name: 'issueNumber',
|
||||
validate: validateIssueNumber,
|
||||
filter: formatIssueNumber,
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a message prompt.
|
||||
*
|
||||
* @param {string} defaultData
|
||||
* @returns
|
||||
*/
|
||||
export const getMessagePromptEditor = (defaultData) => ({
|
||||
default: defaultData,
|
||||
type: process.stdin.isTTY ? 'editor' : 'input',
|
||||
postfix: '.md',
|
||||
message: 'Message',
|
||||
name: 'message',
|
||||
waitUserInput: false,
|
||||
validate: (input) => {
|
||||
if (!input) {
|
||||
return 'You must provide a message';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// Remove any trailing whitespace.
|
||||
filter: (input) => input.split('\n').map((line) => line.trimEnd()).join('\n'),
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a message prompt.
|
||||
*
|
||||
* @param {string} defaultData
|
||||
* @returns
|
||||
*/
|
||||
export const getMessagePromptInput = (defaultData) => ({
|
||||
default: defaultData,
|
||||
type: 'input',
|
||||
message: 'Message (leave empty to use editor)',
|
||||
name: 'message',
|
||||
filter: (input) => input.trim(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a prompt to ask the user if they wish to add another entry.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
export const getAddAnotherPrompt = () => ({
|
||||
type: 'confirm',
|
||||
message: 'Do you want to add another note?',
|
||||
default: false,
|
||||
name: 'addAnother',
|
||||
});
|
||||
@@ -1,103 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
// 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/>.
|
||||
|
||||
import { Argument, Option, program } from 'commander';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { getNoteNames } from './notes/src/noteTypes.mjs';
|
||||
import createAction from './notes/src/create.mjs';
|
||||
import generateAction from './notes/src/generate.mjs';
|
||||
import logger from './notes/src/logger.mjs';
|
||||
|
||||
console.log(`
|
||||
${chalk.bold(chalk.underline(chalk.green('Moodle Upgrade Notes Generator')))}
|
||||
|
||||
This tool is used to generate the upgrade notes for changes you make in Moodle.
|
||||
|
||||
Please remember that the intended audience of these changes is
|
||||
${chalk.italic('plugin developers')} who need to know how to update their plugins
|
||||
for a new Moodle version.
|
||||
|
||||
Upgrade notes should not be used to document changes for site administrators, or
|
||||
for internal API changes which are not expected to be used outside of the
|
||||
relevant component.
|
||||
`)
|
||||
|
||||
program.configureHelp({
|
||||
helpWidth: 100,
|
||||
});
|
||||
|
||||
program.on('option:verbose', () => {
|
||||
logger.level = 'verbose';
|
||||
});
|
||||
|
||||
program.addOption(
|
||||
new Option(
|
||||
'-v, --verbose',
|
||||
'Output more information during the generation process',
|
||||
)
|
||||
.default(false)
|
||||
);
|
||||
|
||||
// Define the command line options.
|
||||
program
|
||||
.command('create')
|
||||
.summary('Generate a new upgrade note')
|
||||
.addOption(
|
||||
new Option('-t, --type <type>', `The type of change to document. Valid types are: ${getNoteNames().join(', ')}`)
|
||||
)
|
||||
.addOption(new Option('-i, --issue <issue>', 'The tracker issue number'))
|
||||
.addOption(new Option('-c, --component <component>', 'The component to write a note for'))
|
||||
.addOption(new Option(
|
||||
'-m, --message <message>',
|
||||
'The message to use for the upgrade note',
|
||||
))
|
||||
.action((options) => createAction(options));
|
||||
|
||||
program
|
||||
.command('summary')
|
||||
.summary('Generate a local copy of the upgrade notes summary')
|
||||
.addArgument(
|
||||
new Argument('[version]', 'The Moodle version to create the summary notes for')
|
||||
)
|
||||
.action((version) => generateAction(version));
|
||||
|
||||
program
|
||||
.command('release')
|
||||
.summary('Generate the markdown copies of the upgrade notes for a Moodle release')
|
||||
.addArgument(
|
||||
new Argument('[version]', 'The Moodle version to create the release notes for')
|
||||
)
|
||||
.addOption(
|
||||
new Option(
|
||||
'--generate-upgrade-notes',
|
||||
'Generate the UPGRADING.md notes for the release. ' +
|
||||
'Note: This option is intended for use by the release manager when generating the upgrade notes.',
|
||||
)
|
||||
.default(true)
|
||||
)
|
||||
.addOption(
|
||||
new Option(
|
||||
'-d, --delete-notes',
|
||||
'Delete the notes after generating the UPGRADING.md notes for the release. ' +
|
||||
'Note: This option is intended for use by the release manager when generating the upgrade notes.' +
|
||||
'This option has no effect unless --generate-upgrade-notes is also set.'
|
||||
)
|
||||
.default(false)
|
||||
)
|
||||
.action((version, options) => generateAction(version, options));
|
||||
|
||||
program.parse();
|
||||
-2608
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
# core_admin (subsystem) Upgrade notes
|
||||
|
||||
## 4.5rc1
|
||||
|
||||
### Removed
|
||||
|
||||
- The HTTP Server setting "Use slash arguments" (slasharguments) configuration setting and related to it has been removed. Calling the option with $CFG->slasharguments or get_config('slasharguments') is no longer available.
|
||||
|
||||
For more information see [MDL-62640](https://tracker.moodle.org/browse/MDL-62640)
|
||||
@@ -1,65 +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/>.
|
||||
|
||||
/**
|
||||
* Manage AI subsystem plugins settings.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2024 Matt Porritt <matt.porritt@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once('../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
$action = required_param('action', PARAM_ALPHANUMEXT);
|
||||
$type = required_param('type', PARAM_PLUGIN); // Must be provider or placement.
|
||||
$name = required_param('name', PARAM_PLUGIN); // Plugin name, e.g openai.
|
||||
|
||||
$syscontext = context_system::instance();
|
||||
$PAGE->set_url('/admin/ai.php');
|
||||
$PAGE->set_context($syscontext);
|
||||
|
||||
require_admin();
|
||||
require_sesskey();
|
||||
|
||||
$return = new moodle_url('/admin/settings.php', ['section' => "aisettings$type"]);
|
||||
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type("ai$type");
|
||||
$sortorder = array_flip(array_keys($plugins));
|
||||
|
||||
if (!isset($plugins[$name])) {
|
||||
throw new moodle_exception('aipluginnotfound', 'core_ai', $return, $name);
|
||||
}
|
||||
|
||||
$plugintypename = $plugins[$name]->type . '_' . $plugins[$name]->name;
|
||||
|
||||
switch ($action) {
|
||||
case 'disable':
|
||||
if ($plugins[$name]->is_enabled()) {
|
||||
$class = core_plugin_manager::resolve_plugininfo_class("aisettings$type");
|
||||
$class::enable_plugin($name, false);
|
||||
}
|
||||
break;
|
||||
case 'enable':
|
||||
if (!$plugins[$name]->is_enabled()) {
|
||||
$class = core_plugin_manager::resolve_plugininfo_class("aisettings$type");
|
||||
$class::enable_plugin($name, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
redirect($return);
|
||||
Vendored
-12
@@ -1,12 +0,0 @@
|
||||
define("core_admin/expand_hash",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=_exports.expandSection=void 0;
|
||||
/**
|
||||
* Expand the collapse section element.
|
||||
*
|
||||
* @module core_admin/expand_hash
|
||||
* @copyright Meirza <meirza.arson@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since 4.5
|
||||
*/
|
||||
const SELECTORS_COLLAPSE_ELEMENTS='[data-bs-toggle="collapse"]',SELECTORS_FOCUSTHENEXPAND_ELEMENTS=".focus-expand";_exports.init=()=>{const focusexpand=document.querySelector(SELECTORS_FOCUSTHENEXPAND_ELEMENTS);null==focusexpand||focusexpand.addEventListener("click",(()=>{expandSection("".concat(focusexpand.getAttribute("href")))}))};const expandSection=hash=>{const container=document.querySelector(hash),targetContainer=null==container?void 0:container.querySelector(SELECTORS_COLLAPSE_ELEMENTS);if("false"===(null==targetContainer?void 0:targetContainer.getAttribute("aria-expanded"))){const collapseId=targetContainer.getAttribute("aria-controls"),collapseContainer=document.getElementById(collapseId);collapseContainer.classList.remove("collapse"),collapseContainer.classList.add("show"),targetContainer.setAttribute("aria-expanded","true"),targetContainer.classList.remove("collapsed");const collapseElement=document.querySelector(".collapseexpand.collapsemenu");collapseElement.setAttribute("aria-expanded","true"),collapseElement.classList.remove("collapsed")}};_exports.expandSection=expandSection}));
|
||||
|
||||
//# sourceMappingURL=expand_hash.min.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"expand_hash.min.js","sources":["../src/expand_hash.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Expand the collapse section element.\n *\n * @module core_admin/expand_hash\n * @copyright Meirza <meirza.arson@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.5\n */\n\nconst SELECTORS = {\n COLLAPSE_ELEMENTS: '[data-bs-toggle=\"collapse\"]',\n FOCUSTHENEXPAND_ELEMENTS: '.focus-expand',\n};\n\n/**\n * Initializes the focus and expand functionality.\n */\nexport const init = () => {\n // Select all collapsible elements only.\n const focusexpand = document.querySelector(SELECTORS.FOCUSTHENEXPAND_ELEMENTS);\n\n // Add click event listener to the anchor element\n focusexpand?.addEventListener('click', () => {\n expandSection(`${focusexpand.getAttribute('href')}`);\n });\n};\n\n/**\n * Expands a section based on the provided URL hash.\n *\n * This function takes a hash string, finds the corresponding element in the DOM,\n * and expands it if it is currently collapsed. It updates the necessary ARIA\n * attributes and classes to reflect the expanded state.\n *\n * @param {string} hash - The hash (e.g., '#elementId') of the element to expand.\n */\nexport const expandSection = (hash) => {\n const container = document.querySelector(hash);\n const targetContainer = container?.querySelector(SELECTORS.COLLAPSE_ELEMENTS);\n\n if (targetContainer?.getAttribute('aria-expanded') === 'false') {\n const collapseId = targetContainer.getAttribute('aria-controls');\n const collapseContainer = document.getElementById(collapseId);\n\n // Show the content.\n collapseContainer.classList.remove('collapse');\n collapseContainer.classList.add('show');\n\n // Update aria-expanded attribute to reflect the new state.\n targetContainer.setAttribute('aria-expanded', 'true');\n targetContainer.classList.remove('collapsed');\n\n // Get collapse expand menu element.\n const collapseElement = document.querySelector('.collapseexpand.collapsemenu');\n // Ensure it gets noticed to make it work.\n collapseElement.setAttribute('aria-expanded', 'true');\n collapseElement.classList.remove('collapsed');\n }\n};\n"],"names":["SELECTORS","focusexpand","document","querySelector","addEventListener","expandSection","getAttribute","hash","container","targetContainer","collapseId","collapseContainer","getElementById","classList","remove","add","setAttribute","collapseElement"],"mappings":";;;;;;;;;MAwBMA,4BACiB,8BADjBA,mCAEwB,8BAMV,WAEVC,YAAcC,SAASC,cAAcH,oCAG3CC,MAAAA,aAAAA,YAAaG,iBAAiB,SAAS,KACnCC,wBAAiBJ,YAAYK,aAAa,oBAarCD,cAAiBE,aACpBC,UAAYN,SAASC,cAAcI,MACnCE,gBAAkBD,MAAAA,iBAAAA,UAAWL,cAAcH,gCAEM,WAAnDS,MAAAA,uBAAAA,gBAAiBH,aAAa,kBAA8B,OACtDI,WAAaD,gBAAgBH,aAAa,iBAC1CK,kBAAoBT,SAASU,eAAeF,YAGlDC,kBAAkBE,UAAUC,OAAO,YACnCH,kBAAkBE,UAAUE,IAAI,QAGhCN,gBAAgBO,aAAa,gBAAiB,QAC9CP,gBAAgBI,UAAUC,OAAO,mBAG3BG,gBAAkBf,SAASC,cAAc,gCAE/Cc,gBAAgBD,aAAa,gBAAiB,QAC9CC,gBAAgBJ,UAAUC,OAAO"}
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
define("core_admin/plugin_management_table",["exports","core_table/dynamic","core_table/local/dynamic/selectors","core/ajax","core/pending","core/notification"],(function(_exports,_dynamic,Selectors,_ajax,_pending,_notification){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,Selectors=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Selectors),_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};let watching=!1;return _exports.default=class{constructor(){!function(obj,key,value){key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value}(this,"clickHandlers",[]),this.addClickHandler(this.handleStateToggle),this.addClickHandler(this.handleMoveUpDown),this.registerEventListeners()}static init(){watching||(watching=!0,new this)}addClickHandler(handler){this.clickHandlers.push(handler.bind(this))}registerEventListeners(){document.addEventListener("click",function(e){const tableRoot=this.getTableRoot(e);tableRoot&&this.clickHandlers.forEach((handler=>handler(tableRoot,e)))}.bind(this))}getTableRoot(e){const tableRoot=e.target.closest(Selectors.main.region);return tableRoot||!1}setPluginState(methodname,plugin,state){return(0,_ajax.call)([{methodname:methodname,args:{plugin:plugin,state:state}}])[0]}setPluginOrder(methodname,plugin,direction){return(0,_ajax.call)([{methodname:methodname,args:{plugin:plugin,direction:direction}}])[0]}async handleStateToggle(tableRoot,e){const stateToggle=e.target.closest('[data-action="togglestate"][data-toggle-method]');if(stateToggle){e.preventDefault();const pendingPromise=new _pending.default("core_table/dynamic:togglestate");await this.setPluginState(stateToggle.dataset.toggleMethod,stateToggle.dataset.plugin,"1"===stateToggle.dataset.state?0:1);const[updatedRoot]=await Promise.all([(0,_dynamic.refreshTableContent)(tableRoot),(0,_notification.fetchNotifications)()]);updatedRoot.querySelector('[data-action="togglestate"][data-plugin="'.concat(stateToggle.dataset.plugin,'"]')).focus(),this.removeTooltips(),pendingPromise.resolve()}}async handleMoveUpDown(tableRoot,e){const actionLink=e.target.closest('[data-action="move"][data-method][data-direction]');if(!actionLink)return;e.preventDefault();const pendingPromise=new _pending.default("core_table/dynamic:processAction");await this.setPluginOrder(actionLink.dataset.method,actionLink.dataset.plugin,"up"===actionLink.dataset.direction?-1:1);const[updatedRoot]=await Promise.all([(0,_dynamic.refreshTableContent)(tableRoot),(0,_notification.fetchNotifications)()]),exactMatch=updatedRoot.querySelector('[data-action="move"][data-plugin="'.concat(actionLink.dataset.plugin,'"][data-direction="').concat(actionLink.dataset.direction,'"]'));var _updatedRoot$querySel;exactMatch?exactMatch.focus():null===(_updatedRoot$querySel=updatedRoot.querySelector('[data-action="move"][data-plugin="'.concat(actionLink.dataset.plugin,'"]')))||void 0===_updatedRoot$querySel||_updatedRoot$querySel.focus();pendingPromise.resolve()}removeTooltips(){const tooltips=document.querySelectorAll('[id*="tooltip"]');tooltips.length>0&&tooltips.forEach((tooltip=>{tooltip.remove()}))}},_exports.default}));
|
||||
define("core_admin/plugin_management_table",["exports","core_table/dynamic","core_table/local/dynamic/selectors","core/ajax","core/pending","core/notification"],(function(_exports,_dynamic,Selectors,_ajax,_pending,_notification){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,Selectors=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Selectors),_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};let watching=!1;return _exports.default=class{constructor(){!function(obj,key,value){key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value}(this,"clickHandlers",[]),this.addClickHandler(this.handleStateToggle),this.addClickHandler(this.handleMoveUpDown),this.registerEventListeners()}static init(){watching||(watching=!0,new this)}addClickHandler(handler){this.clickHandlers.push(handler.bind(this))}registerEventListeners(){document.addEventListener("click",function(e){const tableRoot=this.getTableRoot(e);tableRoot&&this.clickHandlers.forEach((handler=>handler(tableRoot,e)))}.bind(this))}getTableRoot(e){const tableRoot=e.target.closest(Selectors.main.region);return tableRoot||!1}setPluginState(methodname,plugin,state){return(0,_ajax.call)([{methodname:methodname,args:{plugin:plugin,state:state}}])[0]}setPluginOrder(methodname,plugin,direction){return(0,_ajax.call)([{methodname:methodname,args:{plugin:plugin,direction:direction}}])[0]}async handleStateToggle(tableRoot,e){const stateToggle=e.target.closest('[data-action="togglestate"][data-toggle-method]');if(stateToggle){e.preventDefault();const pendingPromise=new _pending.default("core_table/dynamic:togglestate");await this.setPluginState(stateToggle.dataset.toggleMethod,stateToggle.dataset.plugin,"1"===stateToggle.dataset.state?0:1);const[updatedRoot]=await Promise.all([(0,_dynamic.refreshTableContent)(tableRoot),(0,_notification.fetchNotifications)()]);updatedRoot.querySelector('[data-action="togglestate"][data-plugin="'.concat(stateToggle.dataset.plugin,'"]')).focus(),pendingPromise.resolve()}}async handleMoveUpDown(tableRoot,e){const actionLink=e.target.closest('[data-action="move"][data-method][data-direction]');if(!actionLink)return;e.preventDefault();const pendingPromise=new _pending.default("core_table/dynamic:processAction");await this.setPluginOrder(actionLink.dataset.method,actionLink.dataset.plugin,"up"===actionLink.dataset.direction?-1:1);const[updatedRoot]=await Promise.all([(0,_dynamic.refreshTableContent)(tableRoot),(0,_notification.fetchNotifications)()]),exactMatch=updatedRoot.querySelector('[data-action="move"][data-plugin="'.concat(actionLink.dataset.plugin,'"][data-direction="').concat(actionLink.dataset.direction,'"]'));var _updatedRoot$querySel;exactMatch?exactMatch.focus():null===(_updatedRoot$querySel=updatedRoot.querySelector('[data-action="move"][data-plugin="'.concat(actionLink.dataset.plugin,'"]')))||void 0===_updatedRoot$querySel||_updatedRoot$querySel.focus();pendingPromise.resolve()}},_exports.default}));
|
||||
|
||||
//# sourceMappingURL=plugin_management_table.min.js.map
|
||||
File diff suppressed because one or more lines are too long
-11
@@ -1,11 +0,0 @@
|
||||
define("core_admin/plugins_overview",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=function(){const filters=document.querySelectorAll(SELECTORS_PLUGIN_FILTERS),pluginRows=document.querySelectorAll(SELECTORS_PLUGIN_ROWS),pluginTypeRows=document.querySelectorAll(SELECTORS_PLUGIN_TYPE_ROWS),filterPlugins=target=>{const filterBy=target.getAttribute("data-filterby"),headerVisibility={};for(const row of pluginRows){const type=[...row.classList].find((s=>s.startsWith("type-"))),visible="all"===filterBy||row.classList.contains(filterBy);row.style.display=visible?null:"none",visible&&type&&(headerVisibility[type]=!0)}for(const row of pluginTypeRows){const type=[...row.classList].find((s=>s.startsWith("type-")));if(type){const visible="all"===filterBy||headerVisibility[type];row.style.display=visible?null:"none"}}filters.forEach((el=>el.classList.remove("active"))),target.classList.add("active")};if(filters.forEach((target=>target.addEventListener("click",(e=>{e.preventDefault(),window.history.replaceState({},null,e.target.href),filterPlugins(target)})))),window.location.hash.length>1){const anchor=window.location.hash.substring(1),target=[...filters].find((t=>t.getAttribute("data-filterby")===anchor));target&&filterPlugins(target)}};
|
||||
/**
|
||||
* Allows to filter the plugin list on plugins overview page
|
||||
*
|
||||
* @module core_admin/plugins_overview
|
||||
* @copyright 2024 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
const SELECTORS_PLUGIN_FILTERS="#plugins-overview-panel [data-filterby]",SELECTORS_PLUGIN_ROWS="table#plugins-control-panel tbody tr:not(.plugintypeheader)",SELECTORS_PLUGIN_TYPE_ROWS="table#plugins-control-panel tbody tr.plugintypeheader"}));
|
||||
|
||||
//# sourceMappingURL=plugins_overview.min.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"plugins_overview.min.js","sources":["../src/plugins_overview.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Allows to filter the plugin list on plugins overview page\n *\n * @module core_admin/plugins_overview\n * @copyright 2024 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst SELECTORS = {\n PLUGIN_FILTERS: '#plugins-overview-panel [data-filterby]',\n PLUGIN_ROWS: 'table#plugins-control-panel tbody tr:not(.plugintypeheader)',\n PLUGIN_TYPE_ROWS: 'table#plugins-control-panel tbody tr.plugintypeheader',\n};\n\n/**\n * Initialise filters for the \"Plugins overview\" page\n */\nexport function init() {\n const filters = document.querySelectorAll(SELECTORS.PLUGIN_FILTERS);\n const pluginRows = document.querySelectorAll(SELECTORS.PLUGIN_ROWS);\n const pluginTypeRows = document.querySelectorAll(SELECTORS.PLUGIN_TYPE_ROWS);\n\n const filterPlugins = (target) => {\n const filterBy = target.getAttribute('data-filterby');\n const headerVisibility = {};\n\n // Hide all plugin rows in the plugin table that do not match the filter and show all others.\n for (const row of pluginRows) {\n const type = [...row.classList].find(s => s.startsWith('type-'));\n const visible = filterBy === 'all' ? true : row.classList.contains(filterBy);\n row.style.display = visible ? null : 'none';\n if (visible && type) {\n headerVisibility[type] = true;\n }\n }\n\n // Hide all the plugin type headers that do not have any visible plugins and show all others.\n for (const row of pluginTypeRows) {\n const type = [...row.classList].find(s => s.startsWith('type-'));\n if (type) {\n const visible = filterBy === 'all' || headerVisibility[type];\n row.style.display = visible ? null : 'none';\n }\n }\n\n // Toggle 'active' class for the selected filter.\n filters.forEach(el => el.classList.remove('active'));\n target.classList.add('active');\n };\n\n // Add event listeners for the links changing plugins filters.\n filters\n .forEach(target => target.addEventListener('click', (e) => {\n e.preventDefault();\n window.history.replaceState({}, null, e.target.href);\n filterPlugins(target);\n }));\n\n // Pre-filter plugins based on the current url anchor.\n if (window.location.hash.length > 1) {\n const anchor = window.location.hash.substring(1);\n const target = [...filters].find(t => t.getAttribute('data-filterby') === anchor);\n if (target) {\n filterPlugins(target);\n }\n }\n}\n"],"names":["filters","document","querySelectorAll","SELECTORS","pluginRows","pluginTypeRows","filterPlugins","target","filterBy","getAttribute","headerVisibility","row","type","classList","find","s","startsWith","visible","contains","style","display","forEach","el","remove","add","addEventListener","e","preventDefault","window","history","replaceState","href","location","hash","length","anchor","substring","t"],"mappings":"4JAiCUA,QAAUC,SAASC,iBAAiBC,0BACpCC,WAAaH,SAASC,iBAAiBC,uBACvCE,eAAiBJ,SAASC,iBAAiBC,4BAE3CG,cAAiBC,eACbC,SAAWD,OAAOE,aAAa,iBAC/BC,iBAAmB,OAGpB,MAAMC,OAAOP,WAAY,OACpBQ,KAAO,IAAID,IAAIE,WAAWC,MAAKC,GAAKA,EAAEC,WAAW,WACjDC,QAAuB,QAAbT,UAA4BG,IAAIE,UAAUK,SAASV,UACnEG,IAAIQ,MAAMC,QAAUH,QAAU,KAAO,OACjCA,SAAWL,OACXF,iBAAiBE,OAAQ,OAK5B,MAAMD,OAAON,eAAgB,OACxBO,KAAO,IAAID,IAAIE,WAAWC,MAAKC,GAAKA,EAAEC,WAAW,cACnDJ,KAAM,OACAK,QAAuB,QAAbT,UAAsBE,iBAAiBE,MACvDD,IAAIQ,MAAMC,QAAUH,QAAU,KAAO,QAK7CjB,QAAQqB,SAAQC,IAAMA,GAAGT,UAAUU,OAAO,YAC1ChB,OAAOM,UAAUW,IAAI,cAIzBxB,QACCqB,SAAQd,QAAUA,OAAOkB,iBAAiB,SAAUC,IACjDA,EAAEC,iBACFC,OAAOC,QAAQC,aAAa,GAAI,KAAMJ,EAAEnB,OAAOwB,MAC/CzB,cAAcC,aAIdqB,OAAOI,SAASC,KAAKC,OAAS,EAAG,OAC3BC,OAASP,OAAOI,SAASC,KAAKG,UAAU,GACxC7B,OAAS,IAAIP,SAASc,MAAKuB,GAAKA,EAAE5B,aAAa,mBAAqB0B,SACtE5B,QACAD,cAAcC;;;;;;;;MAvDpBJ,yBACc,0CADdA,sBAEW,8DAFXA,2BAGgB"}
|
||||
@@ -1,74 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Expand the collapse section element.
|
||||
*
|
||||
* @module core_admin/expand_hash
|
||||
* @copyright Meirza <meirza.arson@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since 4.5
|
||||
*/
|
||||
|
||||
const SELECTORS = {
|
||||
COLLAPSE_ELEMENTS: '[data-bs-toggle="collapse"]',
|
||||
FOCUSTHENEXPAND_ELEMENTS: '.focus-expand',
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the focus and expand functionality.
|
||||
*/
|
||||
export const init = () => {
|
||||
// Select all collapsible elements only.
|
||||
const focusexpand = document.querySelector(SELECTORS.FOCUSTHENEXPAND_ELEMENTS);
|
||||
|
||||
// Add click event listener to the anchor element
|
||||
focusexpand?.addEventListener('click', () => {
|
||||
expandSection(`${focusexpand.getAttribute('href')}`);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Expands a section based on the provided URL hash.
|
||||
*
|
||||
* This function takes a hash string, finds the corresponding element in the DOM,
|
||||
* and expands it if it is currently collapsed. It updates the necessary ARIA
|
||||
* attributes and classes to reflect the expanded state.
|
||||
*
|
||||
* @param {string} hash - The hash (e.g., '#elementId') of the element to expand.
|
||||
*/
|
||||
export const expandSection = (hash) => {
|
||||
const container = document.querySelector(hash);
|
||||
const targetContainer = container?.querySelector(SELECTORS.COLLAPSE_ELEMENTS);
|
||||
|
||||
if (targetContainer?.getAttribute('aria-expanded') === 'false') {
|
||||
const collapseId = targetContainer.getAttribute('aria-controls');
|
||||
const collapseContainer = document.getElementById(collapseId);
|
||||
|
||||
// Show the content.
|
||||
collapseContainer.classList.remove('collapse');
|
||||
collapseContainer.classList.add('show');
|
||||
|
||||
// Update aria-expanded attribute to reflect the new state.
|
||||
targetContainer.setAttribute('aria-expanded', 'true');
|
||||
targetContainer.classList.remove('collapsed');
|
||||
|
||||
// Get collapse expand menu element.
|
||||
const collapseElement = document.querySelector('.collapseexpand.collapsemenu');
|
||||
// Ensure it gets noticed to make it work.
|
||||
collapseElement.setAttribute('aria-expanded', 'true');
|
||||
collapseElement.classList.remove('collapsed');
|
||||
}
|
||||
};
|
||||
@@ -138,10 +138,6 @@ export default class {
|
||||
|
||||
// Refocus on the link that as pressed in the first place.
|
||||
updatedRoot.querySelector(`[data-action="togglestate"][data-plugin="${stateToggle.dataset.plugin}"]`).focus();
|
||||
|
||||
// When clicking the toggle and it remains focused, a new tooltip will be generated.
|
||||
// Therefore, the old tooltip should be removed.
|
||||
this.removeTooltips();
|
||||
pendingPromise.resolve();
|
||||
}
|
||||
}
|
||||
@@ -180,16 +176,4 @@ export default class {
|
||||
|
||||
pendingPromise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove tooltips.
|
||||
*/
|
||||
removeTooltips() {
|
||||
const tooltips = document.querySelectorAll('[id*="tooltip"]');
|
||||
if (tooltips.length > 0) {
|
||||
tooltips.forEach(tooltip => {
|
||||
tooltip.remove();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Allows to filter the plugin list on plugins overview page
|
||||
*
|
||||
* @module core_admin/plugins_overview
|
||||
* @copyright 2024 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
const SELECTORS = {
|
||||
PLUGIN_FILTERS: '#plugins-overview-panel [data-filterby]',
|
||||
PLUGIN_ROWS: 'table#plugins-control-panel tbody tr:not(.plugintypeheader)',
|
||||
PLUGIN_TYPE_ROWS: 'table#plugins-control-panel tbody tr.plugintypeheader',
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise filters for the "Plugins overview" page
|
||||
*/
|
||||
export function init() {
|
||||
const filters = document.querySelectorAll(SELECTORS.PLUGIN_FILTERS);
|
||||
const pluginRows = document.querySelectorAll(SELECTORS.PLUGIN_ROWS);
|
||||
const pluginTypeRows = document.querySelectorAll(SELECTORS.PLUGIN_TYPE_ROWS);
|
||||
|
||||
const filterPlugins = (target) => {
|
||||
const filterBy = target.getAttribute('data-filterby');
|
||||
const headerVisibility = {};
|
||||
|
||||
// Hide all plugin rows in the plugin table that do not match the filter and show all others.
|
||||
for (const row of pluginRows) {
|
||||
const type = [...row.classList].find(s => s.startsWith('type-'));
|
||||
const visible = filterBy === 'all' ? true : row.classList.contains(filterBy);
|
||||
row.style.display = visible ? null : 'none';
|
||||
if (visible && type) {
|
||||
headerVisibility[type] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide all the plugin type headers that do not have any visible plugins and show all others.
|
||||
for (const row of pluginTypeRows) {
|
||||
const type = [...row.classList].find(s => s.startsWith('type-'));
|
||||
if (type) {
|
||||
const visible = filterBy === 'all' || headerVisibility[type];
|
||||
row.style.display = visible ? null : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle 'active' class for the selected filter.
|
||||
filters.forEach(el => el.classList.remove('active'));
|
||||
target.classList.add('active');
|
||||
};
|
||||
|
||||
// Add event listeners for the links changing plugins filters.
|
||||
filters
|
||||
.forEach(target => target.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
window.history.replaceState({}, null, e.target.href);
|
||||
filterPlugins(target);
|
||||
}));
|
||||
|
||||
// Pre-filter plugins based on the current url anchor.
|
||||
if (window.location.hash.length > 1) {
|
||||
const anchor = window.location.hash.substring(1);
|
||||
const target = [...filters].find(t => t.getAttribute('data-filterby') === anchor);
|
||||
if (target) {
|
||||
filterPlugins(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,10 +118,6 @@ foreach ($settingspage->children as $childpage) {
|
||||
}
|
||||
$outputhtml .= html_writer::tag('div', '<!-- -->', array('class' => 'clearer'));
|
||||
$outputhtml .= $setting->output_html($data);
|
||||
if ($childpage->has_dependencies()) {
|
||||
$opts = ['dependencies' => $childpage->get_dependencies_for_javascript()];
|
||||
$PAGE->requires->js_call_amd('core/showhidesettings', 'init', [$opts]);
|
||||
}
|
||||
}
|
||||
$outputhtml .= html_writer::end_tag('fieldset');
|
||||
}
|
||||
|
||||
@@ -1,73 +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/>.
|
||||
|
||||
namespace core_admin\admin;
|
||||
|
||||
use admin_setting;
|
||||
|
||||
/**
|
||||
* Render a template as part of other admin settings.
|
||||
* Use for rendering additional html in settings.
|
||||
*
|
||||
* @package core_admin
|
||||
* @subpackage admin
|
||||
* @copyright 2024 Matt Porritt <matt.porritt@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class admin_setting_template_render extends admin_setting {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The name of the setting.
|
||||
* @param string $templatename The name of the template to render.
|
||||
* @param array|\stdClass $context The context to pass to the template.
|
||||
*/
|
||||
public function __construct(
|
||||
string $name,
|
||||
/** @var string The name of the template to render. */
|
||||
protected string $templatename,
|
||||
/** @var array|\stdClass The context to pass to the template. */
|
||||
protected array|\stdClass $context
|
||||
) {
|
||||
$this->nosave = true;
|
||||
|
||||
parent::__construct($name, $templatename, '', '');
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function get_setting(): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function get_defaultsetting(): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
// phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
public function write_setting($data): string {
|
||||
// Do not write any setting.
|
||||
return '';
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function output_html($data, $query = ''): string {
|
||||
global $OUTPUT;
|
||||
|
||||
return $OUTPUT->render_from_template($this->templatename, $this->context);
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,6 @@ class purge_caches extends \moodleform {
|
||||
$mform->addElement('header', 'purgecacheheader', get_string('purgeselectedcaches', 'admin'));
|
||||
$checkboxes = [
|
||||
$mform->createElement('advcheckbox', 'theme', '', get_string('purgethemecache', 'admin')),
|
||||
$mform->createElement('advcheckbox', 'courses', '', get_string('purgecoursecache', 'admin')),
|
||||
$mform->createElement('advcheckbox', 'lang', '', get_string('purgelangcache', 'admin')),
|
||||
$mform->createElement('advcheckbox', 'js', '', get_string('purgejscache', 'admin')),
|
||||
$mform->createElement('advcheckbox', 'template', '', get_string('purgetemplates', 'admin')),
|
||||
|
||||
@@ -62,7 +62,7 @@ class filesize extends \admin_setting {
|
||||
* @param int|null $defaultunit GB, MB, etc. (in bytes)
|
||||
*/
|
||||
public function __construct(string $name, string $visiblename, string $description,
|
||||
?int $defaultvalue = null, ?int $defaultunit = null) {
|
||||
int $defaultvalue = null, int $defaultunit = null) {
|
||||
|
||||
$defaultsetting = self::parse_bytes($defaultvalue);
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ class task_log extends base {
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_field("{$tablealias}.classname")
|
||||
->add_field("$tablealias.classname")
|
||||
->set_is_sortable(true)
|
||||
->add_callback(static function(string $classname): string {
|
||||
$output = '';
|
||||
@@ -183,7 +183,15 @@ class task_log extends base {
|
||||
->set_type(column::TYPE_FLOAT)
|
||||
->add_field("{$tablealias}.timeend - {$tablealias}.timestart", 'duration')
|
||||
->set_is_sortable(true)
|
||||
->add_callback([format::class, 'format_time'], 2);
|
||||
->add_callback(static function(float $value): string {
|
||||
$duration = round($value, 2);
|
||||
if (empty($duration)) {
|
||||
// The format_time function returns 'now' when the difference is exactly 0.
|
||||
// Note: format_time performs concatenation in exactly this fashion so we should do this for consistency.
|
||||
return '0 ' . get_string('secs', 'moodle');
|
||||
}
|
||||
return format_time($duration);
|
||||
});
|
||||
|
||||
// Hostname column.
|
||||
$columns[] = (new column(
|
||||
@@ -203,8 +211,11 @@ class task_log extends base {
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_INTEGER)
|
||||
->add_field("{$tablealias}.pid")
|
||||
->set_is_sortable(true);
|
||||
->set_is_sortable(true)
|
||||
// Although this is an integer column, it doesn't make sense to perform numeric aggregation on it.
|
||||
->set_disabled_aggregation(['avg', 'count', 'countdistinct', 'max', 'min', 'sum']);
|
||||
|
||||
// Database column.
|
||||
$columns[] = (new column(
|
||||
@@ -213,14 +224,17 @@ class task_log extends base {
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_INTEGER)
|
||||
->add_fields("{$tablealias}.dbreads, {$tablealias}.dbwrites")
|
||||
->set_is_sortable(true, ["{$tablealias}.dbreads", "{$tablealias}.dbwrites"])
|
||||
->add_callback(static function($value, stdClass $row): string {
|
||||
->add_callback(static function(int $value, stdClass $row): string {
|
||||
$output = '';
|
||||
$output .= \html_writer::div(get_string('task_stats:dbreads', 'admin', $row->dbreads));
|
||||
$output .= \html_writer::div(get_string('task_stats:dbwrites', 'admin', $row->dbwrites));
|
||||
return $output;
|
||||
});
|
||||
})
|
||||
// Although this is an integer column, it doesn't make sense to perform numeric aggregation on it.
|
||||
->set_disabled_aggregation(['avg', 'count', 'countdistinct', 'max', 'min', 'sum']);
|
||||
|
||||
// Database reads column.
|
||||
$columns[] = (new column(
|
||||
@@ -271,6 +285,8 @@ class task_log extends base {
|
||||
* @return filter[]
|
||||
*/
|
||||
protected function get_all_filters(): array {
|
||||
global $DB;
|
||||
|
||||
$tablealias = $this->get_table_alias('task_log');
|
||||
|
||||
// Name filter (Filter by classname).
|
||||
@@ -328,7 +344,7 @@ class task_log extends base {
|
||||
'output',
|
||||
new lang_string('task_logoutput', 'admin'),
|
||||
$this->get_entity_name(),
|
||||
"{$tablealias}.output"
|
||||
$DB->sql_cast_to_char("{$tablealias}.output")
|
||||
))
|
||||
->add_joins($this->get_joins());
|
||||
|
||||
|
||||
@@ -20,12 +20,10 @@ use context_system;
|
||||
use core_admin\reportbuilder\local\entities\task_log;
|
||||
use core_reportbuilder\local\entities\user;
|
||||
use core_reportbuilder\local\report\action;
|
||||
use core_reportbuilder\system_report;
|
||||
use html_writer;
|
||||
use lang_string;
|
||||
use moodle_url;
|
||||
use pix_icon;
|
||||
use stdClass;
|
||||
use core_reportbuilder\system_report;
|
||||
|
||||
/**
|
||||
* Task logs system report class implementation
|
||||
@@ -91,9 +89,7 @@ class task_logs extends system_report {
|
||||
* unique identifier
|
||||
*/
|
||||
public function add_columns(): void {
|
||||
$entitymainalias = $this->get_entity('task_log')->get_table_alias('task_log');
|
||||
|
||||
$this->add_columns_from_entities([
|
||||
$columns = [
|
||||
'task_log:name',
|
||||
'task_log:type',
|
||||
'user:fullname',
|
||||
@@ -103,18 +99,14 @@ class task_logs extends system_report {
|
||||
'task_log:pid',
|
||||
'task_log:database',
|
||||
'task_log:result',
|
||||
]);
|
||||
];
|
||||
|
||||
// Wrap the task name in a link.
|
||||
$this->get_column('task_log:name')
|
||||
->add_field("{$entitymainalias}.id")
|
||||
->add_callback(static function(string $output, stdClass $row): string {
|
||||
return html_writer::link(new moodle_url('/admin/tasklogs.php', ['logid' => $row->id]), $output);
|
||||
});
|
||||
$this->add_columns_from_entities($columns);
|
||||
|
||||
// Rename the user fullname column.
|
||||
$this->get_column('user:fullname')
|
||||
->set_title(new lang_string('user', 'admin'));
|
||||
// It's possible to override the display name of a column, if you don't want to use the value provided by the entity.
|
||||
if ($column = $this->get_column('user:fullname')) {
|
||||
$column->set_title(new lang_string('user', 'admin'));
|
||||
}
|
||||
|
||||
// It's possible to set a default initial sort direction for one column.
|
||||
$this->set_initial_sort_column('task_log:starttime', SORT_DESC);
|
||||
@@ -127,14 +119,16 @@ class task_logs extends system_report {
|
||||
* unique identifier
|
||||
*/
|
||||
protected function add_filters(): void {
|
||||
$this->add_filters_from_entities([
|
||||
$filters = [
|
||||
'task_log:name',
|
||||
'task_log:type',
|
||||
'task_log:output',
|
||||
'task_log:result',
|
||||
'task_log:timestart',
|
||||
'task_log:duration',
|
||||
]);
|
||||
];
|
||||
|
||||
$this->add_filters_from_entities($filters);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,7 +143,7 @@ class task_logs extends system_report {
|
||||
new moodle_url('/admin/tasklogs.php', ['logid' => ':id']),
|
||||
new pix_icon('e/search', ''),
|
||||
[],
|
||||
false,
|
||||
true,
|
||||
new lang_string('view'),
|
||||
)));
|
||||
|
||||
|
||||
@@ -159,11 +159,11 @@ class users extends system_report {
|
||||
->add_callback(static function(string $fullname, \stdClass $row): string {
|
||||
if ($row->suspended) {
|
||||
$fullname .= ' ' . \html_writer::tag('span', get_string('suspended', 'moodle'),
|
||||
['class' => 'badge text-bg-secondary ms-1']);
|
||||
['class' => 'badge badge-secondary ml-1']);
|
||||
}
|
||||
if (!$row->confirmed) {
|
||||
$fullname .= ' ' . \html_writer::tag('span', get_string('confirmationpending', 'admin'),
|
||||
['class' => 'badge text-bg-danger ms-1']);
|
||||
['class' => 'badge badge-danger ml-1']);
|
||||
}
|
||||
return $fullname;
|
||||
});
|
||||
|
||||
@@ -1,85 +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/>.
|
||||
|
||||
namespace core_admin\table;
|
||||
|
||||
use moodle_url;
|
||||
use stdClass;
|
||||
use html_writer;
|
||||
use get_string_manager;
|
||||
|
||||
/**
|
||||
* Availability admin settings.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2024 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class availability_management_table extends plugin_management_table {
|
||||
|
||||
protected function get_table_id(): string {
|
||||
return 'availabilityconditions_administration_table';
|
||||
}
|
||||
|
||||
protected function get_plugintype(): string {
|
||||
return 'availability';
|
||||
}
|
||||
|
||||
protected function get_action_url(array $params = []): moodle_url {
|
||||
return new moodle_url('/admin/tool/availabilityconditions/', $params);
|
||||
}
|
||||
|
||||
public function guess_base_url(): void {
|
||||
$this->define_baseurl(
|
||||
new moodle_url('/admin/tool/availabilityconditions/')
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_column_list(): array {
|
||||
return [
|
||||
'name' => get_string('plugin'),
|
||||
'version' => get_string('version'),
|
||||
'enabled' => get_string('enabled', 'admin'),
|
||||
'defaultdisplaymode' => get_string('defaultdisplaymode', 'tool_availabilityconditions'),
|
||||
];
|
||||
}
|
||||
|
||||
public function setup(): void {
|
||||
$this->set_attribute('id', 'availabilityconditions_administration_table');
|
||||
$this->set_attribute('class', 'admintable generaltable');
|
||||
parent::setup();
|
||||
}
|
||||
|
||||
protected function col_name(stdClass $row): string {
|
||||
return html_writer::span(
|
||||
get_string('pluginname', 'availability_' . $row->plugininfo->name)
|
||||
);
|
||||
}
|
||||
|
||||
protected function col_defaultdisplaymode(stdClass $row): string {
|
||||
global $OUTPUT, $CFG;
|
||||
$displaymode = get_config('availability_' . $row->plugininfo->name, 'defaultdisplaymode') ? 'show' : 'hide';
|
||||
$paramsdisplaymode = [
|
||||
'sesskey' => sesskey(),
|
||||
'plugin' => $row->plugininfo->name,
|
||||
'displaymode' => $displaymode,
|
||||
];
|
||||
$urldisplaymode = new moodle_url('/' . $CFG->admin . '/tool/availabilityconditions/', $paramsdisplaymode);
|
||||
|
||||
return html_writer::link($urldisplaymode, $OUTPUT->pix_icon('t/' . $displaymode,
|
||||
get_string($displaymode)), ['class' => 'display-mode-' . $row->plugininfo->name]);
|
||||
}
|
||||
}
|
||||
@@ -232,7 +232,7 @@ class hook_list_table extends flexible_table {
|
||||
}
|
||||
|
||||
if ($tooltip) {
|
||||
$attributes['data-bs-toggle'] = 'tooltip';
|
||||
$attributes['data-toggle'] = 'tooltip';
|
||||
$attributes['title'] = $tooltip;
|
||||
}
|
||||
return html_writer::span($tag, "badge badge-{$type}", $attributes);
|
||||
|
||||
@@ -303,29 +303,28 @@ abstract class plugin_management_table extends flexible_table implements dynamic
|
||||
global $OUTPUT;
|
||||
|
||||
$enabled = $row->plugininfo->is_enabled();
|
||||
if ($enabled) {
|
||||
$labelstr = get_string('disableplugin', 'core_admin', $row->plugininfo->displayname);
|
||||
} else {
|
||||
$labelstr = get_string('enableplugin', 'core_admin', $row->plugininfo->displayname);
|
||||
}
|
||||
|
||||
$params = [
|
||||
'id' => 'admin-toggle-' . $row->plugininfo->name,
|
||||
'checked' => $enabled,
|
||||
'dataattributes' => [
|
||||
'name' => 'id',
|
||||
'value' => $row->plugininfo->name,
|
||||
'toggle-method' => $this->get_toggle_service(),
|
||||
'action' => 'togglestate',
|
||||
'plugin' => $row->plugin,
|
||||
'state' => $enabled ? 1 : 0,
|
||||
],
|
||||
'title' => $labelstr,
|
||||
'label' => $labelstr,
|
||||
'labelclasses' => 'visually-hidden',
|
||||
'sesskey' => sesskey(),
|
||||
'plugin' => $row->plugininfo->name,
|
||||
'action' => $enabled ? 'disable' : 'enable',
|
||||
];
|
||||
|
||||
return $OUTPUT->render_from_template('core_admin/setting_configtoggle', $params);
|
||||
if ($enabled) {
|
||||
$icon = $OUTPUT->pix_icon('t/hide', get_string('disableplugin', 'core_admin', $row->plugininfo->displayname));
|
||||
} else {
|
||||
$icon = $OUTPUT->pix_icon('t/show', get_string('enableplugin', 'core_admin', $row->plugininfo->displayname));
|
||||
}
|
||||
|
||||
return html_writer::link(
|
||||
$this->get_action_url($params),
|
||||
$icon,
|
||||
[
|
||||
'data-toggle-method' => $this->get_toggle_service(),
|
||||
'data-action' => 'togglestate',
|
||||
'data-plugin' => $row->plugin,
|
||||
'data-state' => $enabled ? 1 : 0,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
protected function col_order(stdClass $row): string {
|
||||
|
||||
@@ -71,7 +71,7 @@ Example:
|
||||
exit(0);
|
||||
}
|
||||
|
||||
error_reporting(E_ALL);
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
$content = core_component::get_cache_content();
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
define('NO_DEBUG_DISPLAY', false);
|
||||
|
||||
// extra execution prevention - we can not just require config.php here
|
||||
if (isset($_SERVER['REMOTE_ADDR'])) {
|
||||
@@ -166,23 +165,19 @@ $CFG->running_installer = true;
|
||||
$CFG->early_install_lang = true;
|
||||
$CFG->ostype = (stristr(PHP_OS, 'win') && !stristr(PHP_OS, 'darwin')) ? 'WINDOWS' : 'UNIX';
|
||||
$CFG->dboptions = array();
|
||||
$CFG->debug = (E_ALL);
|
||||
$CFG->debug = (E_ALL | E_STRICT);
|
||||
$CFG->debugdisplay = true;
|
||||
$CFG->debugdeveloper = true;
|
||||
|
||||
$parts = explode('/', str_replace('\\', '/', dirname(__DIR__)));
|
||||
$CFG->admin = array_pop($parts);
|
||||
|
||||
// Point pear include path to moodles lib/pear so that includes and requires will search there for files before anywhere else
|
||||
// the problem is that we need specific version of quickforms and hacked excel files :-(.
|
||||
//point pear include path to moodles lib/pear so that includes and requires will search there for files before anywhere else
|
||||
//the problem is that we need specific version of quickforms and hacked excel files :-(
|
||||
ini_set('include_path', $CFG->libdir.'/pear' . PATH_SEPARATOR . ini_get('include_path'));
|
||||
|
||||
// The core_component class can be used in any scripts, it does not need anything else.
|
||||
require_once($CFG->libdir.'/classes/component.php');
|
||||
|
||||
// Register our classloader.
|
||||
\core\component::register_autoloader();
|
||||
|
||||
require_once($CFG->libdir.'/classes/text.php');
|
||||
require_once($CFG->libdir.'/classes/string_manager.php');
|
||||
require_once($CFG->libdir.'/classes/string_manager_install.php');
|
||||
@@ -196,6 +191,10 @@ require_once($CFG->libdir.'/moodlelib.php');
|
||||
require_once($CFG->libdir.'/deprecatedlib.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/componentlib.class.php');
|
||||
require_once($CFG->dirroot.'/cache/lib.php');
|
||||
|
||||
// Register our classloader.
|
||||
\core_component::register_autoloader();
|
||||
|
||||
require($CFG->dirroot.'/version.php');
|
||||
$CFG->target_release = $release;
|
||||
@@ -217,6 +216,7 @@ $databases = array('mysqli' => moodle_database::get_driver_instance('mysqli', 'n
|
||||
'auroramysql' => moodle_database::get_driver_instance('auroramysql', 'native'),
|
||||
'mariadb'=> moodle_database::get_driver_instance('mariadb', 'native'),
|
||||
'pgsql' => moodle_database::get_driver_instance('pgsql', 'native'),
|
||||
'oci' => moodle_database::get_driver_instance('oci', 'native'),
|
||||
'sqlsrv' => moodle_database::get_driver_instance('sqlsrv', 'native'), // MS SQL*Server PHP driver
|
||||
);
|
||||
foreach ($databases as $type=>$database) {
|
||||
@@ -560,6 +560,7 @@ do {
|
||||
if ($interactive) {
|
||||
cli_separator();
|
||||
cli_heading(get_string('dbprefix', 'install'));
|
||||
//TODO: solve somehow the prefix trouble for oci.
|
||||
if ($options['prefix'] !== '') {
|
||||
$prompt = get_string('clitypevaluedefault', 'admin', $options['prefix']);
|
||||
} else {
|
||||
|
||||
@@ -50,6 +50,6 @@ Example:
|
||||
exit(0);
|
||||
}
|
||||
|
||||
\core\session\manager::destroy_all();
|
||||
\core\session\manager::kill_all_sessions();
|
||||
|
||||
exit(0);
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
define('IGNORE_COMPONENT_CACHE', true);
|
||||
|
||||
require(__DIR__.'/../../config.php');
|
||||
require_once($CFG->libdir.'/clilib.php');
|
||||
|
||||
@@ -55,14 +55,13 @@ If courseid is set, course module/s will be added into the course.
|
||||
|
||||
Options:
|
||||
-f, --file=STRING Path to the backup file.
|
||||
-c, --categoryid=INT ID of the course category to restore to. This option is ignored when restoring an activity and courseid is set.
|
||||
-C, --courseid=INT ID of the course to restore to. This option is ignored when restoring a course and the categoryid is set.
|
||||
-c, --categoryid=INT ID of the course category to restore to.
|
||||
-C, --courseid=INT ID of the course to restore to. This option is ignored if categoryid is set.
|
||||
-s, --showdebugging Show developer level debugging information
|
||||
-h, --help Print out this help.
|
||||
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/restore_backup.php --file=/path/to/backup/coursebackup.mbz --categoryid=1\n
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/restore_backup.php --file=/path/to/backup/activitybackup.mbz --courseid=1\n
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/restore_backup.php --file=/path/to/backup/file.mbz --categoryid=1\n
|
||||
EOL;
|
||||
|
||||
echo $help;
|
||||
@@ -85,15 +84,11 @@ if ($options['categoryid']) {
|
||||
if (!$category = $DB->get_record('course_categories', ['id' => $options['categoryid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcategoryid');
|
||||
}
|
||||
}
|
||||
|
||||
if ($options['courseid']) {
|
||||
} else if ($options['courseid']) {
|
||||
if (!$course = $DB->get_record('course', ['id' => $options['courseid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcourseid');
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($category) && empty($course)) {
|
||||
} else {
|
||||
throw new \moodle_exception('invalidoption');
|
||||
}
|
||||
|
||||
@@ -105,46 +100,28 @@ $fp = get_file_packer('application/vnd.moodle.backup');
|
||||
$fp->extract_to_pathname($options['file'], $path);
|
||||
|
||||
cli_heading(get_string('preprocessingbackupfile'));
|
||||
|
||||
try {
|
||||
// Create a temporary restore controller to determine the restore type.
|
||||
$tmprc = new restore_controller($backupdir, SITEID, backup::INTERACTIVE_NO,
|
||||
backup::MODE_GENERAL, $admin->id, backup::TARGET_EXISTING_ADDING);
|
||||
// Restore the backup into a new course if:
|
||||
// - It is a course backup and the category is set.
|
||||
// - It is an activity backup and the course is not set.
|
||||
$restoreasnewcourse = ($tmprc->get_type() === backup::TYPE_1COURSE && !empty($category)) ||
|
||||
($tmprc->get_type() !== backup::TYPE_1COURSE && empty($course));
|
||||
// Make sure to clean up the temporary restore controller.
|
||||
$tmprc->destroy();
|
||||
list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoringcourse', 'backup'),
|
||||
get_string('restoringcourseshortname', 'backup'));
|
||||
|
||||
if ($restoreasnewcourse) {
|
||||
list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoringcourse', 'backup'),
|
||||
get_string('restoringcourseshortname', 'backup'));
|
||||
$courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id);
|
||||
$rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
|
||||
backup::MODE_GENERAL, $admin->id, backup::TARGET_NEW_COURSE);
|
||||
} else {
|
||||
if (!empty($course)) {
|
||||
$courseid = $course->id;
|
||||
$rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
|
||||
backup::MODE_GENERAL, $admin->id, backup::TARGET_EXISTING_ADDING);
|
||||
} else {
|
||||
$courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id);
|
||||
$rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
|
||||
backup::MODE_GENERAL, $admin->id, backup::TARGET_NEW_COURSE);
|
||||
}
|
||||
$rc->execute_precheck();
|
||||
$rc->execute_plan();
|
||||
$rc->destroy();
|
||||
|
||||
// Rename the course's full and short names with the backup file's original names if the backup file is an activity backup
|
||||
// that is restored to a new course.
|
||||
if ($restoreasnewcourse && $rc->get_type() !== backup::TYPE_1COURSE) {
|
||||
// Rename course name if the backup is from course module and restore to category.
|
||||
if (empty($course)) {
|
||||
$course = get_course($courseid);
|
||||
$backupinfo = $rc->get_info();
|
||||
$tmpfullname = $backupinfo->original_course_fullname ?? get_string('restoretonewcourse', 'backup');
|
||||
$tmpshortname = $backupinfo->original_course_shortname ?? get_string('newcourse');
|
||||
list($fullname, $shortname) = restore_dbops::calculate_course_names(
|
||||
courseid: 0,
|
||||
fullname: $tmpfullname,
|
||||
shortname: $tmpshortname,
|
||||
);
|
||||
list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoretonewcourse', 'backup'),
|
||||
get_string('newcourse'));
|
||||
$course->fullname = $fullname;
|
||||
$course->shortname = $shortname;
|
||||
$course->visible = 1;
|
||||
|
||||
@@ -4327,7 +4327,6 @@
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.1.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_84" message="unsupportedphpversion84" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -4523,7 +4522,6 @@
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.1.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_84" message="unsupportedphpversion84" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -4705,399 +4703,4 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="5.0" requires="4.2.3">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.11.0" />
|
||||
<VENDOR name="mysql" version="8.4" />
|
||||
<VENDOR name="postgres" version="14" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="auroramysql" version="8.0" />
|
||||
</DATABASE>
|
||||
<PHP version="8.2.0" 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="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</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="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</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_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="sixtyfourbitsrequired" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_async_backup" level="recommended">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_aurora_version" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="5.1" requires="4.2.3">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.11.0" />
|
||||
<VENDOR name="mysql" version="8.4" />
|
||||
<VENDOR name="postgres" version="15" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="auroramysql" version="8.0" />
|
||||
</DATABASE>
|
||||
<PHP version="8.2.0" 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="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</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="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</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_SETTING name="zend.exception_ignore_args" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingzendexceptionignoreargs" />
|
||||
</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_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="sixtyfourbitsrequired" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_async_backup" level="recommended">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_aurora_version" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -40,6 +40,13 @@ if (!function_exists('iconv')) {
|
||||
die();
|
||||
}
|
||||
|
||||
// Make sure php5-json is available.
|
||||
if (!function_exists('json_encode') || !function_exists('json_decode')) {
|
||||
// This also shouldn't happen.
|
||||
echo 'Moodle requires the json PHP extension. Please install or enable the json extension.';
|
||||
die();
|
||||
}
|
||||
|
||||
// Make sure xml extension is available.
|
||||
if (!extension_loaded('xml')) {
|
||||
echo 'Moodle requires the xml PHP extension. Please install or enable the xml extension.';
|
||||
|
||||
+69
-1
@@ -43,6 +43,61 @@ $providers = get_message_providers();
|
||||
$preferences = get_message_output_default_preferences();
|
||||
|
||||
if (($form = data_submitted()) && confirm_sesskey()) {
|
||||
$newpreferences = array();
|
||||
// Prepare default message outputs settings.
|
||||
foreach ($providers as $provider) {
|
||||
$componentproviderbase = $provider->component.'_'.$provider->name;
|
||||
$disableprovidersetting = $componentproviderbase.'_disable';
|
||||
if (!isset($form->$disableprovidersetting)) {
|
||||
$newpreferences[$disableprovidersetting] = 1;
|
||||
} else {
|
||||
$newpreferences[$disableprovidersetting] = 0;
|
||||
}
|
||||
|
||||
$componentprovidersetting = $componentproviderbase.'_locked';
|
||||
foreach ($processors as $processor) {
|
||||
$value = 0;
|
||||
if (isset($form->{$componentprovidersetting}[$processor->name])) {
|
||||
$value = $form->{$componentprovidersetting}[$processor->name];
|
||||
if ($value == 'on') {
|
||||
$value = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Record the site preference.
|
||||
$newpreferences[$processor->name.'_provider_'.$componentprovidersetting] = $value;
|
||||
}
|
||||
|
||||
$componentprovidersetting = $componentproviderbase.'_enabled';
|
||||
$newsettings = [];
|
||||
if (isset($form->$componentprovidersetting)) {
|
||||
// Store defined comma-separated processors as setting value.
|
||||
// Using array_filter eliminates elements set to 0 above.
|
||||
$newsettings = array_keys(array_filter($form->{$componentprovidersetting}));
|
||||
}
|
||||
|
||||
// Let's join existing setting values for disabled processors.
|
||||
$property = 'message_provider_'.$componentprovidersetting;
|
||||
if (property_exists($preferences, $property)) {
|
||||
$existingsetting = $preferences->$property;
|
||||
foreach ($disabledprocessors as $disable) {
|
||||
if (strpos($existingsetting, $disable->name) > -1) {
|
||||
$newsettings[] = $disable->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$value = join(',', $newsettings);
|
||||
if (empty($value)) {
|
||||
$value = null;
|
||||
}
|
||||
|
||||
// Record the site preference.
|
||||
$newpreferences['message_provider_'.$componentprovidersetting] = $value;
|
||||
}
|
||||
|
||||
// Update database.
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
|
||||
// Save processors enabled/disabled status.
|
||||
foreach ($allprocessors as $processor) {
|
||||
@@ -51,11 +106,24 @@ if (($form = data_submitted()) && confirm_sesskey()) {
|
||||
$class::enable_plugin($processor->name, $enabled);
|
||||
}
|
||||
|
||||
foreach ($newpreferences as $name => $value) {
|
||||
$old = isset($preferences->$name) ? $preferences->$name : '';
|
||||
|
||||
if ($old != $value) {
|
||||
add_to_config_log($name, $old, $value, 'core');
|
||||
}
|
||||
|
||||
set_config($name, $value, 'message');
|
||||
}
|
||||
$transaction->allow_commit();
|
||||
|
||||
core_plugin_manager::reset_caches();
|
||||
|
||||
$url = new moodle_url('message.php');
|
||||
redirect($url);
|
||||
}
|
||||
|
||||
// Page settings.
|
||||
// Page settings
|
||||
$PAGE->set_context(context_system::instance());
|
||||
$renderer = $PAGE->get_renderer('core', 'message');
|
||||
|
||||
|
||||
@@ -91,8 +91,7 @@ if (!empty($hostid) && array_key_exists($hostid, $hosts)) {
|
||||
// this query is horrible and has to be remapped afterwards, because of the non-uniqueness
|
||||
// of the remoterep service (it has two plugins so far that use it)
|
||||
// it's possible to get a unique list back using a subquery with LIMIT but that would break oracle
|
||||
// so it's best to just do this small query and then remap the results afterwards.
|
||||
// TODO: Optimise the query, as Oracle-specific constraints no longer apply.
|
||||
// so it's best to just do this small query and then remap the results afterwards
|
||||
$sql = '
|
||||
SELECT DISTINCT
|
||||
' . $DB->sql_concat('r.plugintype', "'_'", 'r.pluginname', "'_'", 's.name') . ' AS uniqueid,
|
||||
|
||||
+7
-4
@@ -29,6 +29,8 @@ 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.
|
||||
@@ -45,7 +47,8 @@ require_admin();
|
||||
$syscontext = context_system::instance();
|
||||
|
||||
// URL params we want to maintain on redirects.
|
||||
$pageurl = new moodle_url('/admin/plugins.php');
|
||||
$pageparams = array('updatesonly' => $updatesonly, 'contribonly' => $contribonly);
|
||||
$pageurl = new moodle_url('/admin/plugins.php', $pageparams);
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
|
||||
@@ -54,7 +57,7 @@ $PAGE->set_primary_active_tab('siteadminnode');
|
||||
if ($uninstall) {
|
||||
|
||||
if (!$confirmed) {
|
||||
admin_externalpage_setup('pluginsoverview');
|
||||
admin_externalpage_setup('pluginsoverview', '', $pageparams);
|
||||
} else {
|
||||
$PAGE->set_url($pageurl);
|
||||
$PAGE->set_context($syscontext);
|
||||
@@ -198,7 +201,7 @@ if ($installupdate and $installupdateversion) {
|
||||
}
|
||||
}
|
||||
|
||||
admin_externalpage_setup('pluginsoverview');
|
||||
admin_externalpage_setup('pluginsoverview', '', $pageparams);
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
@@ -211,4 +214,4 @@ if ($fetchupdates) {
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
echo $output->plugin_management_page($pluginman, $checker);
|
||||
echo $output->plugin_management_page($pluginman, $checker, $pageparams);
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# core_adminpresets (subsystem) Upgrade notes
|
||||
|
||||
## 5.0
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove chat and survey from Adminpresets.
|
||||
|
||||
For more information see [MDL-82457](https://tracker.moodle.org/browse/MDL-82457)
|
||||
- Removed block_mnet_hosts from admin presets
|
||||
|
||||
For more information see [MDL-84309](https://tracker.moodle.org/browse/MDL-84309)
|
||||
@@ -193,12 +193,14 @@ class helper {
|
||||
// Set Activity chooser tabs to "Starred, Recommended, All".
|
||||
static::add_item($presetid, 'activitychoosertabmode', '4');
|
||||
|
||||
// Modules: Hide database, external tool (lti), IMS content package (imscp), lesson, SCORM, wiki, workshop.
|
||||
// Modules: Hide chat, database, external tool (lti), IMS content package (imscp), lesson, SCORM, survey, wiki, workshop.
|
||||
static::add_plugin($presetid, 'mod', 'chat', false);
|
||||
static::add_plugin($presetid, 'mod', 'data', false);
|
||||
static::add_plugin($presetid, 'mod', 'lti', false);
|
||||
static::add_plugin($presetid, 'mod', 'imscp', false);
|
||||
static::add_plugin($presetid, 'mod', 'lesson', false);
|
||||
static::add_plugin($presetid, 'mod', 'scorm', false);
|
||||
static::add_plugin($presetid, 'mod', 'survey', false);
|
||||
static::add_plugin($presetid, 'mod', 'wiki', false);
|
||||
static::add_plugin($presetid, 'mod', 'workshop', false);
|
||||
|
||||
@@ -207,7 +209,7 @@ class helper {
|
||||
static::add_plugin($presetid, 'availability', 'profile', false);
|
||||
|
||||
// Blocks: Hide Activities, Blog menu, Blog tags, Comments, Course completion status, Courses, Flickr,
|
||||
// Global search, Latest badges, Learning plans, Logged in user, Login, Main menu, Mentees, Online users,
|
||||
// Global search, Latest badges, Learning plans, Logged in user, Login, Main menu, Mentees, Network servers, Online users,
|
||||
// Private files, Recent blog entries, Recently accessed courses, Search forums, Section links, Social activities,
|
||||
// Starred courses, Tags, YouTube.
|
||||
// Hidden by default: Course/site summary, RSS feeds, Self completion, Feedback.
|
||||
@@ -226,6 +228,7 @@ class helper {
|
||||
static::add_plugin($presetid, 'block', 'login', false);
|
||||
static::add_plugin($presetid, 'block', 'site_main_menu', false);
|
||||
static::add_plugin($presetid, 'block', 'mentees', false);
|
||||
static::add_plugin($presetid, 'block', 'mnet_hosts', false);
|
||||
static::add_plugin($presetid, 'block', 'private_files', false);
|
||||
static::add_plugin($presetid, 'block', 'blog_recent', false);
|
||||
static::add_plugin($presetid, 'block', 'rss_client', false);
|
||||
@@ -289,7 +292,7 @@ class helper {
|
||||
static::add_item($presetid, 'enablenotes', '1');
|
||||
static::add_item($presetid, 'enableblogs', '1');
|
||||
static::add_item($presetid, 'enablebadges', '1');
|
||||
static::add_item($presetid, 'enableanalytics', '0');
|
||||
static::add_item($presetid, 'enableanalytics', '1');
|
||||
static::add_item($presetid, 'enabled', '1', 'core_competency');
|
||||
static::add_item($presetid, 'pushcourseratingstouserplans', '1', 'core_competency');
|
||||
static::add_item($presetid, 'showdataretentionsummary', '1', 'tool_dataprivacy');
|
||||
@@ -312,7 +315,7 @@ class helper {
|
||||
static::add_plugin($presetid, 'availability', 'profile', true);
|
||||
|
||||
// Blocks: Enable Activities, Blog menu, Blog tags, Comments, Course completion status, Courses, Flickr,
|
||||
// Global search, Latest badges, Learning plans, Logged in user, Login, Main menu, Mentees, Online users,
|
||||
// Global search, Latest badges, Learning plans, Logged in user, Login, Main menu, Mentees, Network servers, Online users,
|
||||
// Private files, Recent blog entries, Recently accessed courses, Search forums, Section links, Social activities,
|
||||
// Starred courses, Tags, YouTube.
|
||||
// Hidden by default: Course/site summary, RSS feeds, Self completion, Feedback.
|
||||
@@ -330,6 +333,7 @@ class helper {
|
||||
static::add_plugin($presetid, 'block', 'login', true);
|
||||
static::add_plugin($presetid, 'block', 'site_main_menu', true);
|
||||
static::add_plugin($presetid, 'block', 'mentees', true);
|
||||
static::add_plugin($presetid, 'block', 'mnet_hosts', true);
|
||||
static::add_plugin($presetid, 'block', 'private_files', true);
|
||||
static::add_plugin($presetid, 'block', 'blog_recent', true);
|
||||
static::add_plugin($presetid, 'block', 'search_forums', true);
|
||||
|
||||
@@ -1133,11 +1133,6 @@ class manager {
|
||||
'visiblevalue' => $visiblevalue,
|
||||
];
|
||||
|
||||
if ($plugininfo && $plugininfo->is_deprecated()) {
|
||||
$skipped[] = $data;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($pluginclass == '\core\plugininfo\orphaned') {
|
||||
$skipped[] = $data;
|
||||
continue;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<PRESET>
|
||||
<NAME>Imported preset</NAME>
|
||||
<COMMENTS><p dir="ltr" style="text-align:left;">Porfolios enabled, Emojipicker enabled, Lesson media width set to 900 and maxanswers set to 2 and disabled advanced. Plugins: disabled block_html, mod_database and mod_page plugins and enabled atto_html, block_activity_modules and mod_lesson.</p></COMMENTS>
|
||||
<COMMENTS><p dir="ltr" style="text-align:left;">Porfolios enabled, Emojipicker enabled, Lesson media width set to 900 and maxanswers set to 2 and disabled advanced. Plugins: disabled block_html, mod_database and mod_chat plugins and enabled atto_html, block_activity_modules and mod_lesson.</p></COMMENTS>
|
||||
<PRESET_DATE>1631615985</PRESET_DATE>
|
||||
<SITE_URL>http://demo.moodle</SITE_URL>
|
||||
<AUTHOR>Ada Lovelace</AUTHOR>
|
||||
@@ -30,7 +30,7 @@
|
||||
<ACTIVITY_MODULES>1</ACTIVITY_MODULES>
|
||||
</BLOCK>
|
||||
<MOD>
|
||||
<PAGE>0</PAGE>
|
||||
<CHAT>0</CHAT>
|
||||
<DATA>0</DATA>
|
||||
<LESSON>1</LESSON>
|
||||
</MOD>
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<PRESET>
|
||||
<NAME>Starter</NAME>
|
||||
<COMMENTS><p dir="ltr" style="text-align:left;">Badges disabled, Emojipicker enabled, Lesson media width set to 900 and maxanswers set to 2 and disabled advanced. Plugins: disabled block_html, mod_database and mod_page plugins and enabled atto_html and block_activity_modules.</p></COMMENTS>
|
||||
<COMMENTS><p dir="ltr" style="text-align:left;">Badges disabled, Emojipicker enabled, Lesson media width set to 900 and maxanswers set to 2 and disabled advanced. Plugins: disabled block_html, mod_database and mod_chat plugins and enabled atto_html and block_activity_modules.</p></COMMENTS>
|
||||
<PRESET_DATE>1631615985</PRESET_DATE>
|
||||
<SITE_URL>http://demo.moodle</SITE_URL>
|
||||
<AUTHOR>Ada Lovelace</AUTHOR>
|
||||
@@ -30,7 +30,7 @@
|
||||
<ACTIVITY_MODULES>1</ACTIVITY_MODULES>
|
||||
</BLOCK>
|
||||
<MOD>
|
||||
<PAGE>0</PAGE>
|
||||
<CHAT>0</CHAT>
|
||||
<DATA>0</DATA>
|
||||
<LESSON>1</LESSON>
|
||||
</MOD>
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace core_adminpresets;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass core_adminpresets_generator
|
||||
*/
|
||||
final class generator_test extends \advanced_testcase {
|
||||
class generator_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test the behaviour of create_preset() method.
|
||||
@@ -180,7 +180,7 @@ final class generator_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function create_preset_provider(): array {
|
||||
public function create_preset_provider(): array {
|
||||
return [
|
||||
'Default values' => [
|
||||
],
|
||||
|
||||
@@ -23,9 +23,9 @@ namespace core_adminpresets;
|
||||
* @category test
|
||||
* @copyright 2021 Sara Arjona (sara@moodle.com)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \core_adminpresets\helper
|
||||
* @coversDefaultClass helper
|
||||
*/
|
||||
final class helper_test extends \advanced_testcase {
|
||||
class helper_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test the behaviour of create_preset() method.
|
||||
@@ -84,7 +84,7 @@ final class helper_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function create_preset_provider(): array {
|
||||
public function create_preset_provider(): array {
|
||||
return [
|
||||
'Default values' => [
|
||||
],
|
||||
@@ -177,7 +177,7 @@ final class helper_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function add_item_provider(): array {
|
||||
public function add_item_provider(): array {
|
||||
return [
|
||||
'Setting without plugin' => [
|
||||
'name' => 'settingname',
|
||||
@@ -239,7 +239,7 @@ final class helper_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function add_plugin_provider(): array {
|
||||
public function add_plugin_provider(): array {
|
||||
return [
|
||||
'Plugin: enabled (using int)' => [
|
||||
'type' => 'plugintype',
|
||||
@@ -285,15 +285,12 @@ final class helper_test extends \advanced_testcase {
|
||||
|
||||
// We need to change some of the default values; otherwise, the full preset won't be applied, because all the settings
|
||||
// and plugins are the same.
|
||||
set_config('enableanalytics', '1');
|
||||
set_config('enableanalytics', '0');
|
||||
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_adminpresets');
|
||||
$generator->create_preset(['name' => 'Preset 1']);
|
||||
|
||||
$invokable = self::get_invokable();
|
||||
set_error_handler($invokable, E_WARNING);
|
||||
$presetid = helper::change_default_preset($preset);
|
||||
restore_error_handler();
|
||||
|
||||
if (empty($settings) && empty($plugins)) {
|
||||
// The preset hasn't been applied.
|
||||
@@ -324,7 +321,7 @@ final class helper_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function change_default_preset_provider(): array {
|
||||
public function change_default_preset_provider(): array {
|
||||
return [
|
||||
'Starter preset' => [
|
||||
'preset' => 'starter',
|
||||
@@ -334,7 +331,7 @@ final class helper_test extends \advanced_testcase {
|
||||
],
|
||||
'plugins' => [
|
||||
'assign' => 1,
|
||||
'wiki' => 0,
|
||||
'chat' => 0,
|
||||
'data' => 0,
|
||||
'lesson' => 0,
|
||||
],
|
||||
@@ -367,20 +364,20 @@ final class helper_test extends \advanced_testcase {
|
||||
'preset' => 'unexisting',
|
||||
],
|
||||
'Valid XML file' => [
|
||||
'preset' => self::get_fixture_path(__NAMESPACE__, 'import_settings_plugins.xml'),
|
||||
'preset' => __DIR__ . '/fixtures/import_settings_plugins.xml',
|
||||
'settings' => [
|
||||
'allowemojipicker' => 1,
|
||||
'enableportfolios' => 1,
|
||||
],
|
||||
'plugins' => [
|
||||
'assign' => 1,
|
||||
'page' => 0,
|
||||
'chat' => 0,
|
||||
'data' => 0,
|
||||
'lesson' => 1,
|
||||
],
|
||||
],
|
||||
'Invalid XML file' => [
|
||||
'preset' => self::get_fixture_path(__NAMESPACE__, 'invalid_xml_file.xml'),
|
||||
'preset' => __DIR__ . '/fixtures/invalid_xml_file.xml',
|
||||
],
|
||||
'Unexisting XML file' => [
|
||||
'preset' => __DIR__ . '/fixtures/unexisting.xml',
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace core_adminpresets\local\setting;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \core_adminpresets\local\setting\adminpresets_admin_setting_bloglevel
|
||||
*/
|
||||
final class adminpresets_admin_setting_bloglevel_test extends \advanced_testcase {
|
||||
class adminpresets_admin_setting_bloglevel_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test the behaviour of save_value() method.
|
||||
@@ -72,18 +72,18 @@ final class adminpresets_admin_setting_bloglevel_test extends \advanced_testcase
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function save_value_provider(): array {
|
||||
public function save_value_provider(): array {
|
||||
return [
|
||||
'Save the bloglevel and set blog_menu block visibility to true' => [
|
||||
'settingvalue' => BLOG_USER_LEVEL,
|
||||
'setttingvalue' => BLOG_USER_LEVEL,
|
||||
'expectedsaved' => true,
|
||||
],
|
||||
'Same value to bloglevel, so it will not be saved' => [
|
||||
'settingvalue' => BLOG_SITE_LEVEL,
|
||||
'setttingvalue' => BLOG_SITE_LEVEL,
|
||||
'expectedsaved' => false,
|
||||
],
|
||||
'Save the bloglevel and set blog_menu block visibility to false' => [
|
||||
'settingvalue' => 0,
|
||||
'setttingvalue' => 0,
|
||||
'expectedsaved' => true,
|
||||
],
|
||||
];
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace core_adminpresets\local\setting;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \core_adminpresets\local\setting\adminpresets_admin_setting_sitesettext
|
||||
*/
|
||||
final class adminpresets_admin_setting_sitesettext_test extends \advanced_testcase {
|
||||
class adminpresets_admin_setting_sitesettext_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test the behaviour of save_value() method.
|
||||
@@ -66,26 +66,26 @@ final class adminpresets_admin_setting_sitesettext_test extends \advanced_testca
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function save_value_provider(): array {
|
||||
public function save_value_provider(): array {
|
||||
return [
|
||||
'Fullname: different value' => [
|
||||
'settingname' => 'fullname',
|
||||
'settingvalue' => 'New site fullname',
|
||||
'setttingvalue' => 'New site fullname',
|
||||
'expectedsaved' => true,
|
||||
],
|
||||
'Fullname: same value' => [
|
||||
'settingname' => 'fullname',
|
||||
'settingvalue' => 'PHPUnit test site',
|
||||
'setttingvalue' => 'PHPUnit test site',
|
||||
'expectedsaved' => false,
|
||||
],
|
||||
'Summary: different value' => [
|
||||
'settingname' => 'summary',
|
||||
'settingvalue' => 'This is a new site summary.',
|
||||
'setttingvalue' => 'This is a new site summary.',
|
||||
'expectedsaved' => true,
|
||||
],
|
||||
'Summary: same value' => [
|
||||
'settingname' => 'summary',
|
||||
'settingvalue' => '',
|
||||
'setttingvalue' => '',
|
||||
'expectedsaved' => false,
|
||||
],
|
||||
];
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace core_adminpresets\local\setting;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \core_adminpresets\local\setting\adminpresets_setting
|
||||
*/
|
||||
final class adminpresets_setting_test extends \advanced_testcase {
|
||||
class adminpresets_setting_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test the behaviour of save_value() method.
|
||||
@@ -77,34 +77,34 @@ final class adminpresets_setting_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function save_value_provider(): array {
|
||||
public function save_value_provider(): array {
|
||||
return [
|
||||
'Core setting with the same value is not saved' => [
|
||||
'category' => 'optionalsubsystems',
|
||||
'settingplugin' => 'core',
|
||||
'settingname' => 'enablebadges',
|
||||
'settingvalue' => '1',
|
||||
'setttingvalue' => '1',
|
||||
'expectedsaved' => false,
|
||||
],
|
||||
'Core setting with a different value is saved' => [
|
||||
'category' => 'optionalsubsystems',
|
||||
'settingplugin' => 'core',
|
||||
'settingname' => 'enablebadges',
|
||||
'settingvalue' => '0',
|
||||
'setttingvalue' => '0',
|
||||
'expectedsaved' => true,
|
||||
],
|
||||
'Plugin setting with the same value is not saved' => [
|
||||
'category' => 'modsettinglesson',
|
||||
'settingplugin' => 'mod_lesson',
|
||||
'settingname' => 'mediawidth',
|
||||
'settingvalue' => '640',
|
||||
'setttingvalue' => '640',
|
||||
'expectedsaved' => false,
|
||||
],
|
||||
'Plugin setting with different value is saved' => [
|
||||
'category' => 'modsettinglesson',
|
||||
'settingplugin' => 'mod_lesson',
|
||||
'settingname' => 'mediawidth',
|
||||
'settingvalue' => '900',
|
||||
'setttingvalue' => '900',
|
||||
'expectedsaved' => true,
|
||||
],
|
||||
];
|
||||
@@ -167,14 +167,14 @@ final class adminpresets_setting_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function save_attributes_values_provider(): array {
|
||||
public function save_attributes_values_provider(): array {
|
||||
return [
|
||||
'Plugin setting with the same value is not saved' => [
|
||||
'category' => 'modsettinglesson',
|
||||
'settingplugin' => 'mod_lesson',
|
||||
'settingname' => 'maxanswers',
|
||||
'advsettingname' => 'maxanswers_adv',
|
||||
'advsettingvalue' => '1',
|
||||
'advsetttingvalue' => '1',
|
||||
'expectedsaved' => false,
|
||||
],
|
||||
'Plugin setting with different value is saved' => [
|
||||
@@ -182,7 +182,7 @@ final class adminpresets_setting_test extends \advanced_testcase {
|
||||
'settingplugin' => 'mod_lesson',
|
||||
'settingname' => 'maxanswers',
|
||||
'advsettingname' => 'maxanswers_adv',
|
||||
'advsettingvalue' => '0',
|
||||
'advsetttingvalue' => '0',
|
||||
'expectedsaved' => true,
|
||||
],
|
||||
'Plugin setting without advanced attributes are not saved' => [
|
||||
@@ -190,7 +190,7 @@ final class adminpresets_setting_test extends \advanced_testcase {
|
||||
'settingplugin' => 'mod_lesson',
|
||||
'settingname' => 'maxanswers',
|
||||
'advsettingname' => null,
|
||||
'advsettingvalue' => '0',
|
||||
'advsetttingvalue' => '0',
|
||||
'expectedsaved' => false,
|
||||
],
|
||||
];
|
||||
|
||||
@@ -28,14 +28,13 @@ use stdClass;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \core_adminpresets\manager
|
||||
*/
|
||||
final class manager_test extends \advanced_testcase {
|
||||
class manager_test extends \advanced_testcase {
|
||||
/**
|
||||
* Include required libraries.
|
||||
*/
|
||||
public static function setUpBeforeClass(): void {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
parent::setUpBeforeClass();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,7 +367,7 @@ final class manager_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function export_preset_provider(): array {
|
||||
public function export_preset_provider(): array {
|
||||
return [
|
||||
'Export settings and plugins, excluding sensible' => [
|
||||
'includesensible' => false,
|
||||
@@ -424,7 +423,7 @@ final class manager_test extends \advanced_testcase {
|
||||
* @param string|null $expectedpresetname Expected preset name.
|
||||
*/
|
||||
public function test_import_preset(string $filecontents, bool $expectedpreset, bool $expectedsettings = false,
|
||||
bool $expectedplugins = false, bool $expecteddebugging = false, ?string $expectedexception = null,
|
||||
bool $expectedplugins = false, bool $expecteddebugging = false, string $expectedexception = null,
|
||||
string $expectedpresetname = 'Imported preset'): void {
|
||||
global $DB;
|
||||
|
||||
@@ -438,10 +437,7 @@ final class manager_test extends \advanced_testcase {
|
||||
// Call the method to be tested.
|
||||
$manager = new manager();
|
||||
try {
|
||||
$invokable = self::get_invokable();
|
||||
set_error_handler($invokable, E_WARNING);
|
||||
list($xml, $preset, $settingsfound, $pluginsfound) = $manager->import_preset($filecontents);
|
||||
restore_error_handler();
|
||||
} catch (\exception $e) {
|
||||
if ($expectedexception) {
|
||||
$this->assertInstanceOf($expectedexception, $e);
|
||||
@@ -509,7 +505,7 @@ final class manager_test extends \advanced_testcase {
|
||||
'activity_modules' => 1,
|
||||
],
|
||||
'mod' => [
|
||||
'page' => 0,
|
||||
'chat' => 0,
|
||||
'data' => 0,
|
||||
'lesson' => 1,
|
||||
],
|
||||
@@ -534,32 +530,26 @@ final class manager_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function import_preset_provider(): array {
|
||||
public function import_preset_provider(): array {
|
||||
return [
|
||||
'Import settings from an empty file' => [
|
||||
'filecontents' => '',
|
||||
'expectedpreset' => false,
|
||||
],
|
||||
'Import settings and plugins from a valid XML file' => [
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'import_settings_plugins.xml')
|
||||
),
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_settings_plugins.xml'),
|
||||
'expectedpreset' => true,
|
||||
'expectedsettings' => true,
|
||||
'expectedplugins' => true,
|
||||
],
|
||||
'Import only settings from a valid XML file' => [
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'import_settings.xml')
|
||||
),
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_settings.xml'),
|
||||
'expectedpreset' => true,
|
||||
'expectedsettings' => true,
|
||||
'expectedplugins' => false,
|
||||
],
|
||||
'Import settings and plugins from a valid XML file with Starter name, which will be marked as non-core' => [
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'import_starter_name.xml')
|
||||
),
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_starter_name.xml'),
|
||||
'expectedpreset' => true,
|
||||
'expectedsettings' => true,
|
||||
'expectedplugins' => true,
|
||||
@@ -568,9 +558,7 @@ final class manager_test extends \advanced_testcase {
|
||||
'expectedpresetname' => 'Starter',
|
||||
],
|
||||
'Import settings from an invalid XML file' => [
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'invalid_xml_file.xml')
|
||||
),
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/invalid_xml_file.xml'),
|
||||
'expectedpreset' => false,
|
||||
'expectedsettings' => false,
|
||||
'expectedplugins' => false,
|
||||
@@ -578,26 +566,20 @@ final class manager_test extends \advanced_testcase {
|
||||
'expectedexception' => \Exception::class,
|
||||
],
|
||||
'Import unexisting settings category' => [
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'unexisting_category.xml')
|
||||
),
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/unexisting_category.xml'),
|
||||
'expectedpreset' => false,
|
||||
'expectedsettings' => false,
|
||||
'expectedplugins' => false,
|
||||
],
|
||||
'Import unexisting setting' => [
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'unexisting_setting.xml')
|
||||
),
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/unexisting_setting.xml'),
|
||||
'expectedpreset' => false,
|
||||
'expectedsettings' => false,
|
||||
'expectedplugins' => false,
|
||||
'expecteddebugging' => true,
|
||||
],
|
||||
'Import valid settings with one unexisting setting too' => [
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'import_settings_with_unexisting_setting.xml'),
|
||||
),
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_settings_with_unexisting_setting.xml'),
|
||||
'expectedpreset' => true,
|
||||
'expectedsettings' => false,
|
||||
'expectedplugins' => false,
|
||||
@@ -606,6 +588,7 @@ final class manager_test extends \advanced_testcase {
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test the behaviour of delete_preset() method when the preset id doesn't exist.
|
||||
*
|
||||
@@ -812,41 +795,4 @@ final class manager_test extends \advanced_testcase {
|
||||
$enabledplugins = \core\plugininfo\qtype::get_enabled_plugins();
|
||||
$this->assertArrayHasKey('truefalse', $enabledplugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test apply_preset for a deprecated plugin type.
|
||||
*
|
||||
* @runInSeparateProcess
|
||||
*
|
||||
* @covers ::apply_preset
|
||||
* @return void
|
||||
*/
|
||||
public function test_apply_preset_deprecated_plugintype(): void {
|
||||
global $CFG;
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create a preset.
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_adminpresets');
|
||||
$presetid = $generator->create_preset();
|
||||
|
||||
// Add a mock plugin into the preset. This plugin will be mocked and deprecated below.
|
||||
helper::add_plugin($presetid, 'fake', 'fullfeatured', true);
|
||||
|
||||
// Inject the mock plugin type + plugin, and deprecate it.
|
||||
$this->add_mocked_plugintype('fake', "$CFG->libdir/tests/fixtures/fakeplugins/fake", true);
|
||||
$this->add_mocked_plugin('fake', 'fullfeatured', $CFG->libdir . '/tests/fixtures/fakeplugins/fake/fullfeatured');
|
||||
|
||||
// Pre-flight check to ensure that the plugin is deprecated.
|
||||
$pluginman = \core\plugin_manager::instance();
|
||||
$plugininfo = $pluginman->get_plugin_info('fake_fullfeatured');
|
||||
// Expected, unit-test-only debugging, since \core\plugin_manager isn't aware of the mock plugininfo class for this type.
|
||||
$this->assertDebuggingCalled();
|
||||
$this->assertTrue($plugininfo->is_deprecated());
|
||||
|
||||
// Finally, check apply_preset method, verifying the deprecated plugin is skipped.
|
||||
$manager = new manager();
|
||||
[$applied, $skipped] = $manager->apply_preset($presetid);
|
||||
$this->assertdebuggingcalledcount(2); // Expected unit-test-only debugging, as above.
|
||||
$this->assertContains('fake', array_column($skipped, 'plugin'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ use core_privacy\tests\provider_testcase;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \core_adminpresets\privacy\provider
|
||||
*/
|
||||
final class privacy_provider_test extends provider_testcase {
|
||||
class privacy_provider_test extends provider_testcase {
|
||||
|
||||
/**
|
||||
* Test for provider::get_metadata().
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/php -f
|
||||
<?php
|
||||
|
||||
//error_reporting(0);
|
||||
//ini_set('display_errors',0);
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
$tmp = explode('@',$_ENV['RECIPIENT']);
|
||||
$address = $tmp[0];
|
||||
|
||||
// BOUNCE EMAILS TO NOREPLY
|
||||
if ($_ENV['RECIPIENT'] == $CFG->noreplyaddress) {
|
||||
$user = new stdClass();
|
||||
$user->email = $_ENV['SENDER'];
|
||||
|
||||
if (!validate_email($user->email)) {
|
||||
die();
|
||||
}
|
||||
|
||||
$site = get_site();
|
||||
$subject = get_string('noreplybouncesubject','moodle',format_string($site->fullname));
|
||||
$body = get_string('noreplybouncemessage','moodle',format_string($site->fullname))."\n\n";
|
||||
|
||||
$fd = fopen('php://stdin','r');
|
||||
if ($fd) {
|
||||
while(!feof($fd)) {
|
||||
$body .= fgets($fd);
|
||||
}
|
||||
fclose($fd);
|
||||
}
|
||||
|
||||
$user->id = 0; // to prevent anything annoying happening
|
||||
|
||||
$from->firstname = null;
|
||||
$from->lastname = null;
|
||||
$from->email = '<>';
|
||||
$from->maildisplay = true;
|
||||
|
||||
email_to_user($user,$from,$subject,$body);
|
||||
die ();
|
||||
}
|
||||
/// ALL OTHER PROCESSING
|
||||
// we need to split up the address
|
||||
$prefix = substr($address,0,4);
|
||||
$mod = substr($address,4,2);
|
||||
$modargs = substr($address,6,-16);
|
||||
$hash = substr($address,-16);
|
||||
|
||||
if (substr(md5($prefix.$mod.$modargs.$CFG->siteidentifier),0,16) != $hash) {
|
||||
die("HASH DIDN'T MATCH!\n");
|
||||
}
|
||||
list(,$modid) = unpack('C',base64_decode($mod.'=='));
|
||||
|
||||
if ($modid == '0') { // special
|
||||
$modname = 'moodle';
|
||||
}
|
||||
else {
|
||||
$modname = $DB->get_field("modules", "name", array("id"=>$modid));
|
||||
include_once('mod/'.$modname.'/lib.php');
|
||||
}
|
||||
$function = $modname.'_process_email';
|
||||
|
||||
if (!function_exists($function)) {
|
||||
die();
|
||||
}
|
||||
$fd = fopen('php://stdin','r');
|
||||
if (!$fd) {
|
||||
exit();
|
||||
}
|
||||
|
||||
while(!feof($fd)) {
|
||||
$body .= fgets($fd);
|
||||
}
|
||||
|
||||
$function($modargs,$body);
|
||||
|
||||
fclose($fd);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('IGNORE_COMPONENT_CACHE', true);
|
||||
|
||||
require_once('../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
|
||||
@@ -44,11 +42,7 @@ if ($data = $form->get_data()) {
|
||||
purge_caches();
|
||||
$message = get_string('purgecachesfinished', 'admin');
|
||||
} else {
|
||||
// When passing selected options, ensure each is cast to boolean for strict comparison.
|
||||
purge_caches(array_map(
|
||||
fn($option) => (bool) $option,
|
||||
$data->purgeselectedoptions,
|
||||
));
|
||||
purge_caches($data->purgeselectedoptions);
|
||||
$message = get_string('purgeselectedcachesfinished', 'admin');
|
||||
}
|
||||
|
||||
|
||||
@@ -34,10 +34,8 @@ admin_externalpage_setup('registrationmoodleorg');
|
||||
|
||||
$unregistration = optional_param('unregistration', false, PARAM_BOOL);
|
||||
$confirm = optional_param('confirm', false, PARAM_BOOL);
|
||||
// Consider the site 'registered' if records exist locally and at the hub.
|
||||
$siteisregistered = \core\hub\registration::is_registered() && core\hub\api::is_site_registered_in_hub();
|
||||
|
||||
if ($unregistration && $siteisregistered) {
|
||||
if ($unregistration && \core\hub\registration::is_registered()) {
|
||||
if ($confirm) {
|
||||
require_sesskey();
|
||||
\core\hub\registration::unregister(false, false);
|
||||
@@ -62,7 +60,7 @@ if (!$returnurl = optional_param('returnurl', null, PARAM_LOCALURL)) {
|
||||
$returnurl = $isinitialregistration ? '/admin/index.php' : '/admin/registration/index.php';
|
||||
}
|
||||
|
||||
$siteregistrationform = new \core\hub\site_registration_form(null, ['registered' => $siteisregistered]);
|
||||
$siteregistrationform = new \core\hub\site_registration_form();
|
||||
$siteregistrationform->set_data(['returnurl' => $returnurl]);
|
||||
if ($fromform = $siteregistrationform->get_data()) {
|
||||
|
||||
@@ -88,7 +86,7 @@ echo $OUTPUT->header();
|
||||
// Current status of registration.
|
||||
|
||||
$notificationtype = \core\output\notification::NOTIFY_ERROR;
|
||||
if ($siteisregistered) {
|
||||
if (\core\hub\registration::is_registered()) {
|
||||
$lastupdated = \core\hub\registration::get_last_updated();
|
||||
if ($lastupdated == 0) {
|
||||
$registrationmessage = get_string('pleaserefreshregistrationunknown', 'admin');
|
||||
@@ -106,7 +104,7 @@ if ($siteisregistered) {
|
||||
}
|
||||
|
||||
// Heading.
|
||||
if ($siteisregistered) {
|
||||
if (\core\hub\registration::is_registered()) {
|
||||
echo $OUTPUT->heading(get_string('registerwithmoodleorgupdate', 'core_hub'));
|
||||
} else if ($isinitialregistration) {
|
||||
echo $OUTPUT->heading(get_string('registerwithmoodleorgcomplete', 'core_hub'));
|
||||
@@ -119,7 +117,7 @@ echo $renderer->moodleorg_registration_message();
|
||||
|
||||
$siteregistrationform->display();
|
||||
|
||||
if ($siteisregistered) {
|
||||
if (\core\hub\registration::is_registered()) {
|
||||
// Unregister link.
|
||||
$unregisterhuburl = new moodle_url("/admin/registration/index.php", ['unregistration' => 1]);
|
||||
echo html_writer::div(html_writer::link($unregisterhuburl, get_string('unregister', 'hub')), 'unregister mt-2');
|
||||
@@ -127,7 +125,4 @@ if ($siteisregistered) {
|
||||
echo html_writer::div(html_writer::link(new moodle_url($returnurl), get_string('skipregistration', 'hub')),
|
||||
'skipregistration mt-2');
|
||||
}
|
||||
|
||||
$PAGE->requires->js_call_amd('core_admin/expand_hash', 'init');
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
+94
-158
@@ -843,14 +843,14 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$registerbutton = $this->single_button(new moodle_url('/admin/registration/index.php'),
|
||||
get_string('register', 'admin'));
|
||||
$str = 'registrationwarning';
|
||||
$type = 'error alert alert-danger';
|
||||
} else {
|
||||
$registerbutton = '';
|
||||
$str = 'registrationwarningcontactadmin';
|
||||
$type = 'info';
|
||||
}
|
||||
|
||||
return $this->warning( get_string($str, 'admin') . ' ' . $registerbutton , $type);
|
||||
return $this->warning( get_string($str, 'admin')
|
||||
. ' ' . $this->help_icon('registration', 'admin') . $registerbutton ,
|
||||
'error alert alert-danger');
|
||||
}
|
||||
|
||||
return '';
|
||||
@@ -874,8 +874,8 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
protected function mobile_configuration_warning($mobileconfigured) {
|
||||
$output = '';
|
||||
if (!$mobileconfigured) {
|
||||
$settingslink = new moodle_url('/admin/search.php', ['query' => 'enablemobilewebservice']);
|
||||
$configurebutton = $this->single_button($settingslink, get_string('enablemobilewebservice', 'admin'), 'get');
|
||||
$settingslink = new moodle_url('/admin/settings.php', ['section' => 'mobilesettings']);
|
||||
$configurebutton = $this->single_button($settingslink, get_string('enablemobilewebservice', 'admin'));
|
||||
$output .= $this->warning(get_string('mobilenotconfiguredwarning', 'admin') . ' ' . $configurebutton);
|
||||
}
|
||||
|
||||
@@ -1004,7 +1004,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
function upgrade_reload($url) {
|
||||
return html_writer::empty_tag('br') .
|
||||
html_writer::tag('div',
|
||||
html_writer::link($url, $this->pix_icon('i/reload', '', '', ['class' => 'icon']) .
|
||||
html_writer::link($url, $this->pix_icon('i/reload', '', '', array('class' => 'icon icon-pre')) .
|
||||
get_string('reload'), array('title' => get_string('reload'))),
|
||||
array('class' => 'continuebutton')) . html_writer::empty_tag('br');
|
||||
}
|
||||
@@ -1024,7 +1024,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
*/
|
||||
public function plugins_check_table(core_plugin_manager $pluginman, $version, array $options = array()) {
|
||||
global $CFG;
|
||||
$plugininfo = $pluginman->get_plugins(true);
|
||||
$plugininfo = $pluginman->get_plugins();
|
||||
|
||||
if (empty($plugininfo)) {
|
||||
return '';
|
||||
@@ -1059,20 +1059,6 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$upgradeabortable = $pluginman->list_restorable_archives();
|
||||
|
||||
foreach ($plugininfo as $type => $plugins) {
|
||||
// Skip deleted plugin types.
|
||||
if (\core_component::is_deleted_plugin_type($type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip deprecated plugintypes having no installed plugins, in which case there is nothing to report.
|
||||
if (\core_component::is_deprecated_plugin_type($type)) {
|
||||
$reportableplugins = array_filter($plugins, function($plugininfo) {
|
||||
return $plugininfo->versiondb != null;
|
||||
});
|
||||
if (empty($reportableplugins)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$header = new html_table_cell($pluginman->plugintype_name_plural($type));
|
||||
$header->header = true;
|
||||
@@ -1121,7 +1107,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
);
|
||||
|
||||
$versiondb = new html_table_cell($plugin->versiondb);
|
||||
$versiondisk = $plugin->is_deprecated() ? new html_table_cell() : new html_table_cell($plugin->versiondisk);
|
||||
$versiondisk = new html_table_cell($plugin->versiondisk);
|
||||
|
||||
if ($isstandard = $plugin->is_standard()) {
|
||||
$row->attributes['class'] .= ' standard';
|
||||
@@ -1140,9 +1126,6 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
$statuscode = $plugin->get_status();
|
||||
$row->attributes['class'] .= ' status-' . $statuscode;
|
||||
if ($plugin->is_deprecated()) {
|
||||
$row->attributes['class'] .= ' deprecatedtype';
|
||||
}
|
||||
$statusclass = 'statustext badge ';
|
||||
switch ($statuscode) {
|
||||
case core_plugin_manager::PLUGIN_STATUS_NEW:
|
||||
@@ -1163,18 +1146,6 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
$status = html_writer::span(get_string('status_' . $statuscode, 'core_plugin'), $statusclass);
|
||||
|
||||
$deprecatedstatus = '';
|
||||
if ($plugin->is_deprecated()) {
|
||||
// During upgrade, omit the status for deprecated plugin types, unless it's 'missing from disk'.
|
||||
// Deprecated plugins cannot be installed, upgraded, downgraded, and won't be automatically deleted.
|
||||
$status = in_array($statuscode,
|
||||
[core_plugin_manager::PLUGIN_STATUS_MISSING, core_plugin_manager::PLUGIN_STATUS_DELETE]) ? $status : '';
|
||||
$deprecatedstatus = html_writer::span(
|
||||
get_string('deprecated_type', 'core_plugin'),
|
||||
'statustext badge bg-danger text-white'
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($installabortable[$plugin->component])) {
|
||||
$status .= $this->output->single_button(
|
||||
new moodle_url($this->page->url, array('abortinstall' => $plugin->component, 'confirmplugincheck' => 0)),
|
||||
@@ -1200,7 +1171,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
}
|
||||
|
||||
$status = new html_table_cell($sourcelabel.' '.$status.' '.$deprecatedstatus);
|
||||
$status = new html_table_cell($sourcelabel.' '.$status);
|
||||
if ($plugin->pluginsupported != null) {
|
||||
$requires = new html_table_cell($this->required_column($plugin, $pluginman, $version, $CFG->branch));
|
||||
} else {
|
||||
@@ -1208,8 +1179,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
$statusisboring = in_array($statuscode, array(
|
||||
core_plugin_manager::PLUGIN_STATUS_NODB, core_plugin_manager::PLUGIN_STATUS_UPTODATE))
|
||||
&& !$plugin->is_deprecated();
|
||||
core_plugin_manager::PLUGIN_STATUS_NODB, core_plugin_manager::PLUGIN_STATUS_UPTODATE));
|
||||
|
||||
if ($options['xdep']) {
|
||||
// we want to see only plugins with failed dependencies
|
||||
@@ -1271,7 +1241,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
new moodle_url($this->page->url, array('installupdatex' => 1)),
|
||||
get_string('updateavailableinstallall', 'core_admin', count($installableupdates)),
|
||||
'post',
|
||||
array('class' => 'singlebutton updateavailableinstallall me-1')
|
||||
array('class' => 'singlebutton updateavailableinstallall mr-1')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1280,7 +1250,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
new moodle_url($this->page->url, array('abortinstallx' => 1, 'confirmplugincheck' => 0)),
|
||||
get_string('cancelinstallall', 'core_plugin', count($installabortable)),
|
||||
'post',
|
||||
array('class' => 'singlebutton cancelinstallall me-1')
|
||||
array('class' => 'singlebutton cancelinstallall mr-1')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1289,17 +1259,17 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
new moodle_url($this->page->url, array('abortupgradex' => 1)),
|
||||
get_string('cancelupgradeall', 'core_plugin', count($upgradeabortable)),
|
||||
'post',
|
||||
array('class' => 'singlebutton cancelupgradeall me-1')
|
||||
array('class' => 'singlebutton cancelupgradeall mr-1')
|
||||
);
|
||||
}
|
||||
|
||||
$out .= html_writer::div(html_writer::link(new moodle_url($this->page->url, array('showallplugins' => 0)),
|
||||
get_string('plugincheckattention', 'core_plugin')).' '.html_writer::span($sumattention, 'badge bg-light text-dark'),
|
||||
'btn btn-link me-1');
|
||||
'btn btn-link mr-1');
|
||||
|
||||
$out .= html_writer::div(html_writer::link(new moodle_url($this->page->url, array('showallplugins' => 1)),
|
||||
get_string('plugincheckall', 'core_plugin')).' '.html_writer::span($sumtotal, 'badge bg-light text-dark'),
|
||||
'btn btn-link me-1');
|
||||
'btn btn-link mr-1');
|
||||
|
||||
$out .= $this->output->container_end(); // End of .actions container.
|
||||
$out .= $this->output->container_end(); // End of #plugins-check-info container.
|
||||
@@ -1318,7 +1288,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
* @param null|moodle_url $cancel URL for the cancel link, defaults to the current page
|
||||
* @return string HTML
|
||||
*/
|
||||
public function plugins_management_confirm_buttons(?moodle_url $continue=null, ?moodle_url $cancel=null) {
|
||||
public function plugins_management_confirm_buttons(moodle_url $continue=null, moodle_url $cancel=null) {
|
||||
|
||||
$out = html_writer::start_div('plugins-management-confirm-buttons');
|
||||
|
||||
@@ -1406,13 +1376,13 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
new moodle_url($this->page->url, array('installdepx' => 1)),
|
||||
get_string('dependencyinstallmissing', 'core_plugin', count($installable)),
|
||||
'post',
|
||||
array('class' => 'singlebutton dependencyinstallmissing d-inline-block me-1')
|
||||
array('class' => 'singlebutton dependencyinstallmissing d-inline-block mr-1')
|
||||
);
|
||||
}
|
||||
|
||||
$out .= html_writer::div(html_writer::link(new moodle_url('/admin/tool/installaddon/'),
|
||||
get_string('dependencyuploadmissing', 'core_plugin'), array('class' => 'btn btn-link')),
|
||||
'dependencyuploadmissing d-inline-block me-1');
|
||||
'dependencyuploadmissing d-inline-block mr-1');
|
||||
|
||||
$out .= $this->output->container_end(); // End of .plugins-check-dependencies-actions container.
|
||||
|
||||
@@ -1478,29 +1448,29 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$info .= html_writer::div(
|
||||
html_writer::link('https://moodle.org/plugins/view.php?plugin='.$plugin->component,
|
||||
get_string('misdepinfoplugin', 'core_plugin')),
|
||||
'misdepinfoplugin d-inline-block me-3 mb-1'
|
||||
'misdepinfoplugin d-inline-block mr-3 mb-1'
|
||||
);
|
||||
|
||||
$info .= html_writer::div(
|
||||
html_writer::link('https://moodle.org/plugins/pluginversion.php?id='.$plugin->version->id,
|
||||
get_string('misdepinfoversion', 'core_plugin')),
|
||||
'misdepinfoversion d-inline-block me-3 mb-1'
|
||||
'misdepinfoversion d-inline-block mr-3 mb-1'
|
||||
);
|
||||
|
||||
$info .= html_writer::div(html_writer::link($plugin->version->downloadurl, get_string('download')),
|
||||
'misdepdownload d-inline-block me-3 mb-1');
|
||||
'misdepdownload d-inline-block mr-3 mb-1');
|
||||
|
||||
if ($pluginman->is_remote_plugin_installable($plugin->component, $plugin->version->version, $reason)) {
|
||||
$info .= $this->output->single_button(
|
||||
new moodle_url($this->page->url, array('installdep' => $plugin->component)),
|
||||
get_string('dependencyinstall', 'core_plugin'),
|
||||
'post',
|
||||
array('class' => 'singlebutton dependencyinstall me-3 mb-1')
|
||||
array('class' => 'singlebutton dependencyinstall mr-3 mb-1')
|
||||
);
|
||||
} else {
|
||||
$reasonhelp = $this->info_remote_plugin_not_installable($reason);
|
||||
if ($reasonhelp) {
|
||||
$info .= html_writer::div($reasonhelp, 'reasonhelp dependencyinstall d-inline-block me-3 mb-1');
|
||||
$info .= html_writer::div($reasonhelp, 'reasonhelp dependencyinstall d-inline-block mr-3 mb-1');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,26 +1655,11 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
*/
|
||||
public function plugins_overview_panel(core_plugin_manager $pluginman, array $options = array()) {
|
||||
|
||||
$plugininfo = $pluginman->get_plugins(true);
|
||||
$this->page->requires->js_call_amd('core_admin/plugins_overview', 'init');
|
||||
$plugininfo = $pluginman->get_plugins();
|
||||
|
||||
$numtotal = $numextension = $numupdatable = $numinstallable = $nummissing = $numnew = 0;
|
||||
$numtotal = $numextension = $numupdatable = $numinstallable = 0;
|
||||
|
||||
foreach ($plugininfo as $type => $plugins) {
|
||||
if (\core_component::is_deleted_plugin_type($type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip deprecated plugintypes having no installed plugins, in which case there is nothing to report.
|
||||
if (\core_component::is_deprecated_plugin_type($type)) {
|
||||
$reportableplugins = array_filter($plugins, function($plugininfo) {
|
||||
return $plugininfo->versiondb != null;
|
||||
});
|
||||
if (empty($reportableplugins)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($plugins as $name => $plugin) {
|
||||
if ($res = $plugin->available_updates()) {
|
||||
$numupdatable++;
|
||||
@@ -1716,12 +1671,8 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
}
|
||||
if ($plugin->get_status() === core_plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
$nummissing++;
|
||||
continue;
|
||||
}
|
||||
if ($plugin->get_status() === core_plugin_manager::PLUGIN_STATUS_NEW) {
|
||||
$numnew++;
|
||||
}
|
||||
$numtotal++;
|
||||
if (!$plugin->is_standard()) {
|
||||
$numextension++;
|
||||
@@ -1730,50 +1681,36 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
$infoall = html_writer::link(
|
||||
$this->page->url,
|
||||
new moodle_url($this->page->url, array('contribonly' => 0, 'updatesonly' => 0)),
|
||||
get_string('overviewall', 'core_plugin'),
|
||||
['title' => get_string('filterall', 'core_plugin'), 'data-filterby' => 'all', 'class' => 'active']
|
||||
).' '.html_writer::span($numtotal, 'badge text-dark number number-all');
|
||||
array('title' => get_string('filterall', 'core_plugin'))
|
||||
).' '.html_writer::span($numtotal, 'badge number number-all');
|
||||
|
||||
$infoext = html_writer::link(
|
||||
new moodle_url($this->page->url, [], 'additional'),
|
||||
new moodle_url($this->page->url, array('contribonly' => 1, 'updatesonly' => 0)),
|
||||
get_string('overviewext', 'core_plugin'),
|
||||
['title' => get_string('filtercontribonly', 'core_plugin'), 'data-filterby' => 'additional']
|
||||
).' '.html_writer::span($numextension, 'badge text-dark number number-additional');
|
||||
array('title' => get_string('filtercontribonly', 'core_plugin'))
|
||||
).' '.html_writer::span($numextension, 'badge number number-additional');
|
||||
|
||||
if ($numupdatable) {
|
||||
$infoupdatable = html_writer::link(
|
||||
new moodle_url($this->page->url, [], 'updatable'),
|
||||
new moodle_url($this->page->url, array('contribonly' => 0, 'updatesonly' => 1)),
|
||||
get_string('overviewupdatable', 'core_plugin'),
|
||||
['title' => get_string('filterupdatesonly', 'core_plugin'), 'data-filterby' => 'updatable']
|
||||
array('title' => get_string('filterupdatesonly', 'core_plugin'))
|
||||
).' '.html_writer::span($numupdatable, 'badge bg-info text-white number number-updatable');
|
||||
} else {
|
||||
// No updates, or the notifications disabled.
|
||||
$infoupdatable = '';
|
||||
}
|
||||
|
||||
if ($numnew) {
|
||||
$infonew = html_writer::link(
|
||||
new moodle_url($this->page->url, [], 'newplugin'),
|
||||
get_string('status_new', 'plugin'),
|
||||
['title' => get_string('filternewpluginsonly', 'core_plugin'), 'data-filterby' => 'newplugin']
|
||||
).' '.html_writer::span($numnew, 'badge bg-success text-white number number-newplugin');
|
||||
} else {
|
||||
$infonew = '';
|
||||
}
|
||||
$out = html_writer::start_div('', array('id' => 'plugins-overview-panel'));
|
||||
|
||||
if ($nummissing) {
|
||||
$infomissing = html_writer::link(
|
||||
new moodle_url($this->page->url, [], 'missing'),
|
||||
get_string('status_missing', 'plugin'),
|
||||
['title' => get_string('filtermissingonly', 'core_plugin'), 'data-filterby' => 'missing']
|
||||
).' '.html_writer::span($nummissing, 'badge bg-danger text-white number number-missing');
|
||||
} else {
|
||||
$infomissing = '';
|
||||
if (!empty($options['updatesonly'])) {
|
||||
$out .= $this->output->heading(get_string('overviewupdatable', 'core_plugin'), 3);
|
||||
} else if (!empty($options['contribonly'])) {
|
||||
$out .= $this->output->heading(get_string('overviewext', 'core_plugin'), 3);
|
||||
}
|
||||
|
||||
$out = html_writer::start_div('', ['id' => 'plugins-overview-panel']);
|
||||
|
||||
if ($numinstallable) {
|
||||
$out .= $this->output->single_button(
|
||||
new moodle_url($this->page->url, array('installupdatex' => 1)),
|
||||
@@ -1784,10 +1721,8 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
$out .= html_writer::div($infoall, 'info info-all').
|
||||
html_writer::div($infoext, 'info info-additional').
|
||||
html_writer::div($infoupdatable, 'info info-updatable').
|
||||
html_writer::div($infonew, 'info info-newplugin').
|
||||
html_writer::div($infomissing, 'info info-missing');
|
||||
html_writer::div($infoext, 'info info-ext').
|
||||
html_writer::div($infoupdatable, 'info info-updatable');
|
||||
|
||||
$out .= html_writer::end_div(); // End of #plugins-overview-panel block.
|
||||
|
||||
@@ -1805,7 +1740,39 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
*/
|
||||
public function plugins_control_panel(core_plugin_manager $pluginman, array $options = array()) {
|
||||
|
||||
$plugininfo = $pluginman->get_plugins(true);
|
||||
$plugininfo = $pluginman->get_plugins();
|
||||
|
||||
// Filter the list of plugins according the options.
|
||||
if (!empty($options['updatesonly'])) {
|
||||
$updateable = array();
|
||||
foreach ($plugininfo as $plugintype => $pluginnames) {
|
||||
foreach ($pluginnames as $pluginname => $pluginfo) {
|
||||
$pluginavailableupdates = $pluginfo->available_updates();
|
||||
if (!empty($pluginavailableupdates)) {
|
||||
foreach ($pluginavailableupdates as $pluginavailableupdate) {
|
||||
$updateable[$plugintype][$pluginname] = $pluginfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$plugininfo = $updateable;
|
||||
}
|
||||
|
||||
if (!empty($options['contribonly'])) {
|
||||
$contribs = array();
|
||||
foreach ($plugininfo as $plugintype => $pluginnames) {
|
||||
foreach ($pluginnames as $pluginname => $pluginfo) {
|
||||
if (!$pluginfo->is_standard()) {
|
||||
$contribs[$plugintype][$pluginname] = $pluginfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
$plugininfo = $contribs;
|
||||
}
|
||||
|
||||
if (empty($plugininfo)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$table = new html_table();
|
||||
$table->id = 'plugins-control-panel';
|
||||
@@ -1822,20 +1789,6 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
);
|
||||
|
||||
foreach ($plugininfo as $type => $plugins) {
|
||||
if (\core_component::is_deleted_plugin_type($type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip deprecated plugintypes having no installed plugins, in which case there is nothing to report.
|
||||
if (\core_component::is_deprecated_plugin_type($type)) {
|
||||
$reportableplugins = array_filter($plugins, function($plugininfo) {
|
||||
return $plugininfo->versiondb != null;
|
||||
});
|
||||
if (empty($reportableplugins)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$heading = $pluginman->plugintype_name_plural($type);
|
||||
$pluginclass = core_plugin_manager::resolve_plugininfo_class($type);
|
||||
if ($manageurl = $pluginclass::get_manage_url()) {
|
||||
@@ -1878,9 +1831,6 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
$status = $plugin->get_status();
|
||||
$row->attributes['class'] .= ' status-'.$status;
|
||||
if ($plugin->is_deprecated()) {
|
||||
$row->attributes['class'] .= ' deprecatedtype';
|
||||
}
|
||||
$pluginname = html_writer::tag('div', $icon.$plugin->displayname, array('class' => 'displayname')).
|
||||
html_writer::tag('div', $plugin->component, array('class' => 'componentname'));
|
||||
$pluginname = new html_table_cell($pluginname);
|
||||
@@ -1921,30 +1871,18 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$row->attributes['class'] .= ' standard';
|
||||
$source = '';
|
||||
} else {
|
||||
$row->attributes['class'] .= ' additional';
|
||||
$source = html_writer::div(get_string('sourceext', 'core_plugin'), 'source badge me-1 text-bg-info');
|
||||
$row->attributes['class'] .= ' extension';
|
||||
$source = html_writer::div(get_string('sourceext', 'core_plugin'), 'source badge bg-info text-white');
|
||||
}
|
||||
|
||||
if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
$row->attributes['class'] .= ' missing';
|
||||
$msg = html_writer::div(get_string('status_missing', 'core_plugin'), 'statusmsg badge text-bg-danger');
|
||||
$msg = html_writer::div(get_string('status_missing', 'core_plugin'), 'statusmsg badge bg-danger text-white');
|
||||
} else if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
|
||||
$row->attributes['class'] .= ' newplugin';
|
||||
$msg = html_writer::div(get_string('status_new', 'core_plugin'), 'statusmsg badge text-bg-success');
|
||||
$msg = html_writer::div(get_string('status_new', 'core_plugin'), 'statusmsg badge bg-success text-white');
|
||||
} else {
|
||||
$msg = '';
|
||||
}
|
||||
|
||||
$deprecatedmsg = '';
|
||||
if ($plugin->is_deprecated()) {
|
||||
// Omit the status for deprecated plugin types, unless it's 'missing from disk'.
|
||||
$msg = $status == core_plugin_manager::PLUGIN_STATUS_MISSING ? $msg : '';
|
||||
$deprecatedmsg = html_writer::div(
|
||||
get_string('deprecated_type', 'core_plugin'),
|
||||
'statusmsg badge bg-danger text-white'
|
||||
);
|
||||
}
|
||||
|
||||
$requriedby = $pluginman->other_plugins_that_require($plugin->component);
|
||||
if ($requriedby) {
|
||||
$requiredby = html_writer::tag('div', get_string('requiredby', 'core_plugin', implode(', ', $requriedby)),
|
||||
@@ -1955,13 +1893,12 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
$updateinfo = '';
|
||||
if (is_array($plugin->available_updates())) {
|
||||
$row->attributes['class'] .= ' updatable';
|
||||
foreach ($plugin->available_updates() as $availableupdate) {
|
||||
$updateinfo .= $this->plugin_available_update_info($pluginman, $availableupdate);
|
||||
}
|
||||
}
|
||||
|
||||
$notes = new html_table_cell($source.' '.$msg.' '.$deprecatedmsg.$requiredby.$updateinfo);
|
||||
$notes = new html_table_cell($source.$msg.$requiredby.$updateinfo);
|
||||
|
||||
$row->cells = array(
|
||||
$pluginname, $version, $availability, $settings, $uninstall, $notes
|
||||
@@ -2063,7 +2000,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
get_string('status'),
|
||||
);
|
||||
$servertable->colclasses = array('centeralign name', 'centeralign info', 'leftalign report', 'leftalign plugin', 'centeralign status');
|
||||
$servertable->attributes['class'] = 'table table-striped admintable environmenttable generaltable table-sm';
|
||||
$servertable->attributes['class'] = 'admintable environmenttable generaltable table-sm';
|
||||
$servertable->id = 'serverstatus';
|
||||
|
||||
$serverdata = array('ok'=>array(), 'warn'=>array(), 'error'=>array());
|
||||
@@ -2076,7 +2013,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
get_string('status'),
|
||||
);
|
||||
$othertable->colclasses = array('aligncenter info', 'alignleft report', 'alignleft plugin', 'aligncenter status');
|
||||
$othertable->attributes['class'] = 'table table-striped admintable environmenttable generaltable table-sm';
|
||||
$othertable->attributes['class'] = 'admintable environmenttable generaltable table-sm';
|
||||
$othertable->id = 'otherserverstatus';
|
||||
|
||||
$otherdata = array('ok'=>array(), 'warn'=>array(), 'error'=>array());
|
||||
@@ -2177,33 +2114,29 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
} else {
|
||||
$report = $this->doc_link(join('/', $linkparts), get_string($stringtouse, 'admin', $rec), true);
|
||||
}
|
||||
// Enclose report text in div so feedback text will be displayed underneath it.
|
||||
$report = html_writer::div($report);
|
||||
|
||||
// Format error or warning line
|
||||
if ($errorline) {
|
||||
$messagetype = 'error';
|
||||
$statusclass = 'bg-danger text-white';
|
||||
$feedbackclass = 'alert-danger';
|
||||
} else if ($warningline) {
|
||||
$messagetype = 'warn';
|
||||
$statusclass = 'bg-warning text-dark';
|
||||
$feedbackclass = 'alert-warning';
|
||||
} else {
|
||||
$messagetype = 'ok';
|
||||
$statusclass = 'bg-success text-white';
|
||||
$feedbackclass = 'alert-success';
|
||||
}
|
||||
$status = html_writer::span($status, 'badge ' . $statusclass);
|
||||
// Here we'll store all the feedback found
|
||||
$feedbacktext = '';
|
||||
// Append the feedback if there is some
|
||||
$feedbacktext .= $environment_result->strToReport($environment_result->getFeedbackStr(),
|
||||
"alert {$feedbackclass} px-2 py-1 m-1");
|
||||
$feedbacktext .= $environment_result->strToReport($environment_result->getFeedbackStr(), $messagetype);
|
||||
//Append the bypass if there is some
|
||||
$feedbacktext .= $environment_result->strToReport($environment_result->getBypassStr(),
|
||||
'alert alert-warning px-2 py-1 m-1');
|
||||
$feedbacktext .= $environment_result->strToReport($environment_result->getBypassStr(), 'warn');
|
||||
//Append the restrict if there is some
|
||||
$feedbacktext .= $environment_result->strToReport($environment_result->getRestrictStr(),
|
||||
'alert alert-danger px-2 py-1 m-1');
|
||||
$feedbacktext .= $environment_result->strToReport($environment_result->getRestrictStr(), 'error');
|
||||
|
||||
$report .= $feedbacktext;
|
||||
|
||||
@@ -2247,11 +2180,10 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
$output = '';
|
||||
$output .= $this->header();
|
||||
$output .= $this->container_start('upgradekeyreq');
|
||||
$output .= $this->heading(get_string('upgradekeyreq', 'core_admin'));
|
||||
$output .= $this->container_start('upgradekeyreq w-25');
|
||||
$output .= html_writer::start_tag('form', array('method' => 'POST', 'action' => $url));
|
||||
$output .= html_writer::empty_tag('input', [
|
||||
'id' => 'upgradekey',
|
||||
'name' => 'upgradekey',
|
||||
'type' => 'password',
|
||||
'class' => 'form-control w-auto',
|
||||
@@ -2274,10 +2206,14 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
* @return string
|
||||
*/
|
||||
public function moodleorg_registration_message() {
|
||||
$a = new stdClass();
|
||||
$a->moreinformation = '#id_sitestats'; // More information anchor.
|
||||
$a->moodleapp = HUB_MOODLEORGHUBURL . '/solutions/moodle-app/';
|
||||
$out = format_text(get_string('registerwithmoodleorginfo', 'core_hub', $a), FORMAT_MARKDOWN);
|
||||
|
||||
$out = format_text(get_string('registerwithmoodleorginfo', 'core_hub'), FORMAT_MARKDOWN);
|
||||
|
||||
$out .= html_writer::link(
|
||||
MOODLE_PRODUCTURL.'/solutions/moodle-app/',
|
||||
$this->output->pix_icon('i/info', '').' '.get_string('registerwithmoodleorginfoapp', 'core_hub'),
|
||||
['class' => 'btn btn-link', 'role' => 'opener', 'target' => '_href']
|
||||
);
|
||||
|
||||
$out .= html_writer::link(
|
||||
HUB_MOODLEORGHUBURL,
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# core_role (subsystem) Upgrade notes
|
||||
|
||||
## 4.5
|
||||
|
||||
### Added
|
||||
|
||||
- All session management has been moved to the `\core\session\manager` class.
|
||||
This removes the dependancy to use the `sessions` table.
|
||||
|
||||
Session management plugins (like Redis) should now inherit
|
||||
the base `\core\session\handler` class, which implements
|
||||
`SessionHandlerInterface`, and override methods as required.
|
||||
|
||||
The following methods in `\core\session\manager` have been deprecated:
|
||||
| Old method name | New method name |
|
||||
| --- | --- |
|
||||
| `kill_all_sessions` | `destroy_all` |
|
||||
| `kill_session` | `destroy` |
|
||||
| `kill_sessions_for_auth_plugin` | `destroy_by_auth_plugin` |
|
||||
| `kill_user_sessions` | `destroy_user_sessions` |
|
||||
|
||||
For more information see [MDL-66151](https://tracker.moodle.org/browse/MDL-66151)
|
||||
@@ -43,7 +43,7 @@ abstract class core_role_capability_table_base {
|
||||
protected $id;
|
||||
|
||||
/** Added to the class="" attribute on output. */
|
||||
protected $classes = ['rolecap table w-auto table-hover'];
|
||||
protected $classes = array('rolecap table-hover');
|
||||
|
||||
/** Default number of capabilities in the table for the search UI to be shown. */
|
||||
const NUM_CAPS_FOR_SEARCH = 12;
|
||||
|
||||
@@ -544,7 +544,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
|
||||
$options[$type] = get_string('archetype'.$type, 'role');
|
||||
}
|
||||
return html_writer::select($options, 'archetype', $this->role->archetype, false,
|
||||
['class' => 'form-select']);
|
||||
array('class' => 'custom-select'));
|
||||
}
|
||||
|
||||
protected function get_assignable_levels_control() {
|
||||
@@ -655,7 +655,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
|
||||
echo "</label>\n";
|
||||
}
|
||||
if ($helpicon) {
|
||||
echo '<span class="float-sm-end text-nowrap">'.$helpicon.'</span>';
|
||||
echo '<span class="float-sm-right text-nowrap">'.$helpicon.'</span>';
|
||||
}
|
||||
echo '</div>';
|
||||
if (isset($this->errors[$name])) {
|
||||
|
||||
@@ -18,12 +18,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace core_role\reportbuilder\local\entities;
|
||||
|
||||
use core\{context, context_helper};
|
||||
use core\lang_string;
|
||||
use context;
|
||||
use context_helper;
|
||||
use lang_string;
|
||||
use stdClass;
|
||||
use core_reportbuilder\local\entities\base;
|
||||
use core_reportbuilder\local\filters\select;
|
||||
use core_reportbuilder\local\report\{column, filter};
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Role entity
|
||||
@@ -83,6 +84,8 @@ class role extends base {
|
||||
* @return column[]
|
||||
*/
|
||||
protected function get_all_columns(): array {
|
||||
global $DB;
|
||||
|
||||
$contextalias = $this->get_table_alias('context');
|
||||
$rolealias = $this->get_table_alias('role');
|
||||
|
||||
@@ -93,16 +96,17 @@ class role extends base {
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_fields("{$rolealias}.name, {$rolealias}.shortname, {$rolealias}.id, {$contextalias}.id AS contextid")
|
||||
->add_fields(context_helper::get_preload_record_columns_sql($contextalias))
|
||||
// The sorting is on name, unless empty then we use shortname.
|
||||
// The sorting is on name, unless empty (determined by single space - thanks Oracle) then we use shortname.
|
||||
->set_is_sortable(true, [
|
||||
"CASE WHEN COALESCE({$rolealias}.name, '') = ''
|
||||
"CASE WHEN " . $DB->sql_concat("{$rolealias}.name", "' '") . " = ' '
|
||||
THEN {$rolealias}.shortname
|
||||
ELSE {$rolealias}.name
|
||||
END",
|
||||
])
|
||||
->add_callback(static function(?string $name, stdClass $role): string {
|
||||
->set_callback(static function($name, stdClass $role): string {
|
||||
if ($name === null) {
|
||||
return '';
|
||||
}
|
||||
@@ -120,17 +124,21 @@ class role extends base {
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_fields("{$rolealias}.name, {$rolealias}.shortname")
|
||||
// The sorting is on name, unless empty then we use shortname.
|
||||
// The sorting is on name, unless empty (determined by single space - thanks Oracle) then we use shortname.
|
||||
->set_is_sortable(true, [
|
||||
"CASE WHEN COALESCE({$rolealias}.name, '') = ''
|
||||
"CASE WHEN " . $DB->sql_concat("{$rolealias}.name", "' '") . " = ' '
|
||||
THEN {$rolealias}.shortname
|
||||
ELSE {$rolealias}.name
|
||||
END",
|
||||
])
|
||||
->add_callback(fn(?string $name, stdClass $role) => match ($name) {
|
||||
null => '',
|
||||
default => role_get_name($role, null, ROLENAME_ORIGINAL),
|
||||
->set_callback(static function($name, stdClass $role): string {
|
||||
if ($name === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return role_get_name($role, null, ROLENAME_ORIGINAL);
|
||||
});
|
||||
|
||||
// Short name column.
|
||||
@@ -140,25 +148,15 @@ class role extends base {
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->add_field("{$rolealias}.shortname")
|
||||
->set_is_sortable(true);
|
||||
|
||||
// Archetype column.
|
||||
$columns[] = (new column(
|
||||
'archetype',
|
||||
new lang_string('archetype', 'core_role'),
|
||||
$this->get_entity_name(),
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->add_field("{$rolealias}.archetype")
|
||||
->add_callback(fn(?string $archetype) => match ($archetype) {
|
||||
null => '',
|
||||
'' => get_string('none'),
|
||||
default => get_string("archetype{$archetype}", 'core_role'),
|
||||
})
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_fields("{$rolealias}.shortname")
|
||||
->set_is_sortable(true);
|
||||
|
||||
// Description column.
|
||||
$descriptionfieldsql = "{$rolealias}.description";
|
||||
if ($DB->get_dbfamily() === 'oracle') {
|
||||
$descriptionfieldsql = $DB->sql_order_by_text($descriptionfieldsql, 1024);
|
||||
}
|
||||
$columns[] = (new column(
|
||||
'description',
|
||||
new lang_string('description'),
|
||||
@@ -166,11 +164,14 @@ class role extends base {
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_LONGTEXT)
|
||||
->add_fields("{$rolealias}.description, {$rolealias}.shortname")
|
||||
->set_is_sortable(true)
|
||||
->add_callback(fn(?string $description, stdClass $role) => match ($description) {
|
||||
null => '',
|
||||
default => role_get_description($role),
|
||||
->add_field($descriptionfieldsql, 'description')
|
||||
->add_field("{$rolealias}.shortname")
|
||||
->set_callback(static function($description, stdClass $role): string {
|
||||
if ($description === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return role_get_description($role);
|
||||
});
|
||||
|
||||
return $columns;
|
||||
@@ -197,22 +198,6 @@ class role extends base {
|
||||
return role_get_names(null, ROLENAME_ORIGINAL, true);
|
||||
});
|
||||
|
||||
// Archetype filter.
|
||||
$filters[] = (new filter(
|
||||
select::class,
|
||||
'archetype',
|
||||
new lang_string('archetype', 'core_role'),
|
||||
$this->get_entity_name(),
|
||||
"{$rolealias}.archetype",
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_options_callback(static function(): array {
|
||||
return array_map(
|
||||
fn(string $archetype) => get_string("archetype{$archetype}", 'core_role'),
|
||||
get_role_archetypes(),
|
||||
);
|
||||
});
|
||||
|
||||
return $filters;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ class role_assignment extends base {
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_field("{$raalias}.component")
|
||||
->set_is_sortable(true);
|
||||
|
||||
@@ -112,6 +113,7 @@ class role_assignment extends base {
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_INTEGER)
|
||||
->add_field("{$raalias}.itemid")
|
||||
->set_is_sortable(true);
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ if (!empty($capabilities)) {
|
||||
$attrs = array('type'=>'submit', 'name'=>'savechanges', 'value'=>get_string('savechanges'), 'class'=>'btn btn-primary');
|
||||
echo html_writer::empty_tag('input', $attrs);
|
||||
$attrs = array('type' => 'submit', 'name' => 'cancel', 'value' => get_string('cancel'),
|
||||
'class' => 'btn btn-secondary ms-1');
|
||||
'class' => 'btn btn-secondary ml-1');
|
||||
echo html_writer::empty_tag('input', $attrs);
|
||||
echo html_writer::end_tag('div');
|
||||
echo html_writer::end_tag('div');
|
||||
|
||||
@@ -26,7 +26,7 @@ use core_role_preset;
|
||||
* @copyright 2013 Petr Skoda {@link http://skodak.org}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
final class preset_test extends \advanced_testcase {
|
||||
class preset_test extends \advanced_testcase {
|
||||
public function test_xml(): void {
|
||||
global $DB;
|
||||
|
||||
@@ -84,7 +84,7 @@ final class preset_test extends \advanced_testcase {
|
||||
public function test_mixed_levels(): void {
|
||||
// The problem here is that we cannot guarantee plugin contexts
|
||||
// have unique short names, so we have to also support level numbers.
|
||||
$xml = file_get_contents(self::get_fixture_path(__NAMESPACE__, 'mixed_levels.xml'));
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/mixed_levels.xml');
|
||||
$this->assertTrue(\core_role_preset::is_valid_preset($xml));
|
||||
|
||||
$preset = \core_role_preset::parse_preset($xml);
|
||||
|
||||
@@ -40,7 +40,7 @@ use core_privacy\local\request\approved_userlist;
|
||||
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
final class provider_test extends provider_testcase {
|
||||
class provider_test extends provider_testcase {
|
||||
/**
|
||||
* Test to check export_user_preferences.
|
||||
* returns user preferences data.
|
||||
@@ -77,7 +77,7 @@ final class provider_test extends provider_testcase {
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$course2 = $this->getDataGenerator()->create_course();
|
||||
$coursecat = $this->getDataGenerator()->create_category();
|
||||
$cm = $this->getDataGenerator()->create_module('assign', ['course' => $course->id]);
|
||||
$cm = $this->getDataGenerator()->create_module('chat', ['course' => $course->id]);
|
||||
$cmcontext = \context_module::instance($cm->cmid);
|
||||
$page = $this->getDataGenerator()->create_module('page', array('course' => $course->id));
|
||||
$cmcontext2 = \context_module::instance($page->cmid);
|
||||
@@ -125,7 +125,7 @@ final class provider_test extends provider_testcase {
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$course2 = $this->getDataGenerator()->create_course();
|
||||
$coursecat = $this->getDataGenerator()->create_category();
|
||||
$cm = $this->getDataGenerator()->create_module('assign', ['course' => $course->id]);
|
||||
$cm = $this->getDataGenerator()->create_module('chat', ['course' => $course->id]);
|
||||
$cmcontext = \context_module::instance($cm->cmid);
|
||||
$page = $this->getDataGenerator()->create_module('page', array('course' => $course->id));
|
||||
$cmcontext2 = \context_module::instance($page->cmid);
|
||||
@@ -257,7 +257,7 @@ final class provider_test extends provider_testcase {
|
||||
$coursecat = $this->getDataGenerator()->create_category();
|
||||
$coursecatcontext = \context_coursecat::instance($coursecat->id);
|
||||
$systemcontext = \context_system::instance();
|
||||
$cm = $this->getDataGenerator()->create_module('assign', ['course' => $course->id]);
|
||||
$cm = $this->getDataGenerator()->create_module('chat', ['course' => $course->id]);
|
||||
$cmcontext = \context_module::instance($cm->cmid);
|
||||
$student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
|
||||
$manager = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST);
|
||||
@@ -348,7 +348,7 @@ final class provider_test extends provider_testcase {
|
||||
$coursecat = $this->getDataGenerator()->create_category();
|
||||
$coursecatcontext = \context_coursecat::instance($coursecat->id);
|
||||
$systemcontext = \context_system::instance();
|
||||
$cm = $this->getDataGenerator()->create_module('assign', ['course' => $course->id]);
|
||||
$cm = $this->getDataGenerator()->create_module('chat', ['course' => $course->id]);
|
||||
$cmcontext = \context_module::instance($cm->cmid);
|
||||
$student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
|
||||
$manager = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST);
|
||||
@@ -499,8 +499,8 @@ final class provider_test extends provider_testcase {
|
||||
// Create course category.
|
||||
$coursecat = $this->getDataGenerator()->create_category();
|
||||
$coursecatcontext = \context_coursecat::instance($coursecat->id);
|
||||
// Create assignment module.
|
||||
$cm = $this->getDataGenerator()->create_module('assign', ['course' => $course1->id]);
|
||||
// Create chat module.
|
||||
$cm = $this->getDataGenerator()->create_module('chat', ['course' => $course1->id]);
|
||||
$cmcontext = \context_module::instance($cm->cmid);
|
||||
|
||||
$systemcontext = \context_system::instance();
|
||||
@@ -619,8 +619,8 @@ final class provider_test extends provider_testcase {
|
||||
// Create course category.
|
||||
$coursecat = $this->getDataGenerator()->create_category();
|
||||
$coursecatcontext = \context_coursecat::instance($coursecat->id);
|
||||
// Create assignment module.
|
||||
$cm = $this->getDataGenerator()->create_module('assign', ['course' => $course1->id]);
|
||||
// Create chat module.
|
||||
$cm = $this->getDataGenerator()->create_module('chat', ['course' => $course1->id]);
|
||||
$cmcontext = \context_module::instance($cm->cmid);
|
||||
|
||||
$systemcontext = \context_system::instance();
|
||||
|
||||
@@ -20,14 +20,19 @@ namespace core_role\reportbuilder\datasource;
|
||||
|
||||
use core\context\course;
|
||||
use core_reportbuilder_generator;
|
||||
use core_reportbuilder_testcase;
|
||||
use core_reportbuilder\local\filters\{date, select, text};
|
||||
use core_reportbuilder\tests\core_reportbuilder_testcase;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
|
||||
|
||||
/**
|
||||
* Unit tests for roles datasource
|
||||
*
|
||||
* @package core_role
|
||||
* @covers \core_role\reportbuilder\datasource\roles
|
||||
* @covers \core_role\reportbuilder\datasource\roles;
|
||||
* @copyright 2024 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
@@ -99,7 +104,6 @@ final class roles_test extends core_reportbuilder_testcase {
|
||||
// Role.
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role:name']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role:shortname']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role:archetype']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role:description']);
|
||||
|
||||
// Role assignment.
|
||||
@@ -110,20 +114,11 @@ final class roles_test extends core_reportbuilder_testcase {
|
||||
$content = $this->get_custom_report_content($report->get('id'));
|
||||
$this->assertCount(1, $content);
|
||||
|
||||
[
|
||||
$rolename,
|
||||
$roleshortname,
|
||||
$rolearchetype,
|
||||
$roledescription,
|
||||
$timemodified,
|
||||
$component,
|
||||
$itemid,
|
||||
] = array_values($content[0]);
|
||||
[$rolename, $roleshortname, $roledescription, $timemodified, $component, $itemid] = array_values($content[0]);
|
||||
|
||||
// Role.
|
||||
$this->assertEquals('Moocher (Manager)', $rolename);
|
||||
$this->assertEquals('manager', $roleshortname);
|
||||
$this->assertEquals('ARCHETYPE: Manager', $rolearchetype);
|
||||
$this->assertEquals('Managers can access courses and modify them, but usually do not participate in them.',
|
||||
$roledescription);
|
||||
|
||||
@@ -149,15 +144,7 @@ final class roles_test extends core_reportbuilder_testcase {
|
||||
], true],
|
||||
'Filter role name (no match)' => ['role:name', [
|
||||
'role:name_operator' => select::EQUAL_TO,
|
||||
'role:name_value' => $DB->get_field('role', 'id', ['shortname' => 'teacher']),
|
||||
], false],
|
||||
'Filter role archetype' => ['role:archetype', [
|
||||
'role:archetype_operator' => select::EQUAL_TO,
|
||||
'role:archetype_value' => 'student',
|
||||
], true],
|
||||
'Filter role archetype (no match)' => ['role:archetype', [
|
||||
'role:archetype_operator' => select::EQUAL_TO,
|
||||
'role:archetype_value' => 'teacher',
|
||||
'role:name_value' => -1,
|
||||
], false],
|
||||
|
||||
// Role assignment.
|
||||
|
||||
@@ -1,88 +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/>.
|
||||
|
||||
/**
|
||||
* Adds settings links to admin tree.
|
||||
*
|
||||
* AI gets top billing in general because it's the future.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2024 Matt Porritt <matt.porritt@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
if ($hassiteconfig) {
|
||||
// Add settings page for AI provider settings.
|
||||
$providers = new admin_settingpage('aiprovider', new lang_string('aiproviders', 'ai'));
|
||||
$providers->add(new admin_setting_heading('availableproviders',
|
||||
get_string('availableproviders', 'core_ai'),
|
||||
get_string('availableproviders_desc', 'core_ai')));
|
||||
// Add call to action to add a new provider.
|
||||
$providers->add(new \core_admin\admin\admin_setting_template_render(
|
||||
name: 'addnewprovider',
|
||||
templatename: 'core_ai/admin_add_provider',
|
||||
context: ['addnewproviderurl' => new moodle_url('/ai/configure.php')]
|
||||
));
|
||||
|
||||
$providers->add(new \core_ai\admin\admin_setting_provider_manager(
|
||||
'aiprovider',
|
||||
\core_ai\table\aiprovider_management_table::class,
|
||||
'manageaiproviders',
|
||||
new lang_string('manageaiproviders', 'core_ai'),
|
||||
));
|
||||
$ADMIN->add('ai', $providers);
|
||||
|
||||
// Add settings page for AI placement settings.
|
||||
$placements = new admin_settingpage('aiplacement', new lang_string('aiplacements', 'ai'));
|
||||
$placements->add(new admin_setting_heading('availableplacements',
|
||||
get_string('availableplacements', 'core_ai'),
|
||||
get_string('availableplacements_desc', 'core_ai')));
|
||||
$placements->add(new \core_admin\admin\admin_setting_plugin_manager(
|
||||
'aiplacement',
|
||||
\core_ai\table\aiplacement_management_table::class,
|
||||
'manageaiplacements',
|
||||
new lang_string('manageaiplacements', 'core_ai'),
|
||||
));
|
||||
$ADMIN->add('ai', $placements);
|
||||
|
||||
// Load settings for all placements.
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('aiplacement');
|
||||
foreach ($plugins as $plugin) {
|
||||
/** @var \core\plugininfo\aiprovider $plugin */
|
||||
$plugin->load_settings($ADMIN, 'ai', $hassiteconfig);
|
||||
}
|
||||
}
|
||||
|
||||
// AI reports category.
|
||||
$ADMIN->add('reports', new admin_category('aireports', get_string('aireports', 'core_ai')));
|
||||
// Add AI policy acceptance report.
|
||||
$aipolicyacceptance = new admin_externalpage(
|
||||
'aipolicyacceptancereport',
|
||||
get_string('aipolicyacceptance', 'core_ai'),
|
||||
new moodle_url('/ai/policy_acceptance_report.php'),
|
||||
'moodle/ai:viewaipolicyacceptancereport'
|
||||
);
|
||||
$ADMIN->add('aireports', $aipolicyacceptance);
|
||||
// Add AI usage report.
|
||||
$aiusage = new admin_externalpage(
|
||||
'aiusagereport',
|
||||
get_string('aiusage', 'core_ai'),
|
||||
new moodle_url('/ai/usage_report.php'),
|
||||
'moodle/ai:viewaiusagereport',
|
||||
);
|
||||
$ADMIN->add('aireports', $aiusage);
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
// This file defines settingpages and externalpages under the "appearance" category
|
||||
|
||||
$ADMIN->add('appearance', new admin_category('themes', new lang_string('themesettingscustom', 'admin')));
|
||||
|
||||
$capabilities = array(
|
||||
'moodle/my:configsyspages',
|
||||
'moodle/tag:manage'
|
||||
@@ -154,12 +152,6 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // sp
|
||||
}
|
||||
$choices[HOMEPAGE_MYCOURSES] = new lang_string('mycourses', 'admin');
|
||||
$choices[HOMEPAGE_USER] = new lang_string('userpreference', 'admin');
|
||||
|
||||
// Allow hook callbacks to extend options.
|
||||
$hook = new \core_user\hook\extend_default_homepage();
|
||||
\core\di::get(\core\hook\manager::class)->dispatch($hook);
|
||||
$choices += $hook->get_options();
|
||||
|
||||
$temp->add(new admin_setting_configselect('defaulthomepage', new lang_string('defaulthomepage', 'admin'),
|
||||
new lang_string('configdefaulthomepage', 'admin'), get_default_home_page(), $choices));
|
||||
if (!isset($CFG->enabledashboard) || $CFG->enabledashboard) {
|
||||
@@ -332,10 +324,6 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // sp
|
||||
$temp->add(new admin_setting_configcheckbox('logininfoinsecurelayout',
|
||||
new lang_string('logininfoinsecurelayout', 'admin'),
|
||||
new lang_string('logininfoinsecurelayout_desc', 'admin'), 0));
|
||||
// Process primary navigation (custom menu) through Moodle filters.
|
||||
$temp->add(new admin_setting_configcheckbox('navfilter',
|
||||
new lang_string('navfilter', 'admin'),
|
||||
new lang_string('navfilter_desc', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configtextarea('custommenuitems', new lang_string('custommenuitems', 'admin'),
|
||||
new lang_string('configcustommenuitems', 'admin'), '', PARAM_RAW, '50', '10'));
|
||||
$defaultsettingcustomusermenuitems = [
|
||||
@@ -361,6 +349,7 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // sp
|
||||
new lang_string('themeselector', 'admin'), $CFG->wwwroot . '/admin/themeselector.php'));
|
||||
|
||||
// Settings page for each theme.
|
||||
$ADMIN->add('appearance', new admin_category('themes', new lang_string('themesettingscustom', 'admin')));
|
||||
foreach (core_component::get_plugin_list('theme') as $theme => $themedir) {
|
||||
$settingspath = "$themedir/settings.php";
|
||||
if (file_exists($settingspath)) {
|
||||
|
||||
@@ -87,7 +87,7 @@ if (($hassiteconfig || has_any_capability(array(
|
||||
$ADMIN->add('badges',
|
||||
new admin_externalpage('newbadge',
|
||||
new lang_string('newbadge', 'badges'),
|
||||
new moodle_url('/badges/edit.php', ['action' => 'new']),
|
||||
new moodle_url('/badges/newbadge.php', array('type' => BADGE_TYPE_SITE)),
|
||||
array('moodle/badges:createbadge'), empty($CFG->enablebadges)
|
||||
)
|
||||
);
|
||||
|
||||
+14
-45
@@ -28,22 +28,13 @@ require_once($CFG->libdir . '/pdflib.php');
|
||||
|
||||
use core_admin\local\settings\filesize;
|
||||
|
||||
$ADMIN->add('courses', new admin_category('coursedefaultsettings', new lang_string('defaultsettingscategory', 'course')));
|
||||
$ADMIN->add('courses', new admin_category('groups', new lang_string('groups')));
|
||||
$ADMIN->add('courses', new admin_category('activitychooser', new lang_string('activitychoosercategory', 'course')));
|
||||
$ADMIN->add('courses', new admin_category('backups', new lang_string('backups', 'admin')));
|
||||
|
||||
$capabilities = [
|
||||
$capabilities = array(
|
||||
'moodle/backup:backupcourse',
|
||||
'moodle/category:manage',
|
||||
'moodle/course:create',
|
||||
'moodle/site:approvecourse',
|
||||
'moodle/restore:restorecourse',
|
||||
'moodle/course:manageactivities',
|
||||
'moodle/course:configurecustomfields',
|
||||
'moodle/group:configurecustomfields',
|
||||
'moodle/course:recommendactivity',
|
||||
];
|
||||
'moodle/restore:restorecourse'
|
||||
);
|
||||
if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
// Speedup for non-admins, add all caps used on this page.
|
||||
$ADMIN->add('courses',
|
||||
@@ -113,6 +104,7 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
}
|
||||
|
||||
// Add a category for the course Default settings.
|
||||
$ADMIN->add('courses', new admin_category('coursedefaultsettings', new lang_string('defaultsettingscategory', 'course')));
|
||||
// Course Default Settings Page.
|
||||
// NOTE: these settings must be applied after all other settings because they depend on them.
|
||||
|
||||
@@ -306,7 +298,8 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
)
|
||||
);
|
||||
|
||||
// Add to the 'Groups' category.
|
||||
// Add a category for the Groups.
|
||||
$ADMIN->add('courses', new admin_category('groups', new lang_string('groups')));
|
||||
$ADMIN->add(
|
||||
'groups',
|
||||
new admin_externalpage(
|
||||
@@ -326,7 +319,8 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
)
|
||||
);
|
||||
|
||||
// Add to the 'Activity Chooser' category.
|
||||
// Add a category for the Activity Chooser.
|
||||
$ADMIN->add('courses', new admin_category('activitychooser', new lang_string('activitychoosercategory', 'course')));
|
||||
$temp = new admin_settingpage('activitychoosersettings', new lang_string('activitychoosersettings', 'course'));
|
||||
// Tab mode for the activity chooser.
|
||||
$temp->add(
|
||||
@@ -378,7 +372,8 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
)
|
||||
);
|
||||
|
||||
// Add to the 'Backups' category.
|
||||
// Add a category for backups.
|
||||
$ADMIN->add('courses', new admin_category('backups', new lang_string('backups','admin')));
|
||||
|
||||
// Create a page for general backups configuration and defaults.
|
||||
$temp = new admin_settingpage('backupgeneralsettings', new lang_string('generalbackdefaults', 'backup'), 'moodle/backup:backupcourse');
|
||||
@@ -420,16 +415,11 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_userscompletion', new lang_string('generaluserscompletion','backup'), new lang_string('configgeneraluserscompletion','backup'), array('value'=>1, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_logs', new lang_string('generallogs','backup'), new lang_string('configgenerallogs','backup'), array('value'=>0, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_histories', new lang_string('generalhistories','backup'), new lang_string('configgeneralhistories','backup'), array('value'=>0, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_questionbank', new lang_string('generalquestionbank','backup'), new lang_string('configgeneralquestionbank','backup'), array('value'=>1, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_groups',
|
||||
new lang_string('generalgroups', 'backup'), new lang_string('configgeneralgroups', 'backup'),
|
||||
array('value' => 1, 'locked' => 0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_competencies', new lang_string('generalcompetencies','backup'), new lang_string('configgeneralcompetencies','backup'), array('value'=>1, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock(
|
||||
'backup/backup_general_customfield',
|
||||
new lang_string('generalcustomfield', 'backup'),
|
||||
new lang_string('configgeneralcustomfield', 'backup'),
|
||||
['value' => 1, 'locked' => 0],
|
||||
));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_contentbankcontent',
|
||||
new lang_string('generalcontentbankcontent', 'backup'),
|
||||
new lang_string('configgeneralcontentbankcontent', 'backup'),
|
||||
@@ -441,6 +431,7 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
['value' => 1, 'locked' => 0])
|
||||
);
|
||||
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_legacyfiles',
|
||||
new lang_string('generallegacyfiles', 'backup'),
|
||||
new lang_string('configlegacyfiles', 'backup'), array('value' => 1, 'locked' => 0)));
|
||||
@@ -463,23 +454,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_import_activities', new lang_string('generalactivities','backup'), new lang_string('configgeneralactivities','backup'), array('value'=>1, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_import_blocks', new lang_string('generalblocks','backup'), new lang_string('configgeneralblocks','backup'), array('value'=>1, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_import_filters', new lang_string('generalfilters','backup'), new lang_string('configgeneralfilters','backup'), array('value'=>1, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock(
|
||||
'backup/backup_import_badges',
|
||||
new lang_string('generalbadges', 'backup'),
|
||||
new lang_string('configgeneralbadges', 'backup'),
|
||||
['value' => 0, 'locked' => 0],
|
||||
));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_import_calendarevents', new lang_string('generalcalendarevents','backup'), new lang_string('configgeneralcalendarevents','backup'), array('value'=>1, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_import_questionbank', new lang_string('generalquestionbank','backup'), new lang_string('configgeneralquestionbank','backup'), array('value'=>1, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_import_groups',
|
||||
new lang_string('generalgroups', 'backup'), new lang_string('configgeneralgroups', 'backup'),
|
||||
array('value' => 1, 'locked' => 0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_import_competencies', new lang_string('generalcompetencies','backup'), new lang_string('configgeneralcompetencies','backup'), array('value'=>1, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock(
|
||||
'backup/backup_import_customfield',
|
||||
new lang_string('generalcustomfield', 'backup'),
|
||||
new lang_string('configgeneralcustomfield', 'backup'),
|
||||
['value' => 1, 'locked' => 0],
|
||||
));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock(
|
||||
'backup/backup_import_contentbankcontent',
|
||||
new lang_string('generalcontentbankcontent', 'backup'),
|
||||
@@ -605,15 +585,10 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_userscompletion', new lang_string('generaluserscompletion','backup'), new lang_string('configgeneraluserscompletion','backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_logs', new lang_string('generallogs', 'backup'), new lang_string('configgenerallogs', 'backup'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_histories', new lang_string('generalhistories','backup'), new lang_string('configgeneralhistories','backup'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_questionbank', new lang_string('generalquestionbank','backup'), new lang_string('configgeneralquestionbank','backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_groups', new lang_string('generalgroups', 'backup'),
|
||||
new lang_string('configgeneralgroups', 'backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_competencies', new lang_string('generalcompetencies','backup'), new lang_string('configgeneralcompetencies','backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox(
|
||||
'backup/backup_auto_customfield',
|
||||
new lang_string('generalcustomfield', 'backup'),
|
||||
new lang_string('configgeneralcustomfield', 'backup'),
|
||||
1,
|
||||
));
|
||||
$temp->add(new admin_setting_configcheckbox(
|
||||
'backup/backup_auto_contentbankcontent',
|
||||
new lang_string('generalcontentbankcontent', 'backup'),
|
||||
@@ -693,12 +668,6 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_competencies',
|
||||
new lang_string('generalcompetencies', 'backup'),
|
||||
new lang_string('configrestorecompetencies', 'backup'), array('value' => 1, 'locked' => 0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock(
|
||||
'restore/restore_general_customfield',
|
||||
new lang_string('generalcustomfield', 'backup'),
|
||||
new lang_string('configrestorecustomfield', 'backup'),
|
||||
['value' => 1, 'locked' => 0],
|
||||
));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_contentbankcontent',
|
||||
new lang_string('generalcontentbankcontent', 'backup'),
|
||||
new lang_string('configrestorecontentbankcontent', 'backup'), array('value' => 1, 'locked' => 0)));
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
// * Miscellaneous settings
|
||||
|
||||
// Experimental settings page.
|
||||
$ADMIN->add('development', new admin_category('experimental', new lang_string('experimental', 'admin')));
|
||||
if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
|
||||
if ($hassiteconfig) { // Speedup for non-admins, add all caps used on this page.
|
||||
// Experimental settings page
|
||||
$ADMIN->add('development', new admin_category('experimental', new lang_string('experimental','admin')));
|
||||
|
||||
$temp = new admin_settingpage('experimentalsettings', new lang_string('experimentalsettings', 'admin'));
|
||||
//TODO: Re-enable cc-import once re-implemented in 2.0.x
|
||||
@@ -109,16 +109,7 @@ if ($hassiteconfig) { // Speedup for non-admins, add all caps used on this page.
|
||||
// Add the 'profiling' page to admin block.
|
||||
$ADMIN->add('development', $temp);
|
||||
|
||||
$ADMIN->add(
|
||||
parentname: 'development',
|
||||
something: new admin_externalpage(
|
||||
name: 'swaggerui',
|
||||
visiblename: new lang_string('swaggerui', 'admin'),
|
||||
url: "$CFG->wwwroot/admin/swaggerui.php",
|
||||
),
|
||||
);
|
||||
|
||||
// Web service test clients DO NOT COMMIT : THE EXTERNAL WEB PAGE IS NOT AN ADMIN PAGE !!!!!
|
||||
// Web service test clients DO NOT COMMIT : THE EXTERNAL WEB PAGE IS NOT AN ADMIN PAGE !!!!!
|
||||
$ADMIN->add('development', new admin_externalpage('testclient', new lang_string('testclient', 'webservice'), "$CFG->wwwroot/$CFG->admin/webservice/testclient.php"));
|
||||
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Configure the settings for file redaction service.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright Meirza <meirza.arson@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
if (!$ADMIN->locate('file_redactor')) {
|
||||
$ADMIN->add('server', new admin_category('file_redactor', get_string('redactor', 'core_files')));
|
||||
}
|
||||
if ($hassiteconfig) {
|
||||
|
||||
$manager = \core\di::get(\core_files\redactor\manager::class);
|
||||
|
||||
// Get settings from each service.
|
||||
foreach ($manager->get_service_classnames() as $servicename => $service) {
|
||||
$servicesettings = new admin_settingpage(
|
||||
$servicename,
|
||||
new lang_string("redactor:{$servicename}", 'core_files'),
|
||||
);
|
||||
$service::add_settings($servicesettings);
|
||||
|
||||
$ADMIN->add('file_redactor', $servicesettings);
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,6 @@
|
||||
|
||||
// This file defines settingpages and externalpages under the "grades" section
|
||||
|
||||
use core\plugininfo\gradepenalty;
|
||||
|
||||
$ADMIN->add('grades', new admin_category('gradereports', new lang_string('reportsettings', 'grades')));
|
||||
$ADMIN->add('grades', new admin_category('gradeimports', new lang_string('importsettings', 'grades')));
|
||||
$ADMIN->add('grades', new admin_category('gradeexports', new lang_string('exportsettings', 'grades')));
|
||||
$ADMIN->add('grades', new admin_category('gradepenalty', new lang_string('gradepenalty', 'grades')));
|
||||
|
||||
if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
or has_capability('moodle/grade:manageletters', $systemcontext)) { // speedup for non-admins, add all caps used on this page
|
||||
|
||||
@@ -98,7 +91,7 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
$temp->add(new admin_setting_my_grades_report());
|
||||
|
||||
$temp->add(new admin_setting_configtext('gradereport_mygradeurl', new lang_string('externalurl', 'grades'),
|
||||
new lang_string('externalurl_desc', 'grades'), ''));
|
||||
new lang_string('externalurl_desc', 'grades'), ''));
|
||||
}
|
||||
$ADMIN->add('grades', $temp);
|
||||
|
||||
@@ -188,6 +181,7 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
// The plugins must implement a settings.php file that adds their admin settings to the $settings object
|
||||
|
||||
// Reports
|
||||
$ADMIN->add('grades', new admin_category('gradereports', new lang_string('reportsettings', 'grades')));
|
||||
foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) {
|
||||
// Include all the settings commands for this plugin if there are any
|
||||
if (file_exists($plugindir.'/settings.php')) {
|
||||
@@ -200,6 +194,7 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
}
|
||||
|
||||
// Imports
|
||||
$ADMIN->add('grades', new admin_category('gradeimports', new lang_string('importsettings', 'grades')));
|
||||
foreach (core_component::get_plugin_list('gradeimport') as $plugin => $plugindir) {
|
||||
|
||||
// Include all the settings commands for this plugin if there are any
|
||||
@@ -214,6 +209,7 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
|
||||
|
||||
// Exports
|
||||
$ADMIN->add('grades', new admin_category('gradeexports', new lang_string('exportsettings', 'grades')));
|
||||
foreach (core_component::get_plugin_list('gradeexport') as $plugin => $plugindir) {
|
||||
// Include all the settings commands for this plugin if there are any
|
||||
if (file_exists($plugindir.'/settings.php')) {
|
||||
@@ -225,42 +221,5 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
}
|
||||
}
|
||||
|
||||
// Penalty.
|
||||
|
||||
// Supported modules.
|
||||
$modules = core_grades\penalty_manager::get_supported_modules();
|
||||
if (!empty($modules)) {
|
||||
$temp = new admin_settingpage('supportedplugins', new lang_string('gradepenalty_supportedplugins', 'grades'),
|
||||
'moodle/grade:manage');
|
||||
|
||||
$options = [];
|
||||
foreach ($modules as $module) {
|
||||
$options[$module] = new lang_string('modulename', $module);
|
||||
}
|
||||
$temp->add(new admin_setting_configmultiselect('gradepenalty_enabledmodules',
|
||||
new lang_string('gradepenalty_enabledmodules', 'grades'),
|
||||
new lang_string('gradepenalty_enabledmodules_help', 'grades'), [], $options));
|
||||
|
||||
$ADMIN->add('gradepenalty', $temp);
|
||||
}
|
||||
|
||||
// External page to manage the penalty plugins.
|
||||
$temp = new admin_externalpage(
|
||||
'managepenaltyplugins',
|
||||
get_string('managepenaltyplugins', 'grades'),
|
||||
new moodle_url('/grade/penalty/manage_penalty_plugins.php'),
|
||||
'moodle/grade:manage'
|
||||
);
|
||||
$ADMIN->add('gradepenalty', $temp);
|
||||
|
||||
// Settings from each penalty plugin.
|
||||
foreach (core_component::get_plugin_list('gradepenalty') as $plugin => $plugindir) {
|
||||
// Check if the plugin is enabled.
|
||||
if (gradepenalty::is_plugin_enabled($plugin)) {
|
||||
// Include all the settings commands for this plugin if there are any.
|
||||
if (file_exists($plugindir . '/settings.php')) {
|
||||
include($plugindir . '/settings.php');
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end of speedup
|
||||
|
||||
|
||||
@@ -39,37 +39,18 @@ if ($hassiteconfig) {
|
||||
$temp->add(new admin_setting_configtext('defaultcity', new lang_string('defaultcity', 'core_admin'),
|
||||
new lang_string('defaultcity_help', 'core_admin'), ''));
|
||||
|
||||
$temp->add(new admin_setting_countrycodes('allcountrycodes', new lang_string('allcountrycodes', 'core_admin'),
|
||||
new lang_string('configallcountrycodes', 'core_admin')));
|
||||
|
||||
$temp->add(new admin_setting_heading('iplookup', new lang_string('iplookup', 'core_admin'),
|
||||
new lang_string('iplookupinfo', 'core_admin')));
|
||||
|
||||
$temp->add(new admin_setting_configfile('geoip2file', new lang_string('geoipfile', 'core_admin'),
|
||||
new lang_string('configgeoipfile', 'core_admin', $CFG->dataroot . '/geoip/'),
|
||||
$CFG->dataroot . '/geoip/GeoIP-City.mmdb'));
|
||||
|
||||
$temp->add(new admin_setting_configselect('geoipdbedition',
|
||||
new lang_string('geoipdbedition', 'core_admin'),
|
||||
new lang_string('geoipdbedition_desc', 'core_admin'), 'GeoLite2-City',
|
||||
['GeoLite2-City' => 'GeoLite2-City', 'GeoIP2-City' => 'GeoIP2-City']));
|
||||
|
||||
$temp->add(new admin_setting_configtext('geoipmaxmindaccid',
|
||||
new lang_string('geoipmaxmindaccid', 'core_admin'),
|
||||
new lang_string('geoipmaxmindaccid_desc', 'core_admin'),
|
||||
'',
|
||||
PARAM_TEXT,
|
||||
));
|
||||
|
||||
$temp->add(new admin_setting_configtext('geoipmaxmindlicensekey',
|
||||
new lang_string('geoipmaxmindlicensekey', 'core_admin'),
|
||||
new lang_string('geoipmaxmindlicensekey_desc', 'core_admin'),
|
||||
'',
|
||||
PARAM_TEXT,
|
||||
));
|
||||
$CFG->dataroot . '/geoip/GeoLite2-City.mmdb'));
|
||||
|
||||
$temp->add(new admin_setting_configtext('googlemapkey3', new lang_string('googlemapkey3', 'core_admin'),
|
||||
new lang_string('googlemapkey3_help', 'core_admin'), '', PARAM_RAW, 60));
|
||||
|
||||
$temp->add(new admin_setting_countrycodes('allcountrycodes', new lang_string('allcountrycodes', 'core_admin'),
|
||||
new lang_string('configallcountrycodes', 'core_admin')));
|
||||
}
|
||||
|
||||
$ADMIN->add('location', $temp);
|
||||
|
||||
@@ -39,6 +39,9 @@ if (isset($CFG->mnet_dispatcher_mode) and $CFG->mnet_dispatcher_mode !== 'off')
|
||||
$ADMIN->add('mnet', new admin_externalpage('ssoaccesscontrol', new lang_string('ssoaccesscontrol', 'mnet'),
|
||||
"$CFG->wwwroot/$CFG->admin/mnet/access_control.php",
|
||||
'moodle/site:config'));
|
||||
$ADMIN->add('mnet', new admin_externalpage('mnetenrol', new lang_string('clientname', 'mnetservice_enrol'),
|
||||
"$CFG->wwwroot/mnet/service/enrol/index.php",
|
||||
'moodle/site:config'));
|
||||
$ADMIN->add('mnet', new admin_externalpage('trustedhosts', new lang_string('trustedhosts', 'mnet'),
|
||||
"$CFG->wwwroot/$CFG->admin/mnet/trustedhosts.php",
|
||||
'moodle/site:config'));
|
||||
|
||||
+36
-79
@@ -24,40 +24,6 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$ADMIN->add('modules', new admin_category('modsettings', new lang_string('activitymodules')));
|
||||
$ADMIN->add('modules', new admin_category('formatsettings', new lang_string('courseformats')));
|
||||
$ADMIN->add('modules', new admin_category('customfieldsettings', new lang_string('customfields', 'core_customfield')));
|
||||
$ADMIN->add('modules', new admin_category('blocksettings', new lang_string('blocks')));
|
||||
$ADMIN->add('modules', new admin_category('authsettings', new lang_string('authentication', 'admin')));
|
||||
$ADMIN->add('modules', new admin_category('enrolments', new lang_string('enrolments', 'enrol')));
|
||||
$ADMIN->add('modules', new admin_category('editorsettings', new lang_string('editors', 'editor')));
|
||||
$ADMIN->add('modules', new admin_category('antivirussettings', new lang_string('antiviruses', 'antivirus')));
|
||||
$ADMIN->add('modules', new admin_category('mlbackendsettings', new lang_string('mlbackendsettings', 'admin')));
|
||||
$ADMIN->add('modules', new admin_category('filtersettings', new lang_string('managefilters')));
|
||||
$ADMIN->add('modules', new admin_category('mediaplayers', new lang_string('type_media_plural', 'plugin')));
|
||||
$ADMIN->add('modules', new admin_category('fileconverterplugins', new lang_string('type_fileconverter_plural', 'plugin')));
|
||||
$ADMIN->add('modules', new admin_category('paymentgateways', new lang_string('type_paygw_plural', 'plugin')));
|
||||
$ADMIN->add('modules', new admin_category('dataformatsettings', new lang_string('dataformats')));
|
||||
$ADMIN->add('modules', new admin_category('portfoliosettings', new lang_string('portfolios', 'portfolio'),
|
||||
empty($CFG->enableportfolios)));
|
||||
$ADMIN->add('modules', new admin_category('repositorysettings', new lang_string('repositories', 'repository')));
|
||||
$ADMIN->add('modules', new admin_category('qbanksettings', new lang_string('type_qbank_plural', 'plugin')));
|
||||
$ADMIN->add('modules', new admin_category('qbehavioursettings', new lang_string('questionbehaviours', 'admin')));
|
||||
$ADMIN->add('modules', new admin_category('qtypesettings', new lang_string('questiontypes', 'admin')));
|
||||
$ADMIN->add('modules', new admin_category('plagiarism', new lang_string('plagiarism', 'plagiarism')));
|
||||
$ADMIN->add('modules', new admin_category('coursereports', new lang_string('coursereports')));
|
||||
$ADMIN->add('modules', new admin_category('reportplugins', new lang_string('reports')));
|
||||
$ADMIN->add('modules', new admin_category('searchplugins', new lang_string('search', 'admin')));
|
||||
$ADMIN->add('modules', new admin_category('tools', new lang_string('tools', 'admin')));
|
||||
$ADMIN->add('modules', new admin_category('cache', new lang_string('caching', 'cache')));
|
||||
$ADMIN->add('cache', new admin_category('cachestores', new lang_string('cachestores', 'cache')));
|
||||
$ADMIN->add('modules', new admin_category('calendartype', new lang_string('calendartypes', 'calendar')));
|
||||
$ADMIN->add('modules', new admin_category('communicationsettings', new lang_string('communication', 'core_communication')));
|
||||
$ADMIN->add('modules', new admin_category('sms', new lang_string('sms', 'core_sms')));
|
||||
$ADMIN->add('modules', new admin_category('contentbanksettings', new lang_string('contentbank')));
|
||||
$ADMIN->add('modules', new admin_category('localplugins', new lang_string('localplugins')));
|
||||
|
||||
|
||||
if ($hassiteconfig) {
|
||||
/* @var admin_root $ADMIN */
|
||||
$ADMIN->locate('modules')->set_sorting(true);
|
||||
@@ -65,6 +31,7 @@ if ($hassiteconfig) {
|
||||
$ADMIN->add('modules', new admin_page_pluginsoverview());
|
||||
|
||||
// activity modules
|
||||
$ADMIN->add('modules', new admin_category('modsettings', new lang_string('activitymodules')));
|
||||
|
||||
$ADMIN->add('modsettings', new admin_page_managemods());
|
||||
|
||||
@@ -81,6 +48,7 @@ if ($hassiteconfig) {
|
||||
}
|
||||
|
||||
// course formats
|
||||
$ADMIN->add('modules', new admin_category('formatsettings', new lang_string('courseformats')));
|
||||
$temp = new admin_settingpage('manageformats', new lang_string('manageformats', 'core_admin'));
|
||||
$temp->add(new admin_setting_manageformats());
|
||||
$ADMIN->add('formatsettings', $temp);
|
||||
@@ -92,6 +60,7 @@ if ($hassiteconfig) {
|
||||
}
|
||||
|
||||
// Custom fields.
|
||||
$ADMIN->add('modules', new admin_category('customfieldsettings', new lang_string('customfields', 'core_customfield')));
|
||||
$temp = new admin_settingpage('managecustomfields', new lang_string('managecustomfields', 'core_admin'));
|
||||
$temp->add(new admin_setting_managecustomfields());
|
||||
$ADMIN->add('customfieldsettings', $temp);
|
||||
@@ -103,6 +72,7 @@ if ($hassiteconfig) {
|
||||
}
|
||||
|
||||
// blocks
|
||||
$ADMIN->add('modules', new admin_category('blocksettings', new lang_string('blocks')));
|
||||
$ADMIN->add('blocksettings', new admin_page_manageblocks());
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('block');
|
||||
core_collator::asort_objects_by_property($plugins, 'displayname');
|
||||
@@ -112,6 +82,8 @@ if ($hassiteconfig) {
|
||||
}
|
||||
|
||||
// authentication plugins
|
||||
$ADMIN->add('modules', new admin_category('authsettings', new lang_string('authentication', 'admin')));
|
||||
|
||||
$temp = new admin_settingpage('manageauths', new lang_string('authsettings', 'admin'));
|
||||
$temp->add(new admin_setting_manageauths());
|
||||
$temp->add(new admin_setting_heading('manageauthscommonheading', new lang_string('commonsettings', 'admin'), ''));
|
||||
@@ -130,8 +102,6 @@ if ($hassiteconfig) {
|
||||
new lang_string('limitconcurrentlogins_desc', 'core_auth'), 0, $options));
|
||||
$temp->add(new admin_setting_configtext('alternateloginurl', new lang_string('alternateloginurl', 'auth'),
|
||||
new lang_string('alternatelogin', 'auth', htmlspecialchars(get_login_url(), ENT_COMPAT)), ''));
|
||||
$temp->add(new admin_setting_configcheckbox('showloginform', new lang_string('showloginform', 'core_auth'),
|
||||
new lang_string('showloginform_desc', 'core_auth'), 1));
|
||||
$temp->add(new admin_setting_configtext('forgottenpasswordurl', new lang_string('forgottenpasswordurl', 'auth'),
|
||||
new lang_string('forgottenpassword', 'auth'), '', PARAM_URL));
|
||||
$temp->add(new admin_setting_confightmleditor('auth_instructions', new lang_string('instructions', 'auth'),
|
||||
@@ -188,6 +158,7 @@ if ($hassiteconfig) {
|
||||
}
|
||||
|
||||
// Enrolment plugins
|
||||
$ADMIN->add('modules', new admin_category('enrolments', new lang_string('enrolments', 'enrol')));
|
||||
$temp = new admin_settingpage('manageenrols', new lang_string('manageenrols', 'enrol'));
|
||||
$temp->add(new admin_setting_manageenrols());
|
||||
$ADMIN->add('enrolments', $temp);
|
||||
@@ -204,6 +175,7 @@ if ($hassiteconfig) {
|
||||
|
||||
|
||||
/// Editor plugins
|
||||
$ADMIN->add('modules', new admin_category('editorsettings', new lang_string('editors', 'editor')));
|
||||
$temp = new admin_settingpage('manageeditors', new lang_string('editorsettings', 'editor'));
|
||||
$temp->add(new \core_admin\admin\admin_setting_plugin_manager(
|
||||
'editor',
|
||||
@@ -220,6 +192,7 @@ if ($hassiteconfig) {
|
||||
}
|
||||
|
||||
// Antivirus plugins.
|
||||
$ADMIN->add('modules', new admin_category('antivirussettings', new lang_string('antiviruses', 'antivirus')));
|
||||
$temp = new admin_settingpage('manageantiviruses', new lang_string('antivirussettings', 'antivirus'));
|
||||
$temp->add(new admin_setting_manageantiviruses());
|
||||
|
||||
@@ -291,12 +264,14 @@ if ($hassiteconfig) {
|
||||
}
|
||||
|
||||
// Machine learning backend plugins.
|
||||
$ADMIN->add('modules', new admin_category('mlbackendsettings', new lang_string('mlbackendsettings', 'admin')));
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('mlbackend');
|
||||
foreach ($plugins as $plugin) {
|
||||
$plugin->load_settings($ADMIN, 'mlbackendsettings', $hassiteconfig);
|
||||
}
|
||||
|
||||
/// Filter plugins
|
||||
$ADMIN->add('modules', new admin_category('filtersettings', new lang_string('managefilters')));
|
||||
|
||||
$ADMIN->add('filtersettings', new admin_page_managefilters());
|
||||
|
||||
@@ -310,7 +285,7 @@ if ($hassiteconfig) {
|
||||
$items[] = new admin_setting_configcheckbox('filtermatchonepertext', new lang_string('filtermatchonepertext', 'admin'), new lang_string('configfiltermatchonepertext', 'admin'), 0);
|
||||
$items[] = new admin_setting_configcheckbox('filternavigationwithsystemcontext',
|
||||
new lang_string('filternavigationwithsystemcontext', 'admin'),
|
||||
new lang_string('configfilternavigationwithsystemcontext', 'admin'), 1);
|
||||
new lang_string('configfilternavigationwithsystemcontext', 'admin'), 0);
|
||||
foreach ($items as $item) {
|
||||
$item->set_updatedcallback('reset_text_filters_cache');
|
||||
$temp->add($item);
|
||||
@@ -326,6 +301,7 @@ if ($hassiteconfig) {
|
||||
}
|
||||
|
||||
// Media players.
|
||||
$ADMIN->add('modules', new admin_category('mediaplayers', new lang_string('type_media_plural', 'plugin')));
|
||||
$temp = new admin_settingpage('managemediaplayers', new lang_string('managemediaplayers', 'media'));
|
||||
$temp->add(new admin_setting_heading('mediaformats', get_string('mediaformats', 'core_media'),
|
||||
format_text(get_string('mediaformats_desc', 'core_media'), FORMAT_MARKDOWN)));
|
||||
@@ -345,6 +321,7 @@ if ($hassiteconfig) {
|
||||
$ADMIN->add('mediaplayers', $temp);
|
||||
|
||||
// Convert plugins.
|
||||
$ADMIN->add('modules', new admin_category('fileconverterplugins', new lang_string('type_fileconverter_plural', 'plugin')));
|
||||
$temp = new admin_settingpage('managefileconverterplugins', new lang_string('type_fileconvertermanage', 'plugin'));
|
||||
$temp->add(new admin_setting_manage_fileconverter_plugins());
|
||||
$ADMIN->add('fileconverterplugins', $temp);
|
||||
@@ -364,6 +341,7 @@ if ($hassiteconfig) {
|
||||
}
|
||||
|
||||
// Payment gateway plugins.
|
||||
$ADMIN->add('modules', new admin_category('paymentgateways', new lang_string('type_paygw_plural', 'plugin')));
|
||||
$temp = new admin_settingpage('managepaymentgateways', new lang_string('type_paygwmanage', 'plugin'));
|
||||
$temp->add(new \core_admin\local\settings\manage_payment_gateway_plugins());
|
||||
$temp->add(new admin_setting_description(
|
||||
@@ -382,6 +360,7 @@ if ($hassiteconfig) {
|
||||
}
|
||||
|
||||
// Data format settings.
|
||||
$ADMIN->add('modules', new admin_category('dataformatsettings', new lang_string('dataformats')));
|
||||
$temp = new admin_settingpage('managedataformats', new lang_string('managedataformats'));
|
||||
$temp->add(new admin_setting_managedataformats());
|
||||
$ADMIN->add('dataformatsettings', $temp);
|
||||
@@ -395,9 +374,12 @@ if ($hassiteconfig) {
|
||||
|
||||
//== Portfolio settings ==
|
||||
require_once($CFG->libdir. '/portfoliolib.php');
|
||||
$catname = new lang_string('portfolios', 'portfolio');
|
||||
$manage = new lang_string('manageportfolios', 'portfolio');
|
||||
$url = "$CFG->wwwroot/$CFG->admin/portfolio.php";
|
||||
|
||||
$ADMIN->add('modules', new admin_category('portfoliosettings', $catname, empty($CFG->enableportfolios)));
|
||||
|
||||
// Add manage page (with table)
|
||||
$temp = new admin_page_manageportfolios();
|
||||
$ADMIN->add('portfoliosettings', $temp);
|
||||
@@ -451,8 +433,10 @@ if ($hassiteconfig) {
|
||||
|
||||
// repository setting
|
||||
require_once("$CFG->dirroot/repository/lib.php");
|
||||
$catname =new lang_string('repositories', 'repository');
|
||||
$managerepo = new lang_string('manage', 'repository');
|
||||
$url = $CFG->wwwroot.'/'.$CFG->admin.'/repository.php';
|
||||
$ADMIN->add('modules', new admin_category('repositorysettings', $catname));
|
||||
|
||||
// Add main page (with table)
|
||||
$temp = new admin_page_managerepositories();
|
||||
@@ -488,6 +472,8 @@ if ($hassiteconfig) {
|
||||
|
||||
// Question bank settings.
|
||||
if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext)) {
|
||||
$ADMIN->add('modules', new admin_category('qbanksettings',
|
||||
new lang_string('type_qbank_plural', 'plugin')));
|
||||
$temp = new admin_settingpage('manageqbanks', new lang_string('manageqbanks', 'admin'));
|
||||
$temp->add(new \core_question\admin\manage_qbank_plugins_page());
|
||||
$ADMIN->add('qbanksettings', $temp);
|
||||
@@ -503,9 +489,11 @@ if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext))
|
||||
if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext)) {
|
||||
|
||||
// Question behaviour settings.
|
||||
$ADMIN->add('modules', new admin_category('qbehavioursettings', new lang_string('questionbehaviours', 'admin')));
|
||||
$ADMIN->add('qbehavioursettings', new admin_page_manageqbehaviours());
|
||||
|
||||
// Question type settings.
|
||||
$ADMIN->add('modules', new admin_category('qtypesettings', new lang_string('questiontypes', 'admin')));
|
||||
$ADMIN->add('qtypesettings', new admin_page_manageqtypes());
|
||||
|
||||
// Question preview defaults.
|
||||
@@ -554,18 +542,6 @@ if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext))
|
||||
$settings->add(new admin_setting_configselect('question_preview/history',
|
||||
get_string('responsehistory', 'question'), '', 0, $hiddenofvisible));
|
||||
|
||||
// Question editing settings.
|
||||
$settings = new admin_settingpage('qediting',
|
||||
get_string('questionediting', 'question'),
|
||||
'moodle/question:config');
|
||||
$ADMIN->add('qtypesettings', $settings);
|
||||
|
||||
$settings->add(new admin_setting_heading('qediting_options',
|
||||
'', get_string('questionediting_desc', 'question')));
|
||||
|
||||
$settings->add(new admin_setting_configcheckbox('questiondefaultssave',
|
||||
get_string('questiondefaultssave', 'question'), get_string('questiondefaultssave_desc', 'question'), 1));
|
||||
|
||||
// Settings for particular question types.
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('qtype');
|
||||
core_collator::asort_objects_by_property($plugins, 'displayname');
|
||||
@@ -577,6 +553,7 @@ if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext))
|
||||
|
||||
// Plagiarism plugin settings
|
||||
if ($hassiteconfig && !empty($CFG->enableplagiarism)) {
|
||||
$ADMIN->add('modules', new admin_category('plagiarism', new lang_string('plagiarism', 'plagiarism')));
|
||||
$ADMIN->add('plagiarism', new admin_externalpage('manageplagiarismplugins', new lang_string('manageplagiarism', 'plagiarism'),
|
||||
$CFG->wwwroot . '/' . $CFG->admin . '/plagiarism.php'));
|
||||
|
||||
@@ -608,6 +585,7 @@ if ($hassiteconfig) {
|
||||
}
|
||||
}
|
||||
if (!empty($pages)) {
|
||||
$ADMIN->add('modules', new admin_category('coursereports', new lang_string('coursereports')));
|
||||
core_collator::asort_objects_by_property($pages, 'visiblename');
|
||||
foreach ($pages as $page) {
|
||||
$ADMIN->add('coursereports', $page);
|
||||
@@ -629,6 +607,7 @@ foreach (core_component::get_plugin_list('report') as $report => $plugindir) {
|
||||
}
|
||||
}
|
||||
}
|
||||
$ADMIN->add('modules', new admin_category('reportplugins', new lang_string('reports')));
|
||||
$ADMIN->add('reportplugins', new admin_externalpage('managereports', new lang_string('reportsmanage', 'admin'),
|
||||
$CFG->wwwroot . '/' . $CFG->admin . '/reports.php'));
|
||||
core_collator::asort_objects_by_property($pages, 'visiblename');
|
||||
@@ -638,6 +617,7 @@ foreach ($pages as $page) {
|
||||
|
||||
if ($hassiteconfig) {
|
||||
// Global Search engine plugins.
|
||||
$ADMIN->add('modules', new admin_category('searchplugins', new lang_string('search', 'admin')));
|
||||
$temp = new admin_settingpage('manageglobalsearch', new lang_string('globalsearchmanage', 'admin'));
|
||||
|
||||
$pages = array();
|
||||
@@ -779,6 +759,7 @@ if ($hassiteconfig) {
|
||||
|
||||
/// Add all admin tools
|
||||
if ($hassiteconfig) {
|
||||
$ADMIN->add('modules', new admin_category('tools', new lang_string('tools', 'admin')));
|
||||
$settingspage = new admin_settingpage('toolsmanagement', new lang_string('toolsmanage', 'admin'));
|
||||
$ADMIN->add('tools', $settingspage);
|
||||
$settingspage->add(new \core_admin\admin\admin_setting_plugin_manager(
|
||||
@@ -799,10 +780,12 @@ foreach ($plugins as $plugin) {
|
||||
|
||||
// Now add the Cache plugins
|
||||
if ($hassiteconfig) {
|
||||
$ADMIN->add('modules', new admin_category('cache', new lang_string('caching', 'cache')));
|
||||
$ADMIN->add('cache', new admin_externalpage('cacheconfig', new lang_string('cacheconfig', 'cache'), $CFG->wwwroot .'/cache/admin.php'));
|
||||
$ADMIN->add('cache', new admin_externalpage('cachetestperformance', new lang_string('testperformance', 'cache'), $CFG->wwwroot . '/cache/testperformance.php'));
|
||||
$ADMIN->add('cache', new admin_externalpage('cacheusage',
|
||||
new lang_string('cacheusage', 'cache'), $CFG->wwwroot . '/cache/usage.php'));
|
||||
$ADMIN->add('cache', new admin_category('cachestores', new lang_string('cachestores', 'cache')));
|
||||
$ADMIN->locate('cachestores')->set_sorting(true);
|
||||
foreach (core_component::get_plugin_list('cachestore') as $plugin => $path) {
|
||||
$settingspath = $path.'/settings.php';
|
||||
@@ -816,6 +799,7 @@ if ($hassiteconfig) {
|
||||
|
||||
// Add Calendar type settings.
|
||||
if ($hassiteconfig) {
|
||||
$ADMIN->add('modules', new admin_category('calendartype', new lang_string('calendartypes', 'calendar')));
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('calendartype');
|
||||
core_collator::asort_objects_by_property($plugins, 'displayname');
|
||||
foreach ($plugins as $plugin) {
|
||||
@@ -826,6 +810,7 @@ if ($hassiteconfig) {
|
||||
|
||||
// Communication plugins.
|
||||
if ($hassiteconfig && core_communication\api::is_available()) {
|
||||
$ADMIN->add('modules', new admin_category('communicationsettings', new lang_string('communication', 'core_communication')));
|
||||
$temp = new admin_settingpage('managecommunicationproviders',
|
||||
new lang_string('managecommunicationproviders', 'core_communication'));
|
||||
$temp->add(new \core_communication\admin\manage_communication_providers_page());
|
||||
@@ -837,41 +822,12 @@ if ($hassiteconfig && core_communication\api::is_available()) {
|
||||
}
|
||||
}
|
||||
|
||||
// SMS plugins.
|
||||
if ($hassiteconfig) {
|
||||
$ADMIN->add(
|
||||
'sms',
|
||||
new admin_externalpage(
|
||||
'smsgateway',
|
||||
new lang_string('manage_sms_gateways', 'core_sms'),
|
||||
$CFG->wwwroot . '/sms/sms_gateways.php',
|
||||
),
|
||||
);
|
||||
foreach (core_component::get_plugin_list('smsgateway') as $plugin => $path) {
|
||||
$settingspath = $path . '/settings.php';
|
||||
if (file_exists($settingspath)) {
|
||||
$settings = new admin_settingpage(
|
||||
'smsgateway_' . $plugin . '_settings',
|
||||
new lang_string('pluginname', 'smsgateway_' . $plugin),
|
||||
'moodle/site:config',
|
||||
);
|
||||
include($settingspath);
|
||||
$ADMIN->add('smsgateway', $settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Content bank content types.
|
||||
if ($hassiteconfig) {
|
||||
$ADMIN->add('modules', new admin_category('contentbanksettings', new lang_string('contentbank')));
|
||||
$temp = new admin_settingpage('managecontentbanktypes', new lang_string('managecontentbanktypes'));
|
||||
$temp->add(new admin_setting_managecontentbankcontenttypes());
|
||||
$ADMIN->add('contentbanksettings', $temp);
|
||||
$ADMIN->add('contentbanksettings',
|
||||
new admin_externalpage('contentbank', new lang_string('contentbankcustomfields', 'contentbank'),
|
||||
$CFG->wwwroot . '/contentbank/customfield.php',
|
||||
'moodle/contentbank:configurecustomfields'
|
||||
)
|
||||
);
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('contenttype');
|
||||
foreach ($plugins as $plugin) {
|
||||
/** @var \core\plugininfo\contentbank $plugin */
|
||||
@@ -881,6 +837,7 @@ if ($hassiteconfig) {
|
||||
|
||||
/// Add all local plugins - must be always last!
|
||||
if ($hassiteconfig) {
|
||||
$ADMIN->add('modules', new admin_category('localplugins', new lang_string('localplugins')));
|
||||
$ADMIN->add('localplugins', new admin_externalpage('managelocalplugins', new lang_string('localpluginsmanage'),
|
||||
$CFG->wwwroot . '/' . $CFG->admin . '/localplugins.php'));
|
||||
}
|
||||
|
||||
@@ -64,15 +64,3 @@ $settings->add(new admin_setting_configcheckbox(
|
||||
new lang_string('customreportsliveediting_desc', 'core_reportbuilder'), 1));
|
||||
|
||||
$ADMIN->add('reportbuilder', $settings);
|
||||
|
||||
$ADMIN->add(
|
||||
'reportbuilder', new accesscallback(
|
||||
'reportbuildercustomfields',
|
||||
get_string('reportbuildercustomfields', 'core_reportbuilder'),
|
||||
(new moodle_url('/reportbuilder/customfield.php'))->out(),
|
||||
static function(): bool {
|
||||
return has_capability('moodle/reportbuilder:configurecustomfields', context_system::instance());
|
||||
},
|
||||
empty($CFG->enablecustomreports)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -126,7 +126,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$temp->add($adminsetting);
|
||||
$temp->add(new admin_setting_configcheckbox('passwordchangelogout',
|
||||
new lang_string('passwordchangelogout', 'admin'),
|
||||
new lang_string('passwordchangelogout_desc', 'admin'), 1));
|
||||
new lang_string('passwordchangelogout_desc', 'admin'), 0));
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('passwordchangetokendeletion',
|
||||
new lang_string('passwordchangetokendeletion', 'admin'),
|
||||
@@ -147,7 +147,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$sensiblesettingsdefault .= 'secretphrase@@url, cronremotepassword@@none, smtpuser@@none, ';
|
||||
$sensiblesettingsdefault .= 'smtppass@@none, proxypassword@@none, quizpassword@@quiz, allowedip@@none, blockedip@@none, ';
|
||||
$sensiblesettingsdefault .= 'dbpass@@logstore_database, messageinbound_hostpass@@none, ';
|
||||
$sensiblesettingsdefault .= 'pass@@auth_db, bind_pw@@auth_ldap, ';
|
||||
$sensiblesettingsdefault .= 'bind_pw@@auth_cas, pass@@auth_db, bind_pw@@auth_ldap, ';
|
||||
$sensiblesettingsdefault .= 'dbpass@@enrol_database, bind_pw@@enrol_ldap, ';
|
||||
$sensiblesettingsdefault .= 'server_password@@search_solr, ssl_keypassword@@search_solr, ';
|
||||
$sensiblesettingsdefault .= 'alternateserver_password@@search_solr, alternatessl_keypassword@@search_solr, ';
|
||||
|
||||
@@ -25,10 +25,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$ADMIN->add('server', new admin_category('taskconfig', new lang_string('taskadmintitle', 'admin')));
|
||||
$ADMIN->add('server', new admin_category('email', new lang_string('categoryemail', 'admin')));
|
||||
$ADMIN->add('server', new admin_category('webservicesettings', new lang_string('webservices', 'webservice')));
|
||||
|
||||
if ($hassiteconfig) {
|
||||
// System paths.
|
||||
$temp = new admin_settingpage('systempaths', new lang_string('systempaths', 'admin'));
|
||||
@@ -185,16 +181,8 @@ if ($hassiteconfig) {
|
||||
new lang_string('configproxyuser', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configpasswordunmask('proxypassword', new lang_string('proxypassword', 'admin'),
|
||||
new lang_string('configproxypassword', 'admin'), ''));
|
||||
|
||||
$setting = new admin_setting_configtext('proxybypass', new lang_string('proxybypass', 'admin'),
|
||||
new lang_string('configproxybypass', 'admin'), 'localhost,127.0.0.1');
|
||||
$setting->set_updatedcallback(function() {
|
||||
// Normalize $CFG->proxybypass value.
|
||||
$normalizedvalue = \core\ip_utils::normalize_internet_address_list(get_config('core', 'proxybypass'));
|
||||
set_config('proxybypass', $normalizedvalue);
|
||||
});
|
||||
$temp->add($setting);
|
||||
|
||||
$temp->add(new admin_setting_configtext('proxybypass', new lang_string('proxybypass', 'admin'),
|
||||
new lang_string('configproxybypass', 'admin'), 'localhost, 127.0.0.1'));
|
||||
$temp->add(new admin_setting_configcheckbox('proxylogunsafe', new lang_string('proxylogunsafe', 'admin'),
|
||||
new lang_string('configproxylogunsafe_help', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('proxyfixunsafe', new lang_string('proxyfixunsafe', 'admin'),
|
||||
@@ -337,6 +325,7 @@ if ($hassiteconfig) {
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
// Tasks.
|
||||
$ADMIN->add('server', new admin_category('taskconfig', new lang_string('taskadmintitle', 'admin')));
|
||||
|
||||
// Task processing.
|
||||
$temp = new admin_settingpage('taskprocessing', new lang_string('taskprocessing', 'admin'));
|
||||
@@ -470,6 +459,7 @@ if ($hassiteconfig) {
|
||||
}
|
||||
|
||||
// Email.
|
||||
$ADMIN->add('server', new admin_category('email', new lang_string('categoryemail', 'admin')));
|
||||
|
||||
// Outgoing mail configuration.
|
||||
$temp = new admin_settingpage('outgoingmailconfig', new lang_string('outgoingmailconfig', 'admin'));
|
||||
@@ -641,6 +631,7 @@ if ($hassiteconfig) {
|
||||
}
|
||||
|
||||
// Web services.
|
||||
$ADMIN->add('server', new admin_category('webservicesettings', new lang_string('webservices', 'webservice')));
|
||||
|
||||
// Web services > Overview.
|
||||
$temp = new admin_settingpage('webservicesoverview', new lang_string('webservicesoverview', 'webservice'));
|
||||
|
||||
@@ -46,9 +46,9 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
|
||||
$optionalsubsystems->add(new admin_setting_configcheckbox('allowstealth', new lang_string('allowstealthmodules'),
|
||||
new lang_string('allowstealthmodules_help'), 0, 1, 0));
|
||||
// TODO: Analytics is now disable on new installs until MDL-84481 overcomes the config of mlbackend_python.
|
||||
|
||||
$optionalsubsystems->add(new admin_setting_configcheckbox('enableanalytics', new lang_string('enableanalytics', 'admin'),
|
||||
new lang_string('configenableanalytics', 'admin'), 0, 1, 0));
|
||||
new lang_string('configenableanalytics', 'admin'), 1, 1, 0));
|
||||
|
||||
$optionalsubsystems->add(new admin_setting_configcheckbox('core_competency/enabled',
|
||||
new lang_string('enablecompetencies', 'core_competency'),
|
||||
|
||||
@@ -25,7 +25,6 @@ if ($hassiteconfig) {
|
||||
$ADMIN->add('root', new admin_category('users', new lang_string('users','admin')));
|
||||
$ADMIN->add('root', new admin_category('courses', new lang_string('courses','admin')));
|
||||
$ADMIN->add('root', new admin_category('grades', new lang_string('grades')));
|
||||
$ADMIN->add('root', new admin_category('ai', new lang_string('ai', 'ai')));
|
||||
$ADMIN->add('root', new admin_category('analytics', new lang_string('analytics', 'analytics')));
|
||||
$ADMIN->add('root', new admin_category('competencies', new lang_string('competencies', 'core_competency')));
|
||||
$ADMIN->add('root', new admin_category('badges', new lang_string('badges'), empty($CFG->enablebadges)));
|
||||
|
||||
@@ -6,20 +6,14 @@ $ADMIN->add('users', new admin_category('accounts', new lang_string('accounts',
|
||||
$ADMIN->add('users', new admin_category('roles', new lang_string('permissions', 'role')));
|
||||
$ADMIN->add('users', new admin_category('privacy', new lang_string('privacyandpolicies', 'admin')));
|
||||
|
||||
$capabilities = [
|
||||
'moodle/user:create',
|
||||
'moodle/user:update',
|
||||
'moodle/user:delete',
|
||||
'moodle/role:manage',
|
||||
'moodle/role:assign',
|
||||
'moodle/cohort:manage',
|
||||
'moodle/cohort:view',
|
||||
'moodle/cohort:configurecustomfields',
|
||||
'moodle/role:safeoverride',
|
||||
'moodle/role:override',
|
||||
];
|
||||
|
||||
if ($hassiteconfig || has_any_capability($capabilities, $systemcontext)) { // Speedup for non-admins, all caps used on this page.
|
||||
if ($hassiteconfig
|
||||
or has_capability('moodle/user:create', $systemcontext)
|
||||
or has_capability('moodle/user:update', $systemcontext)
|
||||
or has_capability('moodle/user:delete', $systemcontext)
|
||||
or has_capability('moodle/role:manage', $systemcontext)
|
||||
or has_capability('moodle/role:assign', $systemcontext)
|
||||
or has_capability('moodle/cohort:manage', $systemcontext)
|
||||
or has_capability('moodle/cohort:view', $systemcontext)) { // Speedup for non-admins, add all caps used on this page.
|
||||
|
||||
|
||||
// Stuff under the "accounts" subcategory.
|
||||
|
||||
@@ -1,87 +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/>.
|
||||
|
||||
/**
|
||||
* Swagger UI for Moodle
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require('../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
$swaggerversion = '5.17.14';
|
||||
|
||||
$PAGE->set_url('/admin/swaggerui.php');
|
||||
|
||||
admin_externalpage_setup('swaggerui');
|
||||
|
||||
$PAGE->requires->css(new moodle_url("https://unpkg.com/swagger-ui-dist@{$swaggerversion}/swagger-ui.css"));
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// These have to be manually added for now because they must be made cross-origin. The `js` method does not yet support this.
|
||||
echo html_writer::tag(
|
||||
tagname: 'script',
|
||||
contents: '',
|
||||
attributes: [
|
||||
'src' => new moodle_url("https://unpkg.com/swagger-ui-dist@{$swaggerversion}/swagger-ui-bundle.js"),
|
||||
'crossorigin' => 'crossorigin',
|
||||
],
|
||||
);
|
||||
echo html_writer::tag(
|
||||
tagname: 'script',
|
||||
contents: '',
|
||||
attributes: [
|
||||
'src' => new moodle_url("https://unpkg.com/swagger-ui-plugin-hierarchical-tags"),
|
||||
'crossorigin' => 'crossorigin',
|
||||
],
|
||||
);
|
||||
|
||||
$openapipath = moodle_url::routed_path('/api/rest/v2/openapi.json')->out();
|
||||
$swaggerinit = <<<JS
|
||||
window.ui = SwaggerUIBundle({
|
||||
url: "{$openapipath}",
|
||||
dom_id: '#swagger-ui',
|
||||
|
||||
// Enable the "Try it out" button by default.
|
||||
tryItOutEnabled: true,
|
||||
|
||||
// Show snippets different OS options.
|
||||
requestSnippetsEnabled: true,
|
||||
|
||||
deepLinking: true,
|
||||
|
||||
plugins: [
|
||||
HierarchicalTagsPlugin,
|
||||
],
|
||||
|
||||
hierarchicalTagSeparator: /[_]/
|
||||
});
|
||||
JS;
|
||||
|
||||
$PAGE->requires->js_init_code(
|
||||
jscode: $swaggerinit,
|
||||
ondomready: true,
|
||||
);
|
||||
|
||||
echo html_writer::div('', '', [
|
||||
'id' => 'swagger-ui',
|
||||
]);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
+1
-34
@@ -24,7 +24,6 @@
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once("{$CFG->libdir}/adminlib.php");
|
||||
require_once("tool/task/lib.php");
|
||||
|
||||
use core_admin\reportbuilder\local\systemreports\task_logs;
|
||||
use core_reportbuilder\system_report_factory;
|
||||
@@ -50,41 +49,9 @@ if (null !== $logid) {
|
||||
if ($download) {
|
||||
$filename = str_replace('\\', '_', $log->classname) . "-{$log->id}.log";
|
||||
header("Content-Disposition: attachment; filename=\"{$filename}\"");
|
||||
readstring_accel($log->output, 'text/plain');
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$class = new $log->classname;
|
||||
$title = $class->get_name();
|
||||
} catch (Exception $e) {
|
||||
$title = $log->classname;
|
||||
}
|
||||
$title .= " ($log->id)";
|
||||
|
||||
$PAGE->navbar->add($title, '');
|
||||
echo $OUTPUT->header();
|
||||
echo html_writer::start_tag('pre', ['class' => 'task-output', 'style' => 'min-height: 24lh']);
|
||||
|
||||
echo tool_task_mtrace_wrapper($log->output);
|
||||
echo html_writer::end_tag('pre');
|
||||
echo $OUTPUT->action_link(
|
||||
new moodle_url('/admin/tasklogs.php'),
|
||||
$strheading,
|
||||
null,
|
||||
null,
|
||||
new pix_icon('i/log', ''),
|
||||
);
|
||||
echo ' ';
|
||||
echo $OUTPUT->action_link(
|
||||
new moodle_url('/admin/tasklogs.php', ['logid' => $log->id, 'download' => true]),
|
||||
new lang_string('download'),
|
||||
null,
|
||||
null,
|
||||
new pix_icon('t/download', ''),
|
||||
);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
readstring_accel($log->output, 'text/plain');
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
<div class="simplesearchform d-flex justify-content-end">
|
||||
<form autocomplete="off" action="{{action}}" method="get" accept-charset="utf-8" class="mform d-flex flex-wrap align-items-center simplesearchform">
|
||||
<div class="input-group">
|
||||
<label for="searchinput-{{uniqid}}">
|
||||
<span class="sr-only">{{#str}} search, core {{/str}}</span>
|
||||
</label>
|
||||
<input type="text"
|
||||
id="searchinput-{{uniqid}}"
|
||||
class="form-control"
|
||||
@@ -38,13 +41,12 @@
|
||||
autocomplete="off"
|
||||
{{#query}}value="{{.}}"{{/query}}
|
||||
>
|
||||
<label for="searchinput-{{uniqid}}">
|
||||
<span class="visually-hidden">{{#str}} search, core {{/str}}</span>
|
||||
</label>
|
||||
<button type="submit" class="btn btn-primary search-icon">
|
||||
{{#pix}} a/search, core {{/pix}}
|
||||
<span class="visually-hidden">{{#str}} search, core {{/str}}</span>
|
||||
</button>
|
||||
<div class="input-group-append">
|
||||
<button type="submit" class="btn btn-primary search-icon">
|
||||
{{#pix}} a/search, core {{/pix}}
|
||||
<span class="sr-only">{{#str}} search, core {{/str}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -59,9 +59,9 @@
|
||||
Setting autocomplete.
|
||||
}}
|
||||
|
||||
<div class="defaultsnext">
|
||||
<div class="form-select defaultsnext">
|
||||
<input type="hidden" name="{{name}}[xxxxx]" value="_qf__force_multiselect_submission">
|
||||
<select class="form-select" name="{{name}}[]"
|
||||
<select class="custom-select" name="{{name}}[]"
|
||||
id="{{id}}"
|
||||
{{#multiple}}multiple{{/multiple}}>
|
||||
{{#options}}
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
Setting.
|
||||
}}
|
||||
<div class="form-item row" id="{{id}}">
|
||||
<div class="form-label col-sm-3 text-sm-end">
|
||||
<div class="form-label col-sm-3 text-sm-right">
|
||||
{{#customcontrol}}
|
||||
<p {{#labelfor}}id="{{labelfor}}_label"{{/labelfor}}>
|
||||
{{{title}}}
|
||||
@@ -81,7 +81,7 @@
|
||||
{{#default}}
|
||||
<div class="form-defaultinfo text-muted {{#forceltr}}text-ltr{{/forceltr}}">{{{default}}}</div>
|
||||
{{/default}}
|
||||
<div class="form-text mt-2">{{{description}}}</div>
|
||||
<div class="form-description mt-3">{{{description}}}</div>
|
||||
{{#dependenton}}<div class="form-dependenton mb-4 text-muted">{{{.}}}</div>{{/dependenton}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
<div class="form-duration defaultsnext">
|
||||
<div class="d-flex flex-wrap align-items-center">
|
||||
<input type="text" size="5" id="{{id}}v" name="{{name}}[v]" value="{{value}}" class="form-control text-ltr" {{#readonly}}disabled{{/readonly}}>
|
||||
<label class="visually-hidden" for="{{id}}u">{{#str}}durationunits, admin{{/str}}</label>
|
||||
<select id="{{id}}u" name="{{name}}[u]" class="form-control form-select" {{#readonly}}disabled{{/readonly}}>
|
||||
<label class="sr-only" for="{{id}}u">{{#str}}durationunits, admin{{/str}}</label>
|
||||
<select id="{{id}}u" name="{{name}}[u]" class="form-control custom-select" {{#readonly}}disabled{{/readonly}}>
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
<div class="form-filesize defaultsnext">
|
||||
<div class="d-flex flex-wrap align-items-center">
|
||||
<input type="text" size="5" id="{{id}}v" name="{{name}}[v]" value="{{value}}" class="form-control text-ltr" {{#readonly}}disabled{{/readonly}}>
|
||||
<label class="visually-hidden" for="{{id}}u">{{#str}}filesizeunits, admin{{/str}}</label>
|
||||
<select id="{{id}}u" name="{{name}}[u]" class="form-control form-select" {{#readonly}}disabled{{/readonly}}>
|
||||
<label class="sr-only" for="{{id}}u">{{#str}}filesizeunits, admin{{/str}}</label>
|
||||
<select id="{{id}}u" name="{{name}}[u]" class="form-control custom-select" {{#readonly}}disabled{{/readonly}}>
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
{{!
|
||||
Setting configmultiselect.
|
||||
}}
|
||||
<div>
|
||||
<div class="form-select">
|
||||
{{^readonly}}<input type="hidden" name="{{name}}[xxxxx]" value="1">{{/readonly}}
|
||||
<select {{#readonly}}disabled{{/readonly}} id="{{id}}" name="{{name}}[]" size="{{size}}" class="form-control" multiple>
|
||||
{{#options}}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user