Compare commits
1169 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ec58cefefb | |||
| e4cda88e76 | |||
| 8752df87ed | |||
| 511dab1cd3 | |||
| b26a5e5e08 | |||
| fcb699808c | |||
| f9dc16ca05 | |||
| a350376b65 | |||
| 29f7a9a210 | |||
| 022a019637 | |||
| 50f5563c1f | |||
| 1c0b8f8c50 | |||
| c879cb24df | |||
| 6890ad18e3 | |||
| b88679e3a1 | |||
| 8c1917588d | |||
| c50c904c9e | |||
| 9023021ae0 | |||
| 919ead58fe | |||
| 27de77007b | |||
| 34d1c23668 | |||
| dc7ca062ca | |||
| 8100d46f85 | |||
| f4dfe66ea8 | |||
| e92c6b19b8 | |||
| fa79a1876c | |||
| c9ab02b0cc | |||
| 9c2241dee4 | |||
| 8028bf10dc | |||
| 04704c2108 | |||
| fbe13d55f3 | |||
| 75d6582fef | |||
| 7ca4fd97d9 | |||
| 940ed72017 | |||
| 477cd8b5fe | |||
| a8efb07714 | |||
| 51c9ea5194 | |||
| b0a1b4ce8b | |||
| 3d9175f6f1 | |||
| fd2427746f | |||
| 49afa008f4 | |||
| 551892e2a7 | |||
| 45c339ef09 | |||
| e9fe9f4ae3 | |||
| 1d1b148ca9 | |||
| 15b4174a9f | |||
| 99ab172211 | |||
| 5cc9f3448c | |||
| 4dd870de20 | |||
| c353963ef8 | |||
| 60585523ad | |||
| eeaf19eb5c | |||
| 63da614e4f | |||
| 73372330a9 | |||
| 5f3de24306 | |||
| c15eac212b | |||
| 01c8c8828b | |||
| 2dbe5f54f1 | |||
| bcf59d235b | |||
| 32574e9cae | |||
| 256f8a261c | |||
| 60232d2b9b | |||
| 864ddb77c5 | |||
| 462fe3e925 | |||
| 6bb7478e8d | |||
| 03960b96cb | |||
| 4d00ebae7a | |||
| 352e2f7787 | |||
| 2d2b8d9170 | |||
| 53f2acb263 | |||
| 3ea25c3b77 | |||
| 7931148cbb | |||
| 1031836d89 | |||
| ec1e1fd01a | |||
| b5a04a9fe2 | |||
| be7b73a24b | |||
| 0c438b4d3e | |||
| 3f0373cb7e | |||
| 6a64b9c5b7 | |||
| 04569f819f | |||
| a850fa5de8 | |||
| 8d0d0b1f59 | |||
| 8ea746fa79 | |||
| 5d7bd0208a | |||
| 52ad601de1 | |||
| 2e02b4d678 | |||
| 859578b0d5 | |||
| 761b8a95f9 | |||
| 4ca3d0a0ae | |||
| 75c793f830 | |||
| d546f308d2 | |||
| 74f37f98ad | |||
| aead807ce6 | |||
| f7ad3eaca3 | |||
| da4fc1e256 | |||
| 35364e22fc | |||
| b1ef67ba62 | |||
| 461bf54590 | |||
| 6ba76c0097 | |||
| 323ea697c3 | |||
| 46f6bae002 | |||
| 8aacc3fa2b | |||
| 0715960dd8 | |||
| 65084e7371 | |||
| da4b94e012 | |||
| 05679468c5 | |||
| 0a64b2ed99 | |||
| e243810142 | |||
| a5fa563757 | |||
| f018e92334 | |||
| 46e3cfa354 | |||
| 25cf4fa5ca | |||
| 0fb7847e09 | |||
| b63f17b5f1 | |||
| 52305c9a2e | |||
| 6b3d163a56 | |||
| efc576fc5c | |||
| 90fbc58de6 | |||
| 087845bb30 | |||
| 7d10f35278 | |||
| 9476b48942 | |||
| 7e11261633 | |||
| 15a4e4c87c | |||
| 895f38cc76 | |||
| acd1c82403 | |||
| c9271eba7c | |||
| 0cf4bb2afc | |||
| 58a89a46e4 | |||
| 1882bb4792 | |||
| bb7d679395 | |||
| 048a652106 | |||
| 23e24a504e | |||
| 761898c876 | |||
| dc976fba1e | |||
| e2faf67247 | |||
| b97899634c | |||
| 2427b92114 | |||
| 34770016ee | |||
| d00c00dd4f | |||
| ed1cc02522 | |||
| e1151bf6f5 | |||
| bbb887f6ae | |||
| 4403b8f60d | |||
| 3c3b43a58c | |||
| 04e2dc7c3b | |||
| 05574af1a6 | |||
| 5337ca485c | |||
| 3b0034cc91 | |||
| ab6ca27571 | |||
| 149e530cc1 | |||
| 9a7aed4a25 | |||
| ed04c3824c | |||
| 97e8cb0de4 | |||
| a435c63e16 | |||
| c2321a263b | |||
| f3d7526419 | |||
| d3432a883c | |||
| e1cab8e18e | |||
| bc28c05995 | |||
| 4865d2a0ae | |||
| 8317134779 | |||
| fbac2e9296 | |||
| c978fa26e2 | |||
| 599eed0f95 | |||
| 7d52d5def6 | |||
| 8813318d61 | |||
| 0459910b53 | |||
| adeaafd59d | |||
| 0dd7bb8374 | |||
| bcba1347f8 | |||
| b0e1edd427 | |||
| b0007a154c | |||
| 8c9d3695e3 | |||
| 184944ce6a | |||
| ad9f9e54a3 | |||
| 943b261760 | |||
| 8dbc7c6532 | |||
| 6f7fe5df9c | |||
| 7e5f0e1fe6 | |||
| 11b6df58db | |||
| 36beec930e | |||
| 750fe24949 | |||
| cc718b59d0 | |||
| 4dcc2d37c6 | |||
| d358b91e2b | |||
| c053b93f0c | |||
| cdf91cc236 | |||
| fab34222ca | |||
| a9f5f8094c | |||
| 10e16c69c8 | |||
| e66e3740a7 | |||
| 6594c54b2e | |||
| 6dc336a5d4 | |||
| 39128991d7 | |||
| e1990f2f33 | |||
| 1ce223c7e1 | |||
| 6694715840 | |||
| 0a43a459ba | |||
| 7e0bcbfb19 | |||
| eaf89f7754 | |||
| 5bbfcc25c0 | |||
| 4a495d66b8 | |||
| b13ec3c353 | |||
| 5903054142 | |||
| 2dd9b53fd6 | |||
| 7f20e2071c | |||
| 0ab106f41c | |||
| 9f82c9aece | |||
| 1f13dff1a7 | |||
| be396eddf0 | |||
| 4af4d709a4 | |||
| 46606b3ddd | |||
| 35bc26b516 | |||
| 106c64ac24 | |||
| ddf72dd60d | |||
| 0ae27225f5 | |||
| a6674bf8a4 | |||
| dc87fd4b3f | |||
| d81a94807b | |||
| c611109ed7 | |||
| 74ef7dc5b1 | |||
| 8996ed98c7 | |||
| 3fcba4be5e | |||
| 55d463b9f2 | |||
| bbb58b10ad | |||
| f266c852c3 | |||
| b14daeaa9a | |||
| 8e083da3d5 | |||
| 8312eeacb0 | |||
| 0ce40927cf | |||
| 0cdfaccd4e | |||
| d386d21360 | |||
| 5429ece3f8 | |||
| 32f99bc4d1 | |||
| df0df3110d | |||
| 2ced8c6674 | |||
| 17056bf206 | |||
| 27b09acf75 | |||
| d159c32b84 | |||
| 221f0e16d0 | |||
| 55189def65 | |||
| 086a2adc35 | |||
| 3c315a874a | |||
| b4a8a99898 | |||
| 08e8205d6f | |||
| 0a54a501eb | |||
| 213ea00afe | |||
| 9428e33d55 | |||
| 31a98b3fb2 | |||
| ae6da7d6a0 | |||
| 4d5bc273ce | |||
| 33c7881448 | |||
| b7146b655a | |||
| 178d5a0e23 | |||
| f576390bd2 | |||
| 7ed7afad98 | |||
| a7e12a77b1 | |||
| 09e02634d4 | |||
| be019636d1 | |||
| 7789be4030 | |||
| 91c9ca0f49 | |||
| 7c0923a3e4 | |||
| 83cba7b9b0 | |||
| cb4418bc5b | |||
| 4db3403481 | |||
| 9296086653 | |||
| 38d4a1b75f | |||
| 1b4ef7cd88 | |||
| 3576eb4835 | |||
| 39eb58c754 | |||
| c6731f8045 | |||
| 252f95e1b7 | |||
| c24c9e174b | |||
| 199333208d | |||
| 91557080d7 | |||
| 3370b20e3c | |||
| 2c98bfc4f4 | |||
| 36f0c3d531 | |||
| 1ebbd18b82 | |||
| 04a02b5bd9 | |||
| 506df9bdbd | |||
| 873b4847f5 | |||
| a2aa548af7 | |||
| d0c89df9ee | |||
| 30eccfabaa | |||
| 63e2c543ae | |||
| a69b38d604 | |||
| 0ea391d1eb | |||
| 17d4bc49f6 | |||
| 57a13a5971 | |||
| 12fce2a4bd | |||
| b68dd3a121 | |||
| eb4c7963c0 | |||
| dde0818f6c | |||
| ad28920d0b | |||
| a5cde22a26 | |||
| 44719d2ad9 | |||
| 784c09c834 | |||
| 004be78003 | |||
| 7fae5f61ef | |||
| d7cadcc244 | |||
| 2cb45addb1 | |||
| 5ea92799c4 | |||
| 55c9482171 | |||
| 1a7928173b | |||
| c3299761f7 | |||
| 9aeb59af73 | |||
| 3759daa952 | |||
| 15044cea7f | |||
| 1170a8b694 | |||
| 69959c371f | |||
| ec46b18e13 | |||
| f1acce7bef | |||
| 1c6e578db4 | |||
| a7ea95030c | |||
| 3f04dbee09 | |||
| 6a91117d4a | |||
| cfe9f53e91 | |||
| decd480c42 | |||
| d947f53d4c | |||
| 00877bf283 | |||
| 6f86e933ed | |||
| 6d7b36da59 | |||
| 7924191691 | |||
| 0628d11380 | |||
| 151a63b4cc | |||
| 4ebfbfe88c | |||
| 93a60507fc | |||
| 0a8371c690 | |||
| 604f19afd6 | |||
| bda1473afa | |||
| d70cfda576 | |||
| 3dc820a057 | |||
| 4b64516b0e | |||
| e8496407e9 | |||
| 0ab3fd7958 | |||
| d103bdba3d | |||
| cf1d32e9c5 | |||
| b5fe033b18 | |||
| 05a3e35677 | |||
| 03058394f2 | |||
| 1a80427018 | |||
| a2b727d7bc | |||
| b2a382016f | |||
| 31efbf2e0e | |||
| 3540343ceb | |||
| 78076a621f | |||
| ca80e9a68d | |||
| 9b9b38f44e | |||
| 8e5b007c3e | |||
| d487ee2240 | |||
| 300e4aef4c | |||
| eefa5c928f | |||
| 407dcd4922 | |||
| 8d9a36fb8a | |||
| b2d43a7db1 | |||
| 876a5c143b | |||
| c562848596 | |||
| 74efdb135d | |||
| 46d1546c6e | |||
| c2ba78902c | |||
| 12fb5964f2 | |||
| 52a84caaaa | |||
| 524f6a656b | |||
| 86e69ea7b2 | |||
| 12820e3a56 | |||
| 36905f42b8 | |||
| fd532533dd | |||
| d6806beb3e | |||
| 9ab387d707 | |||
| 2a4d1c64bf | |||
| a0999ab66f | |||
| 7e3f7e3d7c | |||
| 823bc36276 | |||
| 1f3aacf8fc | |||
| 38bcf316ee | |||
| f993881244 | |||
| 3277fc9db6 | |||
| ef3720efbd | |||
| 41bc6b9400 | |||
| b9f8e3e114 | |||
| 355d07e0b4 | |||
| 5af206ad2a | |||
| 5ec265b48d | |||
| 35b29ce7d9 | |||
| bec49592ce | |||
| 57bb99edd4 | |||
| eb6b828b81 | |||
| 8b09853319 | |||
| fe1031244b | |||
| 03de8ed6d9 | |||
| 6fae5e65e9 | |||
| d7157063c3 | |||
| 477fb6c9d6 | |||
| c50b024463 | |||
| fadd2915eb | |||
| c71355941b | |||
| 18871c74e2 | |||
| 5cffc7f78b | |||
| 946159a554 | |||
| 8d371859dc | |||
| aad6afe979 | |||
| d12c1406df | |||
| 5130127a3e | |||
| 651dbb729c | |||
| 2c8db06e7a | |||
| e98d18241f | |||
| 3e460f45ac | |||
| d5e30e0108 | |||
| 7db1a61a72 | |||
| d335530a28 | |||
| 6fe5bb1b96 | |||
| e2a73965ca | |||
| ccd0b96591 | |||
| 851f0d3354 | |||
| 5576a97713 | |||
| b235c3a5a7 | |||
| c00b8b7cab | |||
| b19f178e0d | |||
| 56b28e8e0b | |||
| 6658d9fba1 | |||
| 09dabe003a | |||
| 85f136094b | |||
| 1c55d84794 | |||
| 3ac504fd3d | |||
| 1f25df48b1 | |||
| 64ba1753a8 | |||
| 0e8d14f4e9 | |||
| 9c28e07d31 | |||
| 4ea44f96e5 | |||
| c5c1b8b121 | |||
| 3490f29ad9 | |||
| 3b03a3da47 | |||
| a6aefe15f0 | |||
| b294665c21 | |||
| 2b50abffa2 | |||
| acb848cdce | |||
| 7cd362b873 | |||
| cc16de4ccc | |||
| c0af823086 | |||
| 8b026809c5 | |||
| 2dbc9a5005 | |||
| d224506353 | |||
| 0d1187b052 | |||
| a2e3aa6806 | |||
| adac2a9e55 | |||
| 2fca843e49 | |||
| 157a497a3e | |||
| 4f0fc4f45b | |||
| 27b1425eb2 | |||
| 40e41c1997 | |||
| 89ce0b387e | |||
| 9b64c178dd | |||
| 69cc1d1dd5 | |||
| 39c8e99e67 | |||
| 833ab0ea9f | |||
| 2b87250347 | |||
| 95d1f1f18d | |||
| d23f05828f | |||
| 972340b678 | |||
| 3971892bd3 | |||
| b18b714165 | |||
| 781545d34d | |||
| 19fe7f27a8 | |||
| bd686af064 | |||
| fd18dc14ff | |||
| e840b14f4c | |||
| 730aa1dcb0 | |||
| 9ef6492e5d | |||
| 41ad54e182 | |||
| 2a1fb5b5e7 | |||
| 56adf1f3d8 | |||
| a36870c175 | |||
| a0f377cf2b | |||
| 7905d70497 | |||
| d0a55062f9 | |||
| 7f177d440c | |||
| 8730ffcbe1 | |||
| 486aa319c2 | |||
| 6fa8e1c86f | |||
| dcfb713ca6 | |||
| 9d82cdb62e | |||
| a88f50d1b2 | |||
| 94adb3429b | |||
| bd516bf05c | |||
| 02829c03c1 | |||
| e9435e8f6d | |||
| 6a750d283d | |||
| b5e39191fc | |||
| 42c1cf3b03 | |||
| a5cd815635 | |||
| 1fdb4fda4a | |||
| 61772eb89b | |||
| e49ccc92c4 | |||
| f9f289f69d | |||
| e16b858ff9 | |||
| f4bdb898c7 | |||
| 2d502fd749 | |||
| b552d604ff | |||
| 6d73afb2bf | |||
| 0ad2d843d7 | |||
| 82a1e8fae7 | |||
| a2c1a20055 | |||
| 76c3dc5f6b | |||
| 62ea8b1cae | |||
| c36d5093e3 | |||
| fae57261e7 | |||
| 11a49b08e7 | |||
| a730c334c7 | |||
| fb5e3957be | |||
| 54524f1ff0 | |||
| bbfbe8e260 | |||
| cfe02e4d3e | |||
| 611399214b | |||
| 321de29e93 | |||
| f200ba55f8 | |||
| 8d791e12ba | |||
| 8923308d47 | |||
| 0e97e40e5a | |||
| 7254648363 | |||
| c3176af430 | |||
| cb82c4d901 | |||
| bf127517b3 | |||
| 29e56fef72 | |||
| b249ab9df4 | |||
| 7805d0bb44 | |||
| 6fcc509ed1 | |||
| ebd136ca12 | |||
| c96a155937 | |||
| fdb7f85140 | |||
| fbae45d7c9 | |||
| a398a60092 | |||
| de0e594a10 | |||
| 93097192e6 | |||
| 1427573cde | |||
| 28790a42ad | |||
| e5f0085cdb | |||
| 682593054d | |||
| 8fba6189fe | |||
| 31188e93d6 | |||
| 9bc368f71c | |||
| 1aa7c68c6f | |||
| 23efc7337a | |||
| cf4b6c8c94 | |||
| abb2037b0f | |||
| c94b6b2ab7 | |||
| ab5d361c80 | |||
| 334333b6c7 | |||
| 3d08cd2272 | |||
| 83a5ed90ce | |||
| d945333b47 | |||
| da84b731c7 | |||
| 36f3b1e418 | |||
| a3cc6898e9 | |||
| fcbca18c7b | |||
| c0280f4405 | |||
| c83543095a | |||
| 13e34fb428 | |||
| c705434a62 | |||
| cfe1a9a8d8 | |||
| 94d05a5bfb | |||
| 2562b9f3a3 | |||
| e8b05c6cb4 | |||
| 8f0297915c | |||
| b25763e875 | |||
| 84bcfbb0d5 | |||
| e419e7acba | |||
| 309aad5a82 | |||
| 8452418666 | |||
| 5ba67416e6 | |||
| bd0de2d965 | |||
| db54910ce2 | |||
| 9d356676c3 | |||
| a9d3f4b96c | |||
| ca6cf0bd21 | |||
| 7d990ee185 | |||
| e2a11dc2aa | |||
| a2a6303397 | |||
| 6c4cdd6d96 | |||
| 4bb41b4e5a | |||
| a937d4d807 | |||
| 2301f9bfaa | |||
| 0e9c755896 | |||
| 3452156e6e | |||
| 6ef1780225 | |||
| a8c60a4c31 | |||
| b2995f7a29 | |||
| 51201bc672 | |||
| aa13890df0 | |||
| 644b80410d | |||
| b36a28b37a | |||
| 386223bd86 | |||
| 95359bf9e7 | |||
| 1bc2a3b345 | |||
| 709b46dbfd | |||
| 94c19e0fea | |||
| 4a60349a8a | |||
| 2189db9c86 | |||
| f54cb0c257 | |||
| 95e0ff974c | |||
| db361e09e7 | |||
| f2b1242364 | |||
| d0fd7bc58c | |||
| 916809d995 | |||
| e22ac10067 | |||
| f558127d0e | |||
| fc1d22ea70 | |||
| 5d1979c911 | |||
| fe346f0afb | |||
| 8d5470145d | |||
| 61d32ad081 | |||
| 558ef4f778 | |||
| c8221dedcd | |||
| 5265491a8f | |||
| b96e85feac | |||
| 817d6dcdbb | |||
| de1a942280 | |||
| 3e1c856bd9 | |||
| cce23499e6 | |||
| 74160de2cb | |||
| 4ca7232b1f | |||
| ded581156a | |||
| 4cfc74d176 | |||
| 893cf77d33 | |||
| e66f450c8f | |||
| f9f41f5061 | |||
| 76e2d15794 | |||
| 31d3fd27fc | |||
| 2874c6d5a1 | |||
| d8892dcca3 | |||
| 85a1c2c99e | |||
| 58bf730494 | |||
| d179137f1b | |||
| 8eafd115cc | |||
| 3b111cf8a0 | |||
| a244344e2e | |||
| 23fed91412 | |||
| dee4097c9d | |||
| 7665c701fd | |||
| 3827cbe523 | |||
| f6a2d57b3e | |||
| 35a5c1adda | |||
| e4d86a6ec4 | |||
| 8d2229db48 | |||
| 4d6b3406c5 | |||
| 11a58dd4b0 | |||
| 0713666486 | |||
| 260e9753d4 | |||
| e83fad7382 | |||
| c7e5431086 | |||
| 10ba6d0aa1 | |||
| a4f4cbf095 | |||
| 66c757f689 | |||
| 2f7236aa3c | |||
| a704b87f8b | |||
| 59f48908aa | |||
| e6f0b5a3a3 | |||
| 7a85cc6d2e | |||
| 3d08c7d396 | |||
| f809bca508 | |||
| fbcc91236e | |||
| 2dab18e681 | |||
| 3565a77362 | |||
| cbecc140f7 | |||
| c3a4859c7d | |||
| 330ba8cb10 | |||
| 4e32add0ac | |||
| e48fecc679 | |||
| d7113bee4e | |||
| 61ce84f178 | |||
| e3bfcb1cde | |||
| 4a6a2636a0 | |||
| 09646d7b53 | |||
| 9211552660 | |||
| f51678c56a | |||
| fa3b387185 | |||
| dddff390da | |||
| 6bcc070827 | |||
| e1e362b7ff | |||
| ae12edc741 | |||
| 5934444b27 | |||
| c187594e5b | |||
| f9f0f1cc26 | |||
| f0b7948c96 | |||
| 3114d04721 | |||
| e78b9f9574 | |||
| b0d96c297b | |||
| 54d32ce4a9 | |||
| 71f44b0611 | |||
| b8a0258357 | |||
| db8fea04f5 | |||
| 227281d355 | |||
| fb6460ca98 | |||
| 424c5df1eb | |||
| 64c4074699 | |||
| b4ab127434 | |||
| 4d03cc37b2 | |||
| 195e7c9cf1 | |||
| 1ffb6b09ee | |||
| 06411e3689 | |||
| e419e18f0d | |||
| 3263daba84 | |||
| 59a5923924 | |||
| f2602288eb | |||
| 4413ca209f | |||
| 427f046cff | |||
| e29edbe89e | |||
| e9df0c43bc | |||
| d71659dd6d | |||
| fb6c682850 | |||
| 356a8ee948 | |||
| fe9ecef92b | |||
| 9c1f7874d8 | |||
| 96fac6d9ce | |||
| 4b327e1109 | |||
| f649cd722f | |||
| 8e0e99e4fd | |||
| adbe92ce0a | |||
| 03e84b68a1 | |||
| 51dc7d230f | |||
| 1044e94507 | |||
| c4303bba51 | |||
| 9d32114bf6 | |||
| 8ddb17b641 | |||
| 30990ac512 | |||
| 0c6f661def | |||
| 24d0335a0a | |||
| 52836faa5b | |||
| 64f64e44d8 | |||
| a133b89976 | |||
| 93fec2c58c | |||
| 3db6d44feb | |||
| 83aa08c7e1 | |||
| 79082f8b6b | |||
| 544c7d68b6 | |||
| 699a82df1a | |||
| d369c098be | |||
| 191448afc5 | |||
| 606fbca6b4 | |||
| 050eb97c33 | |||
| f6f824597a | |||
| f2b4fba61e | |||
| 3a394dd671 | |||
| 98480b3932 | |||
| e010b2e75c | |||
| aa3a9c7895 | |||
| f075ec01ca | |||
| c4c770f48c | |||
| 24ce9b8a10 | |||
| adebc5f811 | |||
| afc19a201c | |||
| aa7707cd52 | |||
| 676c840c5c | |||
| 1222c2125e | |||
| 776b4a85d1 | |||
| 29fe254b17 | |||
| bf84a08900 | |||
| 97043c76b7 | |||
| c1813ed818 | |||
| 49f1803c9d | |||
| 157f8a87b4 | |||
| c66bf80bd8 | |||
| ad25efc776 | |||
| 1019a2b5ba | |||
| 7404858689 | |||
| 7b313f407a | |||
| 931fc89e13 | |||
| fbbfe9aa00 | |||
| b81952a23d | |||
| 12ffcc5097 | |||
| bd1eaea02b | |||
| 99a8358b85 | |||
| 0a352c4790 | |||
| 67dfb55d49 | |||
| 12bd4bc5ad | |||
| 22ec6995ea | |||
| ae3af1d860 | |||
| a0fc902eb1 | |||
| d665dec78e | |||
| a059ec19b9 | |||
| 9e8cfc0235 | |||
| e0f91914a7 | |||
| 39229f3cbd | |||
| 7213b650ee | |||
| b713aa80b4 | |||
| 8bec7c109d | |||
| 1736d2e66f | |||
| 5a3e92e76c | |||
| dec6eebdaa | |||
| 48e5fbe1f5 | |||
| c59247e1e8 | |||
| f27f995522 | |||
| 78193d34b4 | |||
| d337e7a546 | |||
| 8e29cce41c | |||
| 5374c768f3 | |||
| d40cecdb8a | |||
| a470c9064a | |||
| 5132309170 | |||
| 0f89884980 | |||
| 08b8b76655 | |||
| 12403bc004 | |||
| b7146cdff9 | |||
| 452497da41 | |||
| 6c772c3b60 | |||
| d6c8f14ed9 | |||
| 62a7d2b5de | |||
| 2a247aab70 | |||
| d689b2e029 | |||
| b4f6fe06fd | |||
| 7a6ea323e4 | |||
| e9a5485f3e | |||
| 36a34b89f6 | |||
| 1c3cd955ea | |||
| 364d4caeec | |||
| e9d5a2b0a8 | |||
| 4994817908 | |||
| 82e868fd38 | |||
| da4ded8a16 | |||
| e68850295f | |||
| bb32174261 | |||
| 27738e1c07 | |||
| a7d9b53e72 | |||
| 679e8d8b66 | |||
| b58009596f | |||
| b421039a5c | |||
| f87597aae3 | |||
| 0a94e31cf9 | |||
| 05cc2df693 | |||
| 61856e5ef5 | |||
| 407a666064 | |||
| 8a5f125ad7 | |||
| ef8dff0565 | |||
| e77dc824f5 | |||
| d55f2b787c | |||
| 4500d4bb3c | |||
| 509bb3f351 | |||
| fb4c20ee2c | |||
| 1e21a0b3d5 | |||
| 71d61a7c8c | |||
| 8fcba35fd8 | |||
| 39a736ef9a | |||
| ff7ec42832 | |||
| 5516275fda | |||
| 380534b0a1 | |||
| acf199345a | |||
| 41eaa09bbe | |||
| 9d47a69094 | |||
| 06d486d9a3 | |||
| b0e096d870 | |||
| 30a82af15e | |||
| 98579dd7b3 | |||
| 95fc9d9399 | |||
| bd40419f2f | |||
| c2f188311e | |||
| c39b0d178c | |||
| 390512db4f | |||
| 6bc7645868 | |||
| becb9e8579 | |||
| e7008d4686 | |||
| 42fcf7d5da | |||
| 07238ca511 | |||
| f9c0d58da6 | |||
| 4a4905356c | |||
| 7c56d5589d | |||
| adcd69e11f | |||
| c39e659a33 | |||
| 8d1785fec5 | |||
| 68049ac848 | |||
| f8c999616a | |||
| 0bafd769ec | |||
| 9dbb05ffe0 | |||
| fdf7db9502 | |||
| f8666013b3 | |||
| 910755acf5 | |||
| 3dfbd5a16f | |||
| 4d0e43ffc5 | |||
| 6d685cef62 | |||
| 1ce5dbad41 | |||
| 954de4f651 | |||
| 8ab154a5c1 | |||
| 279d691f58 | |||
| fe2e2feef4 | |||
| 5a0fd52e3f | |||
| 24ccd6e908 | |||
| fcc5307e64 | |||
| d208ffb0e2 | |||
| 5c36644c05 | |||
| c84b8976e3 | |||
| 99ddf538ca | |||
| 4144e278a6 | |||
| a1b2045364 | |||
| c4296f77e0 | |||
| 0f70cf0497 | |||
| 7c30725f6b | |||
| 6065090736 | |||
| 42f75f5a52 | |||
| 78572f186d | |||
| 84197640eb | |||
| fc49ce855a | |||
| 486d2a35ba | |||
| 15af3240b3 | |||
| 45722f4188 | |||
| a1087ef609 | |||
| d6ec2d3e44 | |||
| 7add3440c8 | |||
| 3295288d6e | |||
| 3d03d2a0d4 | |||
| e3c28dffa3 | |||
| 2d710f35cd | |||
| 94fdac9117 | |||
| 1dd722145d | |||
| 9d171793d7 | |||
| 8e039a5662 | |||
| 990bd11773 | |||
| ddcde1994d | |||
| cf35d0b26e | |||
| b9a09480b2 | |||
| 5025c1ad82 | |||
| 0ea341f14b | |||
| a03e9e0d9d | |||
| c1c57e816c | |||
| b284293402 | |||
| d61fa24239 | |||
| 11eb85e494 | |||
| c765b1f7e2 | |||
| 8e44da5653 | |||
| 0489e9ceee | |||
| e948a6354e | |||
| 8a6b13b71e | |||
| e2f1e10225 | |||
| 474e768a26 | |||
| 17e99314a2 | |||
| d817ccaca5 | |||
| 0cb248077c | |||
| 1d8cbfb81b | |||
| 6c579b60f2 | |||
| 6b03aebf27 | |||
| 8e929fa58a | |||
| f956926db5 | |||
| cea2645a81 | |||
| 5aff8a7852 | |||
| 7c7c5286a4 | |||
| c39bc627a0 | |||
| 867509ac25 | |||
| 261400d4ea | |||
| f9bcf22483 | |||
| a16ab5697d | |||
| 9b3646417e | |||
| 741d6dde19 | |||
| 14b4ee0827 | |||
| 396a282a2d | |||
| af331f08d4 | |||
| 988d0d4c50 | |||
| a86f428702 | |||
| 5a32562f82 | |||
| 9e28ba2b65 | |||
| 2eb31f8bb3 | |||
| d189edb843 | |||
| 57ad9e1566 | |||
| beca5a9300 | |||
| 083604ea09 | |||
| cd6eadd407 | |||
| 6d5d1935ea | |||
| 05f23d5a2b | |||
| 0d751c196b | |||
| 6f5f08a846 | |||
| 4a4a367251 | |||
| 809be05428 | |||
| 4bd0eaf732 | |||
| 23f33d12ca | |||
| ef4145dd1a | |||
| 4c44813e9e | |||
| c5438f982c | |||
| 2c45ad6f18 | |||
| 9f9682cfe2 | |||
| b8d16ecad1 | |||
| 45871ec48e | |||
| b49cb92e82 | |||
| eb06f92457 | |||
| 7cc18dc2ad | |||
| 4f1c8ce764 | |||
| 805214b38c | |||
| 9e65bc8fa6 | |||
| 760ed019ee | |||
| 22f4eab309 | |||
| 8acaa4e356 | |||
| ebd307b396 | |||
| 2b61f1eb27 | |||
| 586ae77bc2 | |||
| 60c92dcb4b | |||
| d4dc94ec8d | |||
| 168348abeb | |||
| b0627a1a11 | |||
| 2c37677635 | |||
| 69f0ecf605 | |||
| 815f256bcd | |||
| ee23a8cf25 | |||
| b89a37942e | |||
| 0deb19468d | |||
| 0ad85f4148 | |||
| 37c99bd07e | |||
| 4df5ee039a | |||
| 5306f2f2b9 | |||
| e37cdf881e | |||
| 336d0d2927 | |||
| f1d86e0319 | |||
| 5e99058860 | |||
| 41426e0aa4 | |||
| 389744710a | |||
| 848f08e126 | |||
| cdbb433c32 | |||
| 0524f3ae5b | |||
| 1e37778fc1 | |||
| fc5e5d4999 | |||
| 954e4d1132 | |||
| 8cb0b7262b | |||
| 579da44a70 | |||
| 7482fef18b | |||
| 0bf024e48a | |||
| 7d4ee9c50b | |||
| 7a40781aeb | |||
| 0a5291c013 | |||
| 63a66eb2ce | |||
| c032adf341 | |||
| c467de9ac6 | |||
| 145604590f | |||
| 43999a3f2b | |||
| 7f55289912 | |||
| 7a5f2d0b78 | |||
| 3303daf3bf | |||
| e47c53ae4a | |||
| ca02422d66 | |||
| 3786de22f2 | |||
| d07fb8b9e8 | |||
| 877a3f70d0 | |||
| 3d7a8a09ba | |||
| 3bf4744303 | |||
| 70e973d092 | |||
| 3ce1eba180 | |||
| ca864e09b1 | |||
| a95f458cde | |||
| 1ffdc39468 | |||
| 83c18a2dec | |||
| 566b73fbfc | |||
| 80736a93aa | |||
| 41bc63dbf3 | |||
| 4b71cdcd89 | |||
| e4faf5fede | |||
| 8a635e3e24 | |||
| 71bfe91591 | |||
| ceedbf1515 | |||
| 68e240284c | |||
| d464fb43d6 | |||
| b44495cecc | |||
| d0ba284421 | |||
| b27a27adcd | |||
| f87f23777f | |||
| 6ceba9e0e8 | |||
| ecf15a63b4 | |||
| c6ffe9588e | |||
| 8cdb2fcc0e | |||
| 8efa87ed6f | |||
| a5b23f1f4e | |||
| 9679c49c35 | |||
| 82850a0418 | |||
| b583c46297 | |||
| 49a9e8b07d | |||
| 419709e9b2 | |||
| 5a3b9d64dd | |||
| 9eaf7a4c3f | |||
| 834aba2309 | |||
| b5878eaec9 | |||
| ccae2f74f8 | |||
| 752a073885 | |||
| e96987d89e | |||
| 710c3f0c36 | |||
| c39dc16da4 | |||
| b3e45d753a | |||
| 2cadeca3eb | |||
| 8fb519442a | |||
| 66ba391e82 | |||
| 2cde5c5267 | |||
| 2c41fe81e8 | |||
| 0b996db6a3 | |||
| 73a5ba92b7 | |||
| c3015dd0c8 | |||
| 3585c252ce | |||
| e6ff582e1a | |||
| 53df9e34f9 | |||
| 1d6683bb0e | |||
| 9c10de7f35 | |||
| 17ab4fb266 | |||
| 5fa8f1c811 | |||
| 91f26b5874 | |||
| 1b771b1947 | |||
| 548c44c89c | |||
| 8ee9fbca8d | |||
| e13cbf9e27 | |||
| 14f047abdb | |||
| b6c7a25d60 | |||
| d128bf726e | |||
| 3450387277 | |||
| aacfff0bc8 | |||
| 9071b2314f | |||
| 54393e223a | |||
| 868a1c377d | |||
| 675e981004 | |||
| eed4650028 | |||
| 94711c151d | |||
| 8dfa3027a0 | |||
| 38d5e3db1b | |||
| c11e2517a7 | |||
| 5cc173a128 | |||
| c31a32140b | |||
| ee658223ff | |||
| 061347a93a | |||
| c7d5af7d6e | |||
| a68004a433 | |||
| c8388ead0f | |||
| bd23521ca0 | |||
| c557df533a | |||
| cdcb53a114 | |||
| 6346cc3593 | |||
| 680502e4da | |||
| 3afe61d620 | |||
| 9272cc8498 | |||
| 57a005e7c6 | |||
| a6d724fe41 | |||
| 94376c6910 | |||
| 088786d284 | |||
| 1ab9522055 | |||
| c6c6770268 | |||
| e055a45160 | |||
| a59f03d4de | |||
| 5fbb14524d | |||
| dff53373de | |||
| 63f06e0d96 | |||
| 32e9128333 | |||
| d49d4ee47b | |||
| c771b25c0f | |||
| 753f2dcfba | |||
| 26f3788857 | |||
| c7fb9fe55a | |||
| ab5a81321a | |||
| 2c93ca61d0 | |||
| f82fad44d7 | |||
| 2e5e143061 | |||
| 3a679810d5 | |||
| 3484f3e4b5 | |||
| a51797cc0e | |||
| bc0b4ec7f4 | |||
| c09a294ff4 | |||
| 061893d89b | |||
| 1bedd8df20 | |||
| de6b084925 | |||
| 868c7558f8 | |||
| b764343e5a | |||
| dbe3e2dd13 | |||
| edb1a9b4f3 | |||
| a2b286ce17 | |||
| 7be8da04cd | |||
| 813c385320 | |||
| 157c85c20a | |||
| 5f26bdc5e9 | |||
| 8a2d8ec472 | |||
| fad72d7177 | |||
| 747f5ba09b | |||
| b4623c8975 |
+5
-2
@@ -19,6 +19,7 @@ lib/editor/tinymce/plugins/spellchecker/rpc.php
|
||||
lib/editor/tinymce/tiny_mce/
|
||||
lib/mlbackend/php/phpml/
|
||||
lib/adodb/
|
||||
lib/behat/axe/
|
||||
lib/bennu/
|
||||
lib/evalmath/
|
||||
lib/phpspreadsheet/
|
||||
@@ -66,6 +67,9 @@ lib/babel-polyfill/
|
||||
lib/polyfills/
|
||||
lib/emoji-data/
|
||||
lib/plist/
|
||||
lib/zipstream/
|
||||
lib/php-enum/
|
||||
lib/http-message/
|
||||
media/player/videojs/amd/src/video-lazy.js
|
||||
media/player/videojs/amd/src/Youtube-lazy.js
|
||||
media/player/videojs/videojs/
|
||||
@@ -88,5 +92,4 @@ theme/boost/amd/src/bootstrap/tab.js
|
||||
theme/boost/amd/src/bootstrap/toast.js
|
||||
theme/boost/amd/src/bootstrap/tooltip.js
|
||||
theme/boost/amd/src/bootstrap/util.js
|
||||
theme/boost/amd/src/tether.js
|
||||
theme/boost/scss/fontawesome/
|
||||
theme/boost/scss/fontawesome/
|
||||
@@ -211,7 +211,7 @@
|
||||
},
|
||||
// We're using babel transpiling so use their parser
|
||||
// for linting.
|
||||
parser: '@babel/eslint-parser',
|
||||
parser: 'babel-eslint',
|
||||
// Check AMD with some slightly stricter rules.
|
||||
rules: {
|
||||
'no-unused-vars': 'error',
|
||||
@@ -242,8 +242,7 @@
|
||||
},
|
||||
parserOptions: {
|
||||
'ecmaVersion': 9,
|
||||
'sourceType': 'module',
|
||||
'requireConfigFile': false,
|
||||
'sourceType': 'module'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,71 +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/>.
|
||||
|
||||
/**
|
||||
* Template configuraton file for github actions CI/CD.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2020 onwards Eloy Lafuente (stronk7) {@link https://stronk7.com}
|
||||
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
// This cannot be used out from a github actions workflow, so just exit.
|
||||
getenv('GITHUB_WORKFLOW') || die; // phpcs:ignore moodle.Files.MoodleInternal.MoodleInternalGlobalState
|
||||
|
||||
unset($CFG);
|
||||
global $CFG;
|
||||
$CFG = new stdClass();
|
||||
|
||||
$CFG->dbtype = getenv('dbtype');
|
||||
$CFG->dblibrary = 'native';
|
||||
$CFG->dbhost = '127.0.0.1';
|
||||
$CFG->dbname = 'test';
|
||||
$CFG->dbuser = 'test';
|
||||
$CFG->dbpass = 'test';
|
||||
$CFG->prefix = 'm_';
|
||||
$CFG->dboptions = ['dbcollation' => 'utf8mb4_bin'];
|
||||
|
||||
$host = 'localhost';
|
||||
$CFG->wwwroot = "http://{$host}";
|
||||
$CFG->dataroot = realpath(dirname(__DIR__)) . '/moodledata';
|
||||
$CFG->admin = 'admin';
|
||||
$CFG->directorypermissions = 0777;
|
||||
|
||||
// Debug options - possible to be controlled by flag in future.
|
||||
$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;
|
||||
$CFG->debugpageinfo = 1;
|
||||
$CFG->allowthemechangeonurl = 1;
|
||||
$CFG->passwordpolicy = 0;
|
||||
$CFG->cronclionly = 0;
|
||||
$CFG->pathtophp = getenv('pathtophp');
|
||||
|
||||
$CFG->phpunit_dataroot = realpath(dirname(__DIR__)) . '/phpunitdata';
|
||||
$CFG->phpunit_prefix = 't_';
|
||||
|
||||
define('TEST_EXTERNAL_FILES_HTTP_URL', 'http://localhost:8080');
|
||||
define('TEST_EXTERNAL_FILES_HTTPS_URL', 'http://localhost:8080');
|
||||
|
||||
define('TEST_SESSION_REDIS_HOST', 'localhost');
|
||||
define('TEST_CACHESTORE_REDIS_TESTSERVERS', 'localhost');
|
||||
|
||||
// TODO: add others (solr, mongodb, memcached, ldap...).
|
||||
|
||||
// Too much for now: define('PHPUNIT_LONGTEST', true); // Only leaves a few tests out and they are run later by CI.
|
||||
|
||||
require_once(__DIR__ . '/lib/setup.php');
|
||||
@@ -1,112 +0,0 @@
|
||||
name: Core
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- master
|
||||
- MOODLE_[0-9]+_STABLE
|
||||
tags-ignore:
|
||||
- v[0-9]+.[0-9]+.[0-9]+*
|
||||
|
||||
env:
|
||||
php: 7.4
|
||||
|
||||
jobs:
|
||||
Grunt:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checking out code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Configuring node & npm
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
- name: Installing node stuff
|
||||
run: npm install
|
||||
|
||||
- name: Running grunt
|
||||
run: npx grunt
|
||||
|
||||
- name: Looking for uncommitted changes
|
||||
# Add all files to the git index and then run diff --cached to see all changes.
|
||||
# This ensures that we get the status of all files, including new files.
|
||||
# We ignore npm-shrinkwrap.json to make the tasks immune to npm changes.
|
||||
run: |
|
||||
git add .
|
||||
git reset -- npm-shrinkwrap.json
|
||||
git diff --cached --exit-code
|
||||
|
||||
PHPUnit:
|
||||
runs-on: ${{ matrix.os }}
|
||||
services:
|
||||
exttests:
|
||||
image: moodlehq/moodle-exttests
|
||||
ports:
|
||||
- 8080:80
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
php: 7.2
|
||||
db: mysqli
|
||||
- os: ubuntu-22.04
|
||||
php: 7.4
|
||||
db: pgsql
|
||||
|
||||
steps:
|
||||
- name: Setting up DB mysql
|
||||
if: ${{ matrix.db == 'mysqli' }}
|
||||
uses: moodlehq/mysql-action@v1
|
||||
with:
|
||||
collation server: utf8mb4_bin
|
||||
mysql version: 5.7
|
||||
mysql database: test
|
||||
mysql user: test
|
||||
mysql password: test
|
||||
use tmpfs: true
|
||||
tmpfs size: '1024M'
|
||||
extra conf: --skip-log-bin
|
||||
|
||||
- name: Setting up DB pgsql
|
||||
if: ${{ matrix.db == 'pgsql' }}
|
||||
uses: m4nu56/postgresql-action@v1
|
||||
with:
|
||||
postgresql version: 9.6
|
||||
postgresql db: test
|
||||
postgresql user: test
|
||||
postgresql password: test
|
||||
|
||||
- name: Configuring git vars
|
||||
uses: rlespinasse/github-slug-action@v4
|
||||
|
||||
- name: Setting up PHP ${{ matrix.php }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: none
|
||||
|
||||
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setting up PHPUnit
|
||||
env:
|
||||
dbtype: ${{ matrix.db }}
|
||||
run: |
|
||||
echo "pathtophp=$(which php)" >> $GITHUB_ENV # Inject installed pathtophp to env. The template config needs it.
|
||||
cp .github/workflows/config-template.php config.php
|
||||
mkdir ../moodledata
|
||||
sudo locale-gen en_AU.UTF-8
|
||||
php admin/tool/phpunit/cli/init.php --no-composer-self-update
|
||||
|
||||
- name: Running PHPUnit tests
|
||||
env:
|
||||
dbtype: ${{ matrix.db }}
|
||||
run: vendor/bin/phpunit -v
|
||||
+2
-1
@@ -33,6 +33,7 @@ CVS
|
||||
/.project
|
||||
/.buildpath
|
||||
/.cache
|
||||
.phpunit.result.cache
|
||||
phpunit.xml
|
||||
# Composer support. Do not ignore composer.json, or composer.lock. These should be shipped by us.
|
||||
composer.phar
|
||||
@@ -44,4 +45,4 @@ composer.phar
|
||||
/lib/yuilib/*/*/*-coverage.js
|
||||
atlassian-ide-plugin.xml
|
||||
/node_modules/
|
||||
moodle-plugin-ci.phar
|
||||
/.vscode/
|
||||
|
||||
+5
-2
@@ -20,6 +20,7 @@ lib/editor/tinymce/plugins/spellchecker/rpc.php
|
||||
lib/editor/tinymce/tiny_mce/
|
||||
lib/mlbackend/php/phpml/
|
||||
lib/adodb/
|
||||
lib/behat/axe/
|
||||
lib/bennu/
|
||||
lib/evalmath/
|
||||
lib/phpspreadsheet/
|
||||
@@ -67,6 +68,9 @@ lib/babel-polyfill/
|
||||
lib/polyfills/
|
||||
lib/emoji-data/
|
||||
lib/plist/
|
||||
lib/zipstream/
|
||||
lib/php-enum/
|
||||
lib/http-message/
|
||||
media/player/videojs/amd/src/video-lazy.js
|
||||
media/player/videojs/amd/src/Youtube-lazy.js
|
||||
media/player/videojs/videojs/
|
||||
@@ -89,5 +93,4 @@ theme/boost/amd/src/bootstrap/tab.js
|
||||
theme/boost/amd/src/bootstrap/toast.js
|
||||
theme/boost/amd/src/bootstrap/tooltip.js
|
||||
theme/boost/amd/src/bootstrap/util.js
|
||||
theme/boost/amd/src/tether.js
|
||||
theme/boost/scss/fontawesome/
|
||||
theme/boost/scss/fontawesome/
|
||||
+73
-39
@@ -10,20 +10,36 @@ language: php
|
||||
|
||||
os: linux
|
||||
|
||||
dist: bionic
|
||||
dist: xenial
|
||||
|
||||
services:
|
||||
- mysql
|
||||
- docker
|
||||
|
||||
php:
|
||||
# We only run the highest and lowest supported versions to reduce the load on travis-ci.org.
|
||||
- 7.4
|
||||
- 7.2
|
||||
|
||||
addons:
|
||||
postgresql: "9.6"
|
||||
|
||||
branches:
|
||||
except:
|
||||
- master
|
||||
- /MOODLE_[0-9]+_STABLE/
|
||||
- /^v[0-9]+\.[0-9]+\.[0-9]+.*/
|
||||
env:
|
||||
# Although we want to run these jobs and see failures as quickly as possible, we also want to get the slowest job to
|
||||
# start first so that the total run time is not too high.
|
||||
#
|
||||
# We only run MySQL on PHP 7.2, so run that first.
|
||||
# CI Tests should be second-highest in priority as these only take <= 60 seconds to run under normal circumstances.
|
||||
# Postgres is significantly is pretty reasonable in its run-time.
|
||||
|
||||
# Run CI Tests without running PHPUnit.
|
||||
- DB=none TASK=CITEST
|
||||
|
||||
# Run unit tests on Postgres
|
||||
- DB=pgsql TASK=PHPUNIT
|
||||
|
||||
# Perform an upgrade test too.
|
||||
- DB=pgsql TASK=UPGRADE
|
||||
|
||||
jobs:
|
||||
# Enable fast finish.
|
||||
@@ -32,35 +48,12 @@ jobs:
|
||||
fast_finish: true
|
||||
|
||||
include:
|
||||
# First all the lowest php ones (7.2)
|
||||
- php: 7.2
|
||||
env: DB=none TASK=CITEST
|
||||
- php: 7.2
|
||||
env: DB=none TASK=GRUNT NVM_VERSION='lts/gallium'
|
||||
|
||||
- if: env(MOODLE_DATABASE) = "pgsql" OR env(MOODLE_DATABASE) = "all" OR env(MOODLE_DATABASE) IS NOT present
|
||||
php: 7.2
|
||||
env: DB=pgsql TASK=PHPUNIT
|
||||
|
||||
- if: env(MOODLE_DATABASE) = "mysqli" OR env(MOODLE_DATABASE) = "all"
|
||||
php: 7.2
|
||||
env: DB=mysqli TASK=PHPUNIT
|
||||
|
||||
# Then, conditionally, all the highest php ones (7.4)
|
||||
- if: env(MOODLE_PHP) = "all"
|
||||
php: 7.4
|
||||
env: DB=none TASK=CITEST
|
||||
- if: env(MOODLE_PHP) = "all"
|
||||
php: 7.4
|
||||
env: DB=none TASK=GRUNT NVM_VERSION='lts/gallium'
|
||||
|
||||
- if: env(MOODLE_PHP) = "all" AND (env(MOODLE_DATABASE) = "pgsql" OR env(MOODLE_DATABASE) = "all" OR env(MOODLE_DATABASE) IS NOT present)
|
||||
php: 7.4
|
||||
env: DB=pgsql TASK=PHPUNIT
|
||||
|
||||
- if: env(MOODLE_PHP) = "all" AND (env(MOODLE_DATABASE) = "mysqli" OR env(MOODLE_DATABASE) = "all")
|
||||
php: 7.4
|
||||
# Run mysql only on highest - it's just too slow
|
||||
- php: 7.4
|
||||
env: DB=mysqli TASK=PHPUNIT
|
||||
# Run grunt/npm install on highest version too ('node' is an alias for the latest node.js version.)
|
||||
- php: 7.4
|
||||
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@@ -81,8 +74,7 @@ install:
|
||||
sudo service mysql stop
|
||||
sudo mv /var/lib/mysql /mnt/ramdisk
|
||||
sudo ln -s /mnt/ramdisk/mysql /var/lib/mysql
|
||||
echo -e "[mysqld]\nskip-log-bin" | sudo tee -a /etc/mysql/my.cnf
|
||||
sudo service mysql start
|
||||
sudo service mysql restart
|
||||
fi
|
||||
- >
|
||||
if [ "$DB" = 'pgsql' ];
|
||||
@@ -93,7 +85,6 @@ install:
|
||||
sudo mv /var/lib/postgresql /mnt/ramdisk
|
||||
sudo ln -s /mnt/ramdisk/postgresql /var/lib/postgresql
|
||||
sudo service postgresql start 9.6
|
||||
sh -c 'until pg_isready -p 5432; do echo "Waiting for the DB to be up..."; sleep 2; done'
|
||||
fi
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
@@ -122,7 +113,7 @@ install:
|
||||
before_script:
|
||||
- phpenv config-rm xdebug.ini
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
if [ "$TASK" = 'PHPUNIT' -o "$TASK" = 'UPGRADE' ];
|
||||
then
|
||||
# Copy generic configuration in place.
|
||||
cp config-dist.php config.php ;
|
||||
@@ -222,7 +213,7 @@ before_script:
|
||||
# We need the official upstream for comparison
|
||||
git remote add upstream https://github.com/moodle/moodle.git;
|
||||
|
||||
git fetch upstream MOODLE_39_STABLE;
|
||||
git fetch upstream MOODLE_310_STABLE;
|
||||
export GIT_PREVIOUS_COMMIT="`git merge-base FETCH_HEAD $TRAVIS_COMMIT`";
|
||||
export GIT_COMMIT="$TRAVIS_COMMIT";
|
||||
export UPSTREAM_FETCH_HEAD=`git rev-parse FETCH_HEAD`
|
||||
@@ -233,6 +224,32 @@ before_script:
|
||||
export phpcmd=`which php`;
|
||||
fi
|
||||
|
||||
########################################################################
|
||||
# Upgrade test
|
||||
########################################################################
|
||||
- >
|
||||
if [ "$TASK" = 'UPGRADE' ];
|
||||
then
|
||||
# We need the official upstream.
|
||||
git remote add upstream https://github.com/moodle/moodle.git;
|
||||
|
||||
# Checkout 30 STABLE branch (the first version compatible with PHP 7.x)
|
||||
git fetch upstream MOODLE_30_STABLE;
|
||||
git checkout MOODLE_30_STABLE;
|
||||
|
||||
# Perform the upgrade
|
||||
php admin/cli/install_database.php --agree-license --adminpass=Password --adminemail=admin@example.com --fullname="Upgrade test" --shortname=Upgrade;
|
||||
|
||||
# Return to the previous commit
|
||||
git checkout -;
|
||||
|
||||
# Perform the upgrade
|
||||
php admin/cli/upgrade.php --non-interactive --allow-unstable ;
|
||||
|
||||
# The local_ci repository can be used to check upgrade savepoints.
|
||||
git clone https://github.com/moodlehq/moodle-local_ci.git local/ci ;
|
||||
fi
|
||||
|
||||
script:
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
@@ -258,6 +275,23 @@ script:
|
||||
git diff --cached --exit-code ;
|
||||
fi
|
||||
|
||||
########################################################################
|
||||
# Upgrade test
|
||||
########################################################################
|
||||
- >
|
||||
if [ "$TASK" = 'UPGRADE' ];
|
||||
then
|
||||
cp local/ci/check_upgrade_savepoints/check_upgrade_savepoints.php ./check_upgrade_savepoints.php
|
||||
result=`php check_upgrade_savepoints.php`;
|
||||
# Check if there are problems
|
||||
count=`echo "$result" | grep -P "ERROR|WARN" | wc -l` ;
|
||||
if (($count > 0));
|
||||
then
|
||||
echo "$result"
|
||||
exit 1 ;
|
||||
fi
|
||||
fi
|
||||
|
||||
after_script:
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
|
||||
+51
-128
@@ -142,7 +142,7 @@ module.exports = function(grunt) {
|
||||
const path = require('path');
|
||||
const tasks = {};
|
||||
const async = require('async');
|
||||
const DOMParser = require('@xmldom/xmldom').DOMParser;
|
||||
const DOMParser = require('xmldom').DOMParser;
|
||||
const xpath = require('xpath');
|
||||
const semver = require('semver');
|
||||
const watchman = require('fb-watchman');
|
||||
@@ -229,8 +229,8 @@ module.exports = function(grunt) {
|
||||
* @return {String} The rewritten destination path.
|
||||
*/
|
||||
var babelRename = function(destPath, srcPath) {
|
||||
destPath = srcPath.replace(`amd/src`, `amd/build`);
|
||||
destPath = destPath.replace(/\.js$/, '.min.js');
|
||||
destPath = srcPath.replace('src', 'build');
|
||||
destPath = destPath.replace('.js', '.min.js');
|
||||
return destPath;
|
||||
};
|
||||
|
||||
@@ -285,71 +285,6 @@ module.exports = function(grunt) {
|
||||
return ['**/tests/behat/*.feature'];
|
||||
};
|
||||
|
||||
const babelTransform = require('@babel/core').transform;
|
||||
const babel = (options = {}) => {
|
||||
return {
|
||||
name: 'babel',
|
||||
|
||||
transform: (code, id) => {
|
||||
grunt.log.debug(`Transforming ${id}`);
|
||||
options.filename = id;
|
||||
const transformed = babelTransform(code, options);
|
||||
|
||||
return {
|
||||
code: transformed.code,
|
||||
map: transformed.map
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Note: We have to use a rate limit plugin here because rollup runs all tasks asynchronously and in parallel.
|
||||
// When we kick off a full run, if we kick off a rollup of every file this will fork-bomb the machine.
|
||||
// To work around this we use a concurrent Promise queue based on the number of available processors.
|
||||
const rateLimit = () => {
|
||||
const queue = [];
|
||||
let queueRunner;
|
||||
|
||||
const startQueue = () => {
|
||||
if (queueRunner) {
|
||||
return;
|
||||
}
|
||||
|
||||
queueRunner = setTimeout(() => {
|
||||
const limit = Math.max(1, require('os').cpus().length / 2);
|
||||
grunt.log.debug(`Starting rollup with queue size of ${limit}`);
|
||||
runQueue(limit);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
// The queue runner will run the next `size` items in the queue.
|
||||
const runQueue = (size = 1) => {
|
||||
queue.splice(0, size).forEach(resolve => {
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
name: 'ratelimit',
|
||||
|
||||
// The options hook is run in parallel.
|
||||
// We can return an unresolved Promise which is queued for later resolution.
|
||||
options: async() => {
|
||||
return new Promise(resolve => {
|
||||
queue.push(resolve);
|
||||
startQueue();
|
||||
});
|
||||
},
|
||||
|
||||
// When an item in the queue completes, start the next item in the queue.
|
||||
buildEnd: () => {
|
||||
runQueue();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const terser = require('rollup-plugin-terser').terser;
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
eslint: {
|
||||
@@ -366,66 +301,55 @@ module.exports = function(grunt) {
|
||||
// Check YUI module source files.
|
||||
yui: {src: files ? files : yuiSrc},
|
||||
},
|
||||
rollup: {
|
||||
dist: {
|
||||
options: {
|
||||
format: 'esm',
|
||||
dir: 'output',
|
||||
sourcemap: true,
|
||||
treeshake: false,
|
||||
context: 'window',
|
||||
plugins: [
|
||||
rateLimit({initialDelay: 0}),
|
||||
babel({
|
||||
sourceMaps: true,
|
||||
comments: false,
|
||||
compact: false,
|
||||
plugins: [
|
||||
'transform-es2015-modules-amd-lazy',
|
||||
'system-import-transformer',
|
||||
// This plugin modifies the Babel transpiling for "export default"
|
||||
// so that if it's used then only the exported value is returned
|
||||
// by the generated AMD module.
|
||||
//
|
||||
// It also adds the Moodle plugin name to the AMD module definition
|
||||
// so that it can be imported as expected in other modules.
|
||||
path.resolve('babel-plugin-add-module-to-define.js'),
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
'@babel/plugin-syntax-import-meta',
|
||||
['@babel/plugin-proposal-class-properties', {'loose': false}],
|
||||
'@babel/plugin-proposal-json-strings'
|
||||
],
|
||||
presets: [
|
||||
['@babel/preset-env', {
|
||||
targets: {
|
||||
browsers: [
|
||||
">0.25%",
|
||||
"last 2 versions",
|
||||
"not ie <= 10",
|
||||
"not op_mini all",
|
||||
"not Opera > 0",
|
||||
"not dead"
|
||||
]
|
||||
},
|
||||
modules: false,
|
||||
useBuiltIns: false
|
||||
}]
|
||||
babel: {
|
||||
options: {
|
||||
sourceMaps: true,
|
||||
comments: false,
|
||||
plugins: [
|
||||
'transform-es2015-modules-amd-lazy',
|
||||
'system-import-transformer',
|
||||
// This plugin modifies the Babel transpiling for "export default"
|
||||
// so that if it's used then only the exported value is returned
|
||||
// by the generated AMD module.
|
||||
//
|
||||
// It also adds the Moodle plugin name to the AMD module definition
|
||||
// so that it can be imported as expected in other modules.
|
||||
path.resolve('babel-plugin-add-module-to-define.js'),
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
'@babel/plugin-syntax-import-meta',
|
||||
['@babel/plugin-proposal-class-properties', {'loose': false}],
|
||||
'@babel/plugin-proposal-json-strings'
|
||||
],
|
||||
presets: [
|
||||
['minify', {
|
||||
// This minification plugin needs to be disabled because it breaks the
|
||||
// source map generation and causes invalid source maps to be output.
|
||||
simplify: false,
|
||||
builtIns: false
|
||||
}],
|
||||
['@babel/preset-env', {
|
||||
targets: {
|
||||
browsers: [
|
||||
">0.25%",
|
||||
"last 2 versions",
|
||||
"not ie <= 10",
|
||||
"not op_mini all",
|
||||
"not Opera > 0",
|
||||
"not dead"
|
||||
]
|
||||
}),
|
||||
|
||||
terser({
|
||||
// Do not mangle variables.
|
||||
// Makes debugging easier.
|
||||
mangle: false,
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
modules: false,
|
||||
useBuiltIns: false
|
||||
}]
|
||||
]
|
||||
},
|
||||
dist: {
|
||||
files: [{
|
||||
expand: true,
|
||||
src: files ? files : amdSrc,
|
||||
rename: babelRename
|
||||
}],
|
||||
},
|
||||
}]
|
||||
}
|
||||
},
|
||||
sass: {
|
||||
dist: {
|
||||
@@ -500,7 +424,7 @@ module.exports = function(grunt) {
|
||||
'*/**/yui/src/*/meta/',
|
||||
'*/**/build/',
|
||||
].concat(thirdPartyPaths);
|
||||
grunt.file.write('.eslintignore', eslintIgnores.join('\n') + '\n');
|
||||
grunt.file.write('.eslintignore', eslintIgnores.join('\n'));
|
||||
|
||||
// Generate .stylelintignore.
|
||||
const stylelintIgnores = [
|
||||
@@ -509,7 +433,7 @@ module.exports = function(grunt) {
|
||||
'theme/boost/style/moodle.css',
|
||||
'theme/classic/style/moodle.css',
|
||||
].concat(thirdPartyPaths);
|
||||
grunt.file.write('.stylelintignore', stylelintIgnores.join('\n') + '\n');
|
||||
grunt.file.write('.stylelintignore', stylelintIgnores.join('\n'));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -910,8 +834,7 @@ module.exports = function(grunt) {
|
||||
grunt.loadNpmTasks('grunt-sass');
|
||||
grunt.loadNpmTasks('grunt-eslint');
|
||||
grunt.loadNpmTasks('grunt-stylelint');
|
||||
grunt.loadNpmTasks('grunt-rollup');
|
||||
|
||||
grunt.loadNpmTasks('grunt-babel');
|
||||
|
||||
// Rename the grunt-contrib-watch "watch" task because we're going to wrap it.
|
||||
grunt.renameTask('watch', 'watch-grunt');
|
||||
@@ -922,7 +845,7 @@ module.exports = function(grunt) {
|
||||
grunt.registerTask('ignorefiles', 'Generate ignore files for linters', tasks.ignorefiles);
|
||||
grunt.registerTask('watch', 'Run tasks on file changes', tasks.watch);
|
||||
grunt.registerTask('yui', ['eslint:yui', 'shifter']);
|
||||
grunt.registerTask('amd', ['eslint:amd', 'rollup']);
|
||||
grunt.registerTask('amd', ['eslint:amd', 'babel']);
|
||||
grunt.registerTask('js', ['amd', 'yui']);
|
||||
|
||||
// Register CSS tasks.
|
||||
|
||||
+35
-53
@@ -1,66 +1,48 @@
|
||||
MOODLE TRADEMARKS POLICY
|
||||
========================
|
||||
|
||||
The Moodle Trademark
|
||||
--------------------
|
||||
The word "Moodle" is trademarked in many countries around the world. The word
|
||||
was originally an acronym: Modular Object-Oriented Dynamic Learning
|
||||
Environment. The trademark is owned by Martin Dougiamas, Founder and Director
|
||||
of Moodle.
|
||||
|
||||
The brand and word "Moodle" has trade mark protection in many countries around
|
||||
the world. Various Moodle™ trade marks are owned by either Moodle Pty Ltd or
|
||||
one of its associated entities. The law obligates trade mark owners to police
|
||||
their trade marks and prevent the use of confusingly similar names by
|
||||
third parties.
|
||||
The law obligates trademark owners to police their marks and prevent the use of
|
||||
confusingly similar names by third parties. Through this policy we’d like to
|
||||
make it clear how Moodle-related projects, organisations, and people can use
|
||||
the Moodle trademark. We’d also like to be clear about how use of the word is
|
||||
restricted when used to promote commercial Moodle services. We do this to
|
||||
protect the very business model that allows us to continue developing Moodle
|
||||
for you.
|
||||
|
||||
We have created a more concise and thorough set of Trademark Guidelines
|
||||
(https://moodle.com/wp-content/uploads/2023/02/Moodle-Trademark-Guidelines-2023-4.pdf)
|
||||
to help you understand how to comply with Moodle's trade mark requirements.
|
||||
The Trademark Guidelines will also assist our Moodle Certified Partners and the
|
||||
community to understand some of the principles that inform Moodle's stance
|
||||
whenever potential infringement has been detected by us or our community.
|
||||
Allowed uses
|
||||
------------
|
||||
|
||||
We need to be clear about use of the word "Moodle" and how we restrict its use
|
||||
when promoting commercial Moodle™ branded services. The proper use of
|
||||
trade marks reliably assures consumers about the quality of the associated
|
||||
products or services and where they have been derived from. Because the
|
||||
Moodle LMS is made available under the open source ‘GNU General Public License'
|
||||
that permits you to modify the copyrighted software, the distribution of such
|
||||
modified software in combination with Moodle trade marks can potentially
|
||||
mislead others in the community. To be clear, the GNU GPL does not include an
|
||||
implied right or licence to use Moodle's trade marks.
|
||||
The following uses don’t require any permission at all:
|
||||
|
||||
We do all this to protect the very business model that allows us to continue
|
||||
developing various Moodle software solutions for you.
|
||||
|
||||
Allowed uses of "Moodle"
|
||||
------------------------
|
||||
|
||||
The following uses don't require any permission at all:
|
||||
|
||||
* Referring to the software or the Moodle project as the "Moodle™ software"
|
||||
or the "Moodle™ project"
|
||||
* Describing your own implementation of the Moodle™ software platform
|
||||
(including within corporate settings).
|
||||
* Referring to the software or the Moodle project.
|
||||
* Describing your own Moodle implementation (including within corporate
|
||||
settings).
|
||||
* Describing a Moodle-based community hub.
|
||||
* Describing certain software you've made that integrates with Moodle™
|
||||
branded software (e.g. a Moodle™ integration feature on another system).
|
||||
* Describing some software you’ve made that integrates with Moodle
|
||||
(eg a Moodle integration feature on another system).
|
||||
|
||||
Restricted uses of "Moodle"
|
||||
---------------------------
|
||||
Restricted uses
|
||||
---------------
|
||||
|
||||
The following uses are generally prohibited without explicit and direct
|
||||
permission being granted to you by Moodle Pty Ltd. We do this to protect the
|
||||
Moodle™ project from software and sites which could confuse people. If in
|
||||
doubt, reach out for clarification at <trademarks@moodle.com>
|
||||
Moodle project from software and sites which could confuse people. Please
|
||||
contact us to ask for permission in writing.
|
||||
|
||||
* You can't use the word "Moodle" or any Moodle logos for commercial purposes
|
||||
without prior written permission from Moodle HQ.
|
||||
* You can't use "Moodle" in the name of your software (including Mobile apps).
|
||||
* You can't use "Moodle" in your company name.
|
||||
* You can't use "Moodle" in your domain name.
|
||||
* You can't use "Moodle" in advertising-related keywords (such as Adsense).
|
||||
* You can't use "Moodle" to describe services around Moodle
|
||||
(such as hosting, training, support, consulting, course creation services,
|
||||
theme development, customisation, installation, integration, analytics
|
||||
and certification) that cause consumers to be confused that you are
|
||||
associated with Moodle HQ if you are not.
|
||||
This applies even if you do not charge for the services.
|
||||
Note that usually only Moodle Partners have this permission.
|
||||
* You can’t use "Moodle" in the name of your software (including Mobile apps)
|
||||
* You can’t use "Moodle" in your company name
|
||||
* You can’t use "Moodle" in your domain name
|
||||
* You can’t use "Moodle" in advertising-related keywords (such as Adsense)
|
||||
* You can’t use "Moodle" to describe services around Moodle (such as hosting,
|
||||
training, support, consulting, course creation services, theme development,
|
||||
customisation, installation, integration and certification). This applies
|
||||
even if you do not charge for the services. Note that usually only Moodle
|
||||
Partners have this permission.
|
||||
|
||||
For information about the Moodle Partner Certification Mark as well as for how
|
||||
to contact us, please see <https://moodle.com/trademarks/>.
|
||||
|
||||
@@ -43,7 +43,7 @@ class testoutgoingmailconf_form extends \moodleform {
|
||||
$mform = $this->_form;
|
||||
|
||||
// Recipient.
|
||||
$options = ['maxlength' => '100', 'size' => '25'];
|
||||
$options = ['maxlength' => '100', 'size' => '25', 'autocomplete' => 'email'];
|
||||
$mform->addElement('text', 'recipient', get_string('testoutgoingmailconf_toemail', 'admin'), $options);
|
||||
$mform->setType('recipient', PARAM_EMAIL);
|
||||
$mform->addRule('recipient', get_string('required'), 'required');
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* External admin page class that allows a callback to be provided to determine whether page can be accessed
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2019 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_admin\local\externalpage;
|
||||
|
||||
use admin_externalpage;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once("{$CFG->libdir}/adminlib.php");
|
||||
|
||||
/**
|
||||
* Admin externalpage class
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2019 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class accesscallback extends admin_externalpage {
|
||||
|
||||
/** @var callable $accesscheckcallback */
|
||||
protected $accesscheckcallback;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $visiblename
|
||||
* @param string $url
|
||||
* @param callable $accesscheckcallback The callback method that will be executed to check whether user has access to
|
||||
* this page. The setting instance ($this) is passed as an argument to the callback. Should return boolean value
|
||||
* @param bool $hidden
|
||||
*/
|
||||
public function __construct(string $name, string $visiblename, string $url, callable $accesscheckcallback,
|
||||
bool $hidden = false) {
|
||||
|
||||
$this->accesscheckcallback = $accesscheckcallback;
|
||||
|
||||
parent::__construct($name, $visiblename, $url, [], $hidden);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the current user has access to this external page based on access callback
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function check_access() {
|
||||
return ($this->accesscheckcallback)($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Auto complete admin setting.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2020 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_admin\local\settings;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
/**
|
||||
* Auto complete setting class.
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @copyright 2020 The Open University
|
||||
*/
|
||||
class autocomplete extends \admin_setting_configmultiselect {
|
||||
/** @var boolean Should we allow typing new entries to the field? */
|
||||
protected $tags = false;
|
||||
/** @var string Name of an AMD module to send/process ajax requests. */
|
||||
protected $ajax = '';
|
||||
/** @var string Placeholder text for an empty list. */
|
||||
protected $placeholder = '';
|
||||
/** @var bool Whether the search has to be case-sensitive. */
|
||||
protected $casesensitive = false;
|
||||
/** @var bool Show suggestions by default - but this can be turned off. */
|
||||
protected $showsuggestions = true;
|
||||
/** @var string String that is shown when there are no selections. */
|
||||
protected $noselectionstring = '';
|
||||
/** @var string Delimiter to store values in database. */
|
||||
protected $delimiter = ',';
|
||||
/** @var string Should be multiple choices? */
|
||||
protected $multiple = true;
|
||||
/** @var string The link to manage choices. */
|
||||
protected $manageurl = true;
|
||||
/** @var string The text to display in manage link. */
|
||||
protected $managetext = true;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting'
|
||||
* for ones in config_plugins.
|
||||
* @param string $visiblename localised
|
||||
* @param string $description long localised info
|
||||
* @param array $defaultsetting array of selected items
|
||||
* @param array $choices options for autocomplete field
|
||||
* @param array $attributes settings for autocomplete field
|
||||
*/
|
||||
public function __construct($name, $visiblename, $description, $defaultsetting, $choices, $attributes = null) {
|
||||
|
||||
if ($attributes === null) {
|
||||
$attributes = [];
|
||||
}
|
||||
|
||||
$this->placeholder = get_string('search');
|
||||
$this->noselectionstring = get_string('noselection', 'form');
|
||||
$defaultattributes = [
|
||||
'tags',
|
||||
'showsuggestions',
|
||||
'placeholder',
|
||||
'noselectionstring',
|
||||
'ajax',
|
||||
'casesensitive',
|
||||
'delimiter',
|
||||
'multiple',
|
||||
'manageurl',
|
||||
'managetext'
|
||||
];
|
||||
|
||||
foreach ($defaultattributes as $attributename) {
|
||||
if (isset($attributes[$attributename])) {
|
||||
$this->$attributename = $attributes[$attributename];
|
||||
}
|
||||
}
|
||||
|
||||
parent::__construct($name, $visiblename, $description, $defaultsetting, $choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the select setting(s)
|
||||
*
|
||||
* @return mixed null or array. Null if no settings else array of setting(s)
|
||||
*/
|
||||
public function get_setting() {
|
||||
$result = $this->config_read($this->name);
|
||||
if (is_null($result)) {
|
||||
return null;
|
||||
}
|
||||
if ($result === '') {
|
||||
return [];
|
||||
}
|
||||
return explode($this->delimiter, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves setting(s) provided through $data
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
public function write_setting($data) {
|
||||
if (!is_array($data)) {
|
||||
return ''; // Ignore it.
|
||||
}
|
||||
if (!$this->load_choices() || empty($this->choices)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
unset($data['xxxxx']);
|
||||
|
||||
$save = [];
|
||||
foreach ($data as $value) {
|
||||
if (!array_key_exists($value, $this->choices)) {
|
||||
continue; // Ignore it.
|
||||
}
|
||||
$save[] = $value;
|
||||
}
|
||||
|
||||
return ($this->config_write($this->name, implode($this->delimiter, $save)) ? '' : get_string('errorsetting', 'admin'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns XHTML autocomplete field
|
||||
*
|
||||
* @param array $data Array of values to select by default
|
||||
* @param string $query
|
||||
* @return string XHTML autocomplete field
|
||||
*/
|
||||
public function output_html($data, $query = '') {
|
||||
global $OUTPUT;
|
||||
|
||||
if (!$this->load_choices() or empty($this->choices)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$default = $this->get_defaultsetting();
|
||||
if (empty($default)) {
|
||||
$default = [];
|
||||
}
|
||||
|
||||
if (is_null($data)) {
|
||||
$data = [];
|
||||
}
|
||||
|
||||
$context = [
|
||||
'id' => $this->get_id(),
|
||||
'name' => $this->get_full_name()
|
||||
];
|
||||
|
||||
$defaults = [];
|
||||
$options = [];
|
||||
$template = 'core_admin/local/settings/autocomplete';
|
||||
|
||||
foreach ($this->choices as $value => $name) {
|
||||
if (in_array($value, $default)) {
|
||||
$defaults[] = $name;
|
||||
}
|
||||
$options[] = [
|
||||
'value' => $value,
|
||||
'text' => $name,
|
||||
'selected' => in_array($value, $data),
|
||||
'disabled' => false
|
||||
];
|
||||
}
|
||||
|
||||
$context['options'] = $options;
|
||||
$context['tags'] = $this->tags;
|
||||
$context['placeholder'] = $this->placeholder;
|
||||
$context['casesensitive'] = $this->casesensitive;
|
||||
$context['multiple'] = $this->multiple;
|
||||
$context['showsuggestions'] = $this->showsuggestions;
|
||||
$context['manageurl'] = $this->manageurl;
|
||||
$context['managetext'] = $this->managetext;
|
||||
|
||||
if (is_null($default)) {
|
||||
$defaultinfo = null;
|
||||
} if (!empty($defaults)) {
|
||||
$defaultinfo = implode(', ', $defaults);
|
||||
} else {
|
||||
$defaultinfo = get_string('none');
|
||||
}
|
||||
|
||||
$element = $OUTPUT->render_from_template($template, $context);
|
||||
|
||||
return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Payment gateway admin setting.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_admin\local\settings;
|
||||
|
||||
/**
|
||||
* Generic class for managing plugins in a table that allows re-ordering and enable/disable of each plugin.
|
||||
*/
|
||||
class manage_payment_gateway_plugins extends \admin_setting_manage_plugins {
|
||||
/**
|
||||
* Get the admin settings section title (use get_string).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_section_title() {
|
||||
return get_string('type_paygw_plural', 'plugin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of plugin to manage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_plugin_type() {
|
||||
return 'paygw';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the second column.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_info_column_name() {
|
||||
return get_string('supportedcurrencies', 'core_payment');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of plugin to manage.
|
||||
*
|
||||
* @param plugininfo The plugin info class.
|
||||
* @return string
|
||||
*/
|
||||
public function get_info_column($plugininfo) {
|
||||
$codes = $plugininfo->get_supported_currencies();
|
||||
|
||||
$currencies = [];
|
||||
foreach ($codes as $c) {
|
||||
$currencies[$c] = new \lang_string($c, 'core_currencies');
|
||||
}
|
||||
|
||||
return implode(get_string('listsep', 'langconfig') . ' ', $currencies);
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,8 @@ class task_log_table extends \table_sql {
|
||||
'userid' => get_string('user', 'admin'),
|
||||
'timestart' => get_string('task_starttime', 'admin'),
|
||||
'duration' => get_string('task_duration', 'admin'),
|
||||
'hostname' => get_string('hostname', 'tool_task'),
|
||||
'pid' => get_string('pid', 'tool_task'),
|
||||
'db' => get_string('task_dbstats', 'admin'),
|
||||
'result' => get_string('task_result', 'admin'),
|
||||
'actions' => '',
|
||||
@@ -132,6 +134,7 @@ class task_log_table extends \table_sql {
|
||||
|
||||
$sql = "SELECT
|
||||
tl.id, tl.type, tl.component, tl.classname, tl.userid, tl.timestart, tl.timeend,
|
||||
tl.hostname, tl.pid,
|
||||
tl.dbreads, tl.dbwrites, tl.result,
|
||||
tl.dbreads + tl.dbwrites AS db,
|
||||
tl.timeend - tl.timestart AS duration,
|
||||
|
||||
@@ -37,11 +37,13 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'showsql' => false,
|
||||
'showdebugging' => false,
|
||||
'ignorelimits' => false,
|
||||
'force' => false,
|
||||
], [
|
||||
'h' => 'help',
|
||||
'e' => 'execute',
|
||||
'k' => 'keep-alive',
|
||||
'i' => 'ignorelimits',
|
||||
'f' => 'force',
|
||||
]
|
||||
);
|
||||
|
||||
@@ -61,6 +63,7 @@ Options:
|
||||
-e, --execute Run all queued adhoc tasks
|
||||
-k, --keep-alive=N Keep this script alive for N seconds and poll for new adhoc tasks
|
||||
-i --ignorelimits Ignore task_adhoc_concurrency_limit and task_adhoc_max_runtime limits
|
||||
-f, --force Run even if cron is disabled
|
||||
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --execute
|
||||
@@ -92,6 +95,12 @@ if (moodle_needs_upgrading()) {
|
||||
if (empty($options['execute'])) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!get_config('core', 'cron_enabled') && !$options['force']) {
|
||||
mtrace('Cron is disabled. Use --force to override.');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (empty($options['keep-alive'])) {
|
||||
$options['keep-alive'] = 0;
|
||||
}
|
||||
|
||||
+105
-6
@@ -36,14 +36,23 @@ require_once($CFG->libdir.'/cronlib.php');
|
||||
|
||||
// now get cli options
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
array(
|
||||
[
|
||||
'help' => false,
|
||||
'stop' => false,
|
||||
),
|
||||
array(
|
||||
'list' => false,
|
||||
'force' => false,
|
||||
'enable' => false,
|
||||
'disable' => false,
|
||||
'disable-wait' => false,
|
||||
], [
|
||||
'h' => 'help',
|
||||
's' => 'stop',
|
||||
)
|
||||
'l' => 'list',
|
||||
'f' => 'force',
|
||||
'e' => 'enable',
|
||||
'd' => 'disable',
|
||||
'w' => 'disable-wait',
|
||||
]
|
||||
);
|
||||
|
||||
if ($unrecognized) {
|
||||
@@ -56,8 +65,13 @@ if ($options['help']) {
|
||||
"Execute periodic cron actions.
|
||||
|
||||
Options:
|
||||
-h, --help Print out this help
|
||||
-s, --stop Notify all other running cron processes to stop after the current task
|
||||
-h, --help Print out this help
|
||||
-s, --stop Notify all other running cron processes to stop after the current task
|
||||
-l, --list Show the list of currently running tasks and how long they have been running
|
||||
-f, --force Execute task even if cron is disabled
|
||||
-e, --enable Enable cron
|
||||
-d, --disable Disable cron
|
||||
-w, --disable-wait=600 Disable cron and wait until all tasks finished or fail after N seconds (optional param)
|
||||
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/cron.php
|
||||
@@ -74,6 +88,91 @@ if ($options['stop']) {
|
||||
die;
|
||||
}
|
||||
|
||||
if ($options['enable']) {
|
||||
set_config('cron_enabled', 1);
|
||||
mtrace('Cron has been enabled for the site.');
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ($options['disable']) {
|
||||
set_config('cron_enabled', 0);
|
||||
\core\task\manager::clear_static_caches();
|
||||
mtrace('Cron has been disabled for the site.');
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ($options['list']) {
|
||||
$tasks = \core\task\manager::get_running_tasks();
|
||||
mtrace('The list of currently running tasks:');
|
||||
$format = "%7s %-12s %-9s %-20s %-52s\n";
|
||||
printf ($format,
|
||||
'PID',
|
||||
'HOST',
|
||||
'TYPE',
|
||||
'TIME',
|
||||
'CLASSNAME'
|
||||
);
|
||||
foreach ($tasks as $task) {
|
||||
printf ($format,
|
||||
$task->pid,
|
||||
substr($task->hostname, 0, 12),
|
||||
$task->type,
|
||||
format_time(time() - $task->timestarted),
|
||||
substr($task->classname, 0, 52)
|
||||
);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ($wait = $options['disable-wait']) {
|
||||
$started = time();
|
||||
if (true === $wait) {
|
||||
// Default waiting time.
|
||||
$waitsec = 600;
|
||||
} else {
|
||||
$waitsec = $wait;
|
||||
$wait = true;
|
||||
}
|
||||
|
||||
set_config('cron_enabled', 0);
|
||||
\core\task\manager::clear_static_caches();
|
||||
mtrace('Cron has been disabled for the site.');
|
||||
mtrace('Allocating '. format_time($waitsec) . ' for the tasks to finish.');
|
||||
|
||||
$lastcount = 0;
|
||||
while ($wait) {
|
||||
$tasks = \core\task\manager::get_running_tasks();
|
||||
|
||||
if (count($tasks) == 0) {
|
||||
mtrace('');
|
||||
mtrace('All scheduled and adhoc tasks finished.');
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (time() - $started >= $waitsec) {
|
||||
mtrace('');
|
||||
mtrace('Wait time ('. format_time($waitsec) . ') elapsed, but ' . count($tasks) . ' task(s) still running.');
|
||||
mtrace('Exiting with code 1.');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (count($tasks) !== $lastcount) {
|
||||
mtrace('');
|
||||
mtrace(count($tasks) . " tasks currently running.", '');
|
||||
$lastcount = count($tasks);
|
||||
} else {
|
||||
mtrace('.', '');
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!get_config('core', 'cron_enabled') && !$options['force']) {
|
||||
mtrace('Cron is disabled. Use --force to override.');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
\core\local\cli\shutdown::script_supports_graceful_exit();
|
||||
|
||||
cron_run();
|
||||
|
||||
@@ -1,138 +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/>.
|
||||
|
||||
/**
|
||||
* Fix orphaned calendar events that were broken by MDL-67494.
|
||||
*
|
||||
* This script will look for all the calendar events which userids
|
||||
* where broken by a wrong upgrade step, affecting to Moodle 3.9.5
|
||||
* and up.
|
||||
*
|
||||
* It performs checks to both:
|
||||
* a) Detect if the site was affected (ran the wrong upgrade step).
|
||||
* b) Look for orphaned calendar events, categorising them as:
|
||||
* - standard: site / category / course / group / user events
|
||||
* - subscription: events created via subscriptions.
|
||||
* - action: normal action events, created to show common important dates.
|
||||
* - override: user and group override events, particular, that some activities support.
|
||||
* - custom: other events, not being any of the above, common or particular.
|
||||
* By specifying it (--fix) try to recover as many broken events (missing userid) as
|
||||
* possible. Standard, subscription, action, override events in core are fully supported but
|
||||
* override or custom events should be fixed by each plugin as far as there isn't any standard
|
||||
* API (plugin-wise) to launch a rebuild of the calendar events.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2021 onwards Simey Lameze <simey@moodle.com>
|
||||
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir . "/clilib.php");
|
||||
require_once($CFG->libdir . '/db/upgradelib.php');
|
||||
|
||||
// Supported options.
|
||||
$long = ['fix' => false, 'help' => false];
|
||||
$short = ['f' => 'fix', 'h' => 'help'];
|
||||
|
||||
// CLI options.
|
||||
[$options, $unrecognized] = cli_get_params($long, $short);
|
||||
|
||||
if ($unrecognized) {
|
||||
$unrecognized = implode("\n ", $unrecognized);
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
if ($options['help']) {
|
||||
$help = <<<EOT
|
||||
Fix orphaned calendar events.
|
||||
|
||||
This script detects calendar events that have had their
|
||||
userid lost. By default it will perform various checks
|
||||
and report them, showing the site status in an easy way.
|
||||
|
||||
Also, optionally (--fix), it wil try to recover as many
|
||||
lost userids as possible from different sources. Note that
|
||||
this script aims to process well-know events in core,
|
||||
leaving custom events in 3rd part plugins mostly unmodified
|
||||
because there isn't any consistent way to regenerate them.
|
||||
|
||||
For more details: https://tracker.moodle.org/browse/MDL-71156
|
||||
|
||||
Options:
|
||||
-h, --help Print out this help.
|
||||
-f, --fix Fix the orphaned calendar events in the DB.
|
||||
If not specified only check and report problems to STDERR.
|
||||
|
||||
Usage:
|
||||
- Only report: \$ sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_calendar_events.php
|
||||
- Report and fix: \$ sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_calendar_events.php -f
|
||||
EOT;
|
||||
|
||||
cli_writeln($help);
|
||||
die;
|
||||
}
|
||||
|
||||
// Check various usual pre-requisites.
|
||||
if (empty($CFG->version)) {
|
||||
cli_error('Database is not yet installed.');
|
||||
}
|
||||
|
||||
$admin = get_admin();
|
||||
if (!$admin) {
|
||||
cli_error('Error: No admin account was found.');
|
||||
}
|
||||
|
||||
if (moodle_needs_upgrading()) {
|
||||
cli_error('Moodle upgrade pending, script execution suspended.');
|
||||
}
|
||||
|
||||
// Do everything as admin by default.
|
||||
\core\session\manager::set_user($admin);
|
||||
|
||||
// Report current site status.
|
||||
cli_heading('Checking the site status');
|
||||
$needsfix = upgrade_calendar_site_status();
|
||||
|
||||
// Report current calendar events status.
|
||||
cli_heading('Checking the calendar events status');
|
||||
$info = upgrade_calendar_events_status();
|
||||
$hasbadevents = $info['total']->bad > 0 || $info['total']->bad != $info['other']->bad;
|
||||
$needsfix = $needsfix || $hasbadevents;
|
||||
|
||||
// If, selected, fix as many calendar events as possible.
|
||||
if ($options['fix']) {
|
||||
|
||||
// If the report has told us that the fix was not needed... ask for confirmation!
|
||||
if (!$needsfix) {
|
||||
cli_writeln("This site DOES NOT NEED to run the calendar events fix.");
|
||||
$input = cli_input('Are you completely sure that you want to run the fix? (y/N)', 'N', ['y', 'Y', 'n', 'N']);
|
||||
if (strtolower($input) != 'y') {
|
||||
exit(0);
|
||||
}
|
||||
cli_writeln("");
|
||||
}
|
||||
cli_heading('Fixing as many as possible calendar events');
|
||||
upgrade_calendar_events_fix_remaining($info);
|
||||
// Report current (after fix) calendar events status.
|
||||
cli_heading('Checking the calendar events status (after fix)');
|
||||
upgrade_calendar_events_status();
|
||||
} else if ($needsfix) {
|
||||
// Fix option was not provided but problem events have been found. Notify the user and provide info how to fix these events.
|
||||
cli_writeln("This site NEEDS to run the calendar events fix!");
|
||||
cli_writeln("To fix the calendar events, re-run this script with the --fix option.");
|
||||
}
|
||||
@@ -119,7 +119,7 @@ if (!empty($options['collation'])) {
|
||||
if ($dbcollation->value !== $collation || $dbcharset->value !== $charset) {
|
||||
// Try to convert the DB.
|
||||
echo "Converting database to '$collation' for $CFG->wwwroot:\n";
|
||||
$sql = "ALTER DATABASE `$CFG->dbname` DEFAULT CHARACTER SET $charset DEFAULT COLLATE = $collation";
|
||||
$sql = "ALTER DATABASE $CFG->dbname DEFAULT CHARACTER SET $charset DEFAULT COLLATE = $collation";
|
||||
try {
|
||||
$DB->change_database_structure($sql);
|
||||
} catch (exception $e) {
|
||||
@@ -146,7 +146,7 @@ if (!empty($options['collation'])) {
|
||||
|
||||
} else {
|
||||
try {
|
||||
$DB->change_database_structure("ALTER TABLE `$table->name` CONVERT TO CHARACTER SET $charset COLLATE $collation");
|
||||
$DB->change_database_structure("ALTER TABLE $table->name CONVERT TO CHARACTER SET $charset COLLATE $collation");
|
||||
echo "CONVERTED\n";
|
||||
$converted++;
|
||||
} catch (ddl_exception $e) {
|
||||
@@ -163,7 +163,7 @@ if (!empty($options['collation'])) {
|
||||
}
|
||||
}
|
||||
|
||||
$sql = "SHOW FULL COLUMNS FROM `$table->name` WHERE collation IS NOT NULL";
|
||||
$sql = "SHOW FULL COLUMNS FROM $table->name WHERE collation IS NOT NULL";
|
||||
$rs2 = $DB->get_recordset_sql($sql);
|
||||
foreach ($rs2 as $column) {
|
||||
$column = (object)array_change_key_case((array)$column, CASE_LOWER);
|
||||
@@ -181,7 +181,7 @@ if (!empty($options['collation'])) {
|
||||
$notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
|
||||
$default = (!is_null($column->default) and $column->default !== '') ? "DEFAULT '$column->default'" : '';
|
||||
// primary, unique and inc are not supported for texts
|
||||
$sql = "ALTER TABLE `$table->name`
|
||||
$sql = "ALTER TABLE $table->name
|
||||
MODIFY COLUMN $column->field $column->type
|
||||
CHARACTER SET $charset
|
||||
COLLATE $collation $notnull $default";
|
||||
@@ -192,11 +192,11 @@ if (!empty($options['collation'])) {
|
||||
$default = !is_null($column->default) ? "DEFAULT '$column->default'" : '';
|
||||
|
||||
if ($rowformat != '') {
|
||||
$sql = "ALTER TABLE `$table->name` $rowformat";
|
||||
$sql = "ALTER TABLE $table->name $rowformat";
|
||||
$DB->change_database_structure($sql);
|
||||
}
|
||||
|
||||
$sql = "ALTER TABLE `$table->name`
|
||||
$sql = "ALTER TABLE $table->name
|
||||
MODIFY COLUMN $column->field $column->type
|
||||
CHARACTER SET $charset
|
||||
COLLATE $collation $notnull $default";
|
||||
@@ -315,8 +315,8 @@ function mysql_set_row_format($tablename, $charset, $collation, $engine) {
|
||||
if ($rs->row_format == 'Compact' || $rs->row_format == 'Redundant') {
|
||||
$rowformat = $DB->get_row_format_sql($engine, $collation);
|
||||
// Try to convert to compressed format and then try updating the collation again.
|
||||
$DB->change_database_structure("ALTER TABLE `$tablename` $rowformat");
|
||||
$DB->change_database_structure("ALTER TABLE `$tablename` CONVERT TO CHARACTER SET $charset COLLATE $collation");
|
||||
$DB->change_database_structure("ALTER TABLE $tablename $rowformat");
|
||||
$DB->change_database_structure("ALTER TABLE $tablename CONVERT TO CHARACTER SET $charset COLLATE $collation");
|
||||
} else {
|
||||
// Row format may not be the problem. Can not diagnose problem. Send fail reply.
|
||||
return false;
|
||||
|
||||
@@ -158,7 +158,7 @@ if (!empty($options['info'])) {
|
||||
}
|
||||
|
||||
foreach ($fixtables as $table) {
|
||||
$DB->change_database_structure("ALTER TABLE `{$prefix}$table` ROW_FORMAT=Compressed");
|
||||
$DB->change_database_structure("ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed");
|
||||
echo str_pad($prefix . $table, 32, ' ', STR_PAD_RIGHT) . " ... Compressed\n";
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ if (!empty($options['info'])) {
|
||||
echo "SET GLOBAL innodb_file_per_table=1;\n";
|
||||
echo "SET GLOBAL innodb_file_format=Barracuda;\n";
|
||||
foreach ($fixtables as $table) {
|
||||
echo "ALTER TABLE `{$prefix}$table` ROW_FORMAT=Compressed;\n";
|
||||
echo "ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed;\n";
|
||||
}
|
||||
echo "\n";
|
||||
exit(0);
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This script allows to restore a course from CLI.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage cli
|
||||
* @copyright 2020 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', 1);
|
||||
|
||||
require(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir . '/clilib.php');
|
||||
require_once($CFG->dirroot . "/backup/util/includes/restore_includes.php");
|
||||
|
||||
list($options, $unrecognized) = cli_get_params([
|
||||
'file' => '',
|
||||
'categoryid' => '',
|
||||
'showdebugging' => false,
|
||||
'help' => false,
|
||||
], [
|
||||
'f' => 'file',
|
||||
'c' => 'categoryid',
|
||||
's' => 'showdebugging',
|
||||
'h' => 'help',
|
||||
]);
|
||||
|
||||
if ($unrecognized) {
|
||||
$unrecognized = implode("\n ", $unrecognized);
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
if ($options['help'] || !($options['file']) || !($options['categoryid'])) {
|
||||
$help = <<<EOL
|
||||
Restore backup into provided category.
|
||||
|
||||
Options:
|
||||
-f, --file=STRING Path to the backup file.
|
||||
-c, --categoryid=INT ID of the category to restore too.
|
||||
-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/file.mbz --categoryid=1\n
|
||||
EOL;
|
||||
|
||||
echo $help;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ($options['showdebugging']) {
|
||||
set_debugging(DEBUG_DEVELOPER, true);
|
||||
}
|
||||
|
||||
if (!$admin = get_admin()) {
|
||||
print_error('noadmins');
|
||||
}
|
||||
|
||||
if (!file_exists($options['file'])) {
|
||||
print_error('filenotfound');
|
||||
}
|
||||
|
||||
if (!$category = $DB->get_record('course_categories', ['id' => $options['categoryid']], 'id')) {
|
||||
print_error('invalidcategoryid');
|
||||
}
|
||||
|
||||
$backupdir = "restore_" . uniqid();
|
||||
$path = $CFG->tempdir . DIRECTORY_SEPARATOR . "backup" . DIRECTORY_SEPARATOR . $backupdir;
|
||||
|
||||
cli_heading(get_string('extractingbackupfileto', 'backup', $path));
|
||||
$fp = get_file_packer('application/vnd.moodle.backup');
|
||||
$fp->extract_to_pathname($options['file'], $path);
|
||||
|
||||
cli_heading(get_string('preprocessingbackupfile'));
|
||||
try {
|
||||
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);
|
||||
$rc->execute_precheck();
|
||||
$rc->execute_plan();
|
||||
$rc->destroy();
|
||||
} catch (Exception $e) {
|
||||
cli_heading(get_string('cleaningtempdata'));
|
||||
fulldelete($path);
|
||||
print_error('generalexceptionmessage', 'error', '', $e->getMessage());
|
||||
}
|
||||
|
||||
cli_heading(get_string('restoredcourseid', 'backup', $courseid));
|
||||
exit(0);
|
||||
@@ -30,8 +30,17 @@ require_once("$CFG->libdir/clilib.php");
|
||||
require_once("$CFG->libdir/cronlib.php");
|
||||
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
array('help' => false, 'list' => false, 'execute' => false, 'showsql' => false, 'showdebugging' => false),
|
||||
array('h' => 'help')
|
||||
[
|
||||
'help' => false,
|
||||
'list' => false,
|
||||
'execute' => false,
|
||||
'showsql' => false,
|
||||
'showdebugging' => false,
|
||||
'force' => false,
|
||||
], [
|
||||
'h' => 'help',
|
||||
'f' => 'force',
|
||||
]
|
||||
);
|
||||
|
||||
if ($unrecognized) {
|
||||
@@ -49,6 +58,7 @@ if ($options['help'] or (!$options['list'] and !$options['execute'])) {
|
||||
--showsql Show sql queries before they are executed
|
||||
--showdebugging Show developer level debugging information
|
||||
-h, --help Print out this help
|
||||
-f, --force Execute task even if cron is disabled
|
||||
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/scheduled_task.php --execute=\\core\\task\\session_cleanup_task
|
||||
@@ -121,6 +131,13 @@ if ($execute = $options['execute']) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!get_config('core', 'cron_enabled') && !$options['force']) {
|
||||
mtrace('Cron is disabled. Use --force to override.');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
\core\task\manager::scheduled_task_starting($task);
|
||||
|
||||
// Increase memory limit.
|
||||
raise_memory_limit(MEMORY_EXTRA);
|
||||
|
||||
|
||||
@@ -38,17 +38,17 @@ if ($unrecognized) {
|
||||
}
|
||||
|
||||
// If necessary add files that should be ignored - such as in 3rd party plugins.
|
||||
$blacklist = array();
|
||||
$ignorelist = array();
|
||||
$path = $options['path'];
|
||||
if (!file_exists($path)) {
|
||||
cli_error("Invalid path $path");
|
||||
}
|
||||
|
||||
if ($options['ie9fix']) {
|
||||
core_admin_recurse_svgs($path, '', 'core_admin_svgtool_ie9fix', $blacklist);
|
||||
core_admin_recurse_svgs($path, '', 'core_admin_svgtool_ie9fix', $ignorelist);
|
||||
|
||||
} else if ($options['noaspectratio']) {
|
||||
core_admin_recurse_svgs($path, '', 'core_admin_svgtool_noaspectratio', $blacklist);
|
||||
core_admin_recurse_svgs($path, '', 'core_admin_svgtool_noaspectratio', $ignorelist);
|
||||
|
||||
} else {
|
||||
$help =
|
||||
@@ -153,9 +153,9 @@ function core_admin_svgtool_noaspectratio($file) {
|
||||
* @param string $base
|
||||
* @param string $sub
|
||||
* @param string $filecallback
|
||||
* @param array $blacklist
|
||||
* @param array $ignorelist List of files to be ignored and skipped.
|
||||
*/
|
||||
function core_admin_recurse_svgs($base, $sub, $filecallback, $blacklist) {
|
||||
function core_admin_recurse_svgs($base, $sub, $filecallback, $ignorelist) {
|
||||
if (is_dir("$base/$sub")) {
|
||||
$items = new DirectoryIterator("$base/$sub");
|
||||
foreach ($items as $item) {
|
||||
@@ -163,7 +163,7 @@ function core_admin_recurse_svgs($base, $sub, $filecallback, $blacklist) {
|
||||
continue;
|
||||
}
|
||||
$file = $item->getFilename();
|
||||
core_admin_recurse_svgs("$base/$sub", $file, $filecallback, $blacklist);
|
||||
core_admin_recurse_svgs("$base/$sub", $file, $filecallback, $ignorelist);
|
||||
}
|
||||
unset($item);
|
||||
unset($items);
|
||||
@@ -174,7 +174,7 @@ function core_admin_recurse_svgs($base, $sub, $filecallback, $blacklist) {
|
||||
return;
|
||||
}
|
||||
$file = realpath("$base/$sub");
|
||||
if (in_array($file, $blacklist)) {
|
||||
if (in_array($file, $ignorelist)) {
|
||||
return;
|
||||
}
|
||||
$filecallback($file);
|
||||
|
||||
@@ -2815,7 +2815,6 @@
|
||||
<VENDOR name="oracle" version="11.2" />
|
||||
</DATABASE>
|
||||
<PHP version="7.1.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_80" message="unsupportedphpversion80" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -2997,7 +2996,6 @@
|
||||
<VENDOR name="oracle" version="11.2" />
|
||||
</DATABASE>
|
||||
<PHP version="7.2.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_80" message="unsupportedphpversion80" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -3163,11 +3161,6 @@
|
||||
<ON_CHECK message="sixtyfourbitswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_igbinary322_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="igbinary322buggyversion" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="3.10" requires="3.5">
|
||||
@@ -3184,7 +3177,6 @@
|
||||
<VENDOR name="oracle" version="11.2" />
|
||||
</DATABASE>
|
||||
<PHP version="7.2.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_80" message="unsupportedphpversion80" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -3350,768 +3342,6 @@
|
||||
<ON_CHECK message="sixtyfourbitswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_igbinary322_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="igbinary322buggyversion" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="3.11" requires="3.6">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.2.29" />
|
||||
<VENDOR name="mysql" version="5.7" />
|
||||
<VENDOR name="postgres" version="9.6" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="11.2" />
|
||||
</DATABASE>
|
||||
<PHP version="7.3.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_81" message="unsupportedphpversion81" />
|
||||
</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="xmlrpc" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="xmlrpcrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="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="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="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="sixtyfourbitswarning" />
|
||||
</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_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.0" requires="3.6">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.2.29" />
|
||||
<VENDOR name="mysql" version="5.7" />
|
||||
<VENDOR name="postgres" version="10" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="11.2" />
|
||||
</DATABASE>
|
||||
<PHP version="7.3.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_81" message="unsupportedphpversion81" />
|
||||
</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="xmlrpc" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="xmlrpcrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="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="optional"/>
|
||||
<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="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="sixtyfourbitswarning" />
|
||||
</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_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.1" requires="3.9">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.4" />
|
||||
<VENDOR name="mysql" version="5.7" />
|
||||
<VENDOR name="postgres" version="12" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="7.4.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_82" message="unsupportedphpversion82" />
|
||||
</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="optional"/>
|
||||
<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="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="sixtyfourbitswarning" />
|
||||
</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_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.2" requires="3.11.8">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.6.7" />
|
||||
<VENDOR name="mysql" version="8.0" />
|
||||
<VENDOR name="postgres" version="13" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.0.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_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -6,7 +6,7 @@ require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
include_once($CFG->dirroot.'/mnet/lib.php');
|
||||
|
||||
$sort = optional_param('sort', 'username', PARAM_ALPHAEXT);
|
||||
$sort = optional_param('sort', 'username', PARAM_ALPHA);
|
||||
$dir = optional_param('dir', 'ASC', PARAM_ALPHA);
|
||||
$page = optional_param('page', 0, PARAM_INT);
|
||||
$perpage = optional_param('perpage', 30, PARAM_INT);
|
||||
@@ -153,15 +153,7 @@ foreach ($columns as $column) {
|
||||
$headings[$column] = "<a href=\"?sort=$column&dir=$columndir&\">".$string[$column]."</a>$columnicon";
|
||||
}
|
||||
$headings['delete'] = '';
|
||||
|
||||
$sortorder = get_safe_orderby([
|
||||
'username' => 'username',
|
||||
'mnet_host_id' => 'mnet_host_id',
|
||||
'access' => 'accessctrl',
|
||||
'default' => 'username',
|
||||
], $sort, $dir, false);
|
||||
|
||||
$acl = $DB->get_records('mnet_sso_access_control', null, $sortorder);
|
||||
$acl = $DB->get_records('mnet_sso_access_control', null, "$sort $dir", '*'); //, $page * $perpage, $perpage);
|
||||
$aclcount = $DB->count_records('mnet_sso_access_control');
|
||||
|
||||
if (!$acl) {
|
||||
|
||||
+13
-16
@@ -1616,18 +1616,12 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
$plugininfo = $pluginman->get_plugins();
|
||||
|
||||
$numtotal = $numextension = $numupdatable = $numinstallable = 0;
|
||||
$numtotal = $numextension = $numupdatable = 0;
|
||||
|
||||
foreach ($plugininfo as $type => $plugins) {
|
||||
foreach ($plugins as $name => $plugin) {
|
||||
if ($res = $plugin->available_updates()) {
|
||||
if ($plugin->available_updates()) {
|
||||
$numupdatable++;
|
||||
foreach ($res as $updateinfo) {
|
||||
if ($pluginman->is_remote_plugin_installable($updateinfo->component, $updateinfo->version, $reason, false)) {
|
||||
$numinstallable++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($plugin->get_status() === core_plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
continue;
|
||||
@@ -1670,13 +1664,16 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$out .= $this->output->heading(get_string('overviewext', 'core_plugin'), 3);
|
||||
}
|
||||
|
||||
if ($numinstallable) {
|
||||
$out .= $this->output->single_button(
|
||||
new moodle_url($this->page->url, array('installupdatex' => 1)),
|
||||
get_string('updateavailableinstallall', 'core_admin', $numinstallable),
|
||||
'post',
|
||||
array('class' => 'singlebutton updateavailableinstallall')
|
||||
);
|
||||
if ($numupdatable) {
|
||||
$installableupdates = $pluginman->filter_installable($pluginman->available_updates());
|
||||
if ($installableupdates) {
|
||||
$out .= $this->output->single_button(
|
||||
new moodle_url($this->page->url, array('installupdatex' => 1)),
|
||||
get_string('updateavailableinstallall', 'core_admin', count($installableupdates)),
|
||||
'post',
|
||||
array('class' => 'singlebutton updateavailableinstallall')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$out .= html_writer::div($infoall, 'info info-all').
|
||||
@@ -1910,7 +1907,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
'infos'
|
||||
);
|
||||
|
||||
if ($pluginman->is_remote_plugin_installable($updateinfo->component, $updateinfo->version, $reason, false)) {
|
||||
if ($pluginman->is_remote_plugin_installable($updateinfo->component, $updateinfo->version, $reason)) {
|
||||
$box .= $this->output->single_button(
|
||||
new moodle_url($this->page->url, array('installupdate' => $updateinfo->component,
|
||||
'installupdateversion' => $updateinfo->version)),
|
||||
|
||||
@@ -536,7 +536,7 @@ class core_role_privacy_testcase extends provider_testcase {
|
||||
$user1->id,
|
||||
$admin->id
|
||||
];
|
||||
$this->assertEquals($expected, $userlist2->get_userids(), '', 0.0, 10, true);
|
||||
$this->assertEqualsCanonicalizing($expected, $userlist2->get_userids());
|
||||
|
||||
// The user list for coursecontext1 should user1, user2 and admin (role creator).
|
||||
$userlist3 = new \core_privacy\local\request\userlist($coursecontext1, $component);
|
||||
@@ -547,7 +547,7 @@ class core_role_privacy_testcase extends provider_testcase {
|
||||
$user2->id,
|
||||
$admin->id
|
||||
];
|
||||
$this->assertEquals($expected, $userlist3->get_userids(), '', 0.0, 10, true);
|
||||
$this->assertEqualsCanonicalizing($expected, $userlist3->get_userids());
|
||||
|
||||
// The user list for coursecatcontext should user2 and admin (role creator).
|
||||
$userlist4 = new \core_privacy\local\request\userlist($coursecatcontext, $component);
|
||||
@@ -557,7 +557,7 @@ class core_role_privacy_testcase extends provider_testcase {
|
||||
$user2->id,
|
||||
$admin->id
|
||||
];
|
||||
$this->assertEquals($expected, $userlist4->get_userids(), '', 0.0, 10, true);
|
||||
$this->assertEqualsCanonicalizing($expected, $userlist4->get_userids());
|
||||
|
||||
// The user list for systemcontext should user1 and admin (role creator).
|
||||
$userlist6 = new \core_privacy\local\request\userlist($systemcontext, $component);
|
||||
@@ -567,7 +567,7 @@ class core_role_privacy_testcase extends provider_testcase {
|
||||
$user1->id,
|
||||
$admin->id
|
||||
];
|
||||
$this->assertEquals($expected, $userlist6->get_userids(), '', 0.0, 10, true);
|
||||
$this->assertEqualsCanonicalizing($expected, $userlist6->get_userids());
|
||||
|
||||
// The user list for cmcontext should user1, user2 and admin (role creator).
|
||||
$userlist7 = new \core_privacy\local\request\userlist($cmcontext, $component);
|
||||
@@ -578,7 +578,7 @@ class core_role_privacy_testcase extends provider_testcase {
|
||||
$user2->id,
|
||||
$admin->id
|
||||
];
|
||||
$this->assertEquals($expected, $userlist7->get_userids(), '', 0.0, 10, true);
|
||||
$this->assertEqualsCanonicalizing($expected, $userlist7->get_userids());
|
||||
|
||||
// The user list for blockcontext should user1 and admin (role creator).
|
||||
$userlist8 = new \core_privacy\local\request\userlist($blockcontext, $component);
|
||||
@@ -588,7 +588,7 @@ class core_role_privacy_testcase extends provider_testcase {
|
||||
$user1->id,
|
||||
$admin->id
|
||||
];
|
||||
$this->assertEquals($expected, $userlist8->get_userids(), '', 0.0, 10, true);
|
||||
$this->assertEqualsCanonicalizing($expected, $userlist8->get_userids());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -744,4 +744,4 @@ class core_role_privacy_testcase extends provider_testcase {
|
||||
}
|
||||
return $rolesnames;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-3
@@ -68,9 +68,16 @@ if ($errormsg !== '') {
|
||||
$showsettingslinks = true;
|
||||
|
||||
if ($hassiteconfig) {
|
||||
require_once("admin_settings_search_form.php");
|
||||
$form = new admin_settings_search_form();
|
||||
$form->display();
|
||||
$data = [
|
||||
'action' => new moodle_url('/admin/search.php'),
|
||||
'btnclass' => 'btn-primary',
|
||||
'inputname' => 'query',
|
||||
'searchstring' => get_string('search'),
|
||||
'query' => $query,
|
||||
'extraclasses' => 'd-flex justify-content-center'
|
||||
];
|
||||
echo $OUTPUT->render_from_template('core/search_input', $data);
|
||||
|
||||
echo '<hr>';
|
||||
if ($query) {
|
||||
echo admin_search_settings_html($query);
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use core_admin\local\settings\filesize;
|
||||
|
||||
$capabilities = array(
|
||||
'moodle/backup:backupcourse',
|
||||
'moodle/category:manage',
|
||||
@@ -75,6 +77,17 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$temp->add(new admin_setting_configselect('moodlecourse/visible', new lang_string('visible'), new lang_string('visible_help'),
|
||||
1, $choices));
|
||||
|
||||
// Enable/disable download course content.
|
||||
$choices = [
|
||||
DOWNLOAD_COURSE_CONTENT_DISABLED => new lang_string('no'),
|
||||
DOWNLOAD_COURSE_CONTENT_ENABLED => new lang_string('yes'),
|
||||
];
|
||||
$downloadcontentsitedefault = new admin_setting_configselect('moodlecourse/downloadcontentsitedefault',
|
||||
new lang_string('enabledownloadcoursecontent', 'course'),
|
||||
new lang_string('downloadcoursecontent_help', 'course'), 0, $choices);
|
||||
$downloadcontentsitedefault->add_dependent_on('downloadcoursecontentallowed');
|
||||
$temp->add($downloadcontentsitedefault);
|
||||
|
||||
// Course format.
|
||||
$temp->add(new admin_setting_heading('courseformathdr', new lang_string('type_format', 'plugin'), ''));
|
||||
|
||||
@@ -161,6 +174,21 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
|
||||
$ADMIN->add('courses', $temp);
|
||||
|
||||
// Download course content.
|
||||
$downloadcoursedefaulturl = new moodle_url('/admin/settings.php', ['section' => 'coursesettings']);
|
||||
$temp = new admin_settingpage('downloadcoursecontent', new lang_string('downloadcoursecontent', 'course'));
|
||||
$temp->add(new admin_setting_configcheckbox('downloadcoursecontentallowed',
|
||||
new lang_string('downloadcoursecontentallowed', 'admin'),
|
||||
new lang_string('downloadcoursecontentallowed_desc', 'admin', $downloadcoursedefaulturl->out()), 0));
|
||||
|
||||
// 50MB default maximum size per file when downloading course content.
|
||||
$defaultmaxdownloadsize = 50 * filesize::UNIT_MB;
|
||||
$temp->add(new filesize('maxsizeperdownloadcoursefile', new lang_string('maxsizeperdownloadcoursefile', 'admin'),
|
||||
new lang_string('maxsizeperdownloadcoursefile_desc', 'admin'), $defaultmaxdownloadsize, filesize::UNIT_MB));
|
||||
$temp->hide_if('maxsizeperdownloadcoursefile', 'downloadcoursecontentallowed');
|
||||
|
||||
$ADMIN->add('courses', $temp);
|
||||
|
||||
// "courserequests" settingpage.
|
||||
$temp = new admin_settingpage('courserequest', new lang_string('courserequest'));
|
||||
$temp->add(new admin_setting_configcheckbox('enablecourserequests',
|
||||
@@ -184,6 +212,7 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
// 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(
|
||||
new admin_setting_configselect(
|
||||
'activitychoosertabmode',
|
||||
@@ -197,6 +226,31 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
// Build a list of plugins that use the footer callback.
|
||||
$pluginswithfunction = get_plugins_with_function('custom_chooser_footer', 'lib.php');
|
||||
$pluginsoptions = [];
|
||||
$pluginsoptions[COURSE_CHOOSER_FOOTER_NONE] = get_string('activitychooserhidefooter', 'course');
|
||||
if ($pluginswithfunction) {
|
||||
foreach ($pluginswithfunction as $plugintype => $plugins) {
|
||||
foreach ($plugins as $pluginname => $pluginfunction) {
|
||||
$plugin = $plugintype.'_'.$pluginname;
|
||||
$pluginsoptions[$plugin] = get_string('pluginname', $plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Select what plugin to show in the footer.
|
||||
$temp->add(
|
||||
new admin_setting_configselect(
|
||||
'activitychooseractivefooter',
|
||||
new lang_string('activitychooseractivefooter', 'course'),
|
||||
new lang_string('activitychooseractivefooter_desc', 'course'),
|
||||
COURSE_CHOOSER_FOOTER_NONE,
|
||||
$pluginsoptions
|
||||
)
|
||||
);
|
||||
|
||||
$ADMIN->add('activitychooser', $temp);
|
||||
$ADMIN->add('activitychooser',
|
||||
new admin_externalpage('activitychooserrecommended', new lang_string('activitychooserrecommendations', 'course'),
|
||||
@@ -259,6 +313,9 @@ 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)));
|
||||
$ADMIN->add('backups', $temp);
|
||||
|
||||
// Create a page for general import configuration and defaults.
|
||||
@@ -285,6 +342,9 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
new lang_string('configgeneralcontentbankcontent', 'backup'),
|
||||
['value' => 1, 'locked' => 0])
|
||||
);
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_import_legacyfiles',
|
||||
new lang_string('generallegacyfiles', 'backup'),
|
||||
new lang_string('configlegacyfiles', 'backup'), array('value' => 1, 'locked' => 0)));
|
||||
|
||||
$ADMIN->add('backups', $temp);
|
||||
|
||||
@@ -411,6 +471,10 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
1)
|
||||
);
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_legacyfiles',
|
||||
new lang_string('generallegacyfiles', 'backup'),
|
||||
new lang_string('configlegacyfiles', 'backup'), 1));
|
||||
|
||||
//$temp->add(new admin_setting_configcheckbox('backup/backup_auto_messages', new lang_string('messages', 'message'), new lang_string('backupmessageshelp','message'), 0));
|
||||
//$temp->add(new admin_setting_configcheckbox('backup/backup_auto_blogs', new lang_string('blogs', 'blog'), new lang_string('backupblogshelp','blog'), 0));
|
||||
|
||||
@@ -473,6 +537,9 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$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)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_legacyfiles',
|
||||
new lang_string('generallegacyfiles', 'backup'),
|
||||
new lang_string('configlegacyfiles', 'backup'), array('value' => 1, 'locked' => 0)));
|
||||
|
||||
// Restore defaults when merging into another course.
|
||||
$temp->add(new admin_setting_heading('mergerestoredefaults', new lang_string('mergerestoredefaults', 'backup'), ''));
|
||||
|
||||
@@ -41,6 +41,13 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$temp->add(new admin_setting_configcheckbox('debugdisplay', new lang_string('debugdisplay', 'admin'), new lang_string('configdebugdisplay', 'admin'), ini_get_bool('display_errors')));
|
||||
$temp->add(new admin_setting_configcheckbox('perfdebug', new lang_string('perfdebug', 'admin'), new lang_string('configperfdebug', 'admin'), '7', '15', '7'));
|
||||
$temp->add(new admin_setting_configcheckbox('debugstringids', new lang_string('debugstringids', 'admin'), new lang_string('debugstringids_desc', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configselect('debugsqltrace',
|
||||
new lang_string('debugsqltrace', 'admin'),
|
||||
new lang_string('debugsqltrace_desc', 'admin'), 0, array(
|
||||
0 => new lang_string('disabled', 'admin'),
|
||||
1 => new lang_string('debugsqltrace1', 'admin'),
|
||||
2 => new lang_string('debugsqltrace2', 'admin'),
|
||||
100 => new lang_string('debugsqltrace100', 'admin'))));
|
||||
$temp->add(new admin_setting_configcheckbox('debugvalidators', new lang_string('debugvalidators', 'admin'), new lang_string('configdebugvalidators', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('debugpageinfo', new lang_string('debugpageinfo', 'admin'), new lang_string('configdebugpageinfo', 'admin'), 0));
|
||||
$ADMIN->add('development', $temp);
|
||||
|
||||
@@ -8,6 +8,8 @@ if ($hassiteconfig) {
|
||||
$temp = new admin_settingpage('langsettings', new lang_string('languagesettings', 'admin'));
|
||||
$temp->add(new admin_setting_configcheckbox('autolang', new lang_string('autolang', 'admin'), new lang_string('configautolang', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configselect('lang', new lang_string('lang', 'admin'), new lang_string('configlang', 'admin'), current_language(), get_string_manager()->get_list_of_translations())); // $CFG->lang might be set in installer already, default en is in setup.php
|
||||
$temp->add(new admin_setting_configcheckbox('autolangusercreation', new lang_string('autolangusercreation', 'admin'),
|
||||
new lang_string('configautolangusercreation', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('langmenu', new lang_string('langmenu', 'admin'), new lang_string('configlangmenu', 'admin'), 1));
|
||||
$temp->add(new admin_setting_langlist());
|
||||
$temp->add(new admin_setting_configcheckbox('langcache', new lang_string('langcache', 'admin'), new lang_string('langcache_desc', 'admin'), 1));
|
||||
|
||||
@@ -14,22 +14,16 @@
|
||||
// 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_phpunit;
|
||||
|
||||
/**
|
||||
* Fixtures for task tests.
|
||||
* Adds payments links to the admin tree
|
||||
*
|
||||
* @package core
|
||||
* @category phpunit
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class adhoc_test_task extends \core\task\adhoc_task {
|
||||
/**
|
||||
* Execute.
|
||||
*/
|
||||
public function execute() {
|
||||
global $USER;
|
||||
mtrace("Task was run as {$USER->id}");
|
||||
}
|
||||
}
|
||||
|
||||
$ADMIN->add('payment', new admin_externalpage(
|
||||
'paymentaccounts',
|
||||
new lang_string('paymentaccounts', 'payment'),
|
||||
new moodle_url("/payment/accounts.php"),
|
||||
['moodle/payment:manageaccounts', 'moodle/payment:viewpayments']));
|
||||
+105
-2
@@ -167,6 +167,42 @@ if ($hassiteconfig) {
|
||||
$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());
|
||||
|
||||
// Common settings.
|
||||
$temp->add(new admin_setting_heading('antiviruscommonsettings', new lang_string('antiviruscommonsettings', 'antivirus'), ''));
|
||||
|
||||
// Alert email.
|
||||
$temp->add(
|
||||
new admin_setting_configtext(
|
||||
'antivirus/notifyemail',
|
||||
new lang_string('notifyemail', 'antivirus'),
|
||||
new lang_string('notifyemail_help', 'antivirus'),
|
||||
'',
|
||||
PARAM_EMAIL
|
||||
)
|
||||
);
|
||||
|
||||
// Enable quarantine.
|
||||
$temp->add(
|
||||
new admin_setting_configcheckbox(
|
||||
'antivirus/enablequarantine',
|
||||
new lang_string('enablequarantine', 'antivirus'),
|
||||
new lang_string('enablequarantine_help', 'antivirus',
|
||||
\core\antivirus\quarantine::DEFAULT_QUARANTINE_FOLDER),
|
||||
0
|
||||
)
|
||||
);
|
||||
|
||||
// Quarantine time.
|
||||
$temp->add(
|
||||
new admin_setting_configduration(
|
||||
'antivirus/quarantinetime',
|
||||
new lang_string('quarantinetime', 'antivirus'),
|
||||
new lang_string('quarantinetime_desc', 'antivirus'),
|
||||
\core\antivirus\quarantine::DEFAULT_QUARANTINE_TIME
|
||||
)
|
||||
);
|
||||
|
||||
$ADMIN->add('antivirussettings', $temp);
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('antivirus');
|
||||
core_collator::asort_objects_by_property($plugins, 'displayname');
|
||||
@@ -244,6 +280,25 @@ if ($hassiteconfig) {
|
||||
$plugin->load_settings($ADMIN, 'mediaplayers', $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(
|
||||
'managepaymentgatewayspostfix',
|
||||
'',
|
||||
new lang_string('gotopaymentaccounts', 'payment',
|
||||
html_writer::link(new moodle_url('/payment/accounts.php'), get_string('paymentaccounts', 'payment')))
|
||||
));
|
||||
$ADMIN->add('paymentgateways', $temp);
|
||||
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('paygw');
|
||||
core_collator::asort_objects_by_property($plugins, 'displayname');
|
||||
foreach ($plugins as $plugin) {
|
||||
/** @var \core\plugininfo\paygw $plugin */
|
||||
$plugin->load_settings($ADMIN, 'paymentgateways', $hassiteconfig);
|
||||
}
|
||||
|
||||
// Data format settings.
|
||||
$ADMIN->add('modules', new admin_category('dataformatsettings', new lang_string('dataformats')));
|
||||
$temp = new admin_settingpage('managedataformats', new lang_string('managedataformats'));
|
||||
@@ -549,8 +604,19 @@ if ($hassiteconfig) {
|
||||
|
||||
// Search engine selection.
|
||||
$temp->add(new admin_setting_heading('searchengineheading', new lang_string('searchengine', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configselect('searchengine',
|
||||
new lang_string('selectsearchengine', 'admin'), '', 'simpledb', $engines));
|
||||
$searchengineselect = new admin_setting_configselect('searchengine',
|
||||
new lang_string('selectsearchengine', 'admin'), '', 'simpledb', $engines);
|
||||
$searchengineselect->set_validate_function(function(string $value): string {
|
||||
global $CFG;
|
||||
|
||||
// Check nobody's setting the indexing and query-only server to the same one.
|
||||
if (isset($CFG->searchenginequeryonly) && $CFG->searchenginequeryonly === $value) {
|
||||
return get_string('searchenginequeryonlysame', 'admin');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
});
|
||||
$temp->add($searchengineselect);
|
||||
$temp->add(new admin_setting_heading('searchoptionsheading', new lang_string('searchoptions', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configcheckbox('searchindexwhendisabled',
|
||||
new lang_string('searchindexwhendisabled', 'admin'), new lang_string('searchindexwhendisabled_desc', 'admin'),
|
||||
@@ -590,6 +656,43 @@ if ($hassiteconfig) {
|
||||
new lang_string('searchhideallcategory_desc', 'admin'),
|
||||
0));
|
||||
|
||||
$temp->add(new admin_setting_heading('searchmanagement', new lang_string('searchmanagement', 'admin'),
|
||||
new lang_string('searchmanagement_desc', 'admin')));
|
||||
|
||||
// Get list of search engines including those with alternate settings.
|
||||
$searchenginequeryonlyselect = new admin_setting_configselect('searchenginequeryonly',
|
||||
new lang_string('searchenginequeryonly', 'admin'),
|
||||
new lang_string('searchenginequeryonly_desc', 'admin'), '', function() use($engines) {
|
||||
$options = ['' => new lang_string('searchenginequeryonly_none', 'admin')];
|
||||
foreach ($engines as $name => $display) {
|
||||
$options[$name] = $display;
|
||||
|
||||
$classname = '\search_' . $name . '\engine';
|
||||
$engine = new $classname;
|
||||
if ($engine->has_alternate_configuration()) {
|
||||
$options[$name . '-alternate'] =
|
||||
new lang_string('searchenginealternatesettings', 'admin', $display);
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
});
|
||||
$searchenginequeryonlyselect->set_validate_function(function(string $value): string {
|
||||
global $CFG;
|
||||
|
||||
// Check nobody's setting the indexing and query-only server to the same one.
|
||||
if (isset($CFG->searchengine) && $CFG->searchengine === $value) {
|
||||
return get_string('searchenginequeryonlysame', 'admin');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
});
|
||||
$temp->add($searchenginequeryonlyselect);
|
||||
$temp->add(new admin_setting_configcheckbox('searchbannerenable',
|
||||
new lang_string('searchbannerenable', 'admin'), new lang_string('searchbannerenable_desc', 'admin'),
|
||||
0));
|
||||
$temp->add(new admin_setting_confightmleditor('searchbanner',
|
||||
new lang_string('searchbanner', 'admin'), '', ''));
|
||||
|
||||
$ADMIN->add('searchplugins', $temp);
|
||||
$ADMIN->add('searchplugins', new admin_externalpage('searchareas', new lang_string('searchareas', 'admin'),
|
||||
new moodle_url('/admin/searchareas.php')));
|
||||
|
||||
@@ -160,6 +160,23 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$temp->add(new admin_setting_configportlist('curlsecurityallowedport',
|
||||
new lang_string('curlsecurityallowedport', 'admin'),
|
||||
new lang_string('curlsecurityallowedportsyntax', 'admin'), ""));
|
||||
|
||||
// HTTP Header referrer policy settings.
|
||||
$referreroptions = [
|
||||
'default' => get_string('referrernone', 'admin'),
|
||||
'no-referrer' => 'no-referrer',
|
||||
'no-referrer-when-downgrade' => 'no-referrer-when-downgrade',
|
||||
'origin' => 'origin',
|
||||
'origin-when-cross-origin' => 'origin-when-cross-origin',
|
||||
'same-origin' => 'same-origin',
|
||||
'strict-origin' => 'strict-origin',
|
||||
'strict-origin-when-cross-origin' => 'strict-origin-when-cross-origin',
|
||||
'unsafe-url' => 'unsafe-url',
|
||||
];
|
||||
$temp->add(new admin_setting_configselect('referrerpolicy',
|
||||
new lang_string('referrerpolicy', 'admin'),
|
||||
new lang_string('referrerpolicydesc', 'admin'), 'default', $referreroptions));
|
||||
|
||||
$ADMIN->add('security', $temp);
|
||||
|
||||
// "notifications" settingpage
|
||||
|
||||
+460
-318
@@ -1,162 +1,225 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// This file defines settingpages and externalpages under the "server" category
|
||||
/**
|
||||
* Defines settingpages and externalpages under the "server" category.
|
||||
*
|
||||
* @package core
|
||||
* @category admin
|
||||
* @copyright 2006 Martin Dougiamas
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
// "systempaths" settingpage
|
||||
$temp = new admin_settingpage('systempaths', new lang_string('systempaths','admin'));
|
||||
$temp->add(new admin_setting_configexecutable('pathtophp', new lang_string('pathtophp', 'admin'),
|
||||
new lang_string('configpathtophp', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('pathtodu', new lang_string('pathtodu', 'admin'), new lang_string('configpathtodu', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('aspellpath', new lang_string('aspellpath', 'admin'), new lang_string('edhelpaspellpath'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('pathtodot', new lang_string('pathtodot', 'admin'), new lang_string('pathtodot_help', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('pathtogs', new lang_string('pathtogs', 'admin'), new lang_string('pathtogs_help', 'admin'), '/usr/bin/gs'));
|
||||
$temp->add(new admin_setting_configexecutable('pathtopython', new lang_string('pathtopython', 'admin'),
|
||||
new lang_string('pathtopythondesc', 'admin'), ''));
|
||||
$ADMIN->add('server', $temp);
|
||||
if ($hassiteconfig) {
|
||||
// System paths.
|
||||
$temp = new admin_settingpage('systempaths', new lang_string('systempaths', 'admin'));
|
||||
$temp->add(new admin_setting_configexecutable('pathtophp', new lang_string('pathtophp', 'admin'),
|
||||
new lang_string('configpathtophp', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('pathtodu', new lang_string('pathtodu', 'admin'),
|
||||
new lang_string('configpathtodu', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('aspellpath', new lang_string('aspellpath', 'admin'),
|
||||
new lang_string('edhelpaspellpath'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('pathtodot', new lang_string('pathtodot', 'admin'),
|
||||
new lang_string('pathtodot_help', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('pathtogs', new lang_string('pathtogs', 'admin'),
|
||||
new lang_string('pathtogs_help', 'admin'), '/usr/bin/gs'));
|
||||
$temp->add(new admin_setting_configexecutable('pathtopython', new lang_string('pathtopython', 'admin'),
|
||||
new lang_string('pathtopythondesc', 'admin'), ''));
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
// Support contact.
|
||||
$temp = new admin_settingpage('supportcontact', new lang_string('supportcontact', 'admin'));
|
||||
$primaryadmin = get_admin();
|
||||
if ($primaryadmin) {
|
||||
$primaryadminemail = $primaryadmin->email;
|
||||
$primaryadminname = fullname($primaryadmin, true);
|
||||
} else {
|
||||
// No defaults during installation - admin user must be created first.
|
||||
$primaryadminemail = null;
|
||||
$primaryadminname = null;
|
||||
}
|
||||
$temp->add(new admin_setting_configtext('supportname', new lang_string('supportname', 'admin'),
|
||||
new lang_string('configsupportname', 'admin'), $primaryadminname, PARAM_NOTAGS));
|
||||
$setting = new admin_setting_configtext('supportemail', new lang_string('supportemail', 'admin'),
|
||||
new lang_string('configsupportemail', 'admin'), $primaryadminemail, PARAM_EMAIL);
|
||||
$setting->set_force_ltr(true);
|
||||
$temp->add($setting);
|
||||
$temp->add(new admin_setting_configtext('supportpage', new lang_string('supportpage', 'admin'),
|
||||
new lang_string('configsupportpage', 'admin'), '', PARAM_URL));
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
// Session handling.
|
||||
$temp = new admin_settingpage('sessionhandling', new lang_string('sessionhandling', 'admin'));
|
||||
if (empty($CFG->session_handler_class) and $DB->session_lock_supported()) {
|
||||
$temp->add(new admin_setting_configcheckbox('dbsessions', new lang_string('dbsessions', 'admin'),
|
||||
new lang_string('configdbsessions', 'admin'), 0));
|
||||
}
|
||||
|
||||
// "supportcontact" settingpage
|
||||
$temp = new admin_settingpage('supportcontact', new lang_string('supportcontact','admin'));
|
||||
$primaryadmin = get_admin();
|
||||
if ($primaryadmin) {
|
||||
$primaryadminemail = $primaryadmin->email;
|
||||
$primaryadminname = fullname($primaryadmin, true);
|
||||
} else {
|
||||
// no defaults during installation - admin user must be created first
|
||||
$primaryadminemail = NULL;
|
||||
$primaryadminname = NULL;
|
||||
}
|
||||
$temp->add(new admin_setting_configtext('supportname', new lang_string('supportname', 'admin'),
|
||||
new lang_string('configsupportname', 'admin'), $primaryadminname, PARAM_NOTAGS));
|
||||
$setting = new admin_setting_configtext('supportemail', new lang_string('supportemail', 'admin'),
|
||||
new lang_string('configsupportemail', 'admin'), $primaryadminemail, PARAM_EMAIL);
|
||||
$setting->set_force_ltr(true);
|
||||
$temp->add($setting);
|
||||
$temp->add(new admin_setting_configtext('supportpage', new lang_string('supportpage', 'admin'), new lang_string('configsupportpage', 'admin'), '', PARAM_URL));
|
||||
$ADMIN->add('server', $temp);
|
||||
$temp->add(new admin_setting_configduration('sessiontimeout', new lang_string('sessiontimeout', 'admin'),
|
||||
new lang_string('configsessiontimeout', 'admin'), 8 * 60 * 60));
|
||||
|
||||
$temp->add(new admin_setting_configtext('sessioncookie', new lang_string('sessioncookie', 'admin'),
|
||||
new lang_string('configsessioncookie', 'admin'), '', PARAM_ALPHANUM));
|
||||
$temp->add(new admin_setting_configtext('sessioncookiepath', new lang_string('sessioncookiepath', 'admin'),
|
||||
new lang_string('configsessioncookiepath', 'admin'), '', PARAM_RAW));
|
||||
$temp->add(new admin_setting_configtext('sessioncookiedomain', new lang_string('sessioncookiedomain', 'admin'),
|
||||
new lang_string('configsessioncookiedomain', 'admin'), '', PARAM_RAW, 50));
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
// "sessionhandling" settingpage
|
||||
$temp = new admin_settingpage('sessionhandling', new lang_string('sessionhandling', 'admin'));
|
||||
if (empty($CFG->session_handler_class) and $DB->session_lock_supported()) {
|
||||
$temp->add(new admin_setting_configcheckbox('dbsessions', new lang_string('dbsessions', 'admin'), new lang_string('configdbsessions', 'admin'), 0));
|
||||
}
|
||||
// Statistics.
|
||||
$temp = new admin_settingpage('stats', new lang_string('stats'), 'moodle/site:config', empty($CFG->enablestats));
|
||||
$temp->add(new admin_setting_configselect('statsfirstrun', new lang_string('statsfirstrun', 'admin'),
|
||||
new lang_string('configstatsfirstrun', 'admin'), 'none',
|
||||
[
|
||||
'none' => new lang_string('none'),
|
||||
60 * 60 * 24 * 7 => new lang_string('numweeks', 'moodle', 1),
|
||||
60 * 60 * 24 * 14 => new lang_string('numweeks', 'moodle', 2),
|
||||
60 * 60 * 24 * 21 => new lang_string('numweeks', 'moodle', 3),
|
||||
60 * 60 * 24 * 28 => new lang_string('nummonths', 'moodle', 1),
|
||||
60 * 60 * 24 * 56 => new lang_string('nummonths', 'moodle', 2),
|
||||
60 * 60 * 24 * 84 => new lang_string('nummonths', 'moodle', 3),
|
||||
60 * 60 * 24 * 112 => new lang_string('nummonths', 'moodle', 4),
|
||||
60 * 60 * 24 * 140 => new lang_string('nummonths', 'moodle', 5),
|
||||
60 * 60 * 24 * 168 => new lang_string('nummonths', 'moodle', 6),
|
||||
'all' => new lang_string('all')
|
||||
]
|
||||
));
|
||||
$temp->add(new admin_setting_configselect('statsmaxruntime', new lang_string('statsmaxruntime', 'admin'),
|
||||
new lang_string('configstatsmaxruntime3', 'admin'), 0,
|
||||
[
|
||||
0 => new lang_string('untilcomplete'),
|
||||
60 * 30 => '10 ' . new lang_string('minutes'),
|
||||
60 * 30 => '30 ' . new lang_string('minutes'),
|
||||
60 * 60 => '1 ' . new lang_string('hour'),
|
||||
60 * 60 * 2 => '2 ' . new lang_string('hours'),
|
||||
60 * 60 * 3 => '3 ' . new lang_string('hours'),
|
||||
60 * 60 * 4 => '4 ' . new lang_string('hours'),
|
||||
60 * 60 * 5 => '5 ' . new lang_string('hours'),
|
||||
60 * 60 * 6 => '6 ' . new lang_string('hours'),
|
||||
60 * 60 * 7 => '7 ' . new lang_string('hours'),
|
||||
60 * 60 * 8 => '8 ' . new lang_string('hours'),
|
||||
]
|
||||
));
|
||||
$temp->add(new admin_setting_configtext('statsruntimedays', new lang_string('statsruntimedays', 'admin'),
|
||||
new lang_string('configstatsruntimedays', 'admin'), 31, PARAM_INT));
|
||||
$temp->add(new admin_setting_configtext('statsuserthreshold', new lang_string('statsuserthreshold', 'admin'),
|
||||
new lang_string('configstatsuserthreshold', 'admin'), 0, PARAM_INT));
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
$temp->add(new admin_setting_configduration('sessiontimeout', new lang_string('sessiontimeout', 'admin'),
|
||||
new lang_string('configsessiontimeout', 'admin'), 8 * 60 * 60));
|
||||
// HTTP.
|
||||
$temp = new admin_settingpage('http', new lang_string('http', 'admin'));
|
||||
$temp->add(new admin_setting_configcheckbox('slasharguments', new lang_string('slasharguments', 'admin'),
|
||||
new lang_string('configslasharguments', 'admin'), 1));
|
||||
$temp->add(new admin_setting_heading('reverseproxy', new lang_string('reverseproxy', 'admin'), '', ''));
|
||||
$options = [
|
||||
0 => 'HTTP_CLIENT_IP, HTTP_X_FORWARDED_FOR, REMOTE_ADDR',
|
||||
GETREMOTEADDR_SKIP_HTTP_CLIENT_IP => 'HTTP_X_FORWARDED_FOR, REMOTE_ADDR',
|
||||
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR => 'HTTP_CLIENT, REMOTE_ADDR',
|
||||
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR | GETREMOTEADDR_SKIP_HTTP_CLIENT_IP => 'REMOTE_ADDR'
|
||||
];
|
||||
$temp->add(new admin_setting_configselect('getremoteaddrconf', new lang_string('getremoteaddrconf', 'admin'),
|
||||
new lang_string('configgetremoteaddrconf', 'admin'),
|
||||
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR | GETREMOTEADDR_SKIP_HTTP_CLIENT_IP, $options));
|
||||
$temp->add(new admin_setting_configtext('reverseproxyignore', new lang_string('reverseproxyignore', 'admin'),
|
||||
new lang_string('configreverseproxyignore', 'admin'), ''));
|
||||
|
||||
$temp->add(new admin_setting_configtext('sessioncookie', new lang_string('sessioncookie', 'admin'), new lang_string('configsessioncookie', 'admin'), '', PARAM_ALPHANUM));
|
||||
$temp->add(new admin_setting_configtext('sessioncookiepath', new lang_string('sessioncookiepath', 'admin'), new lang_string('configsessioncookiepath', 'admin'), '', PARAM_RAW));
|
||||
$temp->add(new admin_setting_configtext('sessioncookiedomain', new lang_string('sessioncookiedomain', 'admin'), new lang_string('configsessioncookiedomain', 'admin'), '', PARAM_RAW, 50));
|
||||
$ADMIN->add('server', $temp);
|
||||
$temp->add(new admin_setting_heading('webproxy', new lang_string('webproxy', 'admin'),
|
||||
new lang_string('webproxyinfo', 'admin')));
|
||||
$temp->add(new admin_setting_configtext('proxyhost', new lang_string('proxyhost', 'admin'),
|
||||
new lang_string('configproxyhost', 'admin'), '', PARAM_HOST));
|
||||
$temp->add(new admin_setting_configtext('proxyport', new lang_string('proxyport', 'admin'),
|
||||
new lang_string('configproxyport', 'admin'), 0, PARAM_INT));
|
||||
$options = ['HTTP' => 'HTTP'];
|
||||
if (defined('CURLPROXY_SOCKS5')) {
|
||||
$options['SOCKS5'] = 'SOCKS5';
|
||||
}
|
||||
$temp->add(new admin_setting_configselect('proxytype', new lang_string('proxytype', 'admin'),
|
||||
new lang_string('configproxytype', 'admin'), 'HTTP', $options));
|
||||
$temp->add(new admin_setting_configtext('proxyuser', new lang_string('proxyuser', 'admin'),
|
||||
new lang_string('configproxyuser', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configpasswordunmask('proxypassword', new lang_string('proxypassword', 'admin'),
|
||||
new lang_string('configproxypassword', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configtext('proxybypass', new lang_string('proxybypass', 'admin'),
|
||||
new lang_string('configproxybypass', 'admin'), 'localhost, 127.0.0.1'));
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
$temp = new admin_settingpage('maintenancemode', new lang_string('sitemaintenancemode', 'admin'));
|
||||
$options = [0 => new lang_string('disable'), 1 => new lang_string('enable')];
|
||||
$temp->add(new admin_setting_configselect('maintenance_enabled', new lang_string('sitemaintenancemode', 'admin'),
|
||||
new lang_string('helpsitemaintenance', 'admin'), 0, $options));
|
||||
$temp->add(new admin_setting_confightmleditor('maintenance_message', new lang_string('optionalmaintenancemessage', 'admin'),
|
||||
'', ''));
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
// "stats" settingpage
|
||||
$temp = new admin_settingpage('stats', new lang_string('stats'), 'moodle/site:config', empty($CFG->enablestats));
|
||||
$temp->add(new admin_setting_configselect('statsfirstrun', new lang_string('statsfirstrun', 'admin'), new lang_string('configstatsfirstrun', 'admin'), 'none', array('none' => new lang_string('none'),
|
||||
60*60*24*7 => new lang_string('numweeks','moodle',1),
|
||||
60*60*24*14 => new lang_string('numweeks','moodle',2),
|
||||
60*60*24*21 => new lang_string('numweeks','moodle',3),
|
||||
60*60*24*28 => new lang_string('nummonths','moodle',1),
|
||||
60*60*24*56 => new lang_string('nummonths','moodle',2),
|
||||
60*60*24*84 => new lang_string('nummonths','moodle',3),
|
||||
60*60*24*112 => new lang_string('nummonths','moodle',4),
|
||||
60*60*24*140 => new lang_string('nummonths','moodle',5),
|
||||
60*60*24*168 => new lang_string('nummonths','moodle',6),
|
||||
'all' => new lang_string('all') )));
|
||||
$temp->add(new admin_setting_configselect('statsmaxruntime', new lang_string('statsmaxruntime', 'admin'), new lang_string('configstatsmaxruntime3', 'admin'), 0, array(0 => new lang_string('untilcomplete'),
|
||||
60*30 => '10 '.new lang_string('minutes'),
|
||||
60*30 => '30 '.new lang_string('minutes'),
|
||||
60*60 => '1 '.new lang_string('hour'),
|
||||
60*60*2 => '2 '.new lang_string('hours'),
|
||||
60*60*3 => '3 '.new lang_string('hours'),
|
||||
60*60*4 => '4 '.new lang_string('hours'),
|
||||
60*60*5 => '5 '.new lang_string('hours'),
|
||||
60*60*6 => '6 '.new lang_string('hours'),
|
||||
60*60*7 => '7 '.new lang_string('hours'),
|
||||
60*60*8 => '8 '.new lang_string('hours') )));
|
||||
$temp->add(new admin_setting_configtext('statsruntimedays', new lang_string('statsruntimedays', 'admin'), new lang_string('configstatsruntimedays', 'admin'), 31, PARAM_INT));
|
||||
$temp->add(new admin_setting_configtext('statsuserthreshold', new lang_string('statsuserthreshold', 'admin'), new lang_string('configstatsuserthreshold', 'admin'), 0, PARAM_INT));
|
||||
$ADMIN->add('server', $temp);
|
||||
// Cleanup.
|
||||
$temp = new admin_settingpage('cleanup', new lang_string('cleanup', 'admin'));
|
||||
$temp->add(new admin_setting_configselect('deleteunconfirmed', new lang_string('deleteunconfirmed', 'admin'),
|
||||
new lang_string('configdeleteunconfirmed', 'admin'), 168,
|
||||
[
|
||||
0 => new lang_string('never'),
|
||||
168 => new lang_string('numdays', '', 7),
|
||||
144 => new lang_string('numdays', '', 6),
|
||||
120 => new lang_string('numdays', '', 5),
|
||||
96 => new lang_string('numdays', '', 4),
|
||||
72 => new lang_string('numdays', '', 3),
|
||||
48 => new lang_string('numdays', '', 2),
|
||||
24 => new lang_string('numdays', '', 1),
|
||||
12 => new lang_string('numhours', '', 12),
|
||||
6 => new lang_string('numhours', '', 6),
|
||||
1 => new lang_string('numhours', '', 1),
|
||||
]
|
||||
));
|
||||
|
||||
$temp->add(new admin_setting_configselect('deleteincompleteusers', new lang_string('deleteincompleteusers', 'admin'),
|
||||
new lang_string('configdeleteincompleteusers', 'admin'), 0,
|
||||
[
|
||||
0 => new lang_string('never'),
|
||||
168 => new lang_string('numdays', '', 7),
|
||||
144 => new lang_string('numdays', '', 6),
|
||||
120 => new lang_string('numdays', '', 5),
|
||||
96 => new lang_string('numdays', '', 4),
|
||||
72 => new lang_string('numdays', '', 3),
|
||||
48 => new lang_string('numdays', '', 2),
|
||||
24 => new lang_string('numdays', '', 1),
|
||||
]
|
||||
));
|
||||
|
||||
// "http" settingpage
|
||||
$temp = new admin_settingpage('http', new lang_string('http', 'admin'));
|
||||
$temp->add(new admin_setting_configcheckbox('slasharguments', new lang_string('slasharguments', 'admin'), new lang_string('configslasharguments', 'admin'), 1));
|
||||
$temp->add(new admin_setting_heading('reverseproxy', new lang_string('reverseproxy', 'admin'), '', ''));
|
||||
$options = array(
|
||||
0 => 'HTTP_CLIENT_IP, HTTP_X_FORWARDED_FOR, REMOTE_ADDR',
|
||||
GETREMOTEADDR_SKIP_HTTP_CLIENT_IP => 'HTTP_X_FORWARDED_FOR, REMOTE_ADDR',
|
||||
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR => 'HTTP_CLIENT, REMOTE_ADDR',
|
||||
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR|GETREMOTEADDR_SKIP_HTTP_CLIENT_IP => 'REMOTE_ADDR');
|
||||
$temp->add(new admin_setting_configselect('getremoteaddrconf', new lang_string('getremoteaddrconf', 'admin'),
|
||||
new lang_string('configgetremoteaddrconf', 'admin'),
|
||||
GETREMOTEADDR_SKIP_DEFAULT, $options));
|
||||
$temp->add(new admin_setting_configtext('reverseproxyignore', new lang_string('reverseproxyignore', 'admin'), new lang_string('configreverseproxyignore', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configcheckbox('disablegradehistory', new lang_string('disablegradehistory', 'grades'),
|
||||
new lang_string('disablegradehistory_help', 'grades'), 0));
|
||||
|
||||
$temp->add(new admin_setting_heading('webproxy', new lang_string('webproxy', 'admin'), new lang_string('webproxyinfo', 'admin')));
|
||||
$temp->add(new admin_setting_configtext('proxyhost', new lang_string('proxyhost', 'admin'), new lang_string('configproxyhost', 'admin'), '', PARAM_HOST));
|
||||
$temp->add(new admin_setting_configtext('proxyport', new lang_string('proxyport', 'admin'), new lang_string('configproxyport', 'admin'), 0, PARAM_INT));
|
||||
$options = array('HTTP'=>'HTTP');
|
||||
if (defined('CURLPROXY_SOCKS5')) {
|
||||
$options['SOCKS5'] = 'SOCKS5';
|
||||
}
|
||||
$temp->add(new admin_setting_configselect('proxytype', new lang_string('proxytype', 'admin'), new lang_string('configproxytype','admin'), 'HTTP', $options));
|
||||
$temp->add(new admin_setting_configtext('proxyuser', new lang_string('proxyuser', 'admin'), new lang_string('configproxyuser', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configpasswordunmask('proxypassword', new lang_string('proxypassword', 'admin'), new lang_string('configproxypassword', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configtext('proxybypass', new lang_string('proxybypass', 'admin'), new lang_string('configproxybypass', 'admin'), 'localhost, 127.0.0.1'));
|
||||
$ADMIN->add('server', $temp);
|
||||
$temp->add(new admin_setting_configselect('gradehistorylifetime', new lang_string('gradehistorylifetime', 'grades'),
|
||||
new lang_string('gradehistorylifetime_help', 'grades'), 0,
|
||||
[
|
||||
0 => new lang_string('neverdeletehistory', 'grades'),
|
||||
1000 => new lang_string('numdays', '', 1000),
|
||||
365 => new lang_string('numdays', '', 365),
|
||||
180 => new lang_string('numdays', '', 180),
|
||||
150 => new lang_string('numdays', '', 150),
|
||||
120 => new lang_string('numdays', '', 120),
|
||||
90 => new lang_string('numdays', '', 90),
|
||||
60 => new lang_string('numdays', '', 60),
|
||||
30 => new lang_string('numdays', '', 30),
|
||||
]
|
||||
));
|
||||
|
||||
$temp = new admin_settingpage('maintenancemode', new lang_string('sitemaintenancemode', 'admin'));
|
||||
$options = array(0=>new lang_string('disable'), 1=>new lang_string('enable'));
|
||||
$temp->add(new admin_setting_configselect('maintenance_enabled', new lang_string('sitemaintenancemode', 'admin'),
|
||||
new lang_string('helpsitemaintenance', 'admin'), 0, $options));
|
||||
$temp->add(new admin_setting_confightmleditor('maintenance_message', new lang_string('optionalmaintenancemessage', 'admin'),
|
||||
'', ''));
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
$temp = new admin_settingpage('cleanup', new lang_string('cleanup', 'admin'));
|
||||
$temp->add(new admin_setting_configselect('deleteunconfirmed', new lang_string('deleteunconfirmed', 'admin'), new lang_string('configdeleteunconfirmed', 'admin'), 168, array(0 => new lang_string('never'),
|
||||
168 => new lang_string('numdays', '', 7),
|
||||
144 => new lang_string('numdays', '', 6),
|
||||
120 => new lang_string('numdays', '', 5),
|
||||
96 => new lang_string('numdays', '', 4),
|
||||
72 => new lang_string('numdays', '', 3),
|
||||
48 => new lang_string('numdays', '', 2),
|
||||
24 => new lang_string('numdays', '', 1),
|
||||
12 => new lang_string('numhours', '', 12),
|
||||
6 => new lang_string('numhours', '', 6),
|
||||
1 => new lang_string('numhours', '', 1))));
|
||||
|
||||
$temp->add(new admin_setting_configselect('deleteincompleteusers', new lang_string('deleteincompleteusers', 'admin'), new lang_string('configdeleteincompleteusers', 'admin'), 0, array(0 => new lang_string('never'),
|
||||
168 => new lang_string('numdays', '', 7),
|
||||
144 => new lang_string('numdays', '', 6),
|
||||
120 => new lang_string('numdays', '', 5),
|
||||
96 => new lang_string('numdays', '', 4),
|
||||
72 => new lang_string('numdays', '', 3),
|
||||
48 => new lang_string('numdays', '', 2),
|
||||
24 => new lang_string('numdays', '', 1))));
|
||||
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('disablegradehistory', new lang_string('disablegradehistory', 'grades'),
|
||||
new lang_string('disablegradehistory_help', 'grades'), 0));
|
||||
|
||||
$temp->add(new admin_setting_configselect('gradehistorylifetime', new lang_string('gradehistorylifetime', 'grades'),
|
||||
new lang_string('gradehistorylifetime_help', 'grades'), 0, array(0 => new lang_string('neverdeletehistory', 'grades'),
|
||||
1000 => new lang_string('numdays', '', 1000),
|
||||
365 => new lang_string('numdays', '', 365),
|
||||
180 => new lang_string('numdays', '', 180),
|
||||
150 => new lang_string('numdays', '', 150),
|
||||
120 => new lang_string('numdays', '', 120),
|
||||
90 => new lang_string('numdays', '', 90),
|
||||
60 => new lang_string('numdays', '', 60),
|
||||
30 => new lang_string('numdays', '', 30))));
|
||||
|
||||
$temp->add(new admin_setting_configselect('tempdatafoldercleanup', new lang_string('tempdatafoldercleanup', 'admin'),
|
||||
new lang_string('configtempdatafoldercleanup', 'admin'), 168, array(
|
||||
$temp->add(new admin_setting_configselect('tempdatafoldercleanup', new lang_string('tempdatafoldercleanup', 'admin'),
|
||||
new lang_string('configtempdatafoldercleanup', 'admin'), 168,
|
||||
[
|
||||
1 => new lang_string('numhours', '', 1),
|
||||
3 => new lang_string('numhours', '', 3),
|
||||
6 => new lang_string('numhours', '', 6),
|
||||
@@ -166,224 +229,303 @@ $temp->add(new admin_setting_configselect('tempdatafoldercleanup', new lang_stri
|
||||
24 => new lang_string('numhours', '', 24),
|
||||
48 => new lang_string('numdays', '', 2),
|
||||
168 => new lang_string('numdays', '', 7),
|
||||
)));
|
||||
]
|
||||
));
|
||||
|
||||
$ADMIN->add('server', $temp);
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
$temp->add(new admin_setting_configduration('filescleanupperiod',
|
||||
new lang_string('filescleanupperiod', 'admin'),
|
||||
new lang_string('filescleanupperiod_help', 'admin'),
|
||||
86400));
|
||||
|
||||
$ADMIN->add('server', new admin_externalpage('environment', new lang_string('environment','admin'), "$CFG->wwwroot/$CFG->admin/environment.php"));
|
||||
$ADMIN->add('server', new admin_externalpage('phpinfo', new lang_string('phpinfo'), "$CFG->wwwroot/$CFG->admin/phpinfo.php"));
|
||||
$ADMIN->add('server', new admin_externalpage('testoutgoingmailconf', new lang_string('testoutgoingmailconf', 'admin'),
|
||||
new moodle_url("$CFG->wwwroot/$CFG->admin/testoutgoingmailconf.php"), 'moodle/site:config', true));
|
||||
// Environment.
|
||||
$ADMIN->add('server', new admin_externalpage('environment', new lang_string('environment', 'admin'),
|
||||
"{$CFG->wwwroot}/{$CFG->admin}/environment.php"));
|
||||
|
||||
// PHP info.
|
||||
$ADMIN->add('server', new admin_externalpage('phpinfo', new lang_string('phpinfo'),
|
||||
"{$CFG->wwwroot}/{$CFG->admin}/phpinfo.php"));
|
||||
|
||||
// "performance" settingpage
|
||||
$temp = new admin_settingpage('performance', new lang_string('performance', 'admin'));
|
||||
// Test outgoing mail configuration (hidden, accessed via direct link from the settings page).
|
||||
$ADMIN->add('server', new admin_externalpage('testoutgoingmailconf', new lang_string('testoutgoingmailconf', 'admin'),
|
||||
new moodle_url('/admin/testoutgoingmailconf.php'), 'moodle/site:config', true));
|
||||
|
||||
// Memory limit options for large administration tasks.
|
||||
$memoryoptions = array(
|
||||
'64M' => '64M',
|
||||
'128M' => '128M',
|
||||
'256M' => '256M',
|
||||
'512M' => '512M',
|
||||
'1024M' => '1024M',
|
||||
'2048M' => '2048M');
|
||||
// Performance.
|
||||
$temp = new admin_settingpage('performance', new lang_string('performance', 'admin'));
|
||||
|
||||
// Allow larger memory usage for 64-bit sites only.
|
||||
if (PHP_INT_SIZE === 8) {
|
||||
$memoryoptions['3072M'] = '3072M';
|
||||
$memoryoptions['4096M'] = '4096M';
|
||||
}
|
||||
// Memory limit options for large administration tasks.
|
||||
$memoryoptions = [
|
||||
'64M' => '64M',
|
||||
'128M' => '128M',
|
||||
'256M' => '256M',
|
||||
'512M' => '512M',
|
||||
'1024M' => '1024M',
|
||||
'2048M' => '2048M',
|
||||
];
|
||||
|
||||
$temp->add(new admin_setting_configselect('extramemorylimit', new lang_string('extramemorylimit', 'admin'),
|
||||
new lang_string('configextramemorylimit', 'admin'), '512M',
|
||||
$memoryoptions));
|
||||
$temp->add(new admin_setting_configtext('maxtimelimit', new lang_string('maxtimelimit', 'admin'),
|
||||
// Allow larger memory usage for 64-bit sites only.
|
||||
if (PHP_INT_SIZE === 8) {
|
||||
$memoryoptions['3072M'] = '3072M';
|
||||
$memoryoptions['4096M'] = '4096M';
|
||||
}
|
||||
|
||||
$temp->add(new admin_setting_configselect('extramemorylimit', new lang_string('extramemorylimit', 'admin'),
|
||||
new lang_string('configextramemorylimit', 'admin'), '512M', $memoryoptions));
|
||||
|
||||
$temp->add(new admin_setting_configtext('maxtimelimit', new lang_string('maxtimelimit', 'admin'),
|
||||
new lang_string('maxtimelimit_desc', 'admin'), 0, PARAM_INT));
|
||||
|
||||
$temp->add(new admin_setting_configtext('curlcache', new lang_string('curlcache', 'admin'),
|
||||
new lang_string('configcurlcache', 'admin'), 120, PARAM_INT));
|
||||
$temp->add(new admin_setting_configtext('curlcache', new lang_string('curlcache', 'admin'),
|
||||
new lang_string('configcurlcache', 'admin'), 120, PARAM_INT));
|
||||
|
||||
$temp->add(new admin_setting_configtext('curltimeoutkbitrate', new lang_string('curltimeoutkbitrate', 'admin'),
|
||||
new lang_string('curltimeoutkbitrate_help', 'admin'), 56, PARAM_INT));
|
||||
$temp->add(new admin_setting_configtext('curltimeoutkbitrate', new lang_string('curltimeoutkbitrate', 'admin'),
|
||||
new lang_string('curltimeoutkbitrate_help', 'admin'), 56, PARAM_INT));
|
||||
|
||||
$ADMIN->add('server', $temp);
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
// Tasks.
|
||||
$ADMIN->add('server', new admin_category('taskconfig', new lang_string('taskadmintitle', 'admin')));
|
||||
|
||||
$ADMIN->add('server', new admin_category('taskconfig', new lang_string('taskadmintitle', 'admin')));
|
||||
$temp = new admin_settingpage('taskprocessing', new lang_string('taskprocessing','admin'));
|
||||
$temp->add(
|
||||
new admin_setting_configtext(
|
||||
'task_scheduled_concurrency_limit',
|
||||
new lang_string('task_scheduled_concurrency_limit', 'admin'),
|
||||
new lang_string('task_scheduled_concurrency_limit_desc', 'admin'),
|
||||
3,
|
||||
PARAM_INT
|
||||
)
|
||||
);
|
||||
// Task processing.
|
||||
$temp = new admin_settingpage('taskprocessing', new lang_string('taskprocessing', 'admin'));
|
||||
|
||||
$temp->add(
|
||||
new admin_setting_configduration(
|
||||
'task_scheduled_max_runtime',
|
||||
new lang_string('task_scheduled_max_runtime', 'admin'),
|
||||
new lang_string('task_scheduled_max_runtime_desc', 'admin'),
|
||||
30 * MINSECS
|
||||
)
|
||||
);
|
||||
|
||||
$temp->add(
|
||||
new admin_setting_configtext(
|
||||
'task_adhoc_concurrency_limit',
|
||||
new lang_string('task_adhoc_concurrency_limit', 'admin'),
|
||||
new lang_string('task_adhoc_concurrency_limit_desc', 'admin'),
|
||||
3,
|
||||
PARAM_INT
|
||||
)
|
||||
);
|
||||
|
||||
$temp->add(
|
||||
new admin_setting_configduration(
|
||||
'task_adhoc_max_runtime',
|
||||
new lang_string('task_adhoc_max_runtime', 'admin'),
|
||||
new lang_string('task_adhoc_max_runtime_desc', 'admin'),
|
||||
30 * MINSECS
|
||||
)
|
||||
);
|
||||
$ADMIN->add('taskconfig', $temp);
|
||||
|
||||
$temp = new admin_settingpage('tasklogging', new lang_string('tasklogging','admin'));
|
||||
$temp->add(
|
||||
new admin_setting_configselect(
|
||||
'task_logmode',
|
||||
new lang_string('task_logmode', 'admin'),
|
||||
new lang_string('task_logmode_desc', 'admin'),
|
||||
\core\task\logmanager::MODE_ALL,
|
||||
[
|
||||
\core\task\logmanager::MODE_ALL => new lang_string('task_logmode_all', 'admin'),
|
||||
\core\task\logmanager::MODE_FAILONLY => new lang_string('task_logmode_failonly', 'admin'),
|
||||
\core\task\logmanager::MODE_NONE => new lang_string('task_logmode_none', 'admin'),
|
||||
]
|
||||
)
|
||||
);
|
||||
$temp->add(
|
||||
new admin_setting_configcheckbox(
|
||||
'task_logtostdout',
|
||||
new lang_string('task_logtostdout', 'admin'),
|
||||
new lang_string('task_logtostdout_desc', 'admin'),
|
||||
$setting = new admin_setting_configcheckbox(
|
||||
'cron_enabled',
|
||||
new lang_string('cron_enabled', 'admin'),
|
||||
new lang_string('cron_enabled_desc', 'admin'),
|
||||
1
|
||||
)
|
||||
);
|
||||
);
|
||||
$setting->set_updatedcallback('theme_reset_static_caches');
|
||||
$temp->add($setting);
|
||||
|
||||
$temp->add(
|
||||
new admin_setting_configtext(
|
||||
'task_scheduled_concurrency_limit',
|
||||
new lang_string('task_scheduled_concurrency_limit', 'admin'),
|
||||
new lang_string('task_scheduled_concurrency_limit_desc', 'admin'),
|
||||
3,
|
||||
PARAM_INT
|
||||
)
|
||||
);
|
||||
|
||||
if (\core\task\logmanager::uses_standard_settings()) {
|
||||
$temp->add(
|
||||
new admin_setting_configduration(
|
||||
'task_logretention',
|
||||
new \lang_string('task_logretention', 'admin'),
|
||||
new \lang_string('task_logretention_desc', 'admin'),
|
||||
28 * DAYSECS
|
||||
'task_scheduled_max_runtime',
|
||||
new lang_string('task_scheduled_max_runtime', 'admin'),
|
||||
new lang_string('task_scheduled_max_runtime_desc', 'admin'),
|
||||
30 * MINSECS
|
||||
)
|
||||
);
|
||||
|
||||
$temp->add(
|
||||
new admin_setting_configtext(
|
||||
'task_logretainruns',
|
||||
new \lang_string('task_logretainruns', 'admin'),
|
||||
new \lang_string('task_logretainruns_desc', 'admin'),
|
||||
20,
|
||||
'task_adhoc_concurrency_limit',
|
||||
new lang_string('task_adhoc_concurrency_limit', 'admin'),
|
||||
new lang_string('task_adhoc_concurrency_limit_desc', 'admin'),
|
||||
3,
|
||||
PARAM_INT
|
||||
)
|
||||
);
|
||||
}
|
||||
$ADMIN->add('taskconfig', $temp);
|
||||
|
||||
if (\core\task\logmanager::uses_standard_settings()) {
|
||||
$ADMIN->add('taskconfig', new admin_externalpage(
|
||||
'tasklogs',
|
||||
new lang_string('tasklogs','admin'),
|
||||
"{$CFG->wwwroot}/{$CFG->admin}/tasklogs.php"
|
||||
));
|
||||
}
|
||||
$temp->add(
|
||||
new admin_setting_configduration(
|
||||
'task_adhoc_max_runtime',
|
||||
new lang_string('task_adhoc_max_runtime', 'admin'),
|
||||
new lang_string('task_adhoc_max_runtime_desc', 'admin'),
|
||||
30 * MINSECS
|
||||
)
|
||||
);
|
||||
$ADMIN->add('taskconfig', $temp);
|
||||
|
||||
// E-mail settings.
|
||||
$ADMIN->add('server', new admin_category('email', new lang_string('categoryemail', 'admin')));
|
||||
// Task log configuration.
|
||||
$temp = new admin_settingpage('tasklogging', new lang_string('tasklogging', 'admin'));
|
||||
$temp->add(
|
||||
new admin_setting_configselect(
|
||||
'task_logmode',
|
||||
new lang_string('task_logmode', 'admin'),
|
||||
new lang_string('task_logmode_desc', 'admin'),
|
||||
\core\task\logmanager::MODE_ALL,
|
||||
[
|
||||
\core\task\logmanager::MODE_ALL => new lang_string('task_logmode_all', 'admin'),
|
||||
\core\task\logmanager::MODE_FAILONLY => new lang_string('task_logmode_failonly', 'admin'),
|
||||
\core\task\logmanager::MODE_NONE => new lang_string('task_logmode_none', 'admin'),
|
||||
]
|
||||
)
|
||||
);
|
||||
$temp->add(
|
||||
new admin_setting_configcheckbox(
|
||||
'task_logtostdout',
|
||||
new lang_string('task_logtostdout', 'admin'),
|
||||
new lang_string('task_logtostdout_desc', 'admin'),
|
||||
1
|
||||
)
|
||||
);
|
||||
|
||||
$temp = new admin_settingpage('outgoingmailconfig', new lang_string('outgoingmailconfig', 'admin'));
|
||||
if (\core\task\logmanager::uses_standard_settings()) {
|
||||
$temp->add(
|
||||
new admin_setting_configduration(
|
||||
'task_logretention',
|
||||
new \lang_string('task_logretention', 'admin'),
|
||||
new \lang_string('task_logretention_desc', 'admin'),
|
||||
28 * DAYSECS
|
||||
)
|
||||
);
|
||||
|
||||
$temp->add(new admin_setting_heading('smtpheading', new lang_string('smtp', 'admin'),
|
||||
new lang_string('smtpdetail', 'admin')));
|
||||
$temp->add(new admin_setting_configtext('smtphosts', new lang_string('smtphosts', 'admin'),
|
||||
new lang_string('configsmtphosts', 'admin'), '', PARAM_RAW));
|
||||
$options = array('' => new lang_string('none', 'admin'), 'ssl' => 'SSL', 'tls' => 'TLS');
|
||||
$temp->add(new admin_setting_configselect('smtpsecure', new lang_string('smtpsecure', 'admin'),
|
||||
new lang_string('configsmtpsecure', 'admin'), '', $options));
|
||||
$authtypeoptions = array('LOGIN' => 'LOGIN', 'PLAIN' => 'PLAIN', 'NTLM' => 'NTLM', 'CRAM-MD5' => 'CRAM-MD5');
|
||||
$temp->add(new admin_setting_configselect('smtpauthtype', new lang_string('smtpauthtype', 'admin'),
|
||||
new lang_string('configsmtpauthtype', 'admin'), 'LOGIN', $authtypeoptions));
|
||||
$temp->add(new admin_setting_configtext('smtpuser', new lang_string('smtpuser', 'admin'),
|
||||
new lang_string('configsmtpuser', 'admin'), '', PARAM_NOTAGS));
|
||||
$temp->add(new admin_setting_configpasswordunmask('smtppass', new lang_string('smtppass', 'admin'),
|
||||
new lang_string('configsmtpuser', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configtext('smtpmaxbulk', new lang_string('smtpmaxbulk', 'admin'),
|
||||
new lang_string('configsmtpmaxbulk', 'admin'), 1, PARAM_INT));
|
||||
$temp->add(new admin_setting_heading('noreplydomainheading', new lang_string('noreplydomain', 'admin'),
|
||||
$temp->add(
|
||||
new admin_setting_configtext(
|
||||
'task_logretainruns',
|
||||
new \lang_string('task_logretainruns', 'admin'),
|
||||
new \lang_string('task_logretainruns_desc', 'admin'),
|
||||
20,
|
||||
PARAM_INT
|
||||
)
|
||||
);
|
||||
}
|
||||
$ADMIN->add('taskconfig', $temp);
|
||||
|
||||
// Task logs.
|
||||
if (\core\task\logmanager::uses_standard_settings()) {
|
||||
$ADMIN->add('taskconfig', new admin_externalpage(
|
||||
'tasklogs',
|
||||
new lang_string('tasklogs', 'admin'),
|
||||
"{$CFG->wwwroot}/{$CFG->admin}/tasklogs.php"
|
||||
));
|
||||
}
|
||||
|
||||
// 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'));
|
||||
|
||||
$temp->add(new admin_setting_heading('smtpheading', new lang_string('smtp', 'admin'),
|
||||
new lang_string('smtpdetail', 'admin')));
|
||||
|
||||
$temp->add(new admin_setting_configtext('smtphosts', new lang_string('smtphosts', 'admin'),
|
||||
new lang_string('configsmtphosts', 'admin'), '', PARAM_RAW));
|
||||
|
||||
$options = [
|
||||
'' => new lang_string('none', 'admin'),
|
||||
'ssl' => 'SSL',
|
||||
'tls' => 'TLS',
|
||||
];
|
||||
|
||||
$temp->add(new admin_setting_configselect('smtpsecure', new lang_string('smtpsecure', 'admin'),
|
||||
new lang_string('configsmtpsecure', 'admin'), '', $options));
|
||||
|
||||
$authtypeoptions = [
|
||||
'LOGIN' => 'LOGIN',
|
||||
'PLAIN' => 'PLAIN',
|
||||
'NTLM' => 'NTLM',
|
||||
'CRAM-MD5' => 'CRAM-MD5',
|
||||
];
|
||||
|
||||
$temp->add(new admin_setting_configselect('smtpauthtype', new lang_string('smtpauthtype', 'admin'),
|
||||
new lang_string('configsmtpauthtype', 'admin'), 'LOGIN', $authtypeoptions));
|
||||
|
||||
$temp->add(new admin_setting_configtext('smtpuser', new lang_string('smtpuser', 'admin'),
|
||||
new lang_string('configsmtpuser', 'admin'), '', PARAM_NOTAGS));
|
||||
|
||||
$temp->add(new admin_setting_configpasswordunmask('smtppass', new lang_string('smtppass', 'admin'),
|
||||
new lang_string('configsmtpuser', 'admin'), ''));
|
||||
|
||||
$temp->add(new admin_setting_configtext('smtpmaxbulk', new lang_string('smtpmaxbulk', 'admin'),
|
||||
new lang_string('configsmtpmaxbulk', 'admin'), 1, PARAM_INT));
|
||||
|
||||
$temp->add(new admin_setting_heading('noreplydomainheading', new lang_string('noreplydomain', 'admin'),
|
||||
new lang_string('noreplydomaindetail', 'admin')));
|
||||
$temp->add(new admin_setting_configtext('noreplyaddress', new lang_string('noreplyaddress', 'admin'),
|
||||
new lang_string('confignoreplyaddress', 'admin'), 'noreply@' . get_host_from_url($CFG->wwwroot), PARAM_EMAIL));
|
||||
$temp->add(new admin_setting_configtextarea('allowedemaildomains',
|
||||
|
||||
$temp->add(new admin_setting_configtext('noreplyaddress', new lang_string('noreplyaddress', 'admin'),
|
||||
new lang_string('confignoreplyaddress', 'admin'), 'noreply@' . get_host_from_url($CFG->wwwroot), PARAM_EMAIL));
|
||||
|
||||
$temp->add(new admin_setting_configtextarea('allowedemaildomains',
|
||||
new lang_string('allowedemaildomains', 'admin'),
|
||||
new lang_string('configallowedemaildomains', 'admin'),
|
||||
''));
|
||||
$url = new moodle_url('/admin/testoutgoingmailconf.php');
|
||||
$link = html_writer::link($url, get_string('testoutgoingmailconf', 'admin'));
|
||||
$temp->add(new admin_setting_heading('testoutgoinmailc', new lang_string('testoutgoingmailconf', 'admin'),
|
||||
new lang_string('testoutgoingmaildetail', 'admin', $link)));
|
||||
$temp->add(new admin_setting_heading('emaildoesnotfit', new lang_string('doesnotfit', 'admin'),
|
||||
new lang_string('doesnotfitdetail', 'admin')));
|
||||
$charsets = get_list_of_charsets();
|
||||
unset($charsets['UTF-8']); // Not needed here.
|
||||
$options = array();
|
||||
$options['0'] = 'UTF-8';
|
||||
$options = array_merge($options, $charsets);
|
||||
$temp->add(new admin_setting_configselect('sitemailcharset', new lang_string('sitemailcharset', 'admin'),
|
||||
new lang_string('configsitemailcharset','admin'), '0', $options));
|
||||
$temp->add(new admin_setting_configcheckbox('allowusermailcharset', new lang_string('allowusermailcharset', 'admin'),
|
||||
new lang_string('configallowusermailcharset', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('allowattachments', new lang_string('allowattachments', 'admin'),
|
||||
new lang_string('configallowattachments', 'admin'), 1));
|
||||
$options = array('LF' => 'LF', 'CRLF' => 'CRLF');
|
||||
$temp->add(new admin_setting_configselect('mailnewline', new lang_string('mailnewline', 'admin'),
|
||||
new lang_string('configmailnewline', 'admin'), 'LF', $options));
|
||||
|
||||
$choices = array(new lang_string('never', 'admin'),
|
||||
new lang_string('always', 'admin'),
|
||||
new lang_string('onlynoreply', 'admin'));
|
||||
$temp->add(new admin_setting_configselect('emailfromvia', new lang_string('emailfromvia', 'admin'),
|
||||
new lang_string('configemailfromvia', 'admin'), 1, $choices));
|
||||
$temp->add(new admin_setting_heading('divertallemailsheading', new lang_string('divertallemails', 'admin'),
|
||||
new lang_string('divertallemailsdetail', 'admin')));
|
||||
$temp->add(new admin_setting_configtext('divertallemailsto',
|
||||
new lang_string('divertallemailsto', 'admin'),
|
||||
new lang_string('divertallemailsto_desc', 'admin'),
|
||||
''));
|
||||
$temp->add(new admin_setting_configtextarea('divertallemailsexcept',
|
||||
new lang_string('divertallemailsexcept', 'admin'),
|
||||
new lang_string('divertallemailsexcept_desc', 'admin'),
|
||||
'', PARAM_RAW, '50', '4'));
|
||||
|
||||
$noreplyaddress = isset($CFG->noreplyaddress) ? $CFG->noreplyaddress : 'noreply@example.com';
|
||||
$dkimdomain = substr(strrchr($noreplyaddress, "@"), 1);
|
||||
$dkimselector = empty($CFG->emaildkimselector) ? '[selector]' : $CFG->emaildkimselector;
|
||||
$pempath = "\$CFG->dataroot/dkim/{$dkimdomain}/{$dkimselector}.private";
|
||||
$temp->add(new admin_setting_heading('emaildkim', new lang_string('emaildkim', 'admin'),
|
||||
new lang_string('emaildkiminfo', 'admin', ['path' => $pempath, 'docs' => \get_docs_url('Mail_configuration#DKIM')])));
|
||||
$temp->add(new admin_setting_configtext('emaildkimselector', new lang_string('emaildkimselector', 'admin'),
|
||||
new lang_string('configemaildkimselector', 'admin'), '', PARAM_FILE));
|
||||
|
||||
$url = new moodle_url('/admin/testoutgoingmailconf.php');
|
||||
$link = html_writer::link($url, get_string('testoutgoingmailconf', 'admin'));
|
||||
$temp->add(new admin_setting_heading('testoutgoinmailc', new lang_string('testoutgoingmailconf', 'admin'),
|
||||
new lang_string('testoutgoingmaildetail', 'admin', $link)));
|
||||
|
||||
$temp->add(new admin_setting_heading('emaildoesnotfit', new lang_string('doesnotfit', 'admin'),
|
||||
new lang_string('doesnotfitdetail', 'admin')));
|
||||
|
||||
$charsets = get_list_of_charsets();
|
||||
unset($charsets['UTF-8']);
|
||||
$options = [
|
||||
'0' => 'UTF-8',
|
||||
];
|
||||
$options = array_merge($options, $charsets);
|
||||
$temp->add(new admin_setting_configselect('sitemailcharset', new lang_string('sitemailcharset', 'admin'),
|
||||
new lang_string('configsitemailcharset', 'admin'), '0', $options));
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('allowusermailcharset', new lang_string('allowusermailcharset', 'admin'),
|
||||
new lang_string('configallowusermailcharset', 'admin'), 0));
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('allowattachments', new lang_string('allowattachments', 'admin'),
|
||||
new lang_string('configallowattachments', 'admin'), 1));
|
||||
|
||||
$options = [
|
||||
'LF' => 'LF',
|
||||
'CRLF' => 'CRLF',
|
||||
];
|
||||
$temp->add(new admin_setting_configselect('mailnewline', new lang_string('mailnewline', 'admin'),
|
||||
new lang_string('configmailnewline', 'admin'), 'LF', $options));
|
||||
|
||||
$choices = [
|
||||
new lang_string('never', 'admin'),
|
||||
new lang_string('always', 'admin'),
|
||||
new lang_string('onlynoreply', 'admin'),
|
||||
];
|
||||
$temp->add(new admin_setting_configselect('emailfromvia', new lang_string('emailfromvia', 'admin'),
|
||||
new lang_string('configemailfromvia', 'admin'), 1, $choices));
|
||||
|
||||
$temp->add(new admin_setting_configtext('emailsubjectprefix', new lang_string('emailsubjectprefix', 'admin'),
|
||||
new lang_string('configemailsubjectprefix', 'admin'), '', PARAM_RAW));
|
||||
|
||||
$ADMIN->add('email', $temp);
|
||||
$temp->add(new admin_setting_configtextarea('emailheaders', new lang_string('emailheaders', 'admin'),
|
||||
new lang_string('configemailheaders', 'admin'), '', PARAM_RAW, '50', '3'));
|
||||
|
||||
// "update notifications" settingpage
|
||||
if (empty($CFG->disableupdatenotifications)) {
|
||||
$temp = new admin_settingpage('updatenotifications', new lang_string('updatenotifications', 'core_admin'));
|
||||
$temp->add(new admin_setting_configcheckbox('updateautocheck', new lang_string('updateautocheck', 'core_admin'),
|
||||
new lang_string('updateautocheck_desc', 'core_admin'), 1));
|
||||
$temp->add(new admin_setting_configselect('updateminmaturity', new lang_string('updateminmaturity', 'core_admin'),
|
||||
new lang_string('updateminmaturity_desc', 'core_admin'), MATURITY_STABLE,
|
||||
array(
|
||||
MATURITY_ALPHA => new lang_string('maturity'.MATURITY_ALPHA, 'core_admin'),
|
||||
MATURITY_BETA => new lang_string('maturity'.MATURITY_BETA, 'core_admin'),
|
||||
MATURITY_RC => new lang_string('maturity'.MATURITY_RC, 'core_admin'),
|
||||
MATURITY_STABLE => new lang_string('maturity'.MATURITY_STABLE, 'core_admin'),
|
||||
)));
|
||||
$temp->add(new admin_setting_configcheckbox('updatenotifybuilds', new lang_string('updatenotifybuilds', 'core_admin'),
|
||||
new lang_string('updatenotifybuilds_desc', 'core_admin'), 0));
|
||||
$ADMIN->add('server', $temp);
|
||||
$ADMIN->add('email', $temp);
|
||||
|
||||
// Update notifications.
|
||||
if (empty($CFG->disableupdatenotifications)) {
|
||||
$temp = new admin_settingpage('updatenotifications', new lang_string('updatenotifications', 'core_admin'));
|
||||
$temp->add(new admin_setting_configcheckbox('updateautocheck', new lang_string('updateautocheck', 'core_admin'),
|
||||
new lang_string('updateautocheck_desc', 'core_admin'), 1));
|
||||
$temp->add(new admin_setting_configselect('updateminmaturity', new lang_string('updateminmaturity', 'core_admin'),
|
||||
new lang_string('updateminmaturity_desc', 'core_admin'), MATURITY_STABLE,
|
||||
[
|
||||
MATURITY_ALPHA => new lang_string('maturity'.MATURITY_ALPHA, 'core_admin'),
|
||||
MATURITY_BETA => new lang_string('maturity'.MATURITY_BETA, 'core_admin'),
|
||||
MATURITY_RC => new lang_string('maturity'.MATURITY_RC, 'core_admin'),
|
||||
MATURITY_STABLE => new lang_string('maturity'.MATURITY_STABLE, 'core_admin'),
|
||||
]
|
||||
));
|
||||
$temp->add(new admin_setting_configcheckbox('updatenotifybuilds', new lang_string('updatenotifybuilds', 'core_admin'),
|
||||
new lang_string('updatenotifybuilds_desc', 'core_admin'), 0));
|
||||
$ADMIN->add('server', $temp);
|
||||
}
|
||||
}
|
||||
|
||||
} // end of speedup
|
||||
|
||||
@@ -39,6 +39,7 @@ $ADMIN->add('root', new admin_category('license', new lang_string('license')));
|
||||
$ADMIN->add('root', new admin_category('location', new lang_string('location','admin')));
|
||||
$ADMIN->add('root', new admin_category('language', new lang_string('language')));
|
||||
$ADMIN->add('root', new admin_category('messaging', new lang_string('messagingcategory', 'admin')));
|
||||
$ADMIN->add('root', new admin_category('payment', new lang_string('payments', 'payment')));
|
||||
$ADMIN->add('root', new admin_category('modules', new lang_string('plugins', 'admin')));
|
||||
$ADMIN->add('root', new admin_category('security', new lang_string('security','admin')));
|
||||
$ADMIN->add('root', new admin_category('appearance', new lang_string('appearance','admin')));
|
||||
|
||||
@@ -32,7 +32,6 @@ $result = optional_param('result', null, PARAM_INT);
|
||||
|
||||
$pageurl = new \moodle_url('/admin/tasklogs.php');
|
||||
$pageurl->param('filter', $filter);
|
||||
$pageurl->param('result', $result);
|
||||
|
||||
$PAGE->set_url($pageurl);
|
||||
$PAGE->set_context(context_system::instance());
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_admin\local\settings\autocomplete
|
||||
|
||||
Admin setting auto complete.
|
||||
|
||||
Context variables required for this template:
|
||||
* name - element name
|
||||
* id - element id
|
||||
* options - choices
|
||||
* multiple - is multiple choices?
|
||||
* manageurl - url to manage choices
|
||||
* managetext - string to display manage url
|
||||
* tags - Should we allow typing new entries to the field?
|
||||
* ajax - Name of an AMD module to send/process ajax requests
|
||||
* placeholder - Placeholder text for an empty list
|
||||
* casesensitive - Whether the search has to be case-sensitive
|
||||
* showsuggestions - Show suggestions by default - but this can be turned off
|
||||
* noselectionstring - String that is shown when there are no selections
|
||||
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"name": "name0",
|
||||
"id": "id0",
|
||||
"options": [{
|
||||
"value": "1",
|
||||
"text": "option 1",
|
||||
"selected": true,
|
||||
"disabled": false
|
||||
}],
|
||||
"multiple": true,
|
||||
"manageurl": "",
|
||||
"managetext": "",
|
||||
"tags": false,
|
||||
"ajax": "",
|
||||
"placeholder": "",
|
||||
"casesensitive": false,
|
||||
"showsuggestions": true,
|
||||
"noselectionstring": ""
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting autocomplete.
|
||||
}}
|
||||
|
||||
<div class="form-select defaultsnext">
|
||||
<input type="hidden" name="{{name}}[xxxxx]" value="_qf__force_multiselect_submission">
|
||||
<select class="custom-select" name="{{name}}[]"
|
||||
id="{{id}}"
|
||||
{{#multiple}}multiple{{/multiple}}>
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{{text}}}</option>
|
||||
{{/options}}
|
||||
</select>
|
||||
{{#manageurl}}
|
||||
<a href="{{manageurl}}">{{managetext}}</a>
|
||||
{{/manageurl}}
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
{{#js}}
|
||||
require(['core/form-autocomplete'], function(module) {
|
||||
module.enhance({{#quote}}#{{id}}{{/quote}},
|
||||
{{tags}},
|
||||
{{#quote}}{{ajax}}{{/quote}},
|
||||
{{#quote}}{{placeholder}}{{/quote}},
|
||||
{{casesensitive}},
|
||||
{{showsuggestions}},
|
||||
{{#quote}}{{noselectionstring}}{{/quote}});
|
||||
});
|
||||
{{/js}}
|
||||
@@ -53,8 +53,11 @@ class behat_admin extends behat_base {
|
||||
}
|
||||
|
||||
foreach ($data as $label => $value) {
|
||||
// Navigate straight to the search results fo rthis label.
|
||||
$this->execute('behat_general::i_visit', ["/admin/search.php?query=" . urlencode($label)]);
|
||||
$this->execute('behat_navigation::i_select_from_flat_navigation_drawer', [get_string('administrationsite')]);
|
||||
|
||||
// Search by label.
|
||||
$this->execute('behat_forms::i_set_the_field_to', [get_string('search'), $label]);
|
||||
$this->execute("behat_forms::press_button", get_string('search', 'admin'));
|
||||
|
||||
// Admin settings does not use the same DOM structure than other moodle forms
|
||||
// but we also need to use lib/behat/form_field/* to deal with the different moodle form elements.
|
||||
|
||||
@@ -14,10 +14,6 @@ Feature: An administrator can filter user accounts by role, cohort and other pro
|
||||
And the following "cohorts" exist:
|
||||
| name | idnumber |
|
||||
| Cohort 1 | CH1 |
|
||||
And the following "cohort members" exist:
|
||||
| user | cohort |
|
||||
| user2 | CH1 |
|
||||
| user3 | CH1 |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
@@ -27,6 +23,8 @@ Feature: An administrator can filter user accounts by role, cohort and other pro
|
||||
| user2 | C1 | student |
|
||||
| user3 | C1 | student |
|
||||
And I log in as "admin"
|
||||
And I add "User Two (two@example.com)" user to "CH1" cohort members
|
||||
And I add "User Three (three@example.com)" user to "CH1" cohort members
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
|
||||
Scenario: Filter user accounts by role and cohort
|
||||
|
||||
+2
-12
@@ -1,12 +1,2 @@
|
||||
/**
|
||||
* Shows a dialogue with info about this logs.
|
||||
*
|
||||
* @module tool_analytics/log_info
|
||||
* @class log_info
|
||||
* @package tool_analytics
|
||||
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define("tool_analytics/log_info",["jquery","core/str","core/modal_factory","core/notification"],(function($,str,ModalFactory,Notification){return{loadInfo:function(id,info){var link=$('[data-model-log-id="'+id+'"]');str.get_string("loginfo","tool_analytics").then((function(langString){var bodyInfo=$("<ul>");return info.forEach((function(item){bodyInfo.append("<li>"+item+"</li>")})),bodyInfo.append("</ul>"),ModalFactory.create({title:langString,body:bodyInfo.html(),large:!0},link)})).catch(Notification.exception)}}}));
|
||||
|
||||
//# sourceMappingURL=log_info.min.js.map
|
||||
define ("tool_analytics/log_info",["jquery","core/str","core/modal_factory","core/notification"],function(a,b,c,d){return{loadInfo:function loadInfo(e,f){var g=a("[data-model-log-id=\""+e+"\"]");b.get_string("loginfo","tool_analytics").then(function(b){var d=a("<ul>");f.forEach(function(a){d.append("<li>"+a+"</li>")});d.append("</ul>");return c.create({title:b,body:d.html(),large:!0},g)}).catch(d.exception)}}});
|
||||
//# sourceMappingURL=log_info.min.js.map
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"log_info.min.js","sources":["../src/log_info.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 * Shows a dialogue with info about this logs.\n *\n * @module tool_analytics/log_info\n * @class log_info\n * @package tool_analytics\n * @copyright 2017 David Monllao {@link http://www.davidmonllao.com}\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/str', 'core/modal_factory', 'core/notification'], function($, str, ModalFactory, Notification) {\n\n return /** @alias module:tool_analytics/log_info */ {\n\n /**\n * Prepares a modal info for a log's results.\n *\n * @method loadInfo\n * @param {int} id\n * @param {string[]} info\n */\n loadInfo: function(id, info) {\n\n var link = $('[data-model-log-id=\"' + id + '\"]');\n str.get_string('loginfo', 'tool_analytics').then(function(langString) {\n\n var bodyInfo = $(\"<ul>\");\n info.forEach(function(item) {\n bodyInfo.append('<li>' + item + '</li>');\n });\n bodyInfo.append(\"</ul>\");\n\n return ModalFactory.create({\n title: langString,\n body: bodyInfo.html(),\n large: true,\n }, link);\n\n }).catch(Notification.exception);\n }\n };\n});\n"],"names":["define","$","str","ModalFactory","Notification","loadInfo","id","info","link","get_string","then","langString","bodyInfo","forEach","item","append","create","title","body","html","large","catch","exception"],"mappings":";;;;;;;;;AAwBAA,iCAAO,CAAC,SAAU,WAAY,qBAAsB,sBAAsB,SAASC,EAAGC,IAAKC,aAAcC,oBAEjD,CAShDC,SAAU,SAASC,GAAIC,UAEfC,KAAOP,EAAE,uBAAyBK,GAAK,MAC3CJ,IAAIO,WAAW,UAAW,kBAAkBC,MAAK,SAASC,gBAElDC,SAAWX,EAAE,eACjBM,KAAKM,SAAQ,SAASC,MAClBF,SAASG,OAAO,OAASD,KAAO,YAEpCF,SAASG,OAAO,SAETZ,aAAaa,OAAO,CACvBC,MAAON,WACPO,KAAMN,SAASO,OACfC,OAAO,GACRZ,SAEJa,MAAMjB,aAAakB"}
|
||||
{"version":3,"sources":["../src/log_info.js"],"names":["define","$","str","ModalFactory","Notification","loadInfo","id","info","link","get_string","then","langString","bodyInfo","forEach","item","append","create","title","body","html","large","catch","exception"],"mappings":"AAwBAA,OAAM,2BAAC,CAAC,QAAD,CAAW,UAAX,CAAuB,oBAAvB,CAA6C,mBAA7C,CAAD,CAAoE,SAASC,CAAT,CAAYC,CAAZ,CAAiBC,CAAjB,CAA+BC,CAA/B,CAA6C,CAEnH,MAAoD,CAShDC,QAAQ,CAAE,kBAASC,CAAT,CAAaC,CAAb,CAAmB,CAEzB,GAAIC,CAAAA,CAAI,CAAGP,CAAC,CAAC,wBAAyBK,CAAzB,CAA8B,KAA/B,CAAZ,CACAJ,CAAG,CAACO,UAAJ,CAAe,SAAf,CAA0B,gBAA1B,EAA4CC,IAA5C,CAAiD,SAASC,CAAT,CAAqB,CAElE,GAAIC,CAAAA,CAAQ,CAAGX,CAAC,CAAC,MAAD,CAAhB,CACAM,CAAI,CAACM,OAAL,CAAa,SAASC,CAAT,CAAe,CACxBF,CAAQ,CAACG,MAAT,CAAgB,OAASD,CAAT,CAAgB,OAAhC,CACH,CAFD,EAGAF,CAAQ,CAACG,MAAT,CAAgB,OAAhB,EAEA,MAAOZ,CAAAA,CAAY,CAACa,MAAb,CAAoB,CACvBC,KAAK,CAAEN,CADgB,CAEvBO,IAAI,CAAEN,CAAQ,CAACO,IAAT,EAFiB,CAGvBC,KAAK,GAHkB,CAApB,CAIJZ,CAJI,CAMV,CAdD,EAcGa,KAdH,CAcSjB,CAAY,CAACkB,SAdtB,CAeH,CA3B+C,CA6BvD,CA/BK,CAAN","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 * Shows a dialogue with info about this logs.\n *\n * @module tool_analytics/log_info\n * @class log_info\n * @package tool_analytics\n * @copyright 2017 David Monllao {@link http://www.davidmonllao.com}\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/str', 'core/modal_factory', 'core/notification'], function($, str, ModalFactory, Notification) {\n\n return /** @alias module:tool_analytics/log_info */ {\n\n /**\n * Prepares a modal info for a log's results.\n *\n * @method loadInfo\n * @param {int} id\n * @param {string[]} info\n */\n loadInfo: function(id, info) {\n\n var link = $('[data-model-log-id=\"' + id + '\"]');\n str.get_string('loginfo', 'tool_analytics').then(function(langString) {\n\n var bodyInfo = $(\"<ul>\");\n info.forEach(function(item) {\n bodyInfo.append('<li>' + item + '</li>');\n });\n bodyInfo.append(\"</ul>\");\n\n return ModalFactory.create({\n title: langString,\n body: bodyInfo.html(),\n large: true,\n }, link);\n\n }).catch(Notification.exception);\n }\n };\n});\n"],"file":"log_info.min.js"}
|
||||
+2
-10
@@ -1,10 +1,2 @@
|
||||
/**
|
||||
* AMD module for model actions confirmation.
|
||||
*
|
||||
* @module tool_analytics/model
|
||||
* @copyright 2017 David Monllao
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define("tool_analytics/model",["jquery","core/str","core/log","core/notification","core/modal_factory","core/modal_events","core/templates"],(function($,Str,log,Notification,ModalFactory,ModalEvents,Templates){var actionsList={clear:{title:{key:"clearpredictions",component:"tool_analytics"},body:{key:"clearmodelpredictions",component:"tool_analytics"}},delete:{title:{key:"delete",component:"tool_analytics"},body:{key:"deletemodelconfirmation",component:"tool_analytics"}}};return{confirmAction:function(actionId,actionType){$('[data-action-id="'+actionId+'"]').on("click",(function(ev){ev.preventDefault();var a=$(ev.currentTarget);if(void 0!==actionsList[actionType]){var wrap,reqStrings=[actionsList[actionType].title,actionsList[actionType].body];reqStrings[1].param=(wrap=$(a).closest("[data-model-name]")).length?wrap.attr("data-model-name"):(log.error("Unexpected DOM error - unable to obtain the model name"),"");var stringsPromise=Str.get_strings(reqStrings),modalPromise=ModalFactory.create({type:ModalFactory.types.SAVE_CANCEL});$.when(stringsPromise,modalPromise).then((function(strings,modal){return modal.setTitle(strings[0]),modal.setBody(strings[1]),modal.setSaveButtonText(strings[0]),modal.getRoot().on(ModalEvents.save,(function(){window.location.href=a.attr("href")})),modal.show(),modal})).fail(Notification.exception)}else log.error('Action "'+actionType+'" is not allowed.')}))},selectEvaluationOptions:function(actionId,trainedOnlyExternally){$('[data-action-id="'+actionId+'"]').on("click",(function(ev){ev.preventDefault();var a=$(ev.currentTarget),timeSplittingMethods=$(this).attr("data-timesplitting-methods"),stringsPromise=Str.get_strings([{key:"evaluatemodel",component:"tool_analytics"},{key:"evaluate",component:"tool_analytics"}]),modalPromise=ModalFactory.create({type:ModalFactory.types.SAVE_CANCEL}),bodyPromise=Templates.render("tool_analytics/evaluation_options",{trainedexternally:trainedOnlyExternally,timesplittingmethods:JSON.parse(timeSplittingMethods)});$.when(stringsPromise,modalPromise).then((function(strings,modal){return modal.getRoot().on(ModalEvents.hidden,modal.destroy.bind(modal)),modal.setTitle(strings[0]),modal.setSaveButtonText(strings[1]),modal.setBody(bodyPromise),modal.getRoot().on(ModalEvents.save,(function(){"trainedmodel"==$("input[name='evaluationmode']:checked").val()&&a.attr("href",a.attr("href")+"&mode=trainedmodel");var timeSplittingMethod=$("#id-evaluation-timesplitting").val();a.attr("href",a.attr("href")+"×plitting="+timeSplittingMethod),window.location.href=a.attr("href")})),modal.show(),modal})).fail(Notification.exception)}))},selectExportOptions:function(actionId,isTrained){$('[data-action-id="'+actionId+'"]').on("click",(function(ev){ev.preventDefault();var a=$(ev.currentTarget);if(!isTrained)return a.attr("href",a.attr("href")+"&action=exportmodel&includeweights=0"),void(window.location.href=a.attr("href"));var stringsPromise=Str.get_strings([{key:"export",component:"tool_analytics"}]),modalPromise=ModalFactory.create({type:ModalFactory.types.SAVE_CANCEL}),bodyPromise=Templates.render("tool_analytics/export_options",{});$.when(stringsPromise,modalPromise).then((function(strings,modal){return modal.getRoot().on(ModalEvents.hidden,modal.destroy.bind(modal)),modal.setTitle(strings[0]),modal.setSaveButtonText(strings[0]),modal.setBody(bodyPromise),modal.getRoot().on(ModalEvents.save,(function(){"exportdata"==$("input[name='exportoption']:checked").val()?a.attr("href",a.attr("href")+"&action=exportdata"):(a.attr("href",a.attr("href")+"&action=exportmodel"),$("#id-includeweights").is(":checked")?a.attr("href",a.attr("href")+"&includeweights=1"):a.attr("href",a.attr("href")+"&includeweights=0")),window.location.href=a.attr("href")})),modal.show(),modal})).fail(Notification.exception)}))}}}));
|
||||
|
||||
//# sourceMappingURL=model.min.js.map
|
||||
define ("tool_analytics/model",["jquery","core/str","core/log","core/notification","core/modal_factory","core/modal_events","core/templates"],function(b,c,d,e,f,g,h){var i={clear:{title:{key:"clearpredictions",component:"tool_analytics"},body:{key:"clearmodelpredictions",component:"tool_analytics"}},delete:{title:{key:"delete",component:"tool_analytics"},body:{key:"deletemodelconfirmation",component:"tool_analytics"}}},j=function(a){var c=b(a).closest("[data-model-name]");if(c.length){return c.attr("data-model-name")}else{d.error("Unexpected DOM error - unable to obtain the model name");return""}};return{confirmAction:function confirmAction(a,h){b("[data-action-id=\""+a+"\"]").on("click",function(k){k.preventDefault();var l=b(k.currentTarget);if("undefined"==typeof i[h]){d.error("Action \""+h+"\" is not allowed.");return}var a=[i[h].title,i[h].body];a[1].param=j(l);var m=c.get_strings(a),n=f.create({type:f.types.SAVE_CANCEL});b.when(m,n).then(function(a,b){b.setTitle(a[0]);b.setBody(a[1]);b.setSaveButtonText(a[0]);b.getRoot().on(g.save,function(){window.location.href=l.attr("href")});b.show();return b}).fail(e.exception)})},selectEvaluationOptions:function selectEvaluationOptions(a,d){b("[data-action-id=\""+a+"\"]").on("click",function(i){i.preventDefault();var j=b(i.currentTarget),a=b(this).attr("data-timesplitting-methods"),k=c.get_strings([{key:"evaluatemodel",component:"tool_analytics"},{key:"evaluate",component:"tool_analytics"}]),l=f.create({type:f.types.SAVE_CANCEL}),m=h.render("tool_analytics/evaluation_options",{trainedexternally:d,timesplittingmethods:JSON.parse(a)});b.when(k,l).then(function(a,c){c.getRoot().on(g.hidden,c.destroy.bind(c));c.setTitle(a[0]);c.setSaveButtonText(a[1]);c.setBody(m);c.getRoot().on(g.save,function(){var a=b("input[name='evaluationmode']:checked").val();if("trainedmodel"==a){j.attr("href",j.attr("href")+"&mode=trainedmodel")}var c=b("#id-evaluation-timesplitting").val();j.attr("href",j.attr("href")+"×plitting="+c);window.location.href=j.attr("href")});c.show();return c}).fail(e.exception)})},selectExportOptions:function selectExportOptions(a,d){b("[data-action-id=\""+a+"\"]").on("click",function(i){i.preventDefault();var j=b(i.currentTarget);if(!d){j.attr("href",j.attr("href")+"&action=exportmodel&includeweights=0");window.location.href=j.attr("href");return}var a=c.get_strings([{key:"export",component:"tool_analytics"}]),k=f.create({type:f.types.SAVE_CANCEL}),l=h.render("tool_analytics/export_options",{});b.when(a,k).then(function(a,c){c.getRoot().on(g.hidden,c.destroy.bind(c));c.setTitle(a[0]);c.setSaveButtonText(a[0]);c.setBody(l);c.getRoot().on(g.save,function(){var a=b("input[name='exportoption']:checked").val();if("exportdata"==a){j.attr("href",j.attr("href")+"&action=exportdata")}else{j.attr("href",j.attr("href")+"&action=exportmodel");if(b("#id-includeweights").is(":checked")){j.attr("href",j.attr("href")+"&includeweights=1")}else{j.attr("href",j.attr("href")+"&includeweights=0")}}window.location.href=j.attr("href")});c.show();return c}).fail(e.exception)})}}});
|
||||
//# sourceMappingURL=model.min.js.map
|
||||
|
||||
File diff suppressed because one or more lines are too long
+2
-12
@@ -1,12 +1,2 @@
|
||||
/**
|
||||
* Potential contexts selector module.
|
||||
*
|
||||
* @module tool_analytics/potential-contexts
|
||||
* @class potential-contexts
|
||||
* @package tool_analytics
|
||||
* @copyright 2019 David Monllao
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define("tool_analytics/potential-contexts",["jquery","core/ajax"],(function($,Ajax){return{processResults:function(selector,results){var contexts=[];return $.isArray(results)?($.each(results,(function(index,context){contexts.push({value:context.id,label:context.name})})),contexts):results},transport:function(selector,query,success,failure){var modelid=$(selector).attr("modelid")||null;Ajax.call([{methodname:"tool_analytics_potential_contexts",args:{query:query,modelid:modelid}}])[0].then(success).fail(failure)}}}));
|
||||
|
||||
//# sourceMappingURL=potential-contexts.min.js.map
|
||||
define ("tool_analytics/potential-contexts",["jquery","core/ajax"],function(a,b){return{processResults:function processResults(b,c){var d=[];if(a.isArray(c)){a.each(c,function(a,b){d.push({value:b.id,label:b.name})});return d}else{return c}},transport:function transport(c,d,e,f){var g,h=a(c).attr("modelid")||null;g=b.call([{methodname:"tool_analytics_potential_contexts",args:{query:d,modelid:h}}]);g[0].then(e).fail(f)}}});
|
||||
//# sourceMappingURL=potential-contexts.min.js.map
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"potential-contexts.min.js","sources":["../src/potential-contexts.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 * Potential contexts selector module.\n *\n * @module tool_analytics/potential-contexts\n * @class potential-contexts\n * @package tool_analytics\n * @copyright 2019 David Monllao\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'core/ajax'], function($, Ajax) {\n\n return /** @alias module:tool_analytics/potential-contexts */ {\n\n processResults: function(selector, results) {\n var contexts = [];\n if ($.isArray(results)) {\n $.each(results, function(index, context) {\n contexts.push({\n value: context.id,\n label: context.name\n });\n });\n return contexts;\n\n } else {\n return results;\n }\n },\n\n transport: function(selector, query, success, failure) {\n var promise;\n\n let modelid = $(selector).attr('modelid') || null;\n promise = Ajax.call([{\n methodname: 'tool_analytics_potential_contexts',\n args: {\n query: query,\n modelid: modelid\n }\n }]);\n\n promise[0].then(success).fail(failure);\n }\n\n };\n\n});\n"],"names":["define","$","Ajax","processResults","selector","results","contexts","isArray","each","index","context","push","value","id","label","name","transport","query","success","failure","modelid","attr","call","methodname","args","then","fail"],"mappings":";;;;;;;;;AAyBAA,2CAAO,CAAC,SAAU,cAAc,SAASC,EAAGC,YAEsB,CAE1DC,eAAgB,SAASC,SAAUC,aAC3BC,SAAW,UACXL,EAAEM,QAAQF,UACVJ,EAAEO,KAAKH,SAAS,SAASI,MAAOC,SAC5BJ,SAASK,KAAK,CACVC,MAAOF,QAAQG,GACfC,MAAOJ,QAAQK,UAGhBT,UAGAD,SAIfW,UAAW,SAASZ,SAAUa,MAAOC,QAASC,aAGtCC,QAAUnB,EAAEG,UAAUiB,KAAK,YAAc,KACnCnB,KAAKoB,KAAK,CAAC,CACjBC,WAAY,oCACZC,KAAM,CACFP,MAAOA,MACPG,QAASA,YAIT,GAAGK,KAAKP,SAASQ,KAAKP"}
|
||||
{"version":3,"sources":["../src/potential-contexts.js"],"names":["define","$","Ajax","processResults","selector","results","contexts","isArray","each","index","context","push","value","id","label","name","transport","query","success","failure","promise","modelid","attr","call","methodname","args","then","fail"],"mappings":"AAyBAA,OAAM,qCAAC,CAAC,QAAD,CAAW,WAAX,CAAD,CAA0B,SAASC,CAAT,CAAYC,CAAZ,CAAkB,CAE9C,MAA8D,CAE1DC,cAAc,CAAE,wBAASC,CAAT,CAAmBC,CAAnB,CAA4B,CACxC,GAAIC,CAAAA,CAAQ,CAAG,EAAf,CACA,GAAIL,CAAC,CAACM,OAAF,CAAUF,CAAV,CAAJ,CAAwB,CACpBJ,CAAC,CAACO,IAAF,CAAOH,CAAP,CAAgB,SAASI,CAAT,CAAgBC,CAAhB,CAAyB,CACrCJ,CAAQ,CAACK,IAAT,CAAc,CACVC,KAAK,CAAEF,CAAO,CAACG,EADL,CAEVC,KAAK,CAAEJ,CAAO,CAACK,IAFL,CAAd,CAIH,CALD,EAMA,MAAOT,CAAAA,CAEV,CATD,IASO,CACH,MAAOD,CAAAA,CACV,CACJ,CAhByD,CAkB1DW,SAAS,CAAE,mBAASZ,CAAT,CAAmBa,CAAnB,CAA0BC,CAA1B,CAAmCC,CAAnC,CAA4C,IAC/CC,CAAAA,CAD+C,CAG/CC,CAAO,CAAGpB,CAAC,CAACG,CAAD,CAAD,CAAYkB,IAAZ,CAAiB,SAAjB,GAA+B,IAHM,CAInDF,CAAO,CAAGlB,CAAI,CAACqB,IAAL,CAAU,CAAC,CACjBC,UAAU,CAAE,mCADK,CAEjBC,IAAI,CAAE,CACFR,KAAK,CAAEA,CADL,CAEFI,OAAO,CAAEA,CAFP,CAFW,CAAD,CAAV,CAAV,CAQAD,CAAO,CAAC,CAAD,CAAP,CAAWM,IAAX,CAAgBR,CAAhB,EAAyBS,IAAzB,CAA8BR,CAA9B,CACH,CA/ByD,CAmCjE,CArCK,CAAN","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 * Potential contexts selector module.\n *\n * @module tool_analytics/potential-contexts\n * @class potential-contexts\n * @package tool_analytics\n * @copyright 2019 David Monllao\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'core/ajax'], function($, Ajax) {\n\n return /** @alias module:tool_analytics/potential-contexts */ {\n\n processResults: function(selector, results) {\n var contexts = [];\n if ($.isArray(results)) {\n $.each(results, function(index, context) {\n contexts.push({\n value: context.id,\n label: context.name\n });\n });\n return contexts;\n\n } else {\n return results;\n }\n },\n\n transport: function(selector, query, success, failure) {\n var promise;\n\n let modelid = $(selector).attr('modelid') || null;\n promise = Ajax.call([{\n methodname: 'tool_analytics_potential_contexts',\n args: {\n query: query,\n modelid: modelid\n }\n }]);\n\n promise[0].then(success).fail(failure);\n }\n\n };\n\n});\n"],"file":"potential-contexts.min.js"}
|
||||
@@ -64,7 +64,7 @@ class models_list implements \renderable, \templatable {
|
||||
$data = new \stdClass();
|
||||
|
||||
$newmodelmenu = new \action_menu();
|
||||
$newmodelmenu->set_menu_trigger(get_string('newmodel', 'tool_analytics'), 'btn btn-default');
|
||||
$newmodelmenu->set_menu_trigger(get_string('newmodel', 'tool_analytics'), 'btn btn-secondary');
|
||||
$newmodelmenu->set_alignment(\action_menu::TL, \action_menu::BL);
|
||||
|
||||
$newmodelmenu->add(new \action_menu_link(
|
||||
|
||||
@@ -57,10 +57,10 @@
|
||||
{{/trainedexternally}}
|
||||
|
||||
{{! Hidden by default if #trainedexternally as the default option is trainedmodel in this case.}}
|
||||
<div id="id-evaluation-timesplitting-container" class="m-t-1 {{#trainedexternally}}hidden{{/trainedexternally}}">
|
||||
<div id="id-evaluation-timesplitting-container" class="mt-3 {{#trainedexternally}}hidden{{/trainedexternally}}">
|
||||
{{#str}} selecttimesplittingforevaluation, tool_analytics {{/str}}
|
||||
<div>
|
||||
<select id="id-evaluation-timesplitting" name="timesplitting" class="custom-select m-t-1">
|
||||
<select id="id-evaluation-timesplitting" name="timesplitting" class="custom-select mt-3">
|
||||
{{#timesplittingmethods}}
|
||||
<option value="{{id}}">{{text}}</option>
|
||||
{{/timesplittingmethods}}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<input class="custom-control-input" type="radio" name="exportoption" id="id-mode-exportmodel" value="exportmodel" checked>
|
||||
<label class="custom-control-label" for="id-mode-exportmodel">{{#str}} exportmodel, tool_analytics {{/str}}</label>
|
||||
</div>
|
||||
<div class="custom-control custom-checkbox m-l-2" id="id-includeweights-container">
|
||||
<div class="custom-control custom-checkbox ml-5" id="id-includeweights-container">
|
||||
<input class="custom-control-input" type="checkbox" id="id-includeweights" value="1" checked>
|
||||
<label class="custom-control-label" for="id-includeweights">{{#str}} exportincludeweights, tool_analytics {{/str}}</label>
|
||||
</div>
|
||||
|
||||
@@ -66,8 +66,6 @@ class tool_analytics_external_testcase extends externallib_advanced_testcase {
|
||||
|
||||
/**
|
||||
* test_potential_contexts description
|
||||
*
|
||||
* @expectedException required_capability_exception
|
||||
*/
|
||||
public function test_potential_contexts_no_manager() {
|
||||
$this->resetAfterTest();
|
||||
@@ -75,6 +73,7 @@ class tool_analytics_external_testcase extends externallib_advanced_testcase {
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$this->setUser($user);
|
||||
|
||||
$this->expectException(required_capability_exception::class);
|
||||
$this->assertCount(2, \tool_analytics\external::potential_contexts());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2020060900; // Requires this Moodle version.
|
||||
$plugin->version = 2020110900; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2020110300; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_analytics'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2020061500;
|
||||
$plugin->requires = 2020060900;
|
||||
$plugin->version = 2020110900;
|
||||
$plugin->requires = 2020110300;
|
||||
$plugin->component = 'tool_availabilityconditions';
|
||||
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
define("tool_behat/steps",["exports","core/ajax","core/templates","core/pending"],(function(_exports,_ajax,_templates,_pending){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_templates=_interopRequireDefault(_templates),_pending=_interopRequireDefault(_pending);
|
||||
/**
|
||||
* Enhancements for the step definitions page.
|
||||
*
|
||||
* @module tool_behat/steps
|
||||
* @copyright 2022 Catalyst IT EU
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
var getRequiredFieldsContent=function(entityData){var _entityData$required;return null!==(_entityData$required=entityData.required)&&void 0!==_entityData$required&&_entityData$required.length?_templates.default.renderForPromise("tool_behat/steprequiredfields",{fields:entityData.required}):Promise.resolve({html:"",js:""})};_exports.init=function(){var fn,_ref;document.addEventListener("change",(fn=regeneratorRuntime.mark((function _callee(e){var entityElement,stepElement,pendingPromise,entityData,_yield$getRequiredFie,html,js,stepRequiredFields;return regeneratorRuntime.wrap((function(_context){for(;;)switch(_context.prev=_context.next){case 0:if(entityElement=e.target.closest(".entities"),stepElement=e.target.closest(".stepcontent"),entityElement&&stepElement){_context.next=4;break}return _context.abrupt("return");case 4:return pendingPromise=new _pending.default("tool_behat/steps:change"),_context.next=7,entityType=e.target.value,_ajax.default.call([{methodname:"tool_behat_get_entity_generator",args:{entitytype:entityType}}])[0];case 7:return entityData=_context.sent,_context.next=10,getRequiredFieldsContent(entityData);case 10:if(_yield$getRequiredFie=_context.sent,html=_yield$getRequiredFie.html,js=_yield$getRequiredFie.js,!(stepRequiredFields=stepElement.querySelector(".steprequiredfields"))){_context.next=19;break}return _context.next=17,_templates.default.replaceNode(stepRequiredFields,html,js);case 17:_context.next=21;break;case 19:return _context.next=21,_templates.default.appendNodeContents(stepElement,html,js);case 21:pendingPromise.resolve();case 22:case"end":return _context.stop()}var entityType}),_callee)})),_ref=function(){var self=this,args=arguments;return new Promise((function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)}))},function(_x){return _ref.apply(this,arguments)}))}}));
|
||||
|
||||
//# sourceMappingURL=steps.min.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"steps.min.js","sources":["../src/steps.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\nimport Ajax from 'core/ajax';\nimport Templates from 'core/templates';\nimport PendingJS from 'core/pending';\n\n/**\n * Enhancements for the step definitions page.\n *\n * @module tool_behat/steps\n * @copyright 2022 Catalyst IT EU\n * @author Mark Johnson <mark.johnson@catalyst-eu.net>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Call the get_entity_generator web service function\n *\n * Takes the name of an entity generator and returns an object containing a list of the required fields.\n *\n * @param {String} entityType\n * @returns {Promise}\n */\nconst getGeneratorEntities = (entityType) => Ajax.call([{\n methodname: 'tool_behat_get_entity_generator',\n args: {entitytype: entityType}\n}])[0];\n\n/**\n * Render HTML for required fields\n *\n * Takes the entity data returned from getGeneratorEntities and renders the HTML to display the required fields.\n *\n * @param {String} entityData\n * @return {Promise}\n */\nconst getRequiredFieldsContent = (entityData) => {\n if (!entityData.required?.length) {\n return Promise.resolve({\n html: '',\n js: ''\n });\n }\n return Templates.renderForPromise('tool_behat/steprequiredfields', {fields: entityData.required});\n};\n\nexport const init = () => {\n // When an entity is selected in the \"the following exist\" step, fetch and display the required fields.\n document.addEventListener('change', async(e) => {\n const entityElement = e.target.closest('.entities');\n const stepElement = e.target.closest('.stepcontent');\n if (!entityElement || !stepElement) {\n return;\n }\n\n const pendingPromise = new PendingJS('tool_behat/steps:change');\n\n const entityData = await getGeneratorEntities(e.target.value);\n const {html, js} = await getRequiredFieldsContent(entityData);\n\n const stepRequiredFields = stepElement.querySelector('.steprequiredfields');\n if (stepRequiredFields) {\n await Templates.replaceNode(stepRequiredFields, html, js);\n } else {\n await Templates.appendNodeContents(stepElement, html, js);\n }\n pendingPromise.resolve();\n });\n};\n"],"names":["getRequiredFieldsContent","entityData","required","_entityData$required","length","Templates","renderForPromise","fields","Promise","resolve","html","js","document","addEventListener","e","entityElement","target","closest","stepElement","pendingPromise","PendingJS","entityType","value","Ajax","call","methodname","args","entitytype","stepRequiredFields","querySelector","replaceNode","appendNodeContents"],"mappings":";;;;;;;;;IAiDMA,yBAA2B,SAACC,yEACzBA,WAAWC,0CAAXC,qBAAqBC,OAMnBC,mBAAUC,iBAAiB,gCAAiC,CAACC,OAAQN,WAAWC,WAL5EM,QAAQC,QAAQ,CACnBC,KAAM,GACNC,GAAI,oBAMI,uBAEhBC,SAASC,iBAAiB,sCAAU,iBAAMC,oNAChCC,cAAgBD,EAAEE,OAAOC,QAAQ,aACjCC,YAAcJ,EAAEE,OAAOC,QAAQ,gBAChCF,eAAkBG,kFAIjBC,eAAiB,IAAIC,iBAAU,2CAhCfC,WAkCwBP,EAAEE,OAAOM,MAlClBC,cAAKC,KAAK,CAAC,CACpDC,WAAY,kCACZC,KAAM,CAACC,WAAYN,eACnB,iBA+BUpB,0CACmBD,yBAAyBC,2DAA3CS,2BAAAA,KAAMC,yBAAAA,KAEPiB,mBAAqBV,YAAYW,cAAc,wEAE3CxB,mBAAUyB,YAAYF,mBAAoBlB,KAAMC,mEAEhDN,mBAAU0B,mBAAmBb,YAAaR,KAAMC,YAE1DQ,eAAeV,mDA3CM,IAACY"}
|
||||
@@ -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/>.
|
||||
|
||||
import Ajax from 'core/ajax';
|
||||
import Templates from 'core/templates';
|
||||
import PendingJS from 'core/pending';
|
||||
|
||||
/**
|
||||
* Enhancements for the step definitions page.
|
||||
*
|
||||
* @module tool_behat/steps
|
||||
* @copyright 2022 Catalyst IT EU
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Call the get_entity_generator web service function
|
||||
*
|
||||
* Takes the name of an entity generator and returns an object containing a list of the required fields.
|
||||
*
|
||||
* @param {String} entityType
|
||||
* @returns {Promise}
|
||||
*/
|
||||
const getGeneratorEntities = (entityType) => Ajax.call([{
|
||||
methodname: 'tool_behat_get_entity_generator',
|
||||
args: {entitytype: entityType}
|
||||
}])[0];
|
||||
|
||||
/**
|
||||
* Render HTML for required fields
|
||||
*
|
||||
* Takes the entity data returned from getGeneratorEntities and renders the HTML to display the required fields.
|
||||
*
|
||||
* @param {String} entityData
|
||||
* @return {Promise}
|
||||
*/
|
||||
const getRequiredFieldsContent = (entityData) => {
|
||||
if (!entityData.required?.length) {
|
||||
return Promise.resolve({
|
||||
html: '',
|
||||
js: ''
|
||||
});
|
||||
}
|
||||
return Templates.renderForPromise('tool_behat/steprequiredfields', {fields: entityData.required});
|
||||
};
|
||||
|
||||
export const init = () => {
|
||||
// When an entity is selected in the "the following exist" step, fetch and display the required fields.
|
||||
document.addEventListener('change', async(e) => {
|
||||
const entityElement = e.target.closest('.entities');
|
||||
const stepElement = e.target.closest('.stepcontent');
|
||||
if (!entityElement || !stepElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pendingPromise = new PendingJS('tool_behat/steps:change');
|
||||
|
||||
const entityData = await getGeneratorEntities(e.target.value);
|
||||
const {html, js} = await getRequiredFieldsContent(entityData);
|
||||
|
||||
const stepRequiredFields = stepElement.querySelector('.steprequiredfields');
|
||||
if (stepRequiredFields) {
|
||||
await Templates.replaceNode(stepRequiredFields, html, js);
|
||||
} else {
|
||||
await Templates.appendNodeContents(stepElement, html, js);
|
||||
}
|
||||
pendingPromise.resolve();
|
||||
});
|
||||
};
|
||||
@@ -1,92 +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/>.
|
||||
|
||||
/**
|
||||
* Return data about an entity generator.
|
||||
*
|
||||
* @package tool_behat
|
||||
* @copyright 2022 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_behat\external;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
/**
|
||||
* External function for getting properties of entity generators.
|
||||
*/
|
||||
class get_entity_generator extends \external_api {
|
||||
|
||||
/**
|
||||
* Define parameters for external function.
|
||||
*
|
||||
* The parameter is either in the format 'entity' or 'component_name > entity'. There is no appropriate param type for a
|
||||
* string like this containing angle brackets, so we will do PARAM_RAW. The value will be parsed by
|
||||
* behat_data_generators::parse_entity_type, which validates the format of the parameter and throws an exception if it is not
|
||||
* correct.
|
||||
*
|
||||
* @return \external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): \external_function_parameters {
|
||||
return new \external_function_parameters([
|
||||
'entitytype' => new \external_value(PARAM_RAW, 'Entity type that can be created by a generator.'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the required fields for a given entity type.
|
||||
*
|
||||
* @param string $entitytype
|
||||
* @return array
|
||||
*/
|
||||
public static function execute(string $entitytype): array {
|
||||
global $CFG;
|
||||
|
||||
// Ensure we can load Behat and Facebook namespaces in behat libraries.
|
||||
require_once("{$CFG->dirroot}/vendor/autoload.php");
|
||||
require_once("{$CFG->libdir}/tests/behat/behat_data_generators.php");
|
||||
|
||||
$params = self::validate_parameters(self::execute_parameters(), ['entitytype' => $entitytype]);
|
||||
$context = \context_system::instance();
|
||||
self::validate_context($context);
|
||||
require_capability('moodle/site:config', $context);
|
||||
|
||||
$generators = new \behat_data_generators();
|
||||
$entity = $generators->get_entity($params['entitytype']);
|
||||
return ['required' => $entity['required']];
|
||||
}
|
||||
|
||||
/**
|
||||
* Define return values.
|
||||
*
|
||||
* Return required fields
|
||||
*
|
||||
* @return \external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): \external_single_structure {
|
||||
return new \external_single_structure([
|
||||
'required' => new \external_multiple_structure(
|
||||
new \external_value(PARAM_TEXT, 'Required field'),
|
||||
'Required fields',
|
||||
VALUE_OPTIONAL
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,10 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'torun' => 0,
|
||||
'optimize-runs' => '',
|
||||
'add-core-features-to-theme' => false,
|
||||
'axe' => false,
|
||||
'disable-composer' => false,
|
||||
'composer-upgrade' => true,
|
||||
'composer-self-update' => true,
|
||||
),
|
||||
array(
|
||||
'j' => 'parallel',
|
||||
@@ -64,18 +68,36 @@ $help = "
|
||||
Behat utilities to initialise behat tests
|
||||
|
||||
Usage:
|
||||
php init.php [--parallel=value [--maxruns=value] [--fromrun=value --torun=value]] [--help]
|
||||
php init.php [--parallel=value [--maxruns=value] [--fromrun=value --torun=value]]
|
||||
[--axe] [-o | --optimize-runs] [-a | --add-core-features-to-theme]
|
||||
[--no-composer-self-update] [--no-composer-upgrade]
|
||||
[--disable-composer]
|
||||
[--help]
|
||||
|
||||
Options:
|
||||
-j, --parallel Number of parallel behat run to initialise
|
||||
-m, --maxruns Max parallel processes to be executed at one time.
|
||||
--fromrun Execute run starting from (Used for parallel runs on different vms)
|
||||
--torun Execute run till (Used for parallel runs on different vms)
|
||||
-j, --parallel Number of parallel behat run to initialise
|
||||
-m, --maxruns Max parallel processes to be executed at one time
|
||||
--fromrun Execute run starting from (Used for parallel runs on different vms)
|
||||
--torun Execute run till (Used for parallel runs on different vms)
|
||||
--axe Include axe accessibility tests
|
||||
|
||||
-o, --optimize-runs Split features with specified tags in all parallel runs.
|
||||
-a, --add-core-features-to-theme Add all core features to specified theme's
|
||||
-o, --optimize-runs
|
||||
Split features with specified tags in all parallel runs.
|
||||
|
||||
-h, --help Print out this help
|
||||
-a, --add-core-features-to-theme
|
||||
Add all core features to specified theme's
|
||||
|
||||
--no-composer-self-update
|
||||
Prevent upgrade of the composer utility using its self-update command
|
||||
|
||||
--no-composer-upgrade
|
||||
Prevent update development dependencies using composer
|
||||
|
||||
--disable-composer
|
||||
A shortcut to disable composer self-update and dependency update
|
||||
Note: Installation of composer and/or dependencies will still happen as required
|
||||
|
||||
-h, --help Print out this help
|
||||
|
||||
Example from Moodle root directory:
|
||||
\$ php admin/tool/behat/cli/init.php --parallel=2
|
||||
@@ -102,7 +124,10 @@ if ($options['parallel'] && $options['parallel'] > 1) {
|
||||
}
|
||||
} else {
|
||||
// Only sanitize options for single run.
|
||||
$cmdoptionsforsinglerun = array('add-core-features-to-theme');
|
||||
$cmdoptionsforsinglerun = [
|
||||
'add-core-features-to-theme',
|
||||
'axe',
|
||||
];
|
||||
|
||||
foreach ($cmdoptionsforsinglerun as $option) {
|
||||
if (!empty($options[$option])) {
|
||||
@@ -115,8 +140,15 @@ if ($options['parallel'] && $options['parallel'] > 1) {
|
||||
$cwd = getcwd();
|
||||
$output = null;
|
||||
|
||||
// If behat dependencies not downloaded then do it first, else symfony/process can't be used.
|
||||
testing_update_composer_dependencies();
|
||||
if ($options['disable-composer']) {
|
||||
// Disable self-update and upgrade easily.
|
||||
// Note: Installation will still occur regardless of this setting.
|
||||
$options['composer-self-update'] = false;
|
||||
$options['composer-upgrade'] = false;
|
||||
}
|
||||
|
||||
// Install and update composer and dependencies as required.
|
||||
testing_update_composer_dependencies($options['composer-self-update'], $options['composer-upgrade']);
|
||||
|
||||
// Check whether the behat test environment needs to be updated.
|
||||
chdir(__DIR__);
|
||||
|
||||
@@ -45,7 +45,7 @@ list($options, $unrecognised) = cli_get_params(
|
||||
array(
|
||||
'stop-on-failure' => 0,
|
||||
'verbose' => false,
|
||||
'replace' => '',
|
||||
'replace' => false,
|
||||
'help' => false,
|
||||
'tags' => '',
|
||||
'profile' => '',
|
||||
@@ -70,7 +70,7 @@ $help = "
|
||||
Behat utilities to run behat tests in parallel
|
||||
|
||||
Usage:
|
||||
php run.php [--BEHAT_OPTION=\"value\"] [--feature=\"value\"] [--replace=\"{run}\"] [--fromrun=value --torun=value] [--help]
|
||||
php run.php [--BEHAT_OPTION=\"value\"] [--feature=\"value\"] [--replace] [--fromrun=value --torun=value] [--help]
|
||||
|
||||
Options:
|
||||
--BEHAT_OPTION Any combination of behat option specified in http://behat.readthedocs.org/en/v2.5/guides/6.cli.html
|
||||
@@ -144,10 +144,9 @@ $extraopts = $unrecognised;
|
||||
if ($options['profile']) {
|
||||
$profile = $options['profile'];
|
||||
|
||||
// If profile passed is not set, then exit (note we skip if the 'replace' option is found within the 'profile' value).
|
||||
// If profile passed is not set, then exit.
|
||||
if (!isset($CFG->behat_config[$profile]) && !isset($CFG->behat_profiles[$profile]) &&
|
||||
!($options['replace'] && (strpos($profile, (string) $options['replace']) !== false))) {
|
||||
|
||||
!(isset($options['replace']) && (strpos($options['profile'], $options['replace']) >= 0 ))) {
|
||||
echo "Invalid profile passed: " . $profile . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'torun' => 0,
|
||||
'optimize-runs' => '',
|
||||
'add-core-features-to-theme' => false,
|
||||
'axe' => false,
|
||||
),
|
||||
array(
|
||||
'h' => 'help',
|
||||
@@ -69,7 +70,7 @@ $help = "
|
||||
Behat utilities to manage the test environment
|
||||
|
||||
Usage:
|
||||
php util.php [--install|--drop|--enable|--disable|--diag|--updatesteps|--help] [--parallel=value [--maxruns=value]]
|
||||
php util.php [--install|--drop|--enable|--disable|--diag|--updatesteps|--axe|--help] [--parallel=value [--maxruns=value]]
|
||||
|
||||
Options:
|
||||
--install Installs the test environment for acceptance tests
|
||||
@@ -78,6 +79,7 @@ Options:
|
||||
--disable Disables test environment
|
||||
--diag Get behat test environment status code
|
||||
--updatesteps Update feature step file.
|
||||
--axe Include axe accessibility tests
|
||||
|
||||
-j, --parallel Number of parallel behat run operation
|
||||
-m, --maxruns Max parallel processes to be executed at one time.
|
||||
|
||||
@@ -49,6 +49,7 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'updatesteps' => false,
|
||||
'optimize-runs' => '',
|
||||
'add-core-features-to-theme' => false,
|
||||
'axe' => false,
|
||||
),
|
||||
array(
|
||||
'h' => 'help',
|
||||
@@ -75,6 +76,7 @@ Options:
|
||||
--disable Disables test environment
|
||||
--diag Get behat test environment status code
|
||||
--updatesteps Update feature step file.
|
||||
--axe Include axe accessibility tests
|
||||
|
||||
-o, --optimize-runs Split features with specified tags in all parallel runs.
|
||||
-a, --add-core-features-to-theme Add all core features to specified theme's
|
||||
@@ -181,11 +183,17 @@ if ($options['install']) {
|
||||
behat_config_manager::set_behat_run_config_value('behatsiteenabled', 1);
|
||||
}
|
||||
|
||||
// Define whether to run Behat with axe tests.
|
||||
behat_config_manager::set_behat_run_config_value('axe', $options['axe']);
|
||||
|
||||
// Enable test mode.
|
||||
$timestart = microtime(true);
|
||||
mtrace('Creating Behat configuration ...', '');
|
||||
behat_util::start_test_mode($options['add-core-features-to-theme'], $options['optimize-runs'], $parallel, $run);
|
||||
mtrace(' done in ' . round(microtime(true) - $timestart, 2) . ' seconds.');
|
||||
|
||||
// Themes are only built in the 'enable' command.
|
||||
behat_util::build_themes();
|
||||
behat_util::build_themes(true);
|
||||
mtrace("Testing environment themes built");
|
||||
|
||||
// This is only displayed once for parallel install.
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Define web service functions for tool_behat
|
||||
*
|
||||
* @package tool_behat
|
||||
* @copyright 2022 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$functions = [
|
||||
'tool_behat_get_entity_generator' => [
|
||||
'classname' => 'tool_behat\\external\\get_entity_generator',
|
||||
'methodname' => 'execute',
|
||||
'description' => 'Get the generator details for an entity',
|
||||
'type' => 'read',
|
||||
'ajax' => true,
|
||||
'capabilities' => 'moodle/site:config'
|
||||
]
|
||||
];
|
||||
@@ -56,7 +56,6 @@ if ($components) {
|
||||
$form = new steps_definitions_form(null, array('components' => $componentswithsteps));
|
||||
|
||||
// Output contents.
|
||||
$PAGE->requires->js_call_amd('tool_behat/steps', 'init');
|
||||
$renderer = $PAGE->get_renderer('tool_behat');
|
||||
echo $renderer->render_stepsdefinitions($steps, $form);
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@ $string['stepsdefinitionstype'] = 'Type';
|
||||
$string['theninfo'] = 'Then. Checkings to ensure the outcomes are the expected ones';
|
||||
$string['unknownexceptioninfo'] = 'There was a problem with Selenium or your browser. Please ensure you are using the latest version of Selenium. Error:';
|
||||
$string['viewsteps'] = 'Filter';
|
||||
$string['warndirrootconfigfound'] = 'A configuration file was found at {$a}. This file is not automatically updated and may become stale. We recommend removing this file.';
|
||||
$string['wheninfo'] = 'When. Action that provokes an event';
|
||||
$string['wrongbehatsetup'] = 'Something is wrong with the behat setup and so step definitions cannot be listed: <b>{$a->errormsg}</b><br/><br/>Please check:<ul>
|
||||
<li>$CFG->behat_dataroot, $CFG->behat_prefix and $CFG->behat_wwwroot are set in config.php with different values from $CFG->dataroot, $CFG->prefix and $CFG->wwwroot.</li>
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/behat/classes/behat_generator_base.php');
|
||||
|
||||
/**
|
||||
* Renderer for behat tool web features
|
||||
*
|
||||
@@ -108,32 +106,6 @@ class tool_behat_renderer extends plugin_renderer_base {
|
||||
},
|
||||
$stepsdefinitions
|
||||
);
|
||||
|
||||
$elementstrings = [];
|
||||
$count = 1;
|
||||
$stepsdefinitions = preg_replace_callback('/(the following ")ELEMENT\d?_STRING(" exist:)/',
|
||||
function($matches) use (&$elementstrings, &$count) {
|
||||
// Replace element type arguments with a user-friendly select.
|
||||
if (empty($elementstrings)) {
|
||||
$behatgenerators = new behat_data_generators();
|
||||
$componententities = $behatgenerators->get_all_entities();
|
||||
ksort($componententities);
|
||||
$elementstrings = [];
|
||||
foreach ($componententities as $component => $entities) {
|
||||
asort($entities);
|
||||
foreach ($entities as $entity) {
|
||||
$string = ($component === 'core') ? $entity : $component . ' > ' . $entity;
|
||||
$elementstrings[$string] = $string;
|
||||
}
|
||||
}
|
||||
}
|
||||
$select = html_writer::select($elementstrings, 'entities' . $count, '', ['' => 'choosedots'],
|
||||
['class' => 'entities']);
|
||||
$count++;
|
||||
return $matches[1] . $select . $matches[2];
|
||||
},
|
||||
$stepsdefinitions
|
||||
);
|
||||
}
|
||||
|
||||
// Steps definitions.
|
||||
|
||||
@@ -29,9 +29,3 @@
|
||||
#page-admin-tool-behat-index .steps-definitions .stepregex {
|
||||
color: #060;
|
||||
}
|
||||
|
||||
#page-admin-tool-behat-index .steprequiredfields {
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ Feature: Set up contextual data for tests
|
||||
And I log in as "user5"
|
||||
And I should see "You are logged in as"
|
||||
And I am on "Course 1" course homepage
|
||||
And I should see "You cannot enrol yourself in this course."
|
||||
And I should see "You can not enrol yourself in this course."
|
||||
|
||||
Scenario: Add modules
|
||||
Given the following "courses" exist:
|
||||
|
||||
@@ -21,5 +21,5 @@ Feature: Transform date time string arguments
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I should see "##yesterday##%A, %d %B %Y##"
|
||||
And I should see "##yesterday##l, j F Y##"
|
||||
And I log out
|
||||
|
||||
@@ -6,18 +6,14 @@ Feature: Edit capabilities
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| teacher1 | Teacher | 1 |
|
||||
| tutor | Teaching | Assistant |
|
||||
| student | Student | One |
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| tutor | C1 | teacher |
|
||||
| student | C1 | student |
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
|
||||
Scenario: Default system capabilities modification
|
||||
Given I log in as "admin"
|
||||
@@ -64,25 +60,3 @@ Feature: Edit capabilities
|
||||
Then "mod/forum:deleteanypost" capability has "Prohibit" permission
|
||||
And "mod/forum:editanypost" capability has "Prevent" permission
|
||||
And "mod/forum:addquestion" capability has "Allow" permission
|
||||
|
||||
@javascript
|
||||
Scenario: Edit permissions escapes role names correctly
|
||||
When I am on the "C1" "Course" page logged in as "admin"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Your word for 'Teacher' | Teacher >= editing |
|
||||
| Your word for 'Non-editing teacher' | Teacher < "editing" |
|
||||
| Your word for 'Student' | Studier & 'learner' |
|
||||
And I press "Save and display"
|
||||
And I navigate to course participants
|
||||
Then I should see "Teacher >= editing" in the "Teacher 1" "table_row"
|
||||
And I should see "Teacher < \"editing\"" in the "Teaching Assistant" "table_row"
|
||||
And I should see "Studier & 'learner'" in the "Student One" "table_row"
|
||||
And I navigate to "Users > Permissions" in current page administration
|
||||
And I should see "Teacher >= editing" in the "mod/forum:replypost" "table_row"
|
||||
And I should see "Teacher < \"editing\"" in the "mod/forum:replypost" "table_row"
|
||||
And I should see "Studier & 'learner'" in the "mod/forum:replypost" "table_row"
|
||||
And I follow "Prohibit"
|
||||
And "Teacher >= editing" "button" in the "Prohibit role" "dialogue" should be visible
|
||||
And "Teacher < \"editing\"" "button" in the "Prohibit role" "dialogue" should be visible
|
||||
And "Studier & 'learner'" "button" in the "Prohibit role" "dialogue" should be visible
|
||||
|
||||
@@ -30,9 +30,10 @@ Feature: Verify that all form fields values can be get and set
|
||||
| student2 | G2 |
|
||||
| student3 | G2 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | idnumber | name | firstpagetitle | wikimode | visible |
|
||||
| wiki | C1 | wiki1 | Test this one | Test this one | collaborative | 0 |
|
||||
And I am on the "Course 1" course page logged in as admin
|
||||
| activity | course | idnumber | name | intro | firstpagetitle | wikimode | visible |
|
||||
| wiki | C1 | wiki1 | Test this one | Test this one | Test this one | collaborative | 0 |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Reset" in current page administration
|
||||
# Select (multi-select) - Checking "the select box should contain".
|
||||
And I expand all fieldsets
|
||||
@@ -47,7 +48,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
And the "Unenrol users" select box should not contain "Baker"
|
||||
And the "Unenrol users" select box should not contain "President, Baker"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I follow "Test this one"
|
||||
And I press "Create page"
|
||||
# Text (textarea & editor) & Select (multi-select) - Checking "I set the following fields to these values".
|
||||
When I set the following fields to these values:
|
||||
@@ -60,14 +61,18 @@ Feature: Verify that all form fields values can be get and set
|
||||
# Checkbox - Checking "I set the field" and "The field matches value" ticked.
|
||||
And I set the field "Force format" to "1"
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And the field "Force format" matches value "1"
|
||||
And the field "Force format" does not match value ""
|
||||
# Checkbox - Checking "I set the field" and "The field matches value" unticked.
|
||||
And I set the field "Force format" to ""
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And the field "Force format" matches value ""
|
||||
And the field "Force format" does not match value "1"
|
||||
@@ -75,7 +80,9 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I set the following fields to these values:
|
||||
| Force format | 1 |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And the following fields match these values:
|
||||
| Force format | 1 |
|
||||
@@ -85,7 +92,9 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I set the following fields to these values:
|
||||
| Force format | |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And the following fields match these values:
|
||||
| Force format | |
|
||||
@@ -106,21 +115,20 @@ Feature: Verify that all form fields values can be get and set
|
||||
| Wiki name | Test this one baby |
|
||||
| Default format | HTML |
|
||||
And I press "Cancel"
|
||||
And I am on "Course 1" course homepage
|
||||
# Radio - Checking "I set the field" and "the field matches value".
|
||||
And the following "activity" exists:
|
||||
| activity | choice |
|
||||
| course | C1 |
|
||||
| idnumber | choice1 |
|
||||
| intro | Test choice description |
|
||||
| name | Test choice name |
|
||||
| option | Option 1, Option 2, Option 3 |
|
||||
| section | 1 |
|
||||
| allowupdate | 1 |
|
||||
And I am on the "Test choice name" "choice activity" page
|
||||
And I set the field "Option 1" to "1"
|
||||
And I add a "Choice" to section "1" and I fill the form with:
|
||||
| Choice name | Test choice name |
|
||||
| Description | Test choice description |
|
||||
| Allow choice to be updated | Yes |
|
||||
| Option 1 | one |
|
||||
| Option 2 | two |
|
||||
| Option 3 | three |
|
||||
And I follow "Test choice name"
|
||||
And I set the field "one" to "1"
|
||||
And I press "Save my choice"
|
||||
And the field "Option 1" matches value "1"
|
||||
And the field "Option 2" matches value ""
|
||||
And the field "one" matches value "1"
|
||||
And the field "two" matches value ""
|
||||
# Check if field xpath set/match works.
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
@@ -131,13 +139,12 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And the field "Course ID number" matches value "Course id number"
|
||||
|
||||
Scenario: with JS disabled all form fields getters and setters works as expected
|
||||
|
||||
@javascript
|
||||
Scenario: with JS enabled all form fields getters and setters works as expected
|
||||
Given the following "activities" exist:
|
||||
| activity | course | name |
|
||||
| lesson | C1 | Test lesson |
|
||||
When I am on "Course 1" course homepage
|
||||
Then I navigate to "Users > Groups" in current page administration
|
||||
Then I am on "Course 1" course homepage
|
||||
And I navigate to "Users > Groups" in current page administration
|
||||
# Select (multi-select & AJAX) - Checking "I set the field" and "select box should contain".
|
||||
And I set the field "groups" to "Group 2"
|
||||
And the "members" select box should contain "Student 2 (s2@example.com)"
|
||||
@@ -148,8 +155,11 @@ Feature: Verify that all form fields values can be get and set
|
||||
And the "members" select box should contain "Student 2 (s2@example.com)"
|
||||
And the "members" select box should not contain "Student 3 (s3@example.com)"
|
||||
# Checkbox (AJAX) - Checking "I set the field" and "I set the following fields to these values".
|
||||
And I am on the "Test lesson" "lesson activity editing" page
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a "Lesson" to section "1"
|
||||
And I set the following fields to these values:
|
||||
| Name | Test lesson |
|
||||
| Description | Test lesson description |
|
||||
| available[enabled] | 1 |
|
||||
And I set the field "deadline[enabled]" to "1"
|
||||
# Checkbox (AJAX) - Checking "the field matches value" before saving.
|
||||
@@ -164,23 +174,31 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I press "Cancel"
|
||||
# Advanced checkbox requires real browser to allow uncheck to work. MDL-58681. MDL-55386.
|
||||
# Advanced checkbox - Checking "I set the field" and "The field matches value" ticked.
|
||||
And I am on the "Test choice name" "choice activity editing" page
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I set the field "Display description on course page" to "1"
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test choice name" "choice activity editing" page
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And the field "Display description on course page" matches value "1"
|
||||
And the field "Display description on course page" does not match value ""
|
||||
# Advanced checkbox - Checking "I set the field" and "The field matches value" unticked.
|
||||
And I set the field "Display description on course page" to ""
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test choice name" "choice activity editing" page
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And the field "Display description on course page" matches value ""
|
||||
And the field "Display description on course page" does not match value "1"
|
||||
# Advanced checkbox - Checking "I set the following fields to these values:" and "The following fields match these values" ticked.
|
||||
And I set the following fields to these values:
|
||||
| Display description on course page | 1 |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test choice name" "choice activity editing" page
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And the following fields match these values:
|
||||
| Display description on course page | 1 |
|
||||
And the following fields do not match these values:
|
||||
@@ -189,7 +207,9 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I set the following fields to these values:
|
||||
| Display description on course page | |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test choice name" "choice activity editing" page
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And the following fields match these values:
|
||||
| Display description on course page | |
|
||||
And the following fields do not match these values:
|
||||
|
||||
@@ -7,8 +7,8 @@ Feature: Behat steps for interacting with form work
|
||||
@javascript
|
||||
Scenario: Test fields in containers
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | summary | summaryformat |
|
||||
| Course 1 | C1 | Red | 1 |
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
# Just get to any form.
|
||||
@@ -17,15 +17,11 @@ Feature: Behat steps for interacting with form work
|
||||
And I set the following fields in the "Appearance" "fieldset" to these values:
|
||||
| Show activity reports | Yes |
|
||||
| Number of announcements | 1 |
|
||||
And I set the following fields in the "Description" "fieldset" to these values:
|
||||
| Course summary | Green |
|
||||
Then the field "Show activity reports" in the "Appearance" "fieldset" matches value "Yes"
|
||||
And the field "Show activity reports" in the "Appearance" "fieldset" does not match value "No"
|
||||
And the following fields in the "region-main" "region" match these values:
|
||||
| Course full name | Frog |
|
||||
| Number of announcements | 1 |
|
||||
| Course summary | Green |
|
||||
And the following fields in the "region-main" "region" do not match these values:
|
||||
| Course full name | Course 1 |
|
||||
| Number of announcements | 5 |
|
||||
| Course summary | Red |
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
@tool @tool_behat
|
||||
Feature: Use core page resolvers for the I am on the page steps
|
||||
In order to write tests correctly
|
||||
As a developer
|
||||
I need to have steps which take me straight to a page
|
||||
|
||||
Scenario Outline: When I am on an instance
|
||||
Given the following "categories" exist:
|
||||
| name | category | idnumber |
|
||||
| Cat 1 | 0 | CAT1 |
|
||||
And the following "course" exists:
|
||||
| fullname | Economics 101 |
|
||||
| shortname | ECON101 |
|
||||
| idnumber | 2021-econ101 |
|
||||
And the following "activity" exists:
|
||||
| course | ECON101 |
|
||||
| activity | forum |
|
||||
| name | Fundamentals of Economics |
|
||||
| idnumber | fundamentalsofeconomics |
|
||||
And I log in as "admin"
|
||||
When I am on the <identifier> <type> page
|
||||
Then I should see "<shouldsee>"
|
||||
|
||||
Examples:
|
||||
| description | identifier | type | shouldsee |
|
||||
| Course Category idnumber | CAT1 | category | Add a new course |
|
||||
| Course Category name | "Cat 1" | Category | Add a new course |
|
||||
| Course Full name | "Economics 101" | course | Fundamentals of Economics |
|
||||
| Course Short name | ECON101 | COURSE | Fundamentals of Economics |
|
||||
| Course idnumber | "2021-econ101" | Course | Fundamentals of Economics |
|
||||
| Forum idnumber | fundamentalsofeconomics | Activity | Add a new discussion |
|
||||
| Generic activity editing | fundamentalsofeconomics | "Activity editing" | Updating: Forum |
|
||||
| Forum name | "Fundamentals of Economics" | "Forum activity" | Add a new discussion |
|
||||
| Forum name editing | "Fundamentals of Economics" | "Forum activity editing" | Updating: Forum |
|
||||
| Forum name permissions | "Fundamentals of Economics" | "Forum activity permissions" | Permissions in Forum: Fun |
|
||||
| Forum name roles | "Fundamentals of Economics" | "Forum activity roles" | Assign roles in Forum: Fun |
|
||||
|
||||
Scenario Outline: When I am on an instance logged in as
|
||||
Given the following "categories" exist:
|
||||
| name | category | idnumber |
|
||||
| Cat 1 | 0 | CAT1 |
|
||||
And the following "course" exists:
|
||||
| fullname | Economics 101 |
|
||||
| shortname | ECON101 |
|
||||
| idnumber | 2021-econ101 |
|
||||
And the following "activity" exists:
|
||||
| course | ECON101 |
|
||||
| activity | forum |
|
||||
| name | Fundamentals of Economics |
|
||||
| idnumber | fundamentalsofeconomics |
|
||||
When I am on the <identifier> <type> page logged in as admin
|
||||
Then I should see "<shouldsee>"
|
||||
|
||||
Examples:
|
||||
| description | identifier | type | shouldsee |
|
||||
| Course Category idnumber | CAT1 | category | Add a new course |
|
||||
| Course Category name | "Cat 1" | Category | Add a new course |
|
||||
| Course Full name | "Economics 101" | course | Fundamentals of Economics |
|
||||
| Course Short name | ECON101 | COURSE | Fundamentals of Economics |
|
||||
| Course idnumber | "2021-econ101" | Course | Fundamentals of Economics |
|
||||
| Forum idnumber | fundamentalsofeconomics | Activity | Add a new discussion |
|
||||
| Generic activity editing | fundamentalsofeconomics | "Activity editing" | Updating: Forum |
|
||||
| Forum name | "Fundamentals of Economics" | "Forum activity" | Add a new discussion |
|
||||
| Forum name editing | "Fundamentals of Economics" | "Forum activity editing" | Updating: Forum |
|
||||
| Forum name permissions | "Fundamentals of Economics" | "Forum activity permissions" | Permissions in Forum: Fun |
|
||||
| Forum name roles | "Fundamentals of Economics" | "Forum activity roles" | Assign roles in Forum: Fun |
|
||||
|
||||
Scenario Outline: When I am on a named page
|
||||
Given I log in as "admin"
|
||||
When I am on the <identifier> page
|
||||
Then I should see "<shouldsee>"
|
||||
|
||||
Examples:
|
||||
| description | identifier | shouldsee |
|
||||
| Admin page | "Admin notifications" | Check for available updates |
|
||||
| Home page | Homepage | Recently accessed courses |
|
||||
|
||||
Scenario Outline: When I am on a named page logged in as
|
||||
When I am on the <identifier> page logged in as admin
|
||||
Then I should see "<shouldsee>"
|
||||
|
||||
Examples:
|
||||
| description | identifier | shouldsee |
|
||||
| Admin page | "Admin notifications" | Check for available updates |
|
||||
| Home page | Homepage | Recently accessed courses |
|
||||
@@ -1,30 +0,0 @@
|
||||
@tool_behat
|
||||
Feature: Verify that the inplace editable field works as expected
|
||||
In order to use behat step definitions
|
||||
As a test write
|
||||
I need to ensure that the inplace editable works in forms
|
||||
|
||||
Background:
|
||||
Given the following "course" exists:
|
||||
| fullname | Course 1 |
|
||||
| shortname | C1 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | name | idnumber |
|
||||
| forum | C1 | My first forum | forum1 |
|
||||
| assign | C1 | My first assignment | assign1 |
|
||||
| quiz | C1 | My first quiz | quiz1 |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
|
||||
@javascript
|
||||
Scenario: Using an inplace editable updates the name of an activity
|
||||
When I set the field "Edit title" in the "My first assignment" "activity" to "Coursework submission"
|
||||
Then I should see "Coursework submission"
|
||||
And I should not see "My first assignment"
|
||||
But I should see "My first forum"
|
||||
And I should see "My first quiz"
|
||||
And I set the field "Edit title" in the "Coursework submission" "activity" to "My first assignment"
|
||||
And I should not see "Coursework submission"
|
||||
But I should see "My first assignment"
|
||||
And I should see "My first forum"
|
||||
And I should see "My first quiz"
|
||||
@@ -1,52 +0,0 @@
|
||||
@tool_behat
|
||||
Feature: Verify that keyboard steps work as expected
|
||||
In order to use behat step definitions
|
||||
As a test writer
|
||||
I need to verify that the keyboard steps work as expected
|
||||
|
||||
@javascript
|
||||
Scenario: Typing keys into a field causes them to be input
|
||||
Given the following "users" exist:
|
||||
| username | email | firstname | lastname | password |
|
||||
| saffronr | saffron.rutledge@example.com | Saffron | Rutledge | flowerpower |
|
||||
Given I click on "Log in" "link"
|
||||
And I click on "Username" "field"
|
||||
When I type "saffronr"
|
||||
And I press the tab key
|
||||
And I type "flowerpower"
|
||||
And I press enter
|
||||
Then I should see "You are logged in as Saffron Rutledge"
|
||||
|
||||
@javascript
|
||||
Scenario: Using tab changes focus to the next or previous field
|
||||
Given I click on "Log in" "link"
|
||||
And I click on "Username" "field"
|
||||
And the focused element is "Username" "field"
|
||||
When I press the tab key
|
||||
Then the focused element is "Password" "field"
|
||||
|
||||
And I press the shift tab key
|
||||
And the focused element is "Username" "field"
|
||||
|
||||
@javascript
|
||||
Scenario: Using the arrow keys allows me to navigate through menus
|
||||
Given the following "users" exist:
|
||||
| username | email | firstname | lastname |
|
||||
| saffronr | saffron.rutledge@example.com | Saffron | Rutledge |
|
||||
And I log in as "saffronr"
|
||||
And I click on "Saffron Rutledge" "link" in the ".usermenu" "css_element"
|
||||
When I press the up key
|
||||
Then the focused element is "Log out" "link"
|
||||
|
||||
@javascript
|
||||
Scenario: The escape key can be used to close a dialogue
|
||||
Given the following "course" exists:
|
||||
| fullname | C1|
|
||||
| shortname | C1 |
|
||||
And I log in as "admin"
|
||||
And I am on "C1" course homepage
|
||||
And I navigate to course participants
|
||||
And I press "Enrol users"
|
||||
And "Enrol users" "dialogue" should be visible
|
||||
When I press the escape key
|
||||
Then "Enrol users" "dialogue" should not be visible
|
||||
@@ -13,10 +13,6 @@ Feature: List the system steps definitions
|
||||
Scenario: Accessing the list
|
||||
Then I should see "Step definitions"
|
||||
And I should not see "There aren't steps definitions matching this filter"
|
||||
And I should not see "the following \"ELEMENT_STRING\" exist:"
|
||||
And "entities1" "select" should exist
|
||||
And the "entities1" select box should contain "users"
|
||||
And the "entities1" select box should contain "mod_assign > submissions"
|
||||
|
||||
@javascript
|
||||
Scenario: Filtering by type
|
||||
@@ -38,11 +34,3 @@ Feature: List the system steps definitions
|
||||
Then I should not see "There aren't steps definitions matching this filter"
|
||||
And I should see "Checks the provided element and selector type exists in the current page."
|
||||
And I should see "Checks that an element and selector type exists in another element and selector type on the current page."
|
||||
|
||||
@javascript
|
||||
Scenario: Get required fields
|
||||
Given I set the field "entities1" to "users"
|
||||
And I should see "| username |"
|
||||
When I set the field "entities1" to "mod_quiz > user overrides"
|
||||
Then I should not see "| username |"
|
||||
And I should see "| quiz | user |"
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
@tool_behat
|
||||
Feature: Verify that the behat login and logout steps work as expected
|
||||
In order to use behat login and log out steps
|
||||
As a test writer
|
||||
I need to verify that login and logout happen when the steps are used
|
||||
|
||||
Scenario: Log in as a user using the step
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| traverst1 | Thomas | Travers |
|
||||
When I log in as "traverst1"
|
||||
Then I should see "Thomas Travers"
|
||||
|
||||
@javascript
|
||||
Scenario: Log in as a user using the step (javascript)
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| traverst1 | Thomas | Travers |
|
||||
When I log in as "traverst1"
|
||||
Then I should see "Thomas Travers"
|
||||
|
||||
Scenario: Log out using the log out step
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| traverst1 | Thomas | Travers |
|
||||
And I am logged in as traverst1
|
||||
When I log out
|
||||
Then I should not see "Thomas Travers"
|
||||
And I should see "You are not logged in"
|
||||
|
||||
@javascript
|
||||
Scenario: Log out using the log out step (javascript)
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| traverst1 | Thomas | Travers |
|
||||
And I am logged in as traverst1
|
||||
When I log out
|
||||
Then I should not see "Thomas Travers"
|
||||
And I should see "You are not logged in"
|
||||
|
||||
Scenario: Log in step should automatically log user out if already logged in
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| traverst1 | Thomas | Travers |
|
||||
| emeryj | Jane | Emery |
|
||||
And I am logged in as traverst1
|
||||
When I log in as "emeryj"
|
||||
Then I should not see "Thomas Travers"
|
||||
And I should see "Jane Emery"
|
||||
|
||||
@javascript
|
||||
Scenario: Log in step should automatically log user out if already logged in (javascript)
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| traverst1 | Thomas | Travers |
|
||||
| emeryj | Jane | Emery |
|
||||
And I am logged in as traverst1
|
||||
When I log in as "emeryj"
|
||||
Then I should not see "Thomas Travers"
|
||||
And I should see "Jane Emery"
|
||||
|
||||
Scenario: I am on page logged in as should redirect to correct page
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| traverst1 | Thomas | Travers |
|
||||
And the following "course" exists:
|
||||
| fullname | Life, the Universe, and Everything |
|
||||
| shortname | hhgttg |
|
||||
When I am on the hhgttg Course page logged in as traverst1
|
||||
Then I should see "Thomas Travers"
|
||||
And I should see "Life, the Universe, and Everything"
|
||||
|
||||
@javascript
|
||||
Scenario: I am on page logged in as should redirect to correct page (javascript)
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| traverst1 | Thomas | Travers |
|
||||
And the following "course" exists:
|
||||
| fullname | Life, the Universe, and Everything |
|
||||
| shortname | hhgttg |
|
||||
When I am on the hhgttg Course page logged in as traverst1
|
||||
Then I should see "Thomas Travers"
|
||||
And I should see "Life, the Universe, and Everything"
|
||||
|
||||
Scenario: I am on page logged in as should redirect to correct page when automatically logging a user out
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| traverst1 | Thomas | Travers |
|
||||
| emeryj | Jane | Emery |
|
||||
And the following "course" exists:
|
||||
| fullname | Life, the Universe, and Everything |
|
||||
| shortname | hhgttg |
|
||||
And I am logged in as emeryj
|
||||
When I am on the hhgttg Course page logged in as traverst1
|
||||
Then I should see "Thomas Travers"
|
||||
And I should see "Life, the Universe, and Everything"
|
||||
|
||||
@javascript
|
||||
Scenario: I am on page logged in as should redirect to correct page when automatically logging a user out (javacript)
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| traverst1 | Thomas | Travers |
|
||||
| emeryj | Jane | Emery |
|
||||
And the following "course" exists:
|
||||
| fullname | Life, the Universe, and Everything |
|
||||
| shortname | hhgttg |
|
||||
And I am logged in as emeryj
|
||||
When I am on the hhgttg Course page logged in as traverst1
|
||||
Then I should see "Thomas Travers"
|
||||
And I should see "Life, the Universe, and Everything"
|
||||
@@ -14,16 +14,17 @@ Feature: Forms manipulation
|
||||
Then the field "First name" matches value "Field value"
|
||||
And the "Select a country" select box should contain "Japan"
|
||||
And the field "New password" matches value "TestPass"
|
||||
And I take focus off "Update profile" "button"
|
||||
And I press "Update profile"
|
||||
|
||||
@javascript
|
||||
Scenario: Expand all fieldsets and advanced elements
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | section | name |
|
||||
| quiz | C1 | 1 | Quiz 1 |
|
||||
And I am on the "Quiz 1" "quiz activity editing" page logged in as admin
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Quiz" to section "1"
|
||||
When I expand all fieldsets
|
||||
Then I should see "Close the quiz"
|
||||
And I should see "Group mode"
|
||||
|
||||
@@ -1,104 +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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for get_entity_generator web service
|
||||
*
|
||||
* @package tool_behat
|
||||
* @copyright 2022 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_behat\external;
|
||||
|
||||
/**
|
||||
* Tests for get_entity_generator web service
|
||||
*
|
||||
* @covers \tool_behat\external\get_entity_generator
|
||||
*/
|
||||
class get_entity_generator_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Log in as admin
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator for a core entity.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_core_entity(): void {
|
||||
$generator = get_entity_generator::execute('users');
|
||||
$this->assertEquals(['required' => ['username']], $generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator for the plugin entity.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_plugin_entity(): void {
|
||||
$generator = get_entity_generator::execute('mod_book > chapters');
|
||||
$this->assertEquals(['required' => ['book', 'title', 'content']], $generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator for an entity with no required fields.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_no_requried(): void {
|
||||
$generator = get_entity_generator::execute('mod_forum > posts');
|
||||
$this->assertEquals(['required' => []], $generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get the generator for a core entity that does not exist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_invalid_entity(): void {
|
||||
$this->expectException('coding_exception');
|
||||
get_entity_generator::execute('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get a generator form a plugin that does not exist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_invalid_plugin(): void {
|
||||
$this->expectException('coding_exception');
|
||||
get_entity_generator::execute('foo > bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get a generator for an entity that does not exist, from a plugin that does.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_invalid_plugin_entity(): void {
|
||||
$this->expectException('coding_exception');
|
||||
get_entity_generator::execute('mod_book > bar');
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Setup test.
|
||||
*/
|
||||
public function setup() {
|
||||
public function setUp(): void {
|
||||
global $CFG;
|
||||
|
||||
$this->resetAfterTest();
|
||||
@@ -165,7 +165,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
// Check contexts.
|
||||
@@ -324,7 +324,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
// Check contexts.
|
||||
@@ -368,7 +368,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
// Check contexts.
|
||||
@@ -399,7 +399,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
// Check contexts.
|
||||
@@ -428,7 +428,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
// Check contexts.
|
||||
@@ -532,7 +532,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
// Check contexts.
|
||||
@@ -611,7 +611,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
// Check contexts.
|
||||
@@ -646,7 +646,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -662,7 +662,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,7 +678,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -693,7 +693,7 @@ class tool_behat_manager_util_testcase extends advanced_testcase {
|
||||
$this->assertCount(count($paths), $suites[$themename]['paths']);
|
||||
|
||||
foreach ($paths as $key => $feature) {
|
||||
$this->assertContains($feature, $suites[$themename]['paths'][$key]);
|
||||
$this->assertStringContainsString($feature, $suites[$themename]['paths'][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2020061501; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2020060900; // Requires this Moodle version
|
||||
$plugin->version = 2020110900; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2020110300; // Requires this Moodle version
|
||||
$plugin->component = 'tool_behat'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -60,12 +60,12 @@ class tool_capability_settings_form extends moodleform {
|
||||
$form->addElement('select', 'roles', get_string('roleslabel', 'tool_capability'), $roles, $attributes);
|
||||
$form->setType('roles', PARAM_TEXT);
|
||||
|
||||
$filters = [];
|
||||
$filters[] = $form->createElement('checkbox', 'onlydiff', get_string('onlydiff', 'tool_capability'));
|
||||
$form->addElement('checkbox', 'onlydiff',
|
||||
get_string('filters', 'tool_capability'),
|
||||
get_string('onlydiff', 'tool_capability'));
|
||||
$form->setType('onlydiff', PARAM_BOOL);
|
||||
$form->addGroup($filters, 'filters', get_string('filters', 'tool_capability'), array('<br>'), false);
|
||||
|
||||
$form->addElement('submit', 'submitbutton', get_string('getreport', 'tool_capability'));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -53,12 +53,7 @@ function tool_capability_calculate_role_data($capability, array $roles) {
|
||||
$sql = 'SELECT DISTINCT con.path, 1
|
||||
FROM {context} con
|
||||
JOIN {role_capabilities} rc ON rc.contextid = con.id
|
||||
WHERE capability = ? ' .
|
||||
$sqlroletest .
|
||||
// Context path should never be null, but can happen in old database with
|
||||
// bad data (e.g. a course_module where the corresponding course no longer exists).
|
||||
// We need to leave these out of the report to prevent errors.
|
||||
' AND con.path IS NOT NULL';
|
||||
WHERE capability = ? '.$sqlroletest;
|
||||
$relevantpaths = $DB->get_records_sql_menu($sql, $params);
|
||||
$requiredcontexts = array($systemcontext->id);
|
||||
foreach ($relevantpaths as $path => $notused) {
|
||||
@@ -93,10 +88,6 @@ function tool_capability_calculate_role_data($capability, array $roles) {
|
||||
|
||||
// Put the role capabilities into the context tree.
|
||||
foreach ($rolecaps as $rolecap) {
|
||||
if (!isset($contexts[$rolecap->contextid])) {
|
||||
// Skip capabilities in orphaned contexts that are not in the tree.
|
||||
continue;
|
||||
}
|
||||
$contexts[$rolecap->contextid]->rolecapabilities[$rolecap->roleid] = $rolecap->permission;
|
||||
}
|
||||
|
||||
@@ -108,4 +99,4 @@ function tool_capability_calculate_role_data($capability, array $roles) {
|
||||
}
|
||||
|
||||
return $contexts;
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ class tool_capability_events_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Setup testcase.
|
||||
*/
|
||||
public function setUp() {
|
||||
public function setUp(): void {
|
||||
$this->setAdminUser();
|
||||
$this->resetAfterTest();
|
||||
}
|
||||
|
||||
@@ -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/>.
|
||||
|
||||
/**
|
||||
* Tests for the capability overview helper functions.
|
||||
*
|
||||
* @package tool_capability
|
||||
* @copyright 2021 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/capability/locallib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Tests for the capability overview helper functions.
|
||||
*/
|
||||
class tool_capability_locallib_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test the function that gets the data - simple case.
|
||||
*/
|
||||
public function test_tool_capability_calculate_role_data() {
|
||||
global $DB;
|
||||
|
||||
$data = tool_capability_calculate_role_data('mod/quiz:attempt', get_all_roles());
|
||||
|
||||
$systcontext = context_system::instance();
|
||||
$studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student']);
|
||||
|
||||
$this->assertArrayHasKey($systcontext->id, $data);
|
||||
$this->assertCount(1, $data);
|
||||
foreach ($data[$systcontext->id]->rolecapabilities as $roleid => $permission) {
|
||||
if ($roleid == $studentroleid) {
|
||||
$this->assertEquals(CAP_ALLOW, $permission);
|
||||
} else {
|
||||
$this->assertEquals(CAP_INHERIT, $permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the function that gets the data - simple case.
|
||||
*/
|
||||
public function test_tool_capability_calculate_role_data_orphan_contexts() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
// This simulates a situation that seems to happen sometimes, where
|
||||
// we end up with contexts with path = NULL in the database.
|
||||
$systcontext = context_system::instance();
|
||||
$generator = $this->getDataGenerator();
|
||||
$course = $generator->create_course();
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
$studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student']);
|
||||
role_change_permission($studentroleid, $coursecontext, 'mod/quiz:attempt', CAP_PREVENT);
|
||||
// This is where we simulate the breakage.
|
||||
$DB->set_field('context', 'path', null, ['id' => $coursecontext->id]);
|
||||
|
||||
// Now call the function. We mainly just want to know there is no exception.
|
||||
$data = tool_capability_calculate_role_data('mod/quiz:attempt', get_all_roles());
|
||||
|
||||
$this->assertArrayHasKey($systcontext->id, $data);
|
||||
$this->assertCount(1, $data);
|
||||
foreach ($data[$systcontext->id]->rolecapabilities as $roleid => $permission) {
|
||||
if ($roleid == $studentroleid) {
|
||||
$this->assertEquals(CAP_ALLOW, $permission);
|
||||
} else {
|
||||
$this->assertEquals(CAP_INHERIT, $permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2020060900; // Requires this Moodle version.
|
||||
$plugin->version = 2020110900; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2020110300; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_capability'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
admin/tool/capability/yui/build/moodle-tool_capability-search/moodle-tool_capability-search-debug.js
Vendored
+27
-4
@@ -53,6 +53,13 @@ SEARCH.prototype = {
|
||||
* @protected
|
||||
*/
|
||||
button: null,
|
||||
/**
|
||||
* The cancel button for the form.
|
||||
* @property button
|
||||
* @type Node
|
||||
* @protected
|
||||
*/
|
||||
cancel: null,
|
||||
/**
|
||||
* The last search node if there is one.
|
||||
* If there is a last search node then the last search term will be persisted between requests.
|
||||
@@ -76,17 +83,28 @@ SEARCH.prototype = {
|
||||
this.button = this.form.all('input[type=submit]');
|
||||
this.lastsearch = this.form.one('input[name=search]');
|
||||
|
||||
var div = Y.Node.create('<div id="capabilitysearchui" data-fieldtype="text"></div>'),
|
||||
label = Y.Node.create('<label for="capabilitysearch">' + this.get('strsearch') + '</label>');
|
||||
this.input = Y.Node.create('<input type="text" id="capabilitysearch" />');
|
||||
var div = Y.Node.create('<div id="capabilitysearchui" class="input-group simplesearchform mb-2"' +
|
||||
'data-fieldtype="text"></div>'),
|
||||
label = Y.Node.create('<label for="capabilitysearch"><span class="sr-only"' +
|
||||
this.get('strsearch') + '</span></label>');
|
||||
this.cancel = Y.Node.create('<a class="btn btn-clear d-none icon-no-margin">' +
|
||||
'<i class="icon fa fa-times fa-fw " aria-hidden="true"></i>' +
|
||||
'</a>');
|
||||
this.input = Y.Node.create('<input type="text" class="form-control withclear" placeholder="' +
|
||||
this.get('strsearch') + '"id="capabilitysearch" />');
|
||||
|
||||
div.append(label).append(this.input);
|
||||
div.append(label).append(this.input).append(this.cancel);
|
||||
|
||||
this.select.insert(div, 'before');
|
||||
|
||||
this.input.on('keyup', this.typed, this);
|
||||
this.select.on('change', this.validate, this);
|
||||
|
||||
this.cancel.on('click', function() {
|
||||
this.input.set('value', '');
|
||||
this.typed();
|
||||
}, this);
|
||||
|
||||
if (this.lastsearch) {
|
||||
this.input.set('value', this.lastsearch.get('value'));
|
||||
this.typed();
|
||||
@@ -133,6 +151,11 @@ SEARCH.prototype = {
|
||||
last.set('selected', true);
|
||||
}
|
||||
}
|
||||
if (search !== '') {
|
||||
this.cancel.removeClass("d-none");
|
||||
} else {
|
||||
this.cancel.addClass("d-none");
|
||||
}
|
||||
this.validate();
|
||||
}
|
||||
};
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
YUI.add("moodle-tool_capability-search",function(i,t){var e=function(){e.superclass.constructor.apply(this,arguments)};i.extend(e,i.Base,e.prototype={form:null,select:null,selectoptions:{},input:null,button:null,lastsearch:null,initializer:function(){this.form=i.one("#capability-overview-form"),this.select=this.form.one("select[data-search=capability]"),this.select.setStyle("minWidth",this.select.get("offsetWidth")),this.select.get("options").each(function(t){var e=t.get("value");this.selectoptions[e]=t},this),this.button=this.form.all("input[type=submit]"),this.lastsearch=this.form.one("input[name=search]");var t=i.Node.create('<div id="capabilitysearchui" data-fieldtype="text"></div>'),e=i.Node.create('<label for="capabilitysearch">'+this.get("strsearch")+"</label>");this.input=i.Node.create('<input type="text" id="capabilitysearch" />'),t.append(e).append(this.input),this.select.insert(t,"before"),this.input.on("keyup",this.typed,this),this.select.on("change",this.validate,this),this.lastsearch&&(this.input.set("value",this.lastsearch.get("value")),this.typed(),this.select.one("option[selected]")&&this.select.set("scrollTop",this.select.one("option[selected]").get("getX"))),this.validate()},validate:function(){this.button.set("disabled",""===this.select.get("value"))},typed:function(){var t,e=this.input.get("value"),i=0,s=null;for(t in this.lastsearch&&this.lastsearch.set("value",e),this.select.all("option").remove(),this.selectoptions)0<=t.indexOf(e)&&(i++,s=this.selectoptions[t],this.select.append(this.selectoptions[t]));0===i?this.input.addClass("error"):(this.input.removeClass("error"),1===i&&s.set("selected",!0)),this.validate()}},{NAME:"tool_capability-search",ATTRS:{strsearch:{}}}),M.tool_capability=M.tool_capability||{},M.tool_capability.init_capability_search=function(t){new e(t)}},"@VERSION@",{requires:["base","node"]});
|
||||
YUI.add("moodle-tool_capability-search",function(s,t){var e=function(){e.superclass.constructor.apply(this,arguments)};e.prototype={form:null,select:null,selectoptions:{},input:null,button:null,cancel:null,lastsearch:null,initializer:function(){this.form=s.one("#capability-overview-form"),this.select=this.form.one("select[data-search=capability]"),this.select.setStyle("minWidth",this.select.get("offsetWidth")),this.select.get("options").each(function(t){var e=t.get("value");this.selectoptions[e]=t},this),this.button=this.form.all("input[type=submit]"),this.lastsearch=this.form.one("input[name=search]");var t=s.Node.create('<div id="capabilitysearchui" class="input-group simplesearchform mb-2"data-fieldtype="text"></div>'),e=s.Node.create('<label for="capabilitysearch"><span class="sr-only"'+this.get("strsearch")+"</span></label>");this.cancel=s.Node.create('<a class="btn btn-clear d-none icon-no-margin"><i class="icon fa fa-times fa-fw " aria-hidden="true"></i></a>'),this.input=s.Node.create('<input type="text" class="form-control withclear" placeholder="'+this.get("strsearch")+'"id="capabilitysearch" />'),t.append(e).append(this.input).append(this.cancel),this.select.insert(t,"before"),this.input.on("keyup",this.typed,this),this.select.on("change",this.validate,this),this.cancel.on("click",function(){this.input.set("value",""),this.typed()},this),this.lastsearch&&(this.input.set("value",this.lastsearch.get("value")),this.typed(),this.select.one("option[selected]")&&this.select.set("scrollTop",this.select.one("option[selected]").get("getX"))),this.validate()},validate:function(){this.button.set("disabled",""===this.select.get("value"))},typed:function(){var t,e=this.input.get("value"),s=0,i=null;for(t in this.lastsearch&&this.lastsearch.set("value",e),this.select.all("option").remove(),this.selectoptions)0<=t.indexOf(e)&&(s++,i=this.selectoptions[t],this.select.append(this.selectoptions[t]));0===s?this.input.addClass("error"):(this.input.removeClass("error"),1===s&&i.set("selected",!0)),""!==e?this.cancel.removeClass("d-none"):this.cancel.addClass("d-none"),this.validate()}},s.extend(e,s.Base,e.prototype,{NAME:"tool_capability-search",ATTRS:{strsearch:{}}}),M.tool_capability=M.tool_capability||{},M.tool_capability.init_capability_search=function(t){new e(t)}},"@VERSION@",{requires:["base","node"]});
|
||||
Vendored
+27
-4
@@ -53,6 +53,13 @@ SEARCH.prototype = {
|
||||
* @protected
|
||||
*/
|
||||
button: null,
|
||||
/**
|
||||
* The cancel button for the form.
|
||||
* @property button
|
||||
* @type Node
|
||||
* @protected
|
||||
*/
|
||||
cancel: null,
|
||||
/**
|
||||
* The last search node if there is one.
|
||||
* If there is a last search node then the last search term will be persisted between requests.
|
||||
@@ -76,17 +83,28 @@ SEARCH.prototype = {
|
||||
this.button = this.form.all('input[type=submit]');
|
||||
this.lastsearch = this.form.one('input[name=search]');
|
||||
|
||||
var div = Y.Node.create('<div id="capabilitysearchui" data-fieldtype="text"></div>'),
|
||||
label = Y.Node.create('<label for="capabilitysearch">' + this.get('strsearch') + '</label>');
|
||||
this.input = Y.Node.create('<input type="text" id="capabilitysearch" />');
|
||||
var div = Y.Node.create('<div id="capabilitysearchui" class="input-group simplesearchform mb-2"' +
|
||||
'data-fieldtype="text"></div>'),
|
||||
label = Y.Node.create('<label for="capabilitysearch"><span class="sr-only"' +
|
||||
this.get('strsearch') + '</span></label>');
|
||||
this.cancel = Y.Node.create('<a class="btn btn-clear d-none icon-no-margin">' +
|
||||
'<i class="icon fa fa-times fa-fw " aria-hidden="true"></i>' +
|
||||
'</a>');
|
||||
this.input = Y.Node.create('<input type="text" class="form-control withclear" placeholder="' +
|
||||
this.get('strsearch') + '"id="capabilitysearch" />');
|
||||
|
||||
div.append(label).append(this.input);
|
||||
div.append(label).append(this.input).append(this.cancel);
|
||||
|
||||
this.select.insert(div, 'before');
|
||||
|
||||
this.input.on('keyup', this.typed, this);
|
||||
this.select.on('change', this.validate, this);
|
||||
|
||||
this.cancel.on('click', function() {
|
||||
this.input.set('value', '');
|
||||
this.typed();
|
||||
}, this);
|
||||
|
||||
if (this.lastsearch) {
|
||||
this.input.set('value', this.lastsearch.get('value'));
|
||||
this.typed();
|
||||
@@ -133,6 +151,11 @@ SEARCH.prototype = {
|
||||
last.set('selected', true);
|
||||
}
|
||||
}
|
||||
if (search !== '') {
|
||||
this.cancel.removeClass("d-none");
|
||||
} else {
|
||||
this.cancel.addClass("d-none");
|
||||
}
|
||||
this.validate();
|
||||
}
|
||||
};
|
||||
|
||||
+27
-4
@@ -51,6 +51,13 @@ SEARCH.prototype = {
|
||||
* @protected
|
||||
*/
|
||||
button: null,
|
||||
/**
|
||||
* The cancel button for the form.
|
||||
* @property button
|
||||
* @type Node
|
||||
* @protected
|
||||
*/
|
||||
cancel: null,
|
||||
/**
|
||||
* The last search node if there is one.
|
||||
* If there is a last search node then the last search term will be persisted between requests.
|
||||
@@ -74,17 +81,28 @@ SEARCH.prototype = {
|
||||
this.button = this.form.all('input[type=submit]');
|
||||
this.lastsearch = this.form.one('input[name=search]');
|
||||
|
||||
var div = Y.Node.create('<div id="capabilitysearchui" data-fieldtype="text"></div>'),
|
||||
label = Y.Node.create('<label for="capabilitysearch">' + this.get('strsearch') + '</label>');
|
||||
this.input = Y.Node.create('<input type="text" id="capabilitysearch" />');
|
||||
var div = Y.Node.create('<div id="capabilitysearchui" class="input-group simplesearchform mb-2"' +
|
||||
'data-fieldtype="text"></div>'),
|
||||
label = Y.Node.create('<label for="capabilitysearch"><span class="sr-only"' +
|
||||
this.get('strsearch') + '</span></label>');
|
||||
this.cancel = Y.Node.create('<a class="btn btn-clear d-none icon-no-margin">' +
|
||||
'<i class="icon fa fa-times fa-fw " aria-hidden="true"></i>' +
|
||||
'</a>');
|
||||
this.input = Y.Node.create('<input type="text" class="form-control withclear" placeholder="' +
|
||||
this.get('strsearch') + '"id="capabilitysearch" />');
|
||||
|
||||
div.append(label).append(this.input);
|
||||
div.append(label).append(this.input).append(this.cancel);
|
||||
|
||||
this.select.insert(div, 'before');
|
||||
|
||||
this.input.on('keyup', this.typed, this);
|
||||
this.select.on('change', this.validate, this);
|
||||
|
||||
this.cancel.on('click', function() {
|
||||
this.input.set('value', '');
|
||||
this.typed();
|
||||
}, this);
|
||||
|
||||
if (this.lastsearch) {
|
||||
this.input.set('value', this.lastsearch.get('value'));
|
||||
this.typed();
|
||||
@@ -131,6 +149,11 @@ SEARCH.prototype = {
|
||||
last.set('selected', true);
|
||||
}
|
||||
}
|
||||
if (search !== '') {
|
||||
this.cancel.removeClass("d-none");
|
||||
} else {
|
||||
this.cancel.addClass("d-none");
|
||||
}
|
||||
this.validate();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -189,12 +189,7 @@ class cohort_role_assignments_table extends table_sql {
|
||||
FROM {tool_cohortroles} uca
|
||||
JOIN {user} u ON u.id = uca.userid
|
||||
JOIN {cohort} c ON c.id = uca.cohortid";
|
||||
|
||||
// Check if any additional filtering is required.
|
||||
[$sqlwhere, $params] = $this->get_sql_where();
|
||||
if ($sqlwhere) {
|
||||
$sql .= " WHERE {$sqlwhere}";
|
||||
}
|
||||
$params = array();
|
||||
|
||||
// Add order by if needed.
|
||||
if (!$count && $sqlsort = $this->get_sql_sort()) {
|
||||
|
||||
@@ -86,8 +86,8 @@ if ($removeid) {
|
||||
|
||||
$title = get_string('existingcohortroles', 'tool_cohortroles');
|
||||
echo $output->heading($title);
|
||||
|
||||
$table = new tool_cohortroles\output\cohort_role_assignments_table('cohort-role-assignments', $pageurl);
|
||||
$url = new moodle_url('/admin/tool/cohortroles/index.php');
|
||||
$table = new tool_cohortroles\output\cohort_role_assignments_table(uniqid(), $url);
|
||||
echo $table->out(50, true);
|
||||
|
||||
echo $output->spacer();
|
||||
|
||||
@@ -49,7 +49,7 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Setup function- we will create a course and add an assign instance to it.
|
||||
*/
|
||||
protected function setUp() {
|
||||
protected function setUp(): void {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Create some users.
|
||||
@@ -60,9 +60,6 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
|
||||
cohort_add_member($this->cohort->id, $this->userassignover->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException required_capability_exception
|
||||
*/
|
||||
public function test_create_cohort_role_assignment_without_permission() {
|
||||
$this->setUser($this->userassignto);
|
||||
$params = (object) array(
|
||||
@@ -70,12 +67,10 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
|
||||
'roleid' => $this->roleid,
|
||||
'cohortid' => $this->cohort->id
|
||||
);
|
||||
$this->expectException(required_capability_exception::class);
|
||||
api::create_cohort_role_assignment($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException core_competency\invalid_persistent_exception
|
||||
*/
|
||||
public function test_create_cohort_role_assignment_with_invalid_data() {
|
||||
$this->setAdminUser();
|
||||
$params = (object) array(
|
||||
@@ -83,6 +78,7 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
|
||||
'roleid' => -8,
|
||||
'cohortid' => $this->cohort->id
|
||||
);
|
||||
$this->expectException(\core_competency\invalid_persistent_exception::class);
|
||||
api::create_cohort_role_assignment($params);
|
||||
}
|
||||
|
||||
@@ -100,9 +96,6 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
|
||||
$this->assertEquals($result->get('cohortid'), $this->cohort->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException required_capability_exception
|
||||
*/
|
||||
public function test_delete_cohort_role_assignment_without_permission() {
|
||||
$this->setAdminUser();
|
||||
$params = (object) array(
|
||||
@@ -112,12 +105,10 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
|
||||
);
|
||||
$result = api::create_cohort_role_assignment($params);
|
||||
$this->setUser($this->userassignto);
|
||||
$this->expectException(required_capability_exception::class);
|
||||
api::delete_cohort_role_assignment($result->get('id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException dml_missing_record_exception
|
||||
*/
|
||||
public function test_delete_cohort_role_assignment_with_invalid_data() {
|
||||
$this->setAdminUser();
|
||||
$params = (object) array(
|
||||
@@ -126,6 +117,7 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
|
||||
'cohortid' => $this->cohort->id
|
||||
);
|
||||
$result = api::create_cohort_role_assignment($params);
|
||||
$this->expectException(dml_missing_record_exception::class);
|
||||
api::delete_cohort_role_assignment($result->get('id') + 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class tool_cohortroles_privacy_testcase extends \core_privacy\tests\provider_tes
|
||||
/**
|
||||
* Overriding setUp() function to always reset after tests.
|
||||
*/
|
||||
public function setUp() {
|
||||
public function setUp(): void {
|
||||
$this->resetAfterTest(true);
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ class tool_cohortroles_privacy_testcase extends \core_privacy\tests\provider_tes
|
||||
CONTEXT_COURSECAT
|
||||
];
|
||||
// Test the User's contexts equal the system and course category context.
|
||||
$this->assertEquals($expected, $contextlevels, '', 0, 10, true);
|
||||
$this->assertEqualsCanonicalizing($expected, $contextlevels);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2020060900; // Requires this Moodle version.
|
||||
$plugin->version = 2020110900; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2020110300; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_cohortroles'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
$plugin->dependencies = array(
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Creates Formular for customlang file export
|
||||
*
|
||||
* @package tool_customlang
|
||||
* @copyright 2020 Thomas Wedekind <Thomas.Wedekind@univie.ac.at>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_customlang\form;
|
||||
|
||||
use tool_customlang_utils;
|
||||
|
||||
/**
|
||||
* Formular for customlang file export
|
||||
*
|
||||
* @copyright 2020 Thomas Wedekind <Thomas.Wedekind@univie.ac.at>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class export extends \moodleform {
|
||||
|
||||
/**
|
||||
* Add elements to form
|
||||
*/
|
||||
public function definition() {
|
||||
$lng = $this->_customdata['lng'];
|
||||
$mform = $this->_form;
|
||||
|
||||
$langdir = tool_customlang_utils::get_localpack_location($lng);
|
||||
|
||||
// The export button only appears if a local lang is present.
|
||||
if (!check_dir_exists($langdir) || !count(glob("$langdir/*"))) {
|
||||
print_error('nolocallang', 'tool_customlang');
|
||||
}
|
||||
|
||||
$langfiles = scandir($langdir);
|
||||
$fileoptions = [];
|
||||
foreach ($langfiles as $file) {
|
||||
if (substr($file, 0, 1) != '.') {
|
||||
$fileoptions[$file] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
$mform->addElement('hidden', 'lng', $lng);
|
||||
$mform->setType('lng', PARAM_LANG);
|
||||
|
||||
$select = $mform->addElement('select', 'files', get_string('exportfilter', 'tool_customlang'), $fileoptions);
|
||||
$select->setMultiple(true);
|
||||
$mform->addRule('files', get_string('required'), 'required', null, 'client');
|
||||
$mform->setDefault('files', $fileoptions);
|
||||
|
||||
$this->add_action_buttons(true, get_string('export', 'tool_customlang'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Upload a zip of custom lang php files.
|
||||
*
|
||||
* @package tool_customlang
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_customlang\form;
|
||||
|
||||
use tool_customlang\local\importer;
|
||||
|
||||
/**
|
||||
* Upload a zip/php of custom lang php files.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class import extends \moodleform {
|
||||
|
||||
/**
|
||||
* Form definition.
|
||||
*/
|
||||
public function definition() {
|
||||
$mform = $this->_form;
|
||||
$mform->addElement('header', 'settingsheader', get_string('import', 'tool_customlang'));
|
||||
|
||||
$mform->addElement('hidden', 'lng');
|
||||
$mform->setType('lng', PARAM_LANG);
|
||||
$mform->setDefault('lng', $this->_customdata['lng']);
|
||||
|
||||
$filemanageroptions = array(
|
||||
'accepted_types' => array('.php', '.zip'),
|
||||
'maxbytes' => 0,
|
||||
'maxfiles' => 1,
|
||||
'subdirs' => 0
|
||||
);
|
||||
|
||||
$mform->addElement('filepicker', 'pack', get_string('langpack', 'tool_customlang'),
|
||||
null, $filemanageroptions);
|
||||
$mform->addRule('pack', null, 'required');
|
||||
|
||||
$modes = [
|
||||
importer::IMPORTALL => get_string('import_all', 'tool_customlang'),
|
||||
importer::IMPORTUPDATE => get_string('import_update', 'tool_customlang'),
|
||||
importer::IMPORTNEW => get_string('import_new', 'tool_customlang'),
|
||||
];
|
||||
$mform->addElement('select', 'importmode', get_string('import_mode', 'tool_customlang'), $modes);
|
||||
|
||||
$mform->addElement('submit', 'importcustomstrings', get_string('importfile', 'tool_customlang'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Custom lang importer.
|
||||
*
|
||||
* @package tool_customlang
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_customlang\local;
|
||||
|
||||
use tool_customlang\local\mlang\phpparser;
|
||||
use tool_customlang\local\mlang\logstatus;
|
||||
use tool_customlang\local\mlang\langstring;
|
||||
use core\output\notification;
|
||||
use stored_file;
|
||||
use coding_exception;
|
||||
use moodle_exception;
|
||||
use core_component;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class containing tha custom lang importer
|
||||
*
|
||||
* @package tool_customlang
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class importer {
|
||||
|
||||
/** @var int imports will only create new customizations */
|
||||
public const IMPORTNEW = 1;
|
||||
/** @var int imports will only update the current customizations */
|
||||
public const IMPORTUPDATE = 2;
|
||||
/** @var int imports all strings */
|
||||
public const IMPORTALL = 3;
|
||||
|
||||
/**
|
||||
* @var string the language name
|
||||
*/
|
||||
protected $lng;
|
||||
|
||||
/**
|
||||
* @var int the importation mode (new, update, all)
|
||||
*/
|
||||
protected $importmode;
|
||||
|
||||
/**
|
||||
* @var string request folder path
|
||||
*/
|
||||
private $folder;
|
||||
|
||||
/**
|
||||
* @var array import log messages
|
||||
*/
|
||||
private $log;
|
||||
|
||||
/**
|
||||
* Constructor for the importer class.
|
||||
*
|
||||
* @param string $lng the current language to import.
|
||||
* @param int $importmode the import method (IMPORTALL, IMPORTNEW, IMPORTUPDATE).
|
||||
*/
|
||||
public function __construct(string $lng, int $importmode = self::IMPORTALL) {
|
||||
$this->lng = $lng;
|
||||
$this->importmode = $importmode;
|
||||
$this->log = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last parse log.
|
||||
*
|
||||
* @return logstatus[] mlang logstatus with the messages
|
||||
*/
|
||||
public function get_log(): array {
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import customlang files.
|
||||
*
|
||||
* @param stored_file[] $files array of files to import
|
||||
*/
|
||||
public function import(array $files): void {
|
||||
// Create a temporal folder to store the files.
|
||||
$this->folder = make_request_directory(false);
|
||||
|
||||
$langfiles = $this->deploy_files($files);
|
||||
|
||||
$this->process_files($langfiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy all files into a request folder.
|
||||
*
|
||||
* @param stored_file[] $files array of files to deploy
|
||||
* @return string[] of file paths
|
||||
*/
|
||||
private function deploy_files(array $files): array {
|
||||
$result = [];
|
||||
// Desploy all files.
|
||||
foreach ($files as $file) {
|
||||
if ($file->get_mimetype() == 'application/zip') {
|
||||
$result = array_merge($result, $this->unzip_file($file));
|
||||
} else {
|
||||
$path = $this->folder.'/'.$file->get_filename();
|
||||
$file->copy_content_to($path);
|
||||
$result = array_merge($result, [$path]);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unzip a file into the request folder.
|
||||
*
|
||||
* @param stored_file $file the zip file to unzip
|
||||
* @return string[] of zip content paths
|
||||
*/
|
||||
private function unzip_file(stored_file $file): array {
|
||||
$fp = get_file_packer('application/zip');
|
||||
$zipcontents = $fp->extract_to_pathname($file, $this->folder);
|
||||
if (!$zipcontents) {
|
||||
throw new moodle_exception("Error Unzipping file", 1);
|
||||
}
|
||||
$result = [];
|
||||
foreach ($zipcontents as $contentname => $success) {
|
||||
if ($success) {
|
||||
$result[] = $this->folder.'/'.$contentname;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import strings from a list of langfiles.
|
||||
*
|
||||
* @param string[] $langfiles an array with file paths
|
||||
*/
|
||||
private function process_files(array $langfiles): void {
|
||||
$parser = phpparser::get_instance();
|
||||
foreach ($langfiles as $filepath) {
|
||||
$component = $this->component_from_filepath($filepath);
|
||||
if ($component) {
|
||||
$strings = $parser->parse(file_get_contents($filepath));
|
||||
$this->import_strings($strings, $component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get the component from a filepath.
|
||||
*
|
||||
* @param string $filepath the filepath
|
||||
* @return stdCalss|null the DB record of that component
|
||||
*/
|
||||
private function component_from_filepath(string $filepath) {
|
||||
global $DB;
|
||||
|
||||
// Get component from filename.
|
||||
$pathparts = pathinfo($filepath);
|
||||
if (empty($pathparts['filename'])) {
|
||||
throw new coding_exception("Cannot get filename from $filepath", 1);
|
||||
}
|
||||
$filename = $pathparts['filename'];
|
||||
|
||||
$normalized = core_component::normalize_component($filename);
|
||||
if (count($normalized) == 1 || empty($normalized[1])) {
|
||||
$componentname = $normalized[0];
|
||||
} else {
|
||||
$componentname = implode('_', $normalized);
|
||||
}
|
||||
|
||||
$result = $DB->get_record('tool_customlang_components', ['name' => $componentname]);
|
||||
|
||||
if (!$result) {
|
||||
$this->log[] = new logstatus('notice_missingcomponent', notification::NOTIFY_ERROR, null, $componentname);
|
||||
return null;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import an array of strings into the customlang tables.
|
||||
*
|
||||
* @param langstring[] $strings the langstring to set
|
||||
* @param stdClass $component the target component
|
||||
*/
|
||||
private function import_strings(array $strings, stdClass $component): void {
|
||||
global $DB;
|
||||
|
||||
foreach ($strings as $newstring) {
|
||||
// Check current DB entry.
|
||||
$customlang = $DB->get_record('tool_customlang', [
|
||||
'componentid' => $component->id,
|
||||
'stringid' => $newstring->id,
|
||||
'lang' => $this->lng,
|
||||
]);
|
||||
if (!$customlang) {
|
||||
$customlang = null;
|
||||
}
|
||||
|
||||
if ($this->can_save_string($customlang, $newstring, $component)) {
|
||||
$customlang->local = $newstring->text;
|
||||
$customlang->timecustomized = $newstring->timemodified;
|
||||
$customlang->outdated = 0;
|
||||
$customlang->modified = 1;
|
||||
$DB->update_record('tool_customlang', $customlang);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a specific string can be saved based on the current importmode.
|
||||
*
|
||||
* @param stdClass $customlang customlang original record
|
||||
* @param langstring $newstring the new strign to store
|
||||
* @param stdClass $component the component target
|
||||
* @return bool if the string can be stored
|
||||
*/
|
||||
private function can_save_string(?stdClass $customlang, langstring $newstring, stdClass $component): bool {
|
||||
$result = false;
|
||||
$message = 'notice_success';
|
||||
if (empty($customlang)) {
|
||||
$message = 'notice_inexitentstring';
|
||||
$this->log[] = new logstatus($message, notification::NOTIFY_ERROR, null, $component->name, $newstring);
|
||||
return $result;
|
||||
}
|
||||
|
||||
switch ($this->importmode) {
|
||||
case self::IMPORTNEW:
|
||||
$result = empty($customlang->local);
|
||||
$warningmessage = 'notice_ignoreupdate';
|
||||
break;
|
||||
case self::IMPORTUPDATE:
|
||||
$result = !empty($customlang->local);
|
||||
$warningmessage = 'notice_ignorenew';
|
||||
break;
|
||||
case self::IMPORTALL:
|
||||
$result = true;
|
||||
break;
|
||||
}
|
||||
if ($result) {
|
||||
$errorlevel = notification::NOTIFY_SUCCESS;
|
||||
} else {
|
||||
$errorlevel = notification::NOTIFY_ERROR;
|
||||
$message = $warningmessage;
|
||||
}
|
||||
$this->log[] = new logstatus($message, $errorlevel, null, $component->name, $newstring);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Language string based on David Mudrak langstring from local_amos.
|
||||
*
|
||||
* @package tool_customlang
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_customlang\local\mlang;
|
||||
|
||||
use moodle_exception;
|
||||
use stdclass;
|
||||
|
||||
/**
|
||||
* Class containing a lang string cleaned.
|
||||
*
|
||||
* @package tool_customlang
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a single string
|
||||
*/
|
||||
class langstring {
|
||||
|
||||
/** @var string identifier */
|
||||
public $id = null;
|
||||
|
||||
/** @var string */
|
||||
public $text = '';
|
||||
|
||||
/** @var int the time stamp when this string was saved */
|
||||
public $timemodified = null;
|
||||
|
||||
/** @var bool is deleted */
|
||||
public $deleted = false;
|
||||
|
||||
/** @var stdclass extra information about the string */
|
||||
public $extra = null;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param string $id string identifier
|
||||
* @param string $text string text
|
||||
* @param int $timemodified
|
||||
* @param int $deleted
|
||||
* @param stdclass $extra
|
||||
*/
|
||||
public function __construct(string $id, string $text = '', int $timemodified = null,
|
||||
int $deleted = 0, stdclass $extra = null) {
|
||||
|
||||
if (is_null($timemodified)) {
|
||||
$timemodified = time();
|
||||
}
|
||||
$this->id = $id;
|
||||
$this->text = $text;
|
||||
$this->timemodified = $timemodified;
|
||||
$this->deleted = $deleted;
|
||||
$this->extra = $extra;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a string text, returns it being formatted properly for storing in AMOS repository.
|
||||
*
|
||||
* Note: This method is taken directly from local_amos as it is highly tested and robust.
|
||||
* The Moodle 1.x part is keep on puspose to make it easier the copy paste from both codes.
|
||||
* This could change in the future when AMOS stop suporting the 1.x langstrings.
|
||||
*
|
||||
* We need to know for what branch the string should be prepared due to internal changes in
|
||||
* format required by get_string()
|
||||
* - for get_string() in Moodle 1.6 - 1.9 use $format == 1
|
||||
* - for get_string() in Moodle 2.0 and higher use $format == 2
|
||||
*
|
||||
* Typical usages of this methods:
|
||||
* $t = langstring::fix_syntax($t); // sanity new translations of 2.x strings
|
||||
* $t = langstring::fix_syntax($t, 1); // sanity legacy 1.x strings
|
||||
* $t = langstring::fix_syntax($t, 2, 1); // convert format of 1.x strings into 2.x
|
||||
*
|
||||
* Backward converting 2.x format into 1.x is not supported
|
||||
*
|
||||
* @param string $text string text to be fixed
|
||||
* @param int $format target get_string() format version
|
||||
* @param int $from which format version does the text come from, defaults to the same as $format
|
||||
* @return string
|
||||
*/
|
||||
public static function fix_syntax(string $text, int $format = 2, ?int $from = null): string {
|
||||
if (is_null($from)) {
|
||||
$from = $format;
|
||||
}
|
||||
|
||||
// Common filter.
|
||||
$clean = trim($text);
|
||||
$search = [
|
||||
// Remove \r if it is part of \r\n.
|
||||
'/\r(?=\n)/',
|
||||
|
||||
// Control characters to be replaced with \n
|
||||
// LINE TABULATION, FORM FEED, CARRIAGE RETURN, END OF TRANSMISSION BLOCK,
|
||||
// END OF MEDIUM, SUBSTITUTE, BREAK PERMITTED HERE, NEXT LINE, START OF STRING,
|
||||
// STRING TERMINATOR and Unicode character categorys Zl and Zp.
|
||||
'/[\x{0B}-\r\x{17}\x{19}\x{1A}\x{82}\x{85}\x{98}\x{9C}\p{Zl}\p{Zp}]/u',
|
||||
|
||||
// Control characters to be removed
|
||||
// NULL, ENQUIRY, ACKNOWLEDGE, BELL, SHIFT {OUT,IN}, DATA LINK ESCAPE,
|
||||
// DEVICE CONTROL {ONE,TWO,THREE,FOUR}, NEGATIVE ACKNOWLEDGE, SYNCHRONOUS IDLE, ESCAPE,
|
||||
// DELETE, PADDING CHARACTER, HIGH OCTET PRESET, NO BREAK HERE, INDEX,
|
||||
// {START,END} OF SELECTED AREA, CHARACTER TABULATION {SET,WITH JUSTIFICATION},
|
||||
// LINE TABULATION SET, PARTIAL LINE {FORWARD,BACKWARD}, REVERSE LINE FEED,
|
||||
// SINGLE SHIFT {TWO,THREE}, DEVICE CONTROL STRING, PRIVATE USE {ONE,TWO},
|
||||
// SET TRANSMIT STATE, MESSAGE WAITING, {START,END} OF GUARDED AREA,
|
||||
// {SINGLE {GRAPHIC,} CHARACTER,CONTROL SEQUENCE} INTRODUCER, OPERATING SYSTEM COMMAND,
|
||||
// PRIVACY MESSAGE, APPLICATION PROGRAM COMMAND, ZERO WIDTH {,NO-BREAK} SPACE,
|
||||
// REPLACEMENT CHARACTER.
|
||||
'/[\0\x{05}-\x{07}\x{0E}-\x{16}\x{1B}\x{7F}\x{80}\x{81}\x{83}\x{84}\x{86}-\x{93}\x{95}-\x{97}\x{99}-\x{9B}\x{9D}-\x{9F}\x{200B}\x{FEFF}\x{FFFD}]++/u',
|
||||
|
||||
// Remove trailing whitespace at the end of lines in a multiline string.
|
||||
'/[ \t]+(?=\n)/',
|
||||
];
|
||||
$replace = [
|
||||
'',
|
||||
"\n",
|
||||
'',
|
||||
'',
|
||||
];
|
||||
$clean = preg_replace($search, $replace, $clean);
|
||||
|
||||
if (($format === 2) && ($from === 2)) {
|
||||
// Sanity translations of 2.x strings.
|
||||
$clean = preg_replace("/\n{3,}/", "\n\n\n", $clean); // Collapse runs of blank lines.
|
||||
|
||||
} else if (($format === 2) && ($from === 1)) {
|
||||
// Convert 1.x string into 2.x format.
|
||||
$clean = preg_replace("/\n{3,}/", "\n\n\n", $clean); // Collapse runs of blank lines.
|
||||
$clean = preg_replace('/%+/', '%', $clean); // Collapse % characters.
|
||||
$clean = str_replace('\$', '@@@___XXX_ESCAPED_DOLLAR__@@@', $clean); // Remember for later.
|
||||
$clean = str_replace("\\", '', $clean); // Delete all slashes.
|
||||
$clean = preg_replace('/(^|[^{])\$a\b(\->[a-zA-Z0-9_]+)?/', '\\1{$a\\2}', $clean); // Wrap placeholders.
|
||||
$clean = str_replace('@@@___XXX_ESCAPED_DOLLAR__@@@', '$', $clean);
|
||||
$clean = str_replace('$', '$', $clean);
|
||||
|
||||
} else if (($format === 1) && ($from === 1)) {
|
||||
// Sanity legacy 1.x strings.
|
||||
$clean = preg_replace("/\n{3,}/", "\n\n", $clean); // Collapse runs of blank lines.
|
||||
$clean = str_replace('\$', '@@@___XXX_ESCAPED_DOLLAR__@@@', $clean);
|
||||
$clean = str_replace("\\", '', $clean); // Delete all slashes.
|
||||
$clean = str_replace('$', '\$', $clean); // Escape all embedded variables.
|
||||
// Unescape placeholders: only $a and $a->something are allowed. All other $variables are left escaped.
|
||||
$clean = preg_replace('/\\\\\$a\b(\->[a-zA-Z0-9_]+)?/', '$a\\1', $clean); // Unescape placeholders.
|
||||
$clean = str_replace('@@@___XXX_ESCAPED_DOLLAR__@@@', '\$', $clean);
|
||||
$clean = str_replace('"', "\\\"", $clean); // Add slashes for ".
|
||||
$clean = preg_replace('/%+/', '%', $clean); // Collapse % characters.
|
||||
$clean = str_replace('%', '%%', $clean); // Duplicate %.
|
||||
|
||||
} else {
|
||||
throw new moodle_exception('Unknown get_string() format version');
|
||||
}
|
||||
return $clean;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Language string based on David Mudrak langstring from local_amos.
|
||||
*
|
||||
* @package tool_customlang
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_customlang\local\mlang;
|
||||
|
||||
use moodle_exception;
|
||||
use stdclass;
|
||||
|
||||
/**
|
||||
* Class containing a lang string cleaned.
|
||||
*
|
||||
* @package tool_customlang
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a single string
|
||||
*/
|
||||
class logstatus {
|
||||
|
||||
/** @var langstring the current string */
|
||||
public $langstring = null;
|
||||
|
||||
/** @var string the component */
|
||||
public $component = null;
|
||||
|
||||
/** @var string the string ID */
|
||||
public $stringid = null;
|
||||
|
||||
/** @var string the original filename */
|
||||
public $filename = null;
|
||||
|
||||
/** @var int the error level */
|
||||
public $errorlevel = null;
|
||||
|
||||
/** @var string the message identifier */
|
||||
private $message;
|
||||
|
||||
/**
|
||||
* Class creator.
|
||||
*
|
||||
* @param string $message the message identifier to display
|
||||
* @param string $errorlevel the notice level
|
||||
* @param string|null $filename the filename of this log
|
||||
* @param string|null $component the component of this log
|
||||
* @param langstring|null $langstring the langstring of this log
|
||||
*/
|
||||
public function __construct(string $message, string $errorlevel, ?string $filename = null,
|
||||
?string $component = null, ?langstring $langstring = null) {
|
||||
|
||||
$this->filename = $filename;
|
||||
$this->component = $component;
|
||||
$this->langstring = $langstring;
|
||||
$this->message = $message;
|
||||
$this->errorlevel = $errorlevel;
|
||||
|
||||
if ($langstring) {
|
||||
$this->stringid = $langstring->id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the log message.
|
||||
*
|
||||
* @return string the log message.
|
||||
*/
|
||||
public function get_message(): string {
|
||||
return get_string($this->message, 'tool_customlang', $this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Mlang PHP based on David Mudrak phpparser for local_amos.
|
||||
*
|
||||
* @package tool_customlang
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_customlang\local\mlang;
|
||||
|
||||
use coding_exception;
|
||||
use moodle_exception;
|
||||
|
||||
/**
|
||||
* Parser of Moodle strings defined as associative array.
|
||||
*
|
||||
* Moodle core just includes this file format directly as normal PHP code. However
|
||||
* for security reasons, we must not do this for files uploaded by anonymous users.
|
||||
* This parser reconstructs the associative $string array without actually including
|
||||
* the file.
|
||||
*/
|
||||
class phpparser {
|
||||
|
||||
/** @var holds the singleton instance of self */
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Prevents direct creation of object
|
||||
*/
|
||||
private function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent from cloning the instance
|
||||
*/
|
||||
public function __clone() {
|
||||
throw new coding_exception('Cloning os singleton is not allowed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton instance fo this class
|
||||
*
|
||||
* @return phpparser singleton instance of phpparser
|
||||
*/
|
||||
public static function get_instance(): phpparser {
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new phpparser();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given data in Moodle PHP string format
|
||||
*
|
||||
* Note: This method is adapted from local_amos as it is highly tested and robust.
|
||||
* The priority is keeping it similar to the original one to make it easier to mantain.
|
||||
*
|
||||
* @param string $data definition of the associative array
|
||||
* @param int $format the data format on the input, defaults to the one used since 2.0
|
||||
* @return langstring[] array of langstrings of this file
|
||||
*/
|
||||
public function parse(string $data, int $format = 2): array {
|
||||
$result = [];
|
||||
$strings = $this->extract_strings($data);
|
||||
foreach ($strings as $id => $text) {
|
||||
$cleaned = clean_param($id, PARAM_STRINGID);
|
||||
if ($cleaned !== $id) {
|
||||
continue;
|
||||
}
|
||||
$text = langstring::fix_syntax($text, 2, $format);
|
||||
$result[] = new langstring($id, $text);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Low level parsing method
|
||||
*
|
||||
* Note: This method is adapted from local_amos as it is highly tested and robust.
|
||||
* The priority is keeping it similar to the original one to make it easier to mantain.
|
||||
*
|
||||
* @param string $data
|
||||
* @return string[] the data strings
|
||||
*/
|
||||
protected function extract_strings(string $data): array {
|
||||
|
||||
$strings = []; // To be returned.
|
||||
|
||||
if (empty($data)) {
|
||||
return $strings;
|
||||
}
|
||||
|
||||
// Tokenize data - we expect valid PHP code.
|
||||
$tokens = token_get_all($data);
|
||||
|
||||
// Get rid of all non-relevant tokens.
|
||||
$rubbish = [T_WHITESPACE, T_INLINE_HTML, T_COMMENT, T_DOC_COMMENT, T_OPEN_TAG, T_CLOSE_TAG];
|
||||
foreach ($tokens as $i => $token) {
|
||||
if (is_array($token)) {
|
||||
if (in_array($token[0], $rubbish)) {
|
||||
unset($tokens[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$id = null;
|
||||
$text = null;
|
||||
$line = 0;
|
||||
$expect = 'STRING_VAR'; // The first expected token is '$string'.
|
||||
|
||||
// Iterate over tokens and look for valid $string array assignment patterns.
|
||||
foreach ($tokens as $token) {
|
||||
$foundtype = null;
|
||||
$founddata = null;
|
||||
if (is_array($token)) {
|
||||
$foundtype = $token[0];
|
||||
$founddata = $token[1];
|
||||
if (!empty($token[2])) {
|
||||
$line = $token[2];
|
||||
}
|
||||
|
||||
} else {
|
||||
$foundtype = 'char';
|
||||
$founddata = $token;
|
||||
}
|
||||
|
||||
if ($expect == 'STRING_VAR') {
|
||||
if ($foundtype === T_VARIABLE and $founddata === '$string') {
|
||||
$expect = 'LEFT_BRACKET';
|
||||
continue;
|
||||
} else {
|
||||
// Allow other code at the global level.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($expect == 'LEFT_BRACKET') {
|
||||
if ($foundtype === 'char' and $founddata === '[') {
|
||||
$expect = 'STRING_ID';
|
||||
continue;
|
||||
} else {
|
||||
throw new moodle_exception('Parsing error. Expected character [ at line '.$line);
|
||||
}
|
||||
}
|
||||
|
||||
if ($expect == 'STRING_ID') {
|
||||
if ($foundtype === T_CONSTANT_ENCAPSED_STRING) {
|
||||
$id = $this->decapsulate($founddata);
|
||||
$expect = 'RIGHT_BRACKET';
|
||||
continue;
|
||||
} else {
|
||||
throw new moodle_exception('Parsing error. Expected T_CONSTANT_ENCAPSED_STRING array key at line '.$line);
|
||||
}
|
||||
}
|
||||
|
||||
if ($expect == 'RIGHT_BRACKET') {
|
||||
if ($foundtype === 'char' and $founddata === ']') {
|
||||
$expect = 'ASSIGNMENT';
|
||||
continue;
|
||||
} else {
|
||||
throw new moodle_exception('Parsing error. Expected character ] at line '.$line);
|
||||
}
|
||||
}
|
||||
|
||||
if ($expect == 'ASSIGNMENT') {
|
||||
if ($foundtype === 'char' and $founddata === '=') {
|
||||
$expect = 'STRING_TEXT';
|
||||
continue;
|
||||
} else {
|
||||
throw new moodle_exception('Parsing error. Expected character = at line '.$line);
|
||||
}
|
||||
}
|
||||
|
||||
if ($expect == 'STRING_TEXT') {
|
||||
if ($foundtype === T_CONSTANT_ENCAPSED_STRING) {
|
||||
$text = $this->decapsulate($founddata);
|
||||
$expect = 'SEMICOLON';
|
||||
continue;
|
||||
} else {
|
||||
throw new moodle_exception(
|
||||
'Parsing error. Expected T_CONSTANT_ENCAPSED_STRING array item value at line '.$line
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($expect == 'SEMICOLON') {
|
||||
if (is_null($id) or is_null($text)) {
|
||||
throw new moodle_exception('Parsing error. NULL string id or value at line '.$line);
|
||||
}
|
||||
if ($foundtype === 'char' and $founddata === ';') {
|
||||
if (!empty($id)) {
|
||||
$strings[$id] = $text;
|
||||
}
|
||||
$id = null;
|
||||
$text = null;
|
||||
$expect = 'STRING_VAR';
|
||||
continue;
|
||||
} else {
|
||||
throw new moodle_exception('Parsing error. Expected character ; at line '.$line);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one T_CONSTANT_ENCAPSED_STRING, return its value without quotes
|
||||
*
|
||||
* Also processes escaped quotes inside the text.
|
||||
*
|
||||
* Note: This method is taken directly from local_amos as it is highly tested and robust.
|
||||
*
|
||||
* @param string $text value obtained by token_get_all()
|
||||
* @return string value without quotes
|
||||
*/
|
||||
protected function decapsulate(string $text): string {
|
||||
|
||||
if (strlen($text) < 2) {
|
||||
throw new moodle_exception('Parsing error. Expected T_CONSTANT_ENCAPSED_STRING in decapsulate()');
|
||||
}
|
||||
|
||||
if (substr($text, 0, 1) == "'" and substr($text, -1) == "'") {
|
||||
// Single quoted string.
|
||||
$text = trim($text, "'");
|
||||
$text = str_replace("\'", "'", $text);
|
||||
$text = str_replace('\\\\', '\\', $text);
|
||||
return $text;
|
||||
|
||||
} else if (substr($text, 0, 1) == '"' and substr($text, -1) == '"') {
|
||||
// Double quoted string.
|
||||
$text = trim($text, '"');
|
||||
$text = str_replace('\"', '"', $text);
|
||||
$text = str_replace('\\\\', '\\', $text);
|
||||
return $text;
|
||||
|
||||
} else {
|
||||
throw new moodle_exception(
|
||||
'Parsing error. Unexpected quotation in T_CONSTANT_ENCAPSED_STRING in decapsulate(): '.$text
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user