Compare commits
598 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 86716dc120 | |||
| 3a1b615718 | |||
| 54a8516cd2 | |||
| 628e7ecc4c | |||
| 7762fc61e8 | |||
| 3ffafd9232 | |||
| 7c82e1206d | |||
| 0152978745 | |||
| 2302bb7e2b | |||
| d1ccb8702c | |||
| 4cb1509e35 | |||
| f764c332e7 | |||
| 467a28d921 | |||
| 3e4c1c959f | |||
| 69d235426a | |||
| bbb8622464 | |||
| 7311dff041 | |||
| 8f2f95bd28 | |||
| 579a5061ef | |||
| 2ff0e12b24 | |||
| 3f163e8330 | |||
| f5ada5cb0b | |||
| 63b2ceee5f | |||
| ee9d740ccf | |||
| 13c201fbc7 | |||
| b9fd956e73 | |||
| 2f216f5bdb | |||
| fcebf9b8a6 | |||
| 7ace11d396 | |||
| ad377e3085 | |||
| 9b65beb7ed | |||
| 4afd2390e2 | |||
| 184aa8d8ca | |||
| 9e1916ba09 | |||
| 7d01008384 | |||
| 4ca230b174 | |||
| 07e0b64822 | |||
| 9acc242e13 | |||
| fbdd721f0b | |||
| 66ae31ecb5 | |||
| 43b30054ef | |||
| 066edbb11b | |||
| 0076a8fe5c | |||
| 534cf6e3d4 | |||
| 771f183646 | |||
| 348efc1495 | |||
| 7b9191508f | |||
| 67f08a792f | |||
| 36a5a2d4d1 | |||
| 52818283fe | |||
| 053aa290b2 | |||
| 1b1a661a03 | |||
| ad3e6363f1 | |||
| 2627f5ba2c | |||
| 223948bf93 | |||
| 6b5485a0b0 | |||
| b16e808764 | |||
| 76ff7600e4 | |||
| a2ddc55f69 | |||
| cc6b3c161f | |||
| 18e5768332 | |||
| fe3ff7dd69 | |||
| 816fadfcd7 | |||
| b136e428d0 | |||
| f02437f915 | |||
| de6c7d2975 | |||
| 7fe281cc45 | |||
| a410d35ef4 | |||
| f16b42d013 | |||
| c26e73fc9f | |||
| 752c0c77f8 | |||
| b49d7c974f | |||
| 1773a1926d | |||
| 0d056137bb | |||
| 6822ab321b | |||
| d8f055240a | |||
| 7527ca4c49 | |||
| e6023839c9 | |||
| 2cf4f88b52 | |||
| 08be365c2c | |||
| 5c13475743 | |||
| a2524d8caf | |||
| aec53e3547 | |||
| a272c2289f | |||
| 055d5cb3b0 | |||
| 3d7b5d51b9 | |||
| 6109f4dfd4 | |||
| 57791ecd61 | |||
| 3f83ea2456 | |||
| 471838be7b | |||
| dfb2be423b | |||
| b554580520 | |||
| b1bb5671df | |||
| cd5d14d73b | |||
| 98a58ef44c | |||
| 95646071ae | |||
| 29d68c07af | |||
| 773bfa9272 | |||
| 2995721139 | |||
| 6488fc6a20 | |||
| 8c678d2b9a | |||
| cedb8a92cb | |||
| 402153c46e | |||
| 8337ef3be5 | |||
| ecf396842f | |||
| bde37edf3c | |||
| b7ebcf7e2c | |||
| 47a38fd827 | |||
| 3089485e57 | |||
| 15a9f6f119 | |||
| dbd62ed4ea | |||
| 2dc6ab3567 | |||
| 8e31874a3a | |||
| f48edc0cd1 | |||
| b2bfd0dcad | |||
| 94ad185d09 | |||
| f0dae38957 | |||
| 9390787a34 | |||
| e302d0d902 | |||
| 2f04edf37f | |||
| ded87e8d92 | |||
| 8ddb933f5c | |||
| d09a390a05 | |||
| e31d7bdb81 | |||
| 246ad70ba9 | |||
| 3f40af87e4 | |||
| a4a654348d | |||
| ed48b54542 | |||
| d8dbfe5d25 | |||
| 9dd88a4988 | |||
| 358386e4f4 | |||
| 6724e13007 | |||
| 56276d997f | |||
| ca345f8853 | |||
| b372929c9b | |||
| 559db765b3 | |||
| 6179d2ba24 | |||
| ba18db3c7c | |||
| 61b5850a8c | |||
| 24f85416a7 | |||
| 69ce4b683d | |||
| f7ea9dd9cc | |||
| bce9cfdfd5 | |||
| 9ed81d3a8a | |||
| 077465cf90 | |||
| c7b9f2980e | |||
| 2524184384 | |||
| 0a6b4bb15c | |||
| 99f9513b05 | |||
| 8974392cfa | |||
| 8ad9114050 | |||
| 5bda7cac35 | |||
| 13ef307253 | |||
| 0577c54bc0 | |||
| cac02a15b6 | |||
| a979e0ce97 | |||
| cad097a605 | |||
| 40b918348c | |||
| 1184d3c20f | |||
| 711a9c0df5 | |||
| e9b513d561 | |||
| d8e0799023 | |||
| 33fa895d25 | |||
| 93ce6e33d9 | |||
| 4018e95a55 | |||
| 9667e96d89 | |||
| a919969ae7 | |||
| 71f3a87583 | |||
| a09ecad620 | |||
| e0d1d8e469 | |||
| d3070236ac | |||
| 8d77dd09b8 | |||
| 1ea9832c3e | |||
| 9eee64d0d5 | |||
| 46f1b71c20 | |||
| 2ee8296efc | |||
| e2a7040d94 | |||
| 06798fb898 | |||
| 8737f16faa | |||
| 776319ac8e | |||
| 76f66df235 | |||
| 4b302063c3 | |||
| ad4736b5ec | |||
| 6637197d97 | |||
| dd115e572a | |||
| 663eed6780 | |||
| 883f98a3f2 | |||
| 0562c4d552 | |||
| 15409cfa41 | |||
| 116eef7a25 | |||
| 686d9cfd4c | |||
| dec259a249 | |||
| f92753a3d8 | |||
| 3d5fa73133 | |||
| e4989b529a | |||
| f7b2fb473b | |||
| dc7da1a416 | |||
| c819926529 | |||
| d20f1024d8 | |||
| 07c200438c | |||
| e146a9d8cd | |||
| ef964137ce | |||
| 650474c0a7 | |||
| 6bc193134a | |||
| 9dbbd31076 | |||
| 8317aa9b32 | |||
| 1944b58bd6 | |||
| 512670fe94 | |||
| fc93938f23 | |||
| 7d158f18d9 | |||
| c22b7c2f82 | |||
| 8fa9f27c7e | |||
| 91e083981d | |||
| 06ebac56c6 | |||
| 9d9e03ef10 | |||
| 05fdc29294 | |||
| 38708efb50 | |||
| 39ffe174e7 | |||
| fa23ae702c | |||
| 2d9a6fa760 | |||
| 1652b5281e | |||
| d8e3c31b32 | |||
| a985ac2e0c | |||
| ec5d7c3227 | |||
| ccae21a639 | |||
| 345d483ee2 | |||
| 4d9b533fd4 | |||
| 174fc341d6 | |||
| bcbab5517b | |||
| 0848bf8687 | |||
| 11e0579540 | |||
| cc9a537bd2 | |||
| 38909cd64e | |||
| 62aa37f70d | |||
| f6e7eb2ebd | |||
| c0fefd0a4d | |||
| b5599f33d0 | |||
| 5e1588ba63 | |||
| 50618adb13 | |||
| 1c023e7fbb | |||
| c6d8aca226 | |||
| c4c514ee46 | |||
| 6c956d3408 | |||
| 052e646cdc | |||
| f1166fe9e6 | |||
| 0d45970bd3 | |||
| d160890cab | |||
| d6fdd2f5f9 | |||
| d188d58ce9 | |||
| 1f602aabec | |||
| 0257e1696f | |||
| 891b6f796c | |||
| 9fbdf21341 | |||
| 7e39cee0f6 | |||
| 82488f901d | |||
| 7744cf2f28 | |||
| e7263580b9 | |||
| a74443a342 | |||
| 7ff2d18b93 | |||
| 66ff0a871f | |||
| 11fe89c08e | |||
| 76bd425474 | |||
| aeeaea6840 | |||
| 5c30074d99 | |||
| 8e53ef0162 | |||
| 2a2d3c85bb | |||
| 805577664b | |||
| b0a7bc3f42 | |||
| fcd50e4722 | |||
| cf9373c4dd | |||
| 52ada82da2 | |||
| fca2456e1f | |||
| 70a83735f3 | |||
| a067663a63 | |||
| a55e18fb81 | |||
| bd18e026bb | |||
| c15cb5586c | |||
| fce36ecf4f | |||
| 8f8c4e3153 | |||
| 369c5407ab | |||
| 04db4a3e54 | |||
| 23466dd6d1 | |||
| 74b62601d0 | |||
| f428d58df6 | |||
| 6f2fa6011e | |||
| e2452a4b3c | |||
| fc26693229 | |||
| 1eda3a392b | |||
| c3c18bbb20 | |||
| c25092b232 | |||
| a7bdd7a007 | |||
| 99f4f6894f | |||
| 848fd484d5 | |||
| 0839431f16 | |||
| cf98238fdf | |||
| 925c36fb1d | |||
| d78dda7754 | |||
| 2f6519d2de | |||
| ff7530e1d6 | |||
| fbcb5793c3 | |||
| 109879a2a1 | |||
| a0d2e40b4d | |||
| 15c7909885 | |||
| c29a812323 | |||
| 8d65efee7c | |||
| 35312efbf9 | |||
| 96e62487e7 | |||
| b342562457 | |||
| 803df36ce0 | |||
| b3ea1a9d5b | |||
| fb311f1eae | |||
| 0b28c6a254 | |||
| f9432283a9 | |||
| 0c4dc597d7 | |||
| adc138d1f1 | |||
| aff1f3a400 | |||
| 74d66468cb | |||
| 3b31c13678 | |||
| d4c9c36fcd | |||
| 5299097da9 | |||
| 8dad07455d | |||
| c5707a934d | |||
| 6bc7b8e8be | |||
| 8894b1eb42 | |||
| f0c0dbbb06 | |||
| 8e5eda32fe | |||
| 20e40c3882 | |||
| 7127744f39 | |||
| 5d902db0d1 | |||
| fbb6717550 | |||
| ae0cdf3b67 | |||
| a76f40c81b | |||
| 4f8a492374 | |||
| 68a2dd57ef | |||
| c841064432 | |||
| f82ca155ac | |||
| b660e6979a | |||
| ebf12946d6 | |||
| 0195ecbf78 | |||
| 98381d5ab7 | |||
| 00bd11b539 | |||
| 54d446ce43 | |||
| e8d14cde9a | |||
| ccbb3ce62d | |||
| 4f620f537e | |||
| ff0b12cfd3 | |||
| 6988b5b328 | |||
| 282523b96a | |||
| d77a46c804 | |||
| 3b6acb99bd | |||
| 04461bed1c | |||
| 0717d4ea0e | |||
| 9e62b27d12 | |||
| 3c7c965a80 | |||
| 3dc7b4b927 | |||
| 24a5b078f7 | |||
| cee1103bec | |||
| 98419ad77a | |||
| 7e6930f5b9 | |||
| b8f45d20fd | |||
| 8e931f2073 | |||
| 285b364a1e | |||
| 2a2edcde93 | |||
| ce1f9ec96a | |||
| 3720396bb4 | |||
| 47941cb17a | |||
| 880e7e7298 | |||
| 8ebf873b65 | |||
| 0a09e482e4 | |||
| e6b80e155b | |||
| e42eeb62b0 | |||
| a5f1d86040 | |||
| c0ec027149 | |||
| 02e7ab212a | |||
| 312f80d1d7 | |||
| 767e147dac | |||
| c2e501e144 | |||
| 978fb4f1fe | |||
| 748814dc61 | |||
| f6f0787fc8 | |||
| 00d7ed9518 | |||
| cdb81ef363 | |||
| 8a72397e0a | |||
| a3ddbca835 | |||
| f154d35e13 | |||
| 5058c46813 | |||
| aea590716a | |||
| 5d23cfe21f | |||
| 05c1fb3794 | |||
| 0f4b831249 | |||
| 721b02a270 | |||
| e8e5b279b0 | |||
| b0a931b48a | |||
| 35e8d7517f | |||
| 007988a5f2 | |||
| 9b6ed477f8 | |||
| 94efef85bb | |||
| 89e853437b | |||
| 6664d3ebe6 | |||
| d7cae15e57 | |||
| 49393a1608 | |||
| 143a3bf38b | |||
| 5c9a0a80fc | |||
| d1bc94905e | |||
| fb8885a56e | |||
| 0c239cb841 | |||
| f8d8553da6 | |||
| b952716548 | |||
| c9c629dcf7 | |||
| d7834ce7c3 | |||
| 426e4043a4 | |||
| c28639acd9 | |||
| a164c6b5f8 | |||
| 54271fa749 | |||
| 6e0210764a | |||
| c72cd82baf | |||
| 11867ee8eb | |||
| 35209a1d79 | |||
| fe07a2032c | |||
| 57a1df54e1 | |||
| 0ef9be6004 | |||
| 51655f3485 | |||
| bf9a2f43ad | |||
| e3bf7ce603 | |||
| 633d64262d | |||
| ba4393023f | |||
| 608c5044ae | |||
| d46c7851ca | |||
| b3b813c610 | |||
| a2628c3345 | |||
| 3fddb9017e | |||
| 4d2d641d0c | |||
| a779a64656 | |||
| dadf19ad3f | |||
| b1abcd1f42 | |||
| 192210f90e | |||
| 48d0cf6dd9 | |||
| 68b1a94a2e | |||
| 0e857d3710 | |||
| a898eb1964 | |||
| d3bb9121fd | |||
| b22a25f208 | |||
| 31d6d42cfc | |||
| 765ea5dbc3 | |||
| 3b2690ef9c | |||
| d5dbe92232 | |||
| 25e159d1c5 | |||
| b7087ee353 | |||
| ed818157bb | |||
| 62648c74d8 | |||
| 7b105cb467 | |||
| 1e3c3ec907 | |||
| 8ac8ea416a | |||
| 2cfc22350b | |||
| 5c93b9fa6d | |||
| 0ad9a91cf0 | |||
| 6d381af4ab | |||
| 6d966ab9be | |||
| 4ba4250301 | |||
| aafe17e92a | |||
| d281a2bb43 | |||
| e3b5759ca7 | |||
| c526971857 | |||
| d474c049d1 | |||
| c2d8196aa2 | |||
| 432201670d | |||
| 23f56c13a6 | |||
| 3053acf475 | |||
| 7bd76a1230 | |||
| 183901ec6d | |||
| e6e6c7e7b3 | |||
| 4ce427c2ac | |||
| 2a6e9817f1 | |||
| 890217e23e | |||
| e3cee463b1 | |||
| 9b0f057357 | |||
| 5a61806325 | |||
| 489a9fc818 | |||
| 8ad1cceadf | |||
| 92d73c9dee | |||
| c2bdabd63c | |||
| 6625276c7f | |||
| 32412f8a13 | |||
| 8083d74fe2 | |||
| 41722cf56e | |||
| 6e162e4bcd | |||
| 3c480d41ec | |||
| 5f681d2ae2 | |||
| 527e300076 | |||
| 0356a9ba84 | |||
| 04dda99502 | |||
| 96c8cc1590 | |||
| 33847c2920 | |||
| 2a6000fc36 | |||
| ccd2ea3d60 | |||
| 8baa08a6bc | |||
| db8e366ed9 | |||
| bc67d4491c | |||
| 64f63faa3a | |||
| 60810e78fb | |||
| aca404163c | |||
| 319cc7c82c | |||
| 9db9ff3028 | |||
| bd76d860c0 | |||
| c79c417ea0 | |||
| e12ef27c0a | |||
| e2b9b37846 | |||
| fe72c72682 | |||
| ec3723d8d0 | |||
| 7dac997bdc | |||
| ea1cf5d927 | |||
| 4756f9876c | |||
| 0d3cdb0c10 | |||
| 748acadd05 | |||
| a9a76642a4 | |||
| bf47757ef3 | |||
| c0ab693e4e | |||
| 5c7f1b85c6 | |||
| d437bdafc4 | |||
| fc3cbd5015 | |||
| de8180935f | |||
| 7b720a1f56 | |||
| f12e010847 | |||
| 87a9b1c8ba | |||
| a16624f94c | |||
| e25d28ff05 | |||
| 1b18e3328e | |||
| 3a6c0872b9 | |||
| 60e74092cd | |||
| 45bd1bfa49 | |||
| 6f0e80bd21 | |||
| c5967dd7d0 | |||
| a06d7f47be | |||
| 19a25450d2 | |||
| 64fe594e85 | |||
| ae51bda773 | |||
| 367f2bf707 | |||
| f7b3caac2c | |||
| 6dcb455973 | |||
| ec92edec88 | |||
| 4adae8e489 | |||
| 8034ad8be2 | |||
| 08344a8c4b | |||
| 434e5af241 | |||
| f9aa8a5d75 | |||
| fe3054d05b | |||
| 5af5c5d0a6 | |||
| 194458b229 | |||
| 4538b46a96 | |||
| e4ba5d276d | |||
| 79e12570d9 | |||
| b971d76406 | |||
| 4a3603d49c | |||
| e4b3b1c79b | |||
| bcf9d4bf68 | |||
| 92ee1c561e | |||
| 862e1e10c2 | |||
| 96e0a8b04d | |||
| 8fe9f8579d | |||
| 23d6705ad6 | |||
| 2baa3bb4a5 | |||
| f12e1b82a0 | |||
| e3fb15de88 | |||
| 4f6df8a5b9 | |||
| fd046bf6d6 | |||
| 527a11e48c | |||
| c0b521386c | |||
| b2780aa6f6 | |||
| 0608452503 | |||
| d6a9f01cc9 | |||
| 558d836861 | |||
| 0d82ce2629 | |||
| 896763076e | |||
| 7e77e66350 | |||
| c2af464083 | |||
| 09500beae2 | |||
| 152acdd72f | |||
| 3847e0ba04 | |||
| 05ffcf0579 | |||
| baed2a1aa1 | |||
| ddd260ffa4 | |||
| b8fa7e0a0f | |||
| 7fbb02cadc | |||
| 954f779c5d | |||
| f2f4c098ee | |||
| b098b9d61b | |||
| 138c3bcb99 | |||
| 1f43b863f3 | |||
| 59f7404d8b | |||
| 5305ddc0a4 | |||
| ecee875be0 | |||
| efb38571e5 | |||
| e7817d0d55 | |||
| 612b86e193 | |||
| 356e1d8f31 | |||
| a283cf8fbe | |||
| 9437e82a31 | |||
| 1408e3b964 |
@@ -7,6 +7,12 @@ on:
|
||||
- MOODLE_[0-9]+_STABLE
|
||||
tags-ignore:
|
||||
- v[0-9]+.[0-9]+.[0-9]+*
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
phpunit_extra_options:
|
||||
description: Additional options to apply to PHPUnit
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
env:
|
||||
php: 8.1
|
||||
@@ -113,4 +119,4 @@ jobs:
|
||||
env:
|
||||
dbtype: ${{ matrix.db }}
|
||||
phpunit_options: ${{ secrets.phpunit_options }}
|
||||
run: vendor/bin/phpunit $phpunit_options
|
||||
run: vendor/bin/phpunit $phpunit_options ${{ inputs.phpunit_extra_options }}
|
||||
|
||||
@@ -16,4 +16,4 @@ Moodle - the world's open source learning platform
|
||||
This generated documentation includes API documentation for JavaScript written in the AMD and ES2015 module formats within Moodle.
|
||||
|
||||
## Related information
|
||||
See [https://docs.moodle.org/dev](https://docs.moodle.org/dev) for other related Developer Documentation.
|
||||
See [https://moodledev.io](https://moodledev.io) for other related Developer Documentation.
|
||||
|
||||
@@ -114,7 +114,7 @@ module.exports = {
|
||||
],
|
||||
"menu": {
|
||||
"Developer Docs": {
|
||||
href: "https://docs.moodle.org/dev",
|
||||
href: "https://moodledev.io",
|
||||
target: "_blank",
|
||||
"class": "menu-item",
|
||||
id: "devdocs"
|
||||
|
||||
+3
-3
@@ -6,7 +6,7 @@ of developers, designers, teachers, testers, translators and other users. We
|
||||
work in universities, schools, companies and other places. You are very welcome
|
||||
to join us and contribute to the project.
|
||||
|
||||
See <https://docs.moodle.org/dev/Contributing_to_Moodle> for the many ways you
|
||||
See <https://moodledev.io/general/community/contribute> for the many ways you
|
||||
can help, not only with coding.
|
||||
|
||||
Moodle is open to community contributions to core, though all code must go
|
||||
@@ -35,7 +35,7 @@ submitted patches has evolved.
|
||||
* New features are developed on the master branch. Bug fixes are also
|
||||
backported to currently supported maintenance (stable) branches.
|
||||
|
||||
For further details, see <https://docs.moodle.org/dev/Process>.
|
||||
For further details, see <https://moodledev.io/general/development/process>.
|
||||
|
||||
Moodle plugins
|
||||
--------------
|
||||
@@ -53,4 +53,4 @@ be easily installed and updated via the Moodle administration interface.
|
||||
the plugins directory. We do not pull from your code repository; you must do
|
||||
it explicitly.
|
||||
|
||||
For further details, see <https://docs.moodle.org/dev/Plugin_contribution>.
|
||||
For further details, see <https://moodledev.io/general/community/plugincontribution>.
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ Moodle is widely used around the world by universities, schools, companies and
|
||||
all manner of organisations and individuals.
|
||||
|
||||
Moodle is provided freely as open source software, under the GNU General Public
|
||||
License <https://docs.moodle.org/dev/License>.
|
||||
License <https://moodledev.io/general/license>.
|
||||
|
||||
Moodle is written in PHP and JavaScript and uses an SQL database for storing
|
||||
the data.
|
||||
|
||||
+1
-2
@@ -131,8 +131,7 @@ if ($savebutton) {
|
||||
$outputhtml .= html_writer::end_tag('div');
|
||||
}
|
||||
|
||||
$visiblepathtosection = array_reverse($settingspage->visiblepath);
|
||||
$PAGE->set_title("$SITE->shortname: " . implode(": ",$visiblepathtosection));
|
||||
$PAGE->set_title(implode(moodle_page::TITLE_SEPARATOR, $settingspage->visiblepath));
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
if ($buttons) {
|
||||
$PAGE->set_button($buttons);
|
||||
|
||||
@@ -80,8 +80,8 @@ if (!$category = $DB->get_record('course_categories', ['id' => $options['categor
|
||||
throw new \moodle_exception('invalidcategoryid');
|
||||
}
|
||||
|
||||
$backupdir = "restore_" . uniqid();
|
||||
$path = $CFG->tempdir . DIRECTORY_SEPARATOR . "backup" . DIRECTORY_SEPARATOR . $backupdir;
|
||||
$backupdir = restore_controller::get_tempdir_name(SITEID, $USER->id);
|
||||
$path = make_backup_temp_directory($backupdir);
|
||||
|
||||
cli_heading(get_string('extractingbackupfileto', 'backup', $path));
|
||||
$fp = get_file_packer('application/vnd.moodle.backup');
|
||||
|
||||
@@ -4301,6 +4301,199 @@
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.4" requires="4.1.2">
|
||||
<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.1.0" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="sixtyfourbitsrequired" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
+3
-3
@@ -224,7 +224,7 @@ if (!core_tables_exist()) {
|
||||
$strlicense = get_string('license');
|
||||
|
||||
$PAGE->navbar->add($strlicense);
|
||||
$PAGE->set_title($strinstallation.' - Moodle '.$CFG->target_release);
|
||||
$PAGE->set_title($strinstallation . moodle_page::TITLE_SEPARATOR . 'Moodle ' . $CFG->target_release, false);
|
||||
$PAGE->set_heading($strinstallation);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
@@ -267,7 +267,7 @@ if (!core_tables_exist()) {
|
||||
upgrade_init_javascript();
|
||||
|
||||
$PAGE->navbar->add($strdatabasesetup);
|
||||
$PAGE->set_title($strinstallation.' - Moodle '.$CFG->target_release);
|
||||
$PAGE->set_title($strinstallation . moodle_page::TITLE_SEPARATOR . $CFG->target_release, false);
|
||||
$PAGE->set_heading($strinstallation);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
@@ -811,7 +811,7 @@ $context = context_system::instance();
|
||||
|
||||
if (!has_capability('moodle/site:config', $context)) {
|
||||
// Do not throw exception display an empty page with administration menu if visible for current user.
|
||||
$PAGE->set_title($SITE->fullname);
|
||||
$PAGE->set_title(get_string('home'));
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* Displays the list of found local plugins, their version (if found) and
|
||||
* a link to delete the local plugin.
|
||||
*
|
||||
* @see http://docs.moodle.org/dev/Local_customisation
|
||||
* @see https://moodledev.io/docs/apis/plugintypes/local
|
||||
* @package admin
|
||||
* @copyright 2010 David Mudrak <david.mudrak@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* Displays the list of found plagiarism plugins, their version (if found) and
|
||||
* a link to uninstall the plagiarism plugin.
|
||||
*
|
||||
* @see http://docs.moodle.org/dev/Plagiarism_API
|
||||
* @see https://moodledev.io/docs/apis/subsystems/plagiarism
|
||||
* @package admin
|
||||
* @copyright 2012 Dan Marsden <dan@danmarsden.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
+2
-30
@@ -26,42 +26,14 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_configmultiselect extends adminpresets_setting {
|
||||
|
||||
/**
|
||||
* Ensure that the $value values are setting choices.
|
||||
*
|
||||
* @param mixed $value Setting value
|
||||
* @return mixed Returns false if wrong param value
|
||||
*/
|
||||
protected function set_value($value) {
|
||||
if ($value) {
|
||||
$options = explode(',', $value);
|
||||
foreach ($options as $option) {
|
||||
|
||||
foreach ($this->settingdata->choices as $key => $choice) {
|
||||
|
||||
if ($key == $option) {
|
||||
$this->value = $option;
|
||||
$this->set_visiblevalue();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$value = implode(',', $options);
|
||||
}
|
||||
$this->value = $value;
|
||||
$this->set_visiblevalue();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function set_visiblevalue() {
|
||||
$values = explode(',', $this->value);
|
||||
$visiblevalues = [];
|
||||
|
||||
foreach ($values as $value) {
|
||||
|
||||
if (!empty($this->settingdata->choices[$value])) {
|
||||
// Ensure that each value exists as a setting choice.
|
||||
if (array_key_exists($value, $this->settingdata->choices)) {
|
||||
$visiblevalues[] = $this->settingdata->choices[$value];
|
||||
}
|
||||
}
|
||||
|
||||
+8
-6
@@ -44,7 +44,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$output .= $this->heading(get_string('copyrightnotice'));
|
||||
$output .= $this->box($copyrightnotice, 'copyrightnotice');
|
||||
$output .= html_writer::empty_tag('br');
|
||||
$output .= $this->confirm(get_string('doyouagree'), $continue, "http://docs.moodle.org/dev/License");
|
||||
$output .= $this->confirm(get_string('doyouagree'), $continue, "https://moodledev.io/general/license");
|
||||
$output .= $this->footer();
|
||||
|
||||
return $output;
|
||||
@@ -746,10 +746,10 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//// IT IS ILLEGAL AND A VIOLATION OF THE GPL TO HIDE, REMOVE OR MODIFY THIS COPYRIGHT NOTICE ///
|
||||
$copyrighttext = '<a href="http://moodle.org/">Moodle</a> '.
|
||||
'<a href="http://docs.moodle.org/dev/Releases" title="'.$CFG->version.'">'.$CFG->release.'</a><br />'.
|
||||
'<a href="https://moodledev.io/general/releases" title="'.$CFG->version.'">'.$CFG->release.'</a><br />'.
|
||||
'Copyright © 1999 onwards, Martin Dougiamas<br />'.
|
||||
'and <a href="http://moodle.org/dev">many other contributors</a>.<br />'.
|
||||
'<a href="http://docs.moodle.org/dev/License">GNU Public License</a>';
|
||||
'<a href="https://moodledev.io/general/license">GNU Public License</a>';
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
return $this->box($copyrighttext, 'copyright');
|
||||
@@ -898,7 +898,8 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$url = "https://campaign.moodle.org/current/lms/{$lang}/install/";
|
||||
$params = [
|
||||
'url' => $url,
|
||||
'iframeid' => 'campaign-content'
|
||||
'iframeid' => 'campaign-content',
|
||||
'title' => get_string('campaign', 'admin'),
|
||||
];
|
||||
|
||||
return $this->render_from_template('core/external_content_banner', $params);
|
||||
@@ -919,7 +920,8 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$url = "https://campaign.moodle.org/current/lms/{$lang}/servicesandsupport/";
|
||||
$params = [
|
||||
'url' => $url,
|
||||
'iframeid' => 'services-support-content'
|
||||
'iframeid' => 'services-support-content',
|
||||
'title' => get_string('supportandservices', 'admin'),
|
||||
];
|
||||
|
||||
return $this->render_from_template('core/external_content_banner', $params);
|
||||
@@ -991,7 +993,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
protected function release_notes_link() {
|
||||
$releasenoteslink = get_string('releasenoteslink', 'admin', 'http://docs.moodle.org/dev/Releases');
|
||||
$releasenoteslink = get_string('releasenoteslink', 'admin', 'https://moodledev.io/general/releases');
|
||||
$releasenoteslink = str_replace('target="_blank"', 'onclick="this.target=\'_blank\'"', $releasenoteslink); // extremely ugly validation hack
|
||||
return $this->box($releasenoteslink, 'generalbox alert alert-info');
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ switch ($action) {
|
||||
$optionsyes = array('action'=>'delete', 'roleid'=>$roleid, 'sesskey'=>sesskey(), 'confirm'=>1);
|
||||
$a = new stdClass();
|
||||
$a->id = $roleid;
|
||||
$a->name = $roles[$roleid]->name;
|
||||
$a->name = $roles[$roleid]->localname;
|
||||
$a->shortname = $roles[$roleid]->shortname;
|
||||
$a->count = $DB->count_records_select('role_assignments',
|
||||
'roleid = ?', array($roleid), 'COUNT(DISTINCT userid)');
|
||||
|
||||
@@ -32,7 +32,7 @@ require_once($CFG->libdir . '/adminlib.php');
|
||||
admin_externalpage_setup('searchareas', '', null, (new moodle_url('/admin/searchreindex.php'))->out(false));
|
||||
|
||||
// Get area parameter and check it exists.
|
||||
$areaid = required_param('areaid', PARAM_ALPHAEXT);
|
||||
$areaid = required_param('areaid', PARAM_ALPHANUMEXT);
|
||||
$area = \core_search\manager::get_search_area($areaid);
|
||||
if ($area === false) {
|
||||
throw new moodle_exception('invalidrequest');
|
||||
@@ -44,7 +44,7 @@ $PAGE->set_secondary_active_tab('modules');
|
||||
|
||||
// Start page output.
|
||||
$heading = get_string('gradualreindex', 'search', '');
|
||||
$PAGE->set_title($PAGE->title . ': ' . $heading);
|
||||
$PAGE->set_title($areaname . ' - ' . get_string('gradualreindex', 'search', ''));
|
||||
$PAGE->navbar->add($heading);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($heading);
|
||||
|
||||
+1
-3
@@ -129,9 +129,7 @@ if (empty($SITE->fullname)) {
|
||||
$PAGE->set_button($buttons);
|
||||
}
|
||||
|
||||
$visiblepathtosection = array_reverse($settingspage->visiblepath);
|
||||
|
||||
$PAGE->set_title("$SITE->shortname: " . implode(": ",$visiblepathtosection));
|
||||
$PAGE->set_title(implode(moodle_page::TITLE_SEPARATOR, $settingspage->visiblepath));
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
|
||||
@@ -244,6 +244,18 @@ reports,core_reportbuilder|/reportbuilder/index.php',
|
||||
|
||||
// "htmlsettings" settingpage
|
||||
$temp = new admin_settingpage('htmlsettings', new lang_string('htmlsettings', 'admin'));
|
||||
$sitenameintitleoptions = [
|
||||
'shortname' => new lang_string('shortname'),
|
||||
'fullname' => new lang_string('fullname'),
|
||||
];
|
||||
$sitenameintitleconfig = new admin_setting_configselect(
|
||||
'sitenameintitle',
|
||||
new lang_string('sitenameintitle', 'admin'),
|
||||
new lang_string('sitenameintitle_help', 'admin'),
|
||||
'shortname',
|
||||
$sitenameintitleoptions
|
||||
);
|
||||
$temp->add($sitenameintitleconfig);
|
||||
$temp->add(new admin_setting_configcheckbox('formatstringstriptags', new lang_string('stripalltitletags', 'admin'), new lang_string('configstripalltitletags', 'admin'), 1));
|
||||
$temp->add(new admin_setting_emoticons());
|
||||
$ADMIN->add('appearance', $temp);
|
||||
|
||||
@@ -145,7 +145,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$temp->add(new admin_setting_heading('adminpresets', new lang_string('siteadminpresetspluginname', 'core_adminpresets'), ''));
|
||||
$sensiblesettingsdefault = 'recaptchapublickey@@none, recaptchaprivatekey@@none, googlemapkey3@@none, ';
|
||||
$sensiblesettingsdefault .= 'secretphrase@@url, cronremotepassword@@none, smtpuser@@none, ';
|
||||
$sensiblesettingsdefault .= 'smtppass@none, proxypassword@@none, quizpassword@@quiz, allowedip@@none, blockedip@@none, ';
|
||||
$sensiblesettingsdefault .= 'smtppass@@none, proxypassword@@none, quizpassword@@quiz, allowedip@@none, blockedip@@none, ';
|
||||
$sensiblesettingsdefault .= 'dbpass@@logstore_database, messageinbound_hostpass@@none, ';
|
||||
$sensiblesettingsdefault .= 'bind_pw@@auth_cas, pass@@auth_db, bind_pw@@auth_ldap, ';
|
||||
$sensiblesettingsdefault .= 'dbpass@@enrol_database, bind_pw@@enrol_ldap, ';
|
||||
|
||||
@@ -23,12 +23,15 @@
|
||||
* name - form element name
|
||||
* hasoptions - there are some options
|
||||
* options - list of options containing name, key, id, checked, label
|
||||
* readonly - bool
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"name": "test",
|
||||
"hasoptions": true,
|
||||
"options": [ { "name": "Option", "key": "k1", "id": "id0", "checked": true, "label": "Option label"} ]
|
||||
"options": [ { "name": "Option", "key": "k1", "id": "id0", "checked": true, "label": "Option label"} ],
|
||||
"readonly": false
|
||||
|
||||
}
|
||||
}}
|
||||
<div class="form-multicheckbox">
|
||||
@@ -37,7 +40,7 @@
|
||||
<ul>
|
||||
{{#options}}
|
||||
<li>
|
||||
<input type="checkbox" name="{{name}}[{{key}}]" value="1" id="{{id}}_{{key}}" {{#checked}}checked{{/checked}}>
|
||||
<input type="checkbox" name="{{name}}[{{key}}]" value="1" id="{{id}}_{{key}}" {{#readonly}}disabled{{/readonly}} {{#checked}}checked{{/checked}}>
|
||||
<label for="{{id}}_{{key}}">{{{label}}}</label>
|
||||
</li>
|
||||
{{/options}}
|
||||
|
||||
@@ -42,8 +42,8 @@ class import_form extends moodleform {
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
|
||||
// File upload.
|
||||
$mform->addElement('filepicker', 'xmlfile',
|
||||
get_string('selectfile', 'tool_admin_presets'));
|
||||
$mform->addElement('filepicker', 'xmlfile', get_string('selectfile', 'tool_admin_presets'), null,
|
||||
['accepted_types' => ['.xml']]);
|
||||
$mform->addRule('xmlfile', null, 'required');
|
||||
|
||||
$this->add_action_buttons(true, get_string('import', 'tool_admin_presets'));
|
||||
|
||||
@@ -100,8 +100,7 @@ Feature: Set up contextual data for tests
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I am on the "Course 1" course page logged in as student1
|
||||
Then I should see "Topic 1"
|
||||
|
||||
Scenario: Add role assigns
|
||||
@@ -135,17 +134,11 @@ Feature: Set up contextual data for tests
|
||||
When I log in as "user1"
|
||||
And I am on site homepage
|
||||
Then edit mode should be available on the current page
|
||||
And I log out
|
||||
And I log in as "user2"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as user2
|
||||
Then edit mode should be available on the current page
|
||||
And I log out
|
||||
And I log in as "user3"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as user3
|
||||
Then edit mode should be available on the current page
|
||||
And I log out
|
||||
And I log in as "user4"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as user4
|
||||
Then edit mode should be available on the current page
|
||||
And I log out
|
||||
And I log in as "user5"
|
||||
@@ -187,8 +180,7 @@ Feature: Set up contextual data for tests
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | grade |
|
||||
| assign | Test assignment name with scale | Test assignment description | C1 | assign1 | Test Scale 1 |
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
When I am on the "Course 1" course page logged in as admin
|
||||
Then I should see "Test assignment name"
|
||||
# Assignment 2.2 module type is disabled by default
|
||||
# And I should see "Test assignment22 name"
|
||||
@@ -304,9 +296,7 @@ Feature: Set up contextual data for tests
|
||||
And the following "grade categories" exist:
|
||||
| fullname | course | gradecategory |
|
||||
| Grade sub category 2 | C1 | Grade category 1 |
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
When I am on the "Course 1" "grades > Grader report > View" page logged in as "admin"
|
||||
Then I should see "Grade category 1"
|
||||
And I should see "Grade sub category 2"
|
||||
|
||||
@@ -327,9 +317,7 @@ Feature: Set up contextual data for tests
|
||||
| itemname | course | gradecategory |
|
||||
| Test Grade Item 2 | C1 | Grade category 1 |
|
||||
| Test Grade Item 3 | C1 | Grade sub category 2 |
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Setup > Gradebook setup" in the course gradebook
|
||||
When I am on the "Course 1" "grades > gradebook setup" page logged in as "admin"
|
||||
Then I should see "Test Grade Item 1"
|
||||
And I open the action menu in "Test Grade Item 1" "table_row"
|
||||
And I choose "Edit" in the open action menu
|
||||
@@ -358,9 +346,7 @@ Feature: Set up contextual data for tests
|
||||
And the following "scales" exist:
|
||||
| name | scale |
|
||||
| Test Scale 1 | Disappointing, Good, Very good, Excellent |
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Scales" in the course gradebook
|
||||
When I am on the "Course 1" "grades > scales" page logged in as admin
|
||||
Then I should see "Test Scale 1"
|
||||
And I should see "Disappointing, Good, Very good, Excellent"
|
||||
|
||||
@@ -379,9 +365,7 @@ Feature: Set up contextual data for tests
|
||||
| Grade outcome 2 | OT2 | C1 | Test Scale 1 |
|
||||
And the following config values are set as admin:
|
||||
| enableoutcomes | 1 |
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "More > Outcomes" in the course gradebook
|
||||
When I am on the "Course 1" "grades > outcomes" page logged in as admin
|
||||
Then I should see "Grade outcome 1" in the "#addoutcomes" "css_element"
|
||||
And I should see "Grade outcome 2" in the "#removeoutcomes" "css_element"
|
||||
And I press "Manage outcomes"
|
||||
@@ -407,9 +391,7 @@ Feature: Set up contextual data for tests
|
||||
| Test Outcome Grade Item 1 | C1 | OT1 | Grade category 1 |
|
||||
And the following config values are set as admin:
|
||||
| enableoutcomes | 1 |
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Setup > Gradebook setup" in the course gradebook
|
||||
When I am on the "Course 1" "grades > gradebook setup" page logged in as "admin"
|
||||
Then I should see "Test Outcome Grade Item 1"
|
||||
And I open the action menu in "Test Outcome Grade Item 1" "table_row"
|
||||
And I choose "Edit" in the open action menu
|
||||
@@ -425,6 +407,5 @@ Feature: Set up contextual data for tests
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| online_users | Course | C1 | course-view-* | site-pre |
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
When I am on the "Course 1" course page logged in as admin
|
||||
Then I should see "Online users"
|
||||
|
||||
+46
-1
@@ -170,6 +170,19 @@ class brickfield_accessibility_color_test extends brickfield_accessibility_test
|
||||
'yellowgreen' => '9acd32'
|
||||
];
|
||||
|
||||
/** @var string[] Define estimated relative font-size codes to pt values. */
|
||||
public $fontsizenames = [
|
||||
'xx-small' => 9,
|
||||
'x-small' => 10,
|
||||
'small' => 11,
|
||||
'smaller' => 11,
|
||||
'medium' => 12,
|
||||
'large' => 14,
|
||||
'larger' => 14,
|
||||
'x-large' => 18,
|
||||
'xx-large' => 24,
|
||||
];
|
||||
|
||||
/**
|
||||
* Helper method that finds the luminosity between the provided
|
||||
* foreground and background parameters.
|
||||
@@ -227,7 +240,8 @@ class brickfield_accessibility_color_test extends brickfield_accessibility_test
|
||||
$l2 = (.2126 * $r4 + 0.7152 * $g4 + 0.0722 * $b4);
|
||||
}
|
||||
|
||||
$luminosity = round(($l1 + 0.05) / ($l2 + 0.05), 2);
|
||||
// Increase round to 4 to avoid a 4.49 contrast being round up to a false pass of 4.5.
|
||||
$luminosity = round(($l1 + 0.05) / ($l2 + 0.05), 4);
|
||||
return $luminosity;
|
||||
}
|
||||
|
||||
@@ -362,4 +376,35 @@ class brickfield_accessibility_color_test extends brickfield_accessibility_test
|
||||
: $backrgb['b'] - $forergb['b'];
|
||||
return ['red' => $reddiff, 'green' => $greendiff, 'blue' => $bluediff];
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that finds the estimated font-size for the provided
|
||||
* string font-size parameter.
|
||||
* @param string $fontsize The css font-size, in various formats
|
||||
* @return int The estimated font-size
|
||||
*/
|
||||
public function get_fontsize(string $fontsize): int {
|
||||
$newfontsize = 12; // Default value, in pt, equivalent to 16px.
|
||||
|
||||
// Search for rem, em, and px initially, typical font-size values.
|
||||
$pos1 = stripos($fontsize, 'rem');
|
||||
$pos2 = stripos($fontsize, 'em');
|
||||
$pos3 = stripos($fontsize, 'px');
|
||||
if ($pos1 !== false) {
|
||||
$rem = substr($fontsize, 0, -3);
|
||||
$newfontsize = $newfontsize * $rem;
|
||||
} else if ($pos2 !== false) {
|
||||
$em = substr($fontsize, 0, -2);
|
||||
$newfontsize = $newfontsize * $em;
|
||||
} else if ($pos3 !== false) {
|
||||
$px = substr($fontsize, 0, -2);
|
||||
$newfontsize = 0.75 * $px;
|
||||
} else if (in_array($fontsize, array_keys($this->fontsizenames))) {
|
||||
$newfontsize = $this->fontsizenames[$fontsize];
|
||||
} else {
|
||||
preg_match_all('!\d+!', $fontsize, $matches);
|
||||
$newfontsize = $matches[0][0] ?? $newfontsize;
|
||||
}
|
||||
return (int) $newfontsize;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -92,8 +92,7 @@ class css_text_has_contrast extends brickfield_accessibility_color_test {
|
||||
$italic = false;
|
||||
|
||||
if (isset($style['font-size'])) {
|
||||
preg_match_all('!\d+!', $style['font-size'], $matches);
|
||||
$fontsize = $matches[0][0];
|
||||
$fontsize = $this->get_fontsize($style['font-size']);
|
||||
}
|
||||
|
||||
if (isset($style['font-weight'])) {
|
||||
|
||||
+112
@@ -178,6 +178,54 @@ EOD;
|
||||
</html>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML with px18 fail colour values. */
|
||||
private $px18 = <<<EOD
|
||||
<body><p style="color:#EF0000; background-color:white; font-size: 18px">
|
||||
This is not contrasty enough.</p></body>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML with px19bold pass colour values. */
|
||||
private $px19bold = <<<EOD
|
||||
<body><p style="color:#EF0000; background-color:white; font-size: 19px; font-weight: bold;">
|
||||
This is contrasty enough.</p></body>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML with px18 pass colour values. */
|
||||
private $px18pass = <<<EOD
|
||||
<body><p style="color:#E60000; background-color:white; font-size: 18px">
|
||||
This is contrasty enough.</p></body>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML with medium size colour values. */
|
||||
private $mediumfail = <<<EOD
|
||||
<body><p style="color:#EF0000; background-color:white; font-size: medium">
|
||||
This is not contrasty enough.</p></body>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML with px18 colour values. */
|
||||
private $mediumpass = <<<EOD
|
||||
<body><p style="color:#E60000; background-color:white; font-size: medium">
|
||||
This is contrasty enough.</p></body>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML with larger fail colour values. */
|
||||
private $largerfail = <<<EOD
|
||||
<body><p style="color:#FF6161; background-color:white; font-size: larger">
|
||||
This is not contrasty enough.</p></body>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML with px18 colour values. */
|
||||
private $largerpass = <<<EOD
|
||||
<body><p style="color:#FF5C5C; background-color:white; font-size: larger;">
|
||||
This is contrasty enough.</p></body>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML with px18 colour values. */
|
||||
private $largerboldpass = <<<EOD
|
||||
<body><p style="color:#FF5C5C; background-color:white; font-size: larger; font-weight: bold;">
|
||||
This is contrasty enough.</p></body>
|
||||
EOD;
|
||||
|
||||
/**
|
||||
* Test for the area assign intro
|
||||
*/
|
||||
@@ -235,4 +283,68 @@ EOD;
|
||||
$results = $this->get_checker_results($this->emptyvalue);
|
||||
$this->assertEmpty($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for text px18 with insufficient contrast of 4.49.
|
||||
*/
|
||||
public function test_check_for_px18_fail() {
|
||||
$results = $this->get_checker_results($this->px18);
|
||||
$this->assertTrue($results[0]->element->tagName == 'p');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for text px19 bold with sufficient contrast of 4.49.
|
||||
*/
|
||||
public function test_check_for_px19bold_pass() {
|
||||
$results = $this->get_checker_results($this->px19bold);
|
||||
$this->assertEmpty($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for text px18 with sufficient contrast of 4.81.
|
||||
*/
|
||||
public function test_check_for_px18_pass() {
|
||||
$results = $this->get_checker_results($this->px18pass);
|
||||
$this->assertEmpty($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for medium (12pt) text with insufficient contrast of 4.49.
|
||||
*/
|
||||
public function test_check_for_medium_fail() {
|
||||
$results = $this->get_checker_results($this->mediumfail);
|
||||
$this->assertTrue($results[0]->element->tagName == 'p');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for medium (12pt) text with sufficient contrast of 4.81.
|
||||
*/
|
||||
public function test_check_for_medium_pass() {
|
||||
$results = $this->get_checker_results($this->mediumpass);
|
||||
$this->assertEmpty($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for larger (14pt) text with insufficient contrast of 2.94.
|
||||
*/
|
||||
public function test_check_for_larger_fail() {
|
||||
$results = $this->get_checker_results($this->largerfail);
|
||||
$this->assertTrue($results[0]->element->tagName == 'p');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for larger (14pt) text with insufficient contrast of 3.02.
|
||||
*/
|
||||
public function test_check_for_larger_pass() {
|
||||
$results = $this->get_checker_results($this->largerpass);
|
||||
$this->assertTrue($results[0]->element->tagName == 'p');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for larger (14pt) bold text with sufficient contrast of 3.02.
|
||||
*/
|
||||
public function test_check_for_largerbold_pass() {
|
||||
$results = $this->get_checker_results($this->largerboldpass);
|
||||
$this->assertEmpty($results);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ menu: "main"
|
||||
|
||||
## Moodle templates
|
||||
|
||||
[Moodle templates](https://docs.moodle.org/dev/Templates) are use to write HTML and Javascript using mustache files.
|
||||
[Moodle templates](https://moodledev.io/docs/guides/templates) are use to write HTML and Javascript using mustache files.
|
||||
|
||||
If you are creating your own pages in the UI Component library you can load core templates using this (shortcode) syntax:
|
||||
|
||||
@@ -51,4 +51,3 @@ This is the result of adding the core/notification template on this page:
|
||||
"extraclasses": "foo bar"
|
||||
}
|
||||
{{< /mustache >}}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ tags:
|
||||
|
||||
## How to use moodle forms
|
||||
|
||||
Forms are constructed using lib/formslib.php. Using the addElement methods in php a set of different form element types can be added to a form. For more info visit the [Moodledocs](https://docs.moodle.org/dev/lib/formslib.php_Form_Definition) page for forms
|
||||
Forms are constructed using lib/formslib.php. Using the addElement methods in php a set of different form element types can be added to a form. For more info visit the [Moodledocs](https://moodledev.io/docs/apis/subsystems/form) page for forms
|
||||
|
||||
{{< php >}}
|
||||
$mform->addElement('button', 'intro', get_string("buttonlabel"));
|
||||
|
||||
@@ -61,7 +61,7 @@ Disabled toggle with extra classes.
|
||||
|
||||
## Use toggle as a template block
|
||||
|
||||
It is also possible to include *core/toggle* in any other template using [blocks](https://docs.moodle.org/dev/Templates#Blocks), instead of rendering it with a context.
|
||||
It is also possible to include *core/toggle* in any other template using [blocks](https://moodledev.io/docs/guides/templates#blocks), instead of rendering it with a context.
|
||||
The parameters that you can define are:
|
||||
* id: Unique id for the toggle input.
|
||||
* extraclasses: Any extra classes added to the toggle input outer container.
|
||||
|
||||
@@ -16,7 +16,7 @@ to the element that will trigger the confirmation modal.
|
||||
|
||||
## Source files
|
||||
|
||||
* `lib/amd/src/confirm.js` ({{< jsdoc module="core/confirm" >}})
|
||||
* `lib/amd/src/utility.js` ({{< jsdoc module="core/utility" >}})
|
||||
* `lib/templates/modal.mustache`
|
||||
|
||||
## Usage
|
||||
@@ -24,7 +24,7 @@ The confirmation AMD module is loaded automatically, so the only thing you need
|
||||
to the target element:
|
||||
{{< highlight html >}}
|
||||
<button type="button" class="btn btn-primary" data-confirmation="modal" data-confirmation-title-str='["delete", "core"]'
|
||||
data-confirmation-question-str='["areyousure"]' data-confirmation-yes-button-str='["delete", "core"]'>Show confirmation modal</button>
|
||||
data-confirmation-content-str='["areyousure"]' data-confirmation-yes-button-str='["delete", "core"]'>Show confirmation modal</button>
|
||||
{{< /highlight >}}
|
||||
|
||||
You can also use it on PHP, you just need to set the attributes parameter to any moodle output component that takes attributes:
|
||||
@@ -32,7 +32,7 @@ You can also use it on PHP, you just need to set the attributes parameter to any
|
||||
echo $OUTPUT->single_button('#', get_string('delete'), 'get', [
|
||||
'data-confirmation' => 'modal',
|
||||
'data-confirmation-title-str' => json_encode(['delete', 'core']),
|
||||
'data-confirmation-question-str' => json_encode(['areyousure']),
|
||||
'data-confirmation-content-str' => json_encode(['areyousure']),
|
||||
'data-confirmation-yes-button-str' => json_encode(['delete', 'core'])
|
||||
]);
|
||||
{{< / php >}}
|
||||
@@ -56,8 +56,8 @@ echo $OUTPUT->single_button('#', get_string('delete'), 'get', [
|
||||
<td>The modal title language string identifier, must be provided in JSON encoded format.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>data-confirmation-question-str</td>
|
||||
<td>The confirmation question language string identifier, must be provided in JSON encoded format.</td>
|
||||
<td>data-confirmation-content-str</td>
|
||||
<td>The confirmation modal main content language string identifier, must be provided in JSON encoded format.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>data-confirmation-yes-button-str</td>
|
||||
@@ -84,14 +84,14 @@ echo $OUTPUT->single_button('#', get_string('delete'), 'get', [
|
||||
|
||||
{{< example >}}
|
||||
<button type="button" class="btn btn-primary" data-confirmation="modal" data-confirmation-title-str='["delete", "core"]'
|
||||
data-confirmation-question-str='["areyousure"]' data-confirmation-yes-button-str='["delete", "core"]'>Show confirmation modal</button>
|
||||
data-confirmation-content-str='["areyousure"]' data-confirmation-yes-button-str='["delete", "core"]'>Show confirmation modal</button>
|
||||
{{< /example >}}
|
||||
|
||||
### Confirmation modal with a toast
|
||||
|
||||
{{< example >}}
|
||||
<button type="button" class="btn btn-primary" data-confirmation="modal" data-confirmation-title-str='["delete", "core"]'
|
||||
data-confirmation-question-str='["areyousure"]' data-confirmation-yes-button-str='["delete", "core"]' data-confirmation-toast="true"
|
||||
data-confirmation-content-str='["areyousure"]' data-confirmation-yes-button-str='["delete", "core"]' data-confirmation-toast="true"
|
||||
data-confirmation-toast-confirmation-str='["deleteblockinprogress", "block", "Online users"]'>Show confirmation modal</button>
|
||||
{{< /example >}}
|
||||
|
||||
@@ -99,6 +99,6 @@ data-confirmation-toast-confirmation-str='["deleteblockinprogress", "block", "On
|
||||
|
||||
{{< example >}}
|
||||
<button type="button" class="btn btn-primary" data-confirmation="modal" data-confirmation-title-str='["delete", "core"]'
|
||||
data-confirmation-question-str='["areyousure"]' data-confirmation-yes-button-str='["delete", "core"]'
|
||||
data-confirmation-content-str='["areyousure"]' data-confirmation-yes-button-str='["delete", "core"]'
|
||||
data-confirmation-destination="http://moodle.com">Show confirmation modal</button>
|
||||
{{< /example >}}
|
||||
|
||||
@@ -58,7 +58,7 @@ class behat_tool_dataprivacy extends behat_base {
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates the specified element. More info about available elements in http://docs.moodle.org/dev/Acceptance_testing#Fixtures.
|
||||
* Creates the specified element. More info about available elements in https://moodledev.io/general/development/tools/behat.
|
||||
*
|
||||
* @Given /^the following data privacy "(?P<element_string>(?:[^"]|\\")*)" exist:$/
|
||||
*
|
||||
|
||||
@@ -46,7 +46,7 @@ $PAGE->set_url(new \moodle_url('/admin/tool/filetypes/delete.php', array('extens
|
||||
$PAGE->navbar->add($title);
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->set_pagelayout('admin');
|
||||
$PAGE->set_title($SITE->fullname. ': ' . $title);
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_primary_active_tab('siteadminnode');
|
||||
$PAGE->set_secondary_active_tab('server');
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ $PAGE->set_secondary_active_tab('server');
|
||||
$PAGE->navbar->add($oldextension ? s($oldextension) : $title);
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->set_pagelayout('admin');
|
||||
$PAGE->set_title($SITE->fullname. ': ' . $title);
|
||||
$PAGE->set_title($title);
|
||||
|
||||
// Display the page.
|
||||
echo $OUTPUT->header();
|
||||
|
||||
@@ -34,7 +34,7 @@ $context = context_system::instance();
|
||||
$PAGE->set_url(new \moodle_url('/admin/tool/filetypes/index.php'));
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->set_pagelayout('admin');
|
||||
$PAGE->set_title($SITE->fullname. ': ' . $title);
|
||||
$PAGE->set_title($title);
|
||||
|
||||
$renderer = $PAGE->get_renderer('tool_filetypes');
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ $PAGE->set_url(new \moodle_url('/admin/tool/filetypes/revert.php', array('extens
|
||||
$PAGE->navbar->add($title);
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->set_pagelayout('admin');
|
||||
$PAGE->set_title($SITE->fullname. ': ' . $title);
|
||||
$PAGE->set_title($title);
|
||||
|
||||
// Display the page.
|
||||
echo $OUTPUT->header();
|
||||
|
||||
@@ -205,7 +205,7 @@ class tool_generator_course_backend extends tool_generator_backend {
|
||||
* @return int Course id
|
||||
*/
|
||||
public function make() {
|
||||
global $DB, $CFG;
|
||||
global $DB, $CFG, $USER;
|
||||
require_once($CFG->dirroot . '/lib/phpunit/classes/util.php');
|
||||
|
||||
raise_memory_limit(MEMORY_EXTRA);
|
||||
@@ -231,6 +231,12 @@ class tool_generator_course_backend extends tool_generator_backend {
|
||||
$this->create_users();
|
||||
$this->create_forum();
|
||||
|
||||
// We are checking 'enroladminnewcourse' setting to decide to enrol admins or not.
|
||||
if (!empty($CFG->creatornewroleid) && !empty($CFG->enroladminnewcourse) && is_siteadmin($USER->id)) {
|
||||
// Deal with course creators - enrol them internally with default role.
|
||||
enrol_try_internal_enrol($this->course->id, $USER->id, $CFG->creatornewroleid);
|
||||
}
|
||||
|
||||
// Log total time.
|
||||
$this->log('coursecompleted', round(microtime(true) - $entirestart, 1));
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
@core @core_course @tool_generator
|
||||
Feature: Admins can create test courses
|
||||
In order to create testing information
|
||||
As an admin
|
||||
I need to create testing courses quickly
|
||||
|
||||
@javascript
|
||||
Scenario: 'Auto-enrol admin in new courses' setting when creating a test course as admin
|
||||
Given I log in as "admin"
|
||||
And the following config values are set as admin:
|
||||
| enroladminnewcourse | 0 |
|
||||
And I navigate to "Development > Make test course" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Size of course | XS |
|
||||
| Course full name | Fake course for testing |
|
||||
| Course short name | fake |
|
||||
And I press "Create course"
|
||||
And I click on "Continue" "link"
|
||||
And I navigate to course participants
|
||||
Then I should not see "Teacher"
|
||||
And I should not see "Nothing to display"
|
||||
And the following config values are set as admin:
|
||||
| enroladminnewcourse | 1 |
|
||||
And I navigate to "Courses > Add a new course" in site administration
|
||||
And I navigate to "Development > Make test course" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Size of course | XS |
|
||||
| Course full name | New fake course for testing |
|
||||
| Course short name | newfake |
|
||||
And I press "Create course"
|
||||
And I click on "Continue" "link"
|
||||
And I navigate to course participants
|
||||
And I should see "Teacher"
|
||||
@@ -68,9 +68,14 @@ class maketestcourse_test extends \advanced_testcase {
|
||||
$this->assertEquals(2, count($modinfo->get_section_info_all()));
|
||||
|
||||
// Check user is enrolled.
|
||||
// enroladminnewcourse is enabled by default, so admin is also enrolled as teacher.
|
||||
$users = get_enrolled_users($context);
|
||||
$this->assertEquals(1, count($users));
|
||||
$this->assertEquals('tool_generator_000001', reset($users)->username);
|
||||
$this->assertEquals(2, count($users));
|
||||
$usernames = array_map(function($user) {
|
||||
return $user->username;
|
||||
}, $users);
|
||||
$this->assertTrue(in_array('admin', $usernames));
|
||||
$this->assertTrue(in_array('tool_generator_000001', $usernames));
|
||||
|
||||
// Check there's a page on the course.
|
||||
$pages = $modinfo->get_instances_of('page');
|
||||
|
||||
@@ -10,12 +10,12 @@ Feature: Licence manager
|
||||
Then I should see "Licence not specified" in the "unknown" "table_row"
|
||||
And I should see "All rights reserved" in the "allrightsreserved" "table_row"
|
||||
And I should see "Public domain" in the "public" "table_row"
|
||||
And I should see "Creative Commons" in the "cc" "table_row"
|
||||
And I should see "Creative Commons - NoDerivs" in the "cc-nd" "table_row"
|
||||
And I should see "Creative Commons - No Commercial NoDerivs" in the "cc-nc-nd" "table_row"
|
||||
And I should see "Creative Commons - No Commercial" in the "cc-nc" "table_row"
|
||||
And I should see "Creative Commons - No Commercial ShareAlike" in the "cc-nc-sa" "table_row"
|
||||
And I should see "Creative Commons - ShareAlike" in the "cc-sa" "table_row"
|
||||
And I should see "Creative Commons - 4.0 International" in the "cc-4.0" "table_row"
|
||||
And I should see "Creative Commons - NoDerivatives 4.0 International" in the "cc-nd-4.0" "table_row"
|
||||
And I should see "Creative Commons - NonCommercial-NoDerivatives 4.0 International" in the "cc-nc-nd-4.0" "table_row"
|
||||
And I should see "Creative Commons - NonCommercial-ShareAlike 4.0 International" in the "cc-nc-sa-4.0" "table_row"
|
||||
And I should see "Creative Commons - ShareAlike 4.0 International" in the "cc-sa-4.0" "table_row"
|
||||
And I should see "Creative Commons - NonCommercial 4.0 International" in the "cc-nc-4.0" "table_row"
|
||||
|
||||
Scenario: I should be able to enable and disable licences
|
||||
Given I log in as "admin"
|
||||
@@ -25,25 +25,25 @@ Feature: Licence manager
|
||||
And I navigate to "Licence > Licence manager" in site administration
|
||||
Then "This is the site default licence" "icon" should exist in the "public" "table_row"
|
||||
And "Enable licence" "icon" should not exist in the "public" "table_row"
|
||||
And "This is the site default licence" "icon" should not exist in the "cc" "table_row"
|
||||
And "This is the site default licence" "icon" should not exist in the "cc-4.0" "table_row"
|
||||
And I navigate to "Licence > Licence settings" in site administration
|
||||
And I set the field "Default site licence" to "Creative Commons"
|
||||
And I press "Save changes"
|
||||
And I navigate to "Licence > Licence manager" in site administration
|
||||
And "This is the site default licence" "icon" should exist in the "cc" "table_row"
|
||||
And "Enable licence" "icon" should not exist in the "cc" "table_row"
|
||||
And "This is the site default licence" "icon" should exist in the "cc-4.0" "table_row"
|
||||
And "Enable licence" "icon" should not exist in the "cc-4.0" "table_row"
|
||||
And "This is the site default licence" "icon" should not exist in the "public" "table_row"
|
||||
|
||||
@javascript @_file_upload
|
||||
Scenario Outline: User licence preference is remembered depending of setting value
|
||||
Given the following config values are set as admin:
|
||||
| sitedefaultlicense | cc |
|
||||
| sitedefaultlicense | cc-4.0 |
|
||||
| rememberuserlicensepref | <rememberuserlicensepref> |
|
||||
And I log in as "admin"
|
||||
And I follow "Private files" in the user menu
|
||||
And I follow "Add..."
|
||||
And I follow "Upload a file"
|
||||
And the field with xpath "//select[@name='license']" matches value "Creative Commons"
|
||||
And the field with xpath "//select[@name='license']" matches value "Creative Commons - 4.0 International"
|
||||
And I click on "Close" "button" in the "File picker" "dialogue"
|
||||
When I upload "lib/tests/fixtures/empty.txt" file to "Files" filemanager as:
|
||||
| Save as | empty_copy.txt |
|
||||
@@ -53,6 +53,6 @@ Feature: Licence manager
|
||||
Then the field with xpath "//select[@name='license']" matches value "<expectedlicence>"
|
||||
|
||||
Examples:
|
||||
| rememberuserlicensepref | expectedlicence |
|
||||
| 0 | Creative Commons |
|
||||
| 1 | Public domain |
|
||||
| rememberuserlicensepref | expectedlicence |
|
||||
| 0 | Creative Commons - 4.0 International |
|
||||
| 1 | Public domain |
|
||||
|
||||
@@ -174,24 +174,24 @@ class manager_test extends advanced_testcase {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$licenseorder = array_keys(license_manager::get_licenses());
|
||||
$initialposition = array_search('cc-nc', $licenseorder);
|
||||
$initialposition = array_search('cc-nc-4.0', $licenseorder);
|
||||
|
||||
$manager = new tool_licensemanager\manager();
|
||||
|
||||
// We're testing a private method, so we need to setup reflector magic.
|
||||
$method = new ReflectionMethod('\tool_licensemanager\manager', 'change_license_order');
|
||||
$method->setAccessible(true); // Allow accessing of private method.
|
||||
$method->invoke($manager, \tool_licensemanager\manager::ACTION_MOVE_UP, 'cc-nc');
|
||||
$method->invoke($manager, \tool_licensemanager\manager::ACTION_MOVE_UP, 'cc-nc-4.0');
|
||||
|
||||
$licenseorder = array_keys(license_manager::get_licenses());
|
||||
$newposition = array_search('cc-nc', $licenseorder);
|
||||
$newposition = array_search('cc-nc-4.0', $licenseorder);
|
||||
|
||||
$this->assertLessThan($initialposition, $newposition);
|
||||
|
||||
$initialposition = array_search('allrightsreserved', $licenseorder);
|
||||
$method->invoke($manager, \tool_licensemanager\manager::ACTION_MOVE_DOWN, 'allrightsreserved');
|
||||
$licenseorder = array_keys(license_manager::get_licenses());
|
||||
$newposition = array_search('cc-nc', $licenseorder);
|
||||
$newposition = array_search('cc-nc-4.0', $licenseorder);
|
||||
|
||||
$this->assertGreaterThan($initialposition, $newposition);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ trait reader {
|
||||
*/
|
||||
public static function decode_other(?string $other) {
|
||||
if ($other === 'N;' || preg_match('~^.:~', $other ?? '')) {
|
||||
return unserialize($other);
|
||||
return unserialize($other, ['allowed_classes' => [stdClass::class]]);
|
||||
} else {
|
||||
return json_decode($other ?? '', true);
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ class behat_tool_lp_data_generators extends behat_base {
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates the specified element. More info about available elements in http://docs.moodle.org/dev/Acceptance_testing#Fixtures.
|
||||
* Creates the specified element. More info about available elements in https://moodledev.io/general/development/tools/behat.
|
||||
*
|
||||
* @Given /^the following lp "(?P<element_string>(?:[^"]|\\")*)" exist:$/
|
||||
*
|
||||
|
||||
@@ -829,7 +829,7 @@ class manager {
|
||||
|
||||
// An auto-reply may itself include the Bulk Precedence.
|
||||
$precedence = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('Precedence');
|
||||
$isbulk = $isbulk || strtolower($precedence) == 'bulk';
|
||||
$isbulk = $isbulk || strtolower($precedence ?? '') == 'bulk';
|
||||
|
||||
// If the X-Autoreply header is set, and not 'no', then this is an automatic reply.
|
||||
$autoreply = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('X-Autoreply');
|
||||
|
||||
@@ -118,8 +118,12 @@ class api {
|
||||
$langs = $stringmanager->get_list_of_translations(true);
|
||||
foreach ($langs as $langid => $langname) {
|
||||
foreach ($addoninfo['lang'] as $stringinfo) {
|
||||
$lang[$langid][$stringinfo[0]] =
|
||||
$stringmanager->get_string($stringinfo[0], $stringinfo[1], null, $langid);
|
||||
$lang[$langid][$stringinfo[0]] = $stringmanager->get_string(
|
||||
$stringinfo[0],
|
||||
$stringinfo[1] ?? '',
|
||||
null,
|
||||
$langid
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ class external extends external_api {
|
||||
$timenow = time();
|
||||
if ($timenow - $last < $mintimereq) {
|
||||
$minutes = $mintimereq / MINSECS;
|
||||
throw new moodle_exception('autologinkeygenerationlockout', 'tool_mobile', $minutes);
|
||||
throw new moodle_exception('autologinkeygenerationlockout', 'tool_mobile', '', $minutes);
|
||||
}
|
||||
set_user_preference('tool_mobile_autologin_request_last', $timenow, $USER);
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ $context = context_system::instance();
|
||||
$PAGE->set_url(new \moodle_url('/'.$CFG->admin.'/tool/mobile/logout.php'));
|
||||
$PAGE->navbar->add($title);
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->set_title($SITE->fullname. ': ' . $title);
|
||||
$PAGE->set_title($title);
|
||||
|
||||
// Display the page.
|
||||
echo $OUTPUT->header();
|
||||
|
||||
@@ -387,18 +387,18 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$result = external::get_autologin_key($token->privatetoken);
|
||||
$result = \external_api::clean_returnvalue(external::get_autologin_key_returns(), $result);
|
||||
|
||||
// Change min time between requests to 30 seconds.
|
||||
set_config('autologinmintimebetweenreq', 30, 'tool_mobile');
|
||||
// Change min time between requests to 3 minutes.
|
||||
set_config('autologinmintimebetweenreq', 3 * MINSECS, 'tool_mobile');
|
||||
|
||||
// Mock a previous request, 60 seconds ago.
|
||||
$mocktime = time() - MINSECS;
|
||||
// Mock a previous request, 4 minutes ago.
|
||||
$mocktime = time() - (4 * MINSECS);
|
||||
set_user_preference('tool_mobile_autologin_request_last', $mocktime, $USER);
|
||||
$result = external::get_autologin_key($token->privatetoken); // All good, we were expecint 30 seconds or more.
|
||||
$result = external::get_autologin_key($token->privatetoken);
|
||||
$result = \external_api::clean_returnvalue(external::get_autologin_key_returns(), $result);
|
||||
|
||||
// We just requested one token, we must wait.
|
||||
$this->expectException('moodle_exception');
|
||||
$this->expectExceptionMessage(get_string('autologinkeygenerationlockout', 'tool_mobile'));
|
||||
$this->expectExceptionMessage(get_string('autologinkeygenerationlockout', 'tool_mobile', 3));
|
||||
$result = external::get_autologin_key($token->privatetoken);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,15 @@ class remote_resource_test extends \advanced_testcase {
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertGreaterThan(0, $remoteres->get_download_size());
|
||||
// We need to handle size of -1 (missing "Content-Length" header), or where it is set and greater than zero.
|
||||
$this->assertThat(
|
||||
$remoteres->get_download_size(),
|
||||
$this->logicalOr(
|
||||
$this->equalTo(-1),
|
||||
$this->greaterThan(0),
|
||||
),
|
||||
);
|
||||
|
||||
[$path, $name] = $remoteres->download_to_requestdir();
|
||||
$this->assertIsString($path);
|
||||
$this->assertEquals('test.html', $name);
|
||||
|
||||
@@ -54,10 +54,7 @@ Feature: Backup user data
|
||||
And I navigate to "Recycle bin" in current page administration
|
||||
And I should see "Quiz 1"
|
||||
And I click on "Restore" "link" in the "region-main" "region"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I navigate to "User report" in the course gradebook
|
||||
When I am on the "Course 1" "grades > User report > View" page logged in as "student1"
|
||||
Then "Quiz 1" row "Grade" column of "user-grade" table should contain "50"
|
||||
And "Quiz 1" row "Percentage" column of "user-grade" table should contain "50"
|
||||
|
||||
|
||||
@@ -37,3 +37,13 @@ function tool_task_status_checks() : array {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Function used to handle mtrace by outputting the text to normal browser window.
|
||||
*
|
||||
* @param string $message Message to output
|
||||
* @param string $eol End of line character
|
||||
*/
|
||||
function tool_task_mtrace_wrapper(string $message, string $eol): void {
|
||||
$message = s($message);
|
||||
echo $message . $eol;
|
||||
}
|
||||
|
||||
@@ -30,16 +30,6 @@ require('../../../config.php');
|
||||
|
||||
require_once($CFG->libdir.'/cronlib.php');
|
||||
|
||||
/**
|
||||
* Function used to handle mtrace by outputting the text to normal browser window.
|
||||
*
|
||||
* @param string $message Message to output
|
||||
* @param string $eol End of line character
|
||||
*/
|
||||
function tool_task_mtrace_wrapper($message, $eol) {
|
||||
echo s($message . $eol);
|
||||
}
|
||||
|
||||
// Allow execution of single task. This requires login and has different rules.
|
||||
$taskname = required_param('task', PARAM_RAW_TRIMMED);
|
||||
|
||||
@@ -97,6 +87,7 @@ require_sesskey();
|
||||
|
||||
// Prepare to handle output via mtrace.
|
||||
echo html_writer::start_tag('pre');
|
||||
require('lib.php');
|
||||
$CFG->mtrace_wrapper = 'tool_task_mtrace_wrapper';
|
||||
|
||||
// Run the specified task (this will output an error if it doesn't exist).
|
||||
|
||||
@@ -236,6 +236,8 @@ class form_test extends \advanced_testcase {
|
||||
$checker->set_day_of_week('6');
|
||||
$this->assertTrue($checker->is_valid($checker::FIELD_DAYOFWEEK));
|
||||
$checker->set_day_of_week('7');
|
||||
$this->assertTrue($checker->is_valid($checker::FIELD_DAYOFWEEK));
|
||||
$checker->set_day_of_week('8');
|
||||
$this->assertFalse($checker->is_valid($checker::FIELD_DAYOFWEEK));
|
||||
$checker->set_day_of_week('20');
|
||||
$this->assertFalse($checker->is_valid($checker::FIELD_DAYOFWEEK));
|
||||
@@ -247,7 +249,7 @@ class form_test extends \advanced_testcase {
|
||||
$checker->set_day_of_week('*/6');
|
||||
$this->assertTrue($checker->is_valid($checker::FIELD_DAYOFWEEK));
|
||||
$checker->set_day_of_week('*/7');
|
||||
$this->assertFalse($checker->is_valid($checker::FIELD_DAYOFWEEK));
|
||||
$this->assertTrue($checker->is_valid($checker::FIELD_DAYOFWEEK));
|
||||
$checker->set_day_of_week('*/13');
|
||||
$this->assertFalse($checker->is_valid($checker::FIELD_DAYOFWEEK));
|
||||
$checker->set_day_of_week('*/35');
|
||||
@@ -271,6 +273,8 @@ class form_test extends \advanced_testcase {
|
||||
$checker->set_day_of_week('65-2');
|
||||
$this->assertFalse($checker->is_valid($checker::FIELD_DAYOFWEEK));
|
||||
$checker->set_day_of_week('3-7');
|
||||
$this->assertTrue($checker->is_valid($checker::FIELD_DAYOFWEEK));
|
||||
$checker->set_day_of_week('3-8');
|
||||
$this->assertFalse($checker->is_valid($checker::FIELD_DAYOFWEEK));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,13 +173,16 @@ class tool_uploadcourse_tracker {
|
||||
} else {
|
||||
$outcome = $OUTPUT->pix_icon('i/invalid', '');
|
||||
}
|
||||
|
||||
echo html_writer::start_tag('tr', array('class' => 'r' . $this->rownb % 2));
|
||||
echo html_writer::tag('td', $line, array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', $outcome, array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', isset($data['id']) ? $data['id'] : '', array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', isset($data['shortname']) ? $data['shortname'] : '', array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', isset($data['fullname']) ? $data['fullname'] : '', array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', isset($data['idnumber']) ? $data['idnumber'] : '', array('class' => 'c' . $ci++));
|
||||
|
||||
// Ensure our data is suitable for HTML output.
|
||||
echo html_writer::tag('td', isset($data['shortname']) ? s($data['shortname']) : '', array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', isset($data['fullname']) ? s($data['fullname']) : '', array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', isset($data['idnumber']) ? s($data['idnumber']) : '', array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', $status, array('class' => 'c' . $ci++));
|
||||
echo html_writer::end_tag('tr');
|
||||
}
|
||||
|
||||
@@ -29,13 +29,6 @@ require_once($CFG->dirroot . '/webservice/lib.php');
|
||||
|
||||
admin_externalpage_setup('webservicedocumentation');
|
||||
|
||||
// get all the function descriptions
|
||||
$functions = $DB->get_records('external_functions', array(), 'name');
|
||||
$functiondescs = array();
|
||||
foreach ($functions as $function) {
|
||||
$functiondescs[$function->name] = external_api::external_function_info($function);
|
||||
}
|
||||
|
||||
// TODO: MDL-76078 - Incorrect inter-communication, core cannot have plugin dependencies like this.
|
||||
|
||||
//display the documentation for all documented protocols,
|
||||
@@ -50,6 +43,19 @@ $printableformat = optional_param('print', false, PARAM_BOOL);
|
||||
/// OUTPUT
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// Get all the function descriptions.
|
||||
$functions = $DB->get_records('external_functions', [], 'name');
|
||||
$functiondescs = [];
|
||||
foreach ($functions as $function) {
|
||||
|
||||
// Skip invalid or otherwise incorrectly defined functions, otherwise the entire page is rendered inaccessible.
|
||||
try {
|
||||
$functiondescs[$function->name] = external_api::external_function_info($function);
|
||||
} catch (Throwable $exception) {
|
||||
echo $OUTPUT->notification($exception->getMessage(), \core\output\notification::NOTIFY_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
$renderer = $PAGE->get_renderer('core', 'webservice');
|
||||
echo $renderer->documentation_html($functiondescs,
|
||||
$printableformat, $protocols, array(), $PAGE->url);
|
||||
|
||||
@@ -37,8 +37,9 @@ interface analysable {
|
||||
|
||||
/**
|
||||
* Max timestamp.
|
||||
* We are limited by both PHP's max int value and DB (cross-db) max int allowed. Use the smallest one.
|
||||
*/
|
||||
const MAX_TIME = 9999999999;
|
||||
const MAX_TIME = PHP_INT_MAX < 9999999999 ? PHP_MAX_INT : 9999999999;
|
||||
|
||||
/**
|
||||
* The analysable unique identifier in the site.
|
||||
|
||||
@@ -89,7 +89,7 @@ class login implements renderable, templatable {
|
||||
$languagedata = new \core\output\language_menu($PAGE);
|
||||
|
||||
$this->languagemenu = $languagedata->export_for_action_menu($OUTPUT);
|
||||
$this->canloginasguest = $CFG->guestloginbutton and !isguestuser();
|
||||
$this->canloginasguest = $CFG->guestloginbutton && !isguestuser();
|
||||
$this->canloginbyemail = !empty($CFG->authloginviaemail);
|
||||
$this->cansignup = $CFG->registerauth == 'email' || !empty($CFG->registerauth);
|
||||
if ($CFG->rememberusername == 0) {
|
||||
|
||||
@@ -26,7 +26,7 @@ $sesskey = sesskey();
|
||||
// when we've already left the page that set the timer.
|
||||
$loginsite = get_string("loginsite");
|
||||
$PAGE->navbar->add($loginsite);
|
||||
$PAGE->set_title("$site->fullname: $loginsite");
|
||||
$PAGE->set_title($loginsite);
|
||||
$PAGE->set_heading($site->fullname);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ if (!$authplugin->ntlmsso_finish()) {
|
||||
// here (and not add 3 more secs).
|
||||
$loginsite = get_string("loginsite");
|
||||
$PAGE->navbar->add($loginsite);
|
||||
$PAGE->set_title("$site->fullname: $loginsite");
|
||||
$PAGE->set_title($loginsite);
|
||||
$PAGE->set_heading($site->fullname);
|
||||
echo $OUTPUT->header();
|
||||
redirect($CFG->wwwroot . '/login/index.php?authldap_skipntlmsso=1',
|
||||
|
||||
@@ -40,7 +40,7 @@ if (!\auth_oauth2\api::is_enabled()) {
|
||||
|
||||
$confirmed = $auth->user_confirm($username, $usersecret);
|
||||
|
||||
if ($confirmed == AUTH_CONFIRM_ALREADY) {
|
||||
if ($confirmed == AUTH_CONFIRM_ALREADY && !isloggedin()) {
|
||||
$user = get_complete_user_data('username', $username);
|
||||
$PAGE->navbar->add(get_string("alreadyconfirmed"));
|
||||
$PAGE->set_title(get_string("alreadyconfirmed"));
|
||||
@@ -61,11 +61,7 @@ if ($confirmed == AUTH_CONFIRM_ALREADY) {
|
||||
throw new \moodle_exception('cannotfinduser', '', '', s($username));
|
||||
}
|
||||
|
||||
if (!$user->suspended) {
|
||||
complete_user_login($user);
|
||||
|
||||
\core\session\manager::apply_concurrent_login_limit($user->id, session_id());
|
||||
|
||||
if ($user->id == $USER->id) {
|
||||
// Check where to go, $redirect has a higher preference.
|
||||
if (empty($redirect) and !empty($SESSION->wantsurl) ) {
|
||||
$redirect = $SESSION->wantsurl;
|
||||
@@ -82,14 +78,20 @@ if ($confirmed == AUTH_CONFIRM_ALREADY) {
|
||||
$PAGE->set_heading($COURSE->fullname);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->box_start('generalbox centerpara boxwidthnormal boxaligncenter');
|
||||
echo "<h3>".get_string("thanks").", ". fullname($USER) . "</h3>\n";
|
||||
echo "<h3>".get_string("thanks").", ". fullname($user) . "</h3>\n";
|
||||
echo "<p>".get_string("confirmed")."</p>\n";
|
||||
echo $OUTPUT->single_button("$CFG->wwwroot/course/", get_string('courses'));
|
||||
if (!isloggedin() || isguestuser()) {
|
||||
echo $OUTPUT->single_button(get_login_url(), get_string('login'));
|
||||
} else {
|
||||
echo $OUTPUT->single_button("$CFG->wwwroot/login/logout.php", get_string('logout'));
|
||||
}
|
||||
echo $OUTPUT->box_end();
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
} else {
|
||||
\core\notification::error(get_string('confirmationinvalid', 'auth_oauth2'));
|
||||
if (!isloggedin()) {
|
||||
\core\notification::error(get_string('confirmationinvalid', 'auth_oauth2'));
|
||||
}
|
||||
}
|
||||
|
||||
redirect("$CFG->wwwroot/");
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
$PAGE->set_url('/auth/shibboleth/login.php');
|
||||
$PAGE->set_context(context_system::instance());
|
||||
$PAGE->navbar->add($loginsite);
|
||||
$PAGE->set_title("$site->fullname: $loginsite");
|
||||
$PAGE->set_title($loginsite);
|
||||
$PAGE->set_heading($site->fullname);
|
||||
$PAGE->set_pagelayout('login');
|
||||
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ information provided here is intended especially for developers.
|
||||
* The auth_db and auth_ldap plugins' implementations of update_user_record() have been removed and both now
|
||||
call the new implementation added in the base class.
|
||||
* Self registration plugins should use core_privacy\local\sitepolicy\manager instead of directly checking
|
||||
$CFG->sitepolicy , especially in custom signup forms. See https://docs.moodle.org/dev/Site_policy_handler
|
||||
$CFG->sitepolicy , especially in custom signup forms.
|
||||
|
||||
=== 3.3 ===
|
||||
|
||||
|
||||
@@ -149,15 +149,23 @@ class condition extends \core_availability\condition {
|
||||
|
||||
$allow = true;
|
||||
if ($this->expectedcompletion == COMPLETION_COMPLETE) {
|
||||
// Complete also allows the pass, fail states.
|
||||
// Complete also allows the pass state.
|
||||
switch ($completiondata->completionstate) {
|
||||
case COMPLETION_COMPLETE:
|
||||
case COMPLETION_COMPLETE_FAIL:
|
||||
case COMPLETION_COMPLETE_PASS:
|
||||
break;
|
||||
default:
|
||||
$allow = false;
|
||||
}
|
||||
} else if ($this->expectedcompletion == COMPLETION_INCOMPLETE) {
|
||||
// Incomplete also allows the fail state.
|
||||
switch ($completiondata->completionstate) {
|
||||
case COMPLETION_INCOMPLETE:
|
||||
case COMPLETION_COMPLETE_FAIL:
|
||||
break;
|
||||
default:
|
||||
$allow = false;
|
||||
}
|
||||
} else {
|
||||
// Other values require exact match.
|
||||
if ($completiondata->completionstate != $this->expectedcompletion) {
|
||||
|
||||
@@ -74,3 +74,48 @@ Feature: availability_completion
|
||||
And I click on "forum 1" "link" in the "region-main" "region"
|
||||
And I am on "Course 1" course homepage
|
||||
And I should see "Page 2" in the "region-main" "region"
|
||||
|
||||
@javascript
|
||||
Scenario Outline: Restrict access for activity completion should display correctly
|
||||
Given the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Course | C1 | Test questions |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | questiontext |
|
||||
| Test questions | truefalse | First question | Answer the first question |
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | idnumber | gradepass | completion | completionpassgrade | completionusegrade |
|
||||
| quiz | Test quiz name | C1 | quiz1 | 5.00 | 2 | 1 | 1 |
|
||||
And quiz "Test quiz name" contains the following questions:
|
||||
| question | page |
|
||||
| First question | 1 |
|
||||
And I am on the "Page 2" "page activity editing" page logged in as "teacher1"
|
||||
And I expand all fieldsets
|
||||
And I press "Add restriction..."
|
||||
And I click on "Activity completion" "button" in the "Add restriction..." "dialogue"
|
||||
And I click on ".availability-item .availability-eye img" "css_element"
|
||||
And I set the following fields to these values:
|
||||
| Required completion status | <condition> |
|
||||
| cm | quiz |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Course 1" "course" page logged in as "student1"
|
||||
And I <shouldornot> see "Page 2" in the "region-main" "region"
|
||||
# Failed grade for quiz.
|
||||
When user "student1" has attempted "Test quiz name" with responses:
|
||||
| slot | response |
|
||||
| 1 | <answer1> |
|
||||
And I reload the page
|
||||
And I <shouldornotanswer1> see "Page 2" in the "region-main" "region"
|
||||
# Passing grade for quiz.
|
||||
But user "student1" has attempted "Test quiz name" with responses:
|
||||
| slot | response |
|
||||
| 1 | <answer2> |
|
||||
And I reload the page
|
||||
And I <shouldornotanswer2> see "Page 2" in the "region-main" "region"
|
||||
|
||||
Examples:
|
||||
| condition | answer1 | answer2 | shouldornot | shouldornotanswer1 | shouldornotanswer2 |
|
||||
| must be marked complete | False | True | should not | should not | should |
|
||||
| must not be marked complete | False | True | should | should | should not |
|
||||
| must be complete with pass grade | False | True | should not | should not | should |
|
||||
| must be complete with fail grade | False | True | should not | should | should not |
|
||||
|
||||
@@ -301,14 +301,14 @@ class condition_test extends \advanced_testcase {
|
||||
$cond = new condition((object)[
|
||||
'cm' => (int)$assigncm->id, 'e' => COMPLETION_INCOMPLETE
|
||||
]);
|
||||
$this->assertFalse($cond->is_available(false, $info, true, $user->id));
|
||||
$this->assertTrue($cond->is_available(true, $info, true, $user->id));
|
||||
$this->assertTrue($cond->is_available(false, $info, true, $user->id));
|
||||
$this->assertFalse($cond->is_available(true, $info, true, $user->id));
|
||||
|
||||
$cond = new condition((object)[
|
||||
'cm' => (int)$assigncm->id, 'e' => COMPLETION_COMPLETE
|
||||
]);
|
||||
$this->assertTrue($cond->is_available(false, $info, true, $user->id));
|
||||
$this->assertFalse($cond->is_available(true, $info, true, $user->id));
|
||||
$this->assertFalse($cond->is_available(false, $info, true, $user->id));
|
||||
$this->assertTrue($cond->is_available(true, $info, true, $user->id));
|
||||
|
||||
$cond = new condition((object)[
|
||||
'cm' => (int)$assigncm->id, 'e' => COMPLETION_COMPLETE_PASS
|
||||
@@ -531,10 +531,10 @@ class condition_test extends \advanced_testcase {
|
||||
],
|
||||
// Depending on assign with grade.
|
||||
'Previous complete condition with previous fail grade' => [
|
||||
40, COMPLETION_COMPLETE, '', 'page3', true, false, '~Assign!.*is marked complete~'
|
||||
40, COMPLETION_COMPLETE, '', 'page3', false, true, '~Assign!.*is marked complete~',
|
||||
],
|
||||
'Previous incomplete condition with previous fail grade' => [
|
||||
40, COMPLETION_INCOMPLETE, '', 'page3', false, true, '~Assign!.*is incomplete~'
|
||||
40, COMPLETION_INCOMPLETE, '', 'page3', true, false, '~Assign!.*is incomplete~',
|
||||
],
|
||||
'Previous complete pass condition with previous fail grade' => [
|
||||
40, COMPLETION_COMPLETE_PASS, '', 'page3', false, true, '~Assign!.*is complete and passed~'
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
@availability @availability_date @javascript
|
||||
Feature: As a teacher I can set availability dates restriction to an activity and see a warning when conflicting dates are set
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | format | enablecompletion |
|
||||
| Course 1 | C1 | topics | 1 |
|
||||
And the following "users" exist:
|
||||
| username |
|
||||
| teacher1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | introformat | course | content | contentformat | idnumber |
|
||||
| page | PageName1 | PageDesc1 | 1 | C1 | Page 1 | 1 | 1 |
|
||||
|
||||
Scenario: When I set dates to potential conflicting dates in the same subset, I should see a warning.
|
||||
Given I am on the PageName1 "page activity editing" page logged in as teacher1
|
||||
And I expand all fieldsets
|
||||
And I click on "Add restriction..." "button" in the "root" "core_availability > Availability Button Area"
|
||||
And I click on "Date" "button" in the "Add restriction..." "dialogue"
|
||||
And I set the field "year" in the "1" "availability_date > Date Restriction" to "2023"
|
||||
And I set the field "Month" in the "1" "availability_date > Date Restriction" to "April"
|
||||
And I set the field "day" in the "1" "availability_date > Date Restriction" to "4"
|
||||
And I set the field "Direction" in the "1" "availability_date > Date Restriction" to "from"
|
||||
And I click on "Add restriction..." "button" in the "root" "core_availability > Availability Button Area"
|
||||
And I click on "Date" "button" in the "Add restriction..." "dialogue"
|
||||
And I set the field "year" in the "2" "availability_date > Date Restriction" to "2023"
|
||||
And I set the field "Month" in the "2" "availability_date > Date Restriction" to "April"
|
||||
And I set the field "day" in the "2" "availability_date > Date Restriction" to "6"
|
||||
And I set the field "Direction" in the "2" "availability_date > Date Restriction" to "until"
|
||||
And I click on "Add restriction..." "button" in the "root" "core_availability > Availability Button Area"
|
||||
And I click on "Date" "button" in the "Add restriction..." "dialogue"
|
||||
And I set the field "year" in the "3" "availability_date > Date Restriction" to "2023"
|
||||
And I set the field "Month" in the "3" "availability_date > Date Restriction" to "April"
|
||||
And I set the field "day" in the "3" "availability_date > Date Restriction" to "6"
|
||||
When I set the field "Direction" in the "3" "availability_date > Date Restriction" to "from"
|
||||
Then I should see "Conflicts with other date restrictions"
|
||||
|
||||
Scenario: If there are conflicting dates in the same subset, I should not see a warning if condition are separated by "any".
|
||||
Given I am on the PageName1 "page activity editing" page logged in as teacher1
|
||||
And I expand all fieldsets
|
||||
And I click on "Add restriction..." "button" in the "root" "core_availability > Availability Button Area"
|
||||
And I click on "Restriction set" "button" in the "Add restriction..." "dialogue"
|
||||
And I click on "Add restriction..." "button" in the "1" "core_availability > Availability Button Area"
|
||||
And I click on "Date" "button" in the "Add restriction..." "dialogue"
|
||||
And I set the field "year" in the "1.1" "availability_date > Date Restriction" to "2023"
|
||||
And I set the field "Month" in the "1.1" "availability_date > Date Restriction" to "April"
|
||||
And I set the field "day" in the "1.1" "availability_date > Date Restriction" to "4"
|
||||
And I set the field "Direction" in the "1.1" "availability_date > Date Restriction" to "from"
|
||||
And I click on "Add restriction..." "button" in the "1" "core_availability > Availability Button Area"
|
||||
And I click on "Date" "button" in the "Add restriction..." "dialogue"
|
||||
And I set the field "year" in the "1.2" "availability_date > Date Restriction" to "2023"
|
||||
And I set the field "Month" in the "1.2" "availability_date > Date Restriction" to "April"
|
||||
And I set the field "day" in the "1.2" "availability_date > Date Restriction" to "6"
|
||||
And I set the field "Direction" in the "1.2" "availability_date > Date Restriction" to "until"
|
||||
And I click on "Add restriction..." "button" in the "1" "core_availability > Availability Button Area"
|
||||
And I click on "Date" "button" in the "Add restriction..." "dialogue"
|
||||
And I set the field "year" in the "1.3" "availability_date > Date Restriction" to "2023"
|
||||
And I set the field "Month" in the "1.3" "availability_date > Date Restriction" to "April"
|
||||
And I set the field "day" in the "1.3" "availability_date > Date Restriction" to "6"
|
||||
And I set the field "Direction" in the "1.3" "availability_date > Date Restriction" to "from"
|
||||
When I set the field "Required restrictions" in the "1" "core_availability > Set Of Restrictions" to "any"
|
||||
Then I should not see "Conflicts with other date restrictions"
|
||||
|
||||
Scenario: There should a conflicting availability dates are in the same subset separated by "all".
|
||||
Given I am on the PageName1 "page activity editing" page logged in as teacher1
|
||||
And I expand all fieldsets
|
||||
# Root level: Student "must" match the following.
|
||||
And I click on "Add restriction..." "button" in the "root" "core_availability > Availability Button Area"
|
||||
And I click on "Restriction set" "button" in the "Add restriction..." "dialogue"
|
||||
# This is the second level: Student "must" match any of the following.
|
||||
And I click on "Add restriction..." "button" in the "1" "core_availability > Availability Button Area"
|
||||
And I click on "Restriction set" "button" in the "Add restriction..." "dialogue"
|
||||
# And now the third and final level.
|
||||
And I click on "Add restriction..." "button" in the "1.1" "core_availability > Availability Button Area"
|
||||
And I click on "Date" "button" in the "Add restriction..." "dialogue"
|
||||
And I set the field "year" in the "1.1.1" "availability_date > Date Restriction" to "2023"
|
||||
And I set the field "Month" in the "1.1.1" "availability_date > Date Restriction" to "April"
|
||||
And I set the field "day" in the "1.1.1" "availability_date > Date Restriction" to "2"
|
||||
And I set the field "Direction" in the "1.1.1" "availability_date > Date Restriction" to "from"
|
||||
And I click on "Add restriction..." "button" in the "1.1" "core_availability > Availability Button Area"
|
||||
And I click on "Date" "button" in the "Add restriction..." "dialogue"
|
||||
And I set the field "year" in the "1.1.2" "availability_date > Date Restriction" to "2023"
|
||||
And I set the field "Month" in the "1.1.2" "availability_date > Date Restriction" to "April"
|
||||
And I set the field "day" in the "1.1.2" "availability_date > Date Restriction" to "3"
|
||||
And I set the field "Direction" in the "1.1.2" "availability_date > Date Restriction" to "until"
|
||||
# Then add a restriction to the second level.
|
||||
And I click on "Add restriction..." "button" in the "1" "core_availability > Availability Button Area"
|
||||
And I click on "Restriction set" "button" in the "Add restriction..." "dialogue"
|
||||
And I click on "Add restriction..." "button" in the "1.2" "core_availability > Availability Button Area"
|
||||
And I click on "Date" "button" in the "Add restriction..." "dialogue"
|
||||
And I set the field "year" in the "1.2.1" "availability_date > Date Restriction" to "2023"
|
||||
And I set the field "Month" in the "1.2.1" "availability_date > Date Restriction" to "April"
|
||||
And I set the field "day" in the "1.2.1" "availability_date > Date Restriction" to "4"
|
||||
And I set the field "Direction" in the "1.2.1" "availability_date > Date Restriction" to "from"
|
||||
And I click on "Add restriction..." "button" in the "1.2" "core_availability > Availability Button Area"
|
||||
And I click on "Date" "button" in the "Add restriction..." "dialogue"
|
||||
And I set the field "year" in the "1.2.2" "availability_date > Date Restriction" to "2023"
|
||||
And I set the field "Month" in the "1.2.2" "availability_date > Date Restriction" to "April"
|
||||
And I set the field "day" in the "1.2.2" "availability_date > Date Restriction" to "3"
|
||||
When I set the field "Direction" in the "1.2.2" "availability_date > Date Restriction" to "until"
|
||||
# Same subset, we can detect conflicts.
|
||||
Then I should see "Conflicts with other date restrictions"
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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/>.
|
||||
use Behat\Mink\Element\NodeElement;
|
||||
|
||||
/**
|
||||
* Behat availabilty-related steps definitions.
|
||||
*
|
||||
* @package availability_date
|
||||
* @category test
|
||||
* @copyright 2023 Laurent David <laurent.david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_availability_date extends behat_base {
|
||||
/**
|
||||
* Return the list of partial named selectors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_partial_named_selectors(): array {
|
||||
return [
|
||||
new behat_component_named_selector(
|
||||
'Date Restriction', ["//div[h3[@data-restriction-order=%locator% and contains(text(), 'Date restriction')]]"]
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
+58
-42
@@ -65,6 +65,11 @@ M.availability_date.form.getNode = function(json) {
|
||||
// Set default time that corresponds to the HTML selectors.
|
||||
node.setData('time', this.defaultTime);
|
||||
}
|
||||
if (json.nodeUID === undefined) {
|
||||
var miliTime = new Date();
|
||||
json.nodeUID = miliTime.getTime();
|
||||
}
|
||||
node.setData('nodeUID', json.nodeUID);
|
||||
if (json.d !== undefined) {
|
||||
node.one('select[name=direction]').set('value', json.d);
|
||||
}
|
||||
@@ -114,7 +119,7 @@ M.availability_date.form.getNode = function(json) {
|
||||
* gets an AJAX response.
|
||||
*
|
||||
* @method updateTime
|
||||
* @param {Y.Node} component Node for plugin controls
|
||||
* @param {Y.Node} node Node for plugin controls
|
||||
*/
|
||||
M.availability_date.form.updateTime = function(node) {
|
||||
// After a change to the date/time we need to recompute the
|
||||
@@ -140,39 +145,53 @@ M.availability_date.form.updateTime = function(node) {
|
||||
M.availability_date.form.fillValue = function(value, node) {
|
||||
value.d = node.one('select[name=direction]').get('value');
|
||||
value.t = parseInt(node.getData('time'), 10);
|
||||
value.nodeUID = node.getData('nodeUID');
|
||||
};
|
||||
|
||||
/**
|
||||
* List out Date node value in an array node.
|
||||
* List out Date node value in the same branch.
|
||||
*
|
||||
* This will go through all array node and list from earlier date node to current date node.
|
||||
* This will go through all array node and list nodes that are sibling of the current node.
|
||||
*
|
||||
* @method convertTreeDateValue
|
||||
* @param {array} tree Tree node to convert
|
||||
* @param {array} arrayDateNode
|
||||
* @param {array} currentNode current node.
|
||||
*
|
||||
* @return {array} arrayDateNode
|
||||
* @method findAllDateSiblings
|
||||
* @param {Array} tree Tree items to convert
|
||||
* @param {Number} nodeUIDToFind node UID to find.
|
||||
* @return {Array|null} array of surrounding date avaiability values
|
||||
*/
|
||||
M.availability_date.form.convertTreeDateValue = function(tree, arrayDateNode, currentNode) {
|
||||
var shouldSkip = false;
|
||||
tree.forEach(function(node) {
|
||||
if (shouldSkip) {
|
||||
return;
|
||||
}
|
||||
if (node.type === 'date') {
|
||||
// We go through all tree node, if we meet the current node then return.
|
||||
if (node.t === parseInt(currentNode.getData('time'), 10)
|
||||
&& currentNode.one('select[name=direction]').get('value') == node.d) {
|
||||
shouldSkip = true;
|
||||
return;
|
||||
M.availability_date.form.findAllDateSiblings = function(tree, nodeUIDToFind) {
|
||||
var itemValue = null;
|
||||
var siblingsFinderRecursive = function(itemsTree) {
|
||||
var dateSiblings = [];
|
||||
var nodeFound = false;
|
||||
var index;
|
||||
var childDates;
|
||||
var currentOp = itemsTree.op !== undefined ? itemsTree.op : null;
|
||||
if (itemsTree.c !== undefined) {
|
||||
var children = itemsTree.c;
|
||||
for (index = 0; index < children.length; index++) {
|
||||
itemValue = children.at(index);
|
||||
if (itemValue.type === undefined) {
|
||||
childDates = siblingsFinderRecursive(itemValue);
|
||||
if (childDates) {
|
||||
return childDates;
|
||||
}
|
||||
}
|
||||
if (itemValue.type === 'date') {
|
||||
// We go through all tree node, if we meet the current node then we add all nodes in the current branch.
|
||||
if (nodeUIDToFind === itemValue.nodeUID) {
|
||||
nodeFound = true;
|
||||
} else if (currentOp === '&') {
|
||||
dateSiblings.push(itemValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodeFound) {
|
||||
return dateSiblings;
|
||||
}
|
||||
arrayDateNode.push(node);
|
||||
} else if (node.type === undefined) {
|
||||
M.availability_date.form.convertTreeDateValue(node.c, arrayDateNode, currentNode);
|
||||
}
|
||||
});
|
||||
return arrayDateNode;
|
||||
return null;
|
||||
};
|
||||
return siblingsFinderRecursive(tree);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -181,37 +200,34 @@ M.availability_date.form.convertTreeDateValue = function(tree, arrayDateNode, cu
|
||||
* This will check current date node with all date node in tree node.
|
||||
*
|
||||
* @method checkConditionDate
|
||||
* @param {array} currentNode The curent node.
|
||||
* @param {Y.Node} currentNode The curent node.
|
||||
*
|
||||
* @return {boolean} error Return true if the date is conflict.
|
||||
*/
|
||||
M.availability_date.form.checkConditionDate = function(currentNode) {
|
||||
var error = false;
|
||||
if (M.core_availability.form.rootList.getValue().op === '&') {
|
||||
var jsValue = M.core_availability.form.rootList.getValue().c;
|
||||
var arrayDateNode = M.availability_date.form.convertTreeDateValue(jsValue, [], currentNode);
|
||||
var currentNodeDirection = currentNode.one('select[name=direction]').get('value');
|
||||
var currentNodeTime = parseInt(currentNode.getData('time'), 10);
|
||||
arrayDateNode.forEach(function(checkNode) {
|
||||
var currentNodeUID = currentNode.getData('nodeUID');
|
||||
var currentNodeDirection = currentNode.one('select[name=direction]').get('value');
|
||||
var currentNodeTime = parseInt(currentNode.getData('time'), 10);
|
||||
var dateSiblings = M.availability_date.form.findAllDateSiblings(
|
||||
M.core_availability.form.rootList.getValue(),
|
||||
currentNodeUID);
|
||||
if (dateSiblings) {
|
||||
dateSiblings.forEach(function(dateSibling) {
|
||||
// Validate if the date is conflict.
|
||||
if (checkNode.d === '<') {
|
||||
if (currentNodeDirection === '>=' && currentNodeTime >= checkNode.t) {
|
||||
if (dateSibling.d === '<') {
|
||||
if (currentNodeDirection === '>=' && currentNodeTime >= dateSibling.t) {
|
||||
error = true;
|
||||
}
|
||||
} else {
|
||||
if (currentNodeDirection === '<' && currentNodeTime <= checkNode.t) {
|
||||
if (currentNodeDirection === '<' && currentNodeTime <= dateSibling.t) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
});
|
||||
return error;
|
||||
} else {
|
||||
if (currentNode.one('div > .badge-warning')) {
|
||||
currentNode.one('div > .badge-warning').remove();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
return error;
|
||||
};
|
||||
|
||||
M.availability_date.form.fillErrors = function(errors, node) {
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
YUI.add("moodle-availability_date-form",function(o,e){M.availability_date=M.availability_date||{},M.availability_date.form=o.Object(M.core_availability.plugin),M.availability_date.form.initInner=function(e,a){this.html=e,this.defaultTime=a},M.availability_date.form.getNode=function(e){var t,i,a='<span class="col-form-label pr-3">'+M.util.get_string("direction_before","availability_date")+'</span> <span class="availability-group"><label><span class="accesshide">'+M.util.get_string("direction_label","availability_date")+' </span><select name="direction" class="custom-select"><option value=">=">'+M.util.get_string("direction_from","availability_date")+'</option><option value="<">'+M.util.get_string("direction_until","availability_date")+"</option></select></label></span> "+this.html,n=o.Node.create("<span>"+a+"</span>");return e.t!==undefined?(n.setData("time",e.t),n.all("select:not([name=direction])").each(function(e){e.set("disabled",!0)}),a=M.cfg.wwwroot+"/availability/condition/date/ajax.php?action=fromtime&time="+e.t,o.io(a,{on:{success:function(e,a){var t,i,l=o.JSON.parse(a.responseText);for(t in l)(i=n.one("select[name=x\\["+t+"\\]]")).set("value",""+l[t]),i.set("disabled",!1)},failure:function(){window.alert(M.util.get_string("ajaxerror","availability_date"))}}})):n.setData("time",this.defaultTime),e.d!==undefined&&n.one("select[name=direction]").set("value",e.d),M.availability_date.form.addedEvents||(M.availability_date.form.addedEvents=!0,(a=o.one(".availability-field")).delegate("change",function(){M.core_availability.form.update()},".availability_date select[name=direction]"),a.delegate("change",function(){M.availability_date.form.updateTime(this.ancestor("span.availability_date"))},".availability_date select:not([name=direction])")),n.one("a[href=#]")&&(M.form.dateselector.init_single_date_selector(n),t=n.one("select[name=x\\[year\\]]"),i=t.set,t.set=function(e,a){i.call(t,e,a),"selectedIndex"===e&&setTimeout(function(){M.availability_date.form.updateTime(n)},0)}),n},M.availability_date.form.updateTime=function(t){var e=M.cfg.wwwroot+"/availability/condition/date/ajax.php?action=totime&year="+t.one("select[name=x\\[year\\]]").get("value")+"&month="+t.one("select[name=x\\[month\\]]").get("value")+"&day="+t.one("select[name=x\\[day\\]]").get("value")+"&hour="+t.one("select[name=x\\[hour\\]]").get("value")+"&minute="+t.one("select[name=x\\[minute\\]]").get("value");o.io(e,{on:{success:function(e,a){t.setData("time",a.responseText),M.core_availability.form.update()},failure:function(){window.alert(M.util.get_string("ajaxerror","availability_date"))}}})},M.availability_date.form.fillValue=function(e,a){e.d=a.one("select[name=direction]").get("value"),e.t=parseInt(a.getData("time"),10)},M.availability_date.form.convertTreeDateValue=function(e,a,t){var i=!1;return e.forEach(function(e){i||("date"===e.type?e.t!==parseInt(t.getData("time"),10)||t.one("select[name=direction]").get("value")!=e.d?a.push(e):i=!0:e.type===undefined&&M.availability_date.form.convertTreeDateValue(e.c,a,t))}),a},M.availability_date.form.checkConditionDate=function(e){var a,t,i,l=!1;return"&"===M.core_availability.form.rootList.getValue().op?(a=M.core_availability.form.rootList.getValue().c,a=M.availability_date.form.convertTreeDateValue(a,[],e),t=e.one("select[name=direction]").get("value"),i=parseInt(e.getData("time"),10),a.forEach(function(e){return"<"===e.d?">="===t&&i>=e.t&&(l=!0):"<"===t&&i<=e.t&&(l=!0),l})):e.one("div > .badge-warning")&&e.one("div > .badge-warning").remove(),l},M.availability_date.form.fillErrors=function(e,a){M.availability_date.form.checkConditionDate(a)&&e.push("availability_date:error_dateconflict")}},"@VERSION@",{requires:["base","node","event","io","moodle-core_availability-form"]});
|
||||
YUI.add("moodle-availability_date-form",function(o,e){M.availability_date=M.availability_date||{},M.availability_date.form=o.Object(M.core_availability.plugin),M.availability_date.form.initInner=function(e,a){this.html=e,this.defaultTime=a},M.availability_date.form.getNode=function(e){var t,i,a='<span class="col-form-label pr-3">'+M.util.get_string("direction_before","availability_date")+'</span> <span class="availability-group"><label><span class="accesshide">'+M.util.get_string("direction_label","availability_date")+' </span><select name="direction" class="custom-select"><option value=">=">'+M.util.get_string("direction_from","availability_date")+'</option><option value="<">'+M.util.get_string("direction_until","availability_date")+"</option></select></label></span> "+this.html,l=o.Node.create("<span>"+a+"</span>");return e.t!==undefined?(l.setData("time",e.t),l.all("select:not([name=direction])").each(function(e){e.set("disabled",!0)}),a=M.cfg.wwwroot+"/availability/condition/date/ajax.php?action=fromtime&time="+e.t,o.io(a,{on:{success:function(e,a){var t,i,n=o.JSON.parse(a.responseText);for(t in n)(i=l.one("select[name=x\\["+t+"\\]]")).set("value",""+n[t]),i.set("disabled",!1)},failure:function(){window.alert(M.util.get_string("ajaxerror","availability_date"))}}})):l.setData("time",this.defaultTime),e.nodeUID===undefined&&(a=new Date,e.nodeUID=a.getTime()),l.setData("nodeUID",e.nodeUID),e.d!==undefined&&l.one("select[name=direction]").set("value",e.d),M.availability_date.form.addedEvents||(M.availability_date.form.addedEvents=!0,(a=o.one(".availability-field")).delegate("change",function(){M.core_availability.form.update()},".availability_date select[name=direction]"),a.delegate("change",function(){M.availability_date.form.updateTime(this.ancestor("span.availability_date"))},".availability_date select:not([name=direction])")),l.one("a[href=#]")&&(M.form.dateselector.init_single_date_selector(l),t=l.one("select[name=x\\[year\\]]"),i=t.set,t.set=function(e,a){i.call(t,e,a),"selectedIndex"===e&&setTimeout(function(){M.availability_date.form.updateTime(l)},0)}),l},M.availability_date.form.updateTime=function(t){var e=M.cfg.wwwroot+"/availability/condition/date/ajax.php?action=totime&year="+t.one("select[name=x\\[year\\]]").get("value")+"&month="+t.one("select[name=x\\[month\\]]").get("value")+"&day="+t.one("select[name=x\\[day\\]]").get("value")+"&hour="+t.one("select[name=x\\[hour\\]]").get("value")+"&minute="+t.one("select[name=x\\[minute\\]]").get("value");o.io(e,{on:{success:function(e,a){t.setData("time",a.responseText),M.core_availability.form.update()},failure:function(){window.alert(M.util.get_string("ajaxerror","availability_date"))}}})},M.availability_date.form.fillValue=function(e,a){e.d=a.one("select[name=direction]").get("value"),e.t=parseInt(a.getData("time"),10),e.nodeUID=a.getData("nodeUID")},M.availability_date.form.findAllDateSiblings=function(e,d){var r,c=function(e){var a,t,i,n=[],l=!1,o=e.op!==undefined?e.op:null;if(e.c!==undefined){for(i=e.c,a=0;a<i.length;a++){if((r=i.at(a)).type===undefined&&(t=c(r)))return t;"date"===r.type&&(d===r.nodeUID?l=!0:"&"===o&&n.push(r))}if(l)return n}return null};return c(e)},M.availability_date.form.checkConditionDate=function(e){var a=!1,t=e.getData("nodeUID"),i=e.one("select[name=direction]").get("value"),n=parseInt(e.getData("time"),10),e=M.availability_date.form.findAllDateSiblings(M.core_availability.form.rootList.getValue(),t);return e&&e.forEach(function(e){return"<"===e.d?">="===i&&n>=e.t&&(a=!0):"<"===i&&n<=e.t&&(a=!0),a}),a},M.availability_date.form.fillErrors=function(e,a){M.availability_date.form.checkConditionDate(a)&&e.push("availability_date:error_dateconflict")}},"@VERSION@",{requires:["base","node","event","io","moodle-core_availability-form"]});
|
||||
availability/condition/date/yui/build/moodle-availability_date-form/moodle-availability_date-form.js
Vendored
+58
-42
@@ -65,6 +65,11 @@ M.availability_date.form.getNode = function(json) {
|
||||
// Set default time that corresponds to the HTML selectors.
|
||||
node.setData('time', this.defaultTime);
|
||||
}
|
||||
if (json.nodeUID === undefined) {
|
||||
var miliTime = new Date();
|
||||
json.nodeUID = miliTime.getTime();
|
||||
}
|
||||
node.setData('nodeUID', json.nodeUID);
|
||||
if (json.d !== undefined) {
|
||||
node.one('select[name=direction]').set('value', json.d);
|
||||
}
|
||||
@@ -114,7 +119,7 @@ M.availability_date.form.getNode = function(json) {
|
||||
* gets an AJAX response.
|
||||
*
|
||||
* @method updateTime
|
||||
* @param {Y.Node} component Node for plugin controls
|
||||
* @param {Y.Node} node Node for plugin controls
|
||||
*/
|
||||
M.availability_date.form.updateTime = function(node) {
|
||||
// After a change to the date/time we need to recompute the
|
||||
@@ -140,39 +145,53 @@ M.availability_date.form.updateTime = function(node) {
|
||||
M.availability_date.form.fillValue = function(value, node) {
|
||||
value.d = node.one('select[name=direction]').get('value');
|
||||
value.t = parseInt(node.getData('time'), 10);
|
||||
value.nodeUID = node.getData('nodeUID');
|
||||
};
|
||||
|
||||
/**
|
||||
* List out Date node value in an array node.
|
||||
* List out Date node value in the same branch.
|
||||
*
|
||||
* This will go through all array node and list from earlier date node to current date node.
|
||||
* This will go through all array node and list nodes that are sibling of the current node.
|
||||
*
|
||||
* @method convertTreeDateValue
|
||||
* @param {array} tree Tree node to convert
|
||||
* @param {array} arrayDateNode
|
||||
* @param {array} currentNode current node.
|
||||
*
|
||||
* @return {array} arrayDateNode
|
||||
* @method findAllDateSiblings
|
||||
* @param {Array} tree Tree items to convert
|
||||
* @param {Number} nodeUIDToFind node UID to find.
|
||||
* @return {Array|null} array of surrounding date avaiability values
|
||||
*/
|
||||
M.availability_date.form.convertTreeDateValue = function(tree, arrayDateNode, currentNode) {
|
||||
var shouldSkip = false;
|
||||
tree.forEach(function(node) {
|
||||
if (shouldSkip) {
|
||||
return;
|
||||
}
|
||||
if (node.type === 'date') {
|
||||
// We go through all tree node, if we meet the current node then return.
|
||||
if (node.t === parseInt(currentNode.getData('time'), 10)
|
||||
&& currentNode.one('select[name=direction]').get('value') == node.d) {
|
||||
shouldSkip = true;
|
||||
return;
|
||||
M.availability_date.form.findAllDateSiblings = function(tree, nodeUIDToFind) {
|
||||
var itemValue = null;
|
||||
var siblingsFinderRecursive = function(itemsTree) {
|
||||
var dateSiblings = [];
|
||||
var nodeFound = false;
|
||||
var index;
|
||||
var childDates;
|
||||
var currentOp = itemsTree.op !== undefined ? itemsTree.op : null;
|
||||
if (itemsTree.c !== undefined) {
|
||||
var children = itemsTree.c;
|
||||
for (index = 0; index < children.length; index++) {
|
||||
itemValue = children.at(index);
|
||||
if (itemValue.type === undefined) {
|
||||
childDates = siblingsFinderRecursive(itemValue);
|
||||
if (childDates) {
|
||||
return childDates;
|
||||
}
|
||||
}
|
||||
if (itemValue.type === 'date') {
|
||||
// We go through all tree node, if we meet the current node then we add all nodes in the current branch.
|
||||
if (nodeUIDToFind === itemValue.nodeUID) {
|
||||
nodeFound = true;
|
||||
} else if (currentOp === '&') {
|
||||
dateSiblings.push(itemValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodeFound) {
|
||||
return dateSiblings;
|
||||
}
|
||||
arrayDateNode.push(node);
|
||||
} else if (node.type === undefined) {
|
||||
M.availability_date.form.convertTreeDateValue(node.c, arrayDateNode, currentNode);
|
||||
}
|
||||
});
|
||||
return arrayDateNode;
|
||||
return null;
|
||||
};
|
||||
return siblingsFinderRecursive(tree);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -181,37 +200,34 @@ M.availability_date.form.convertTreeDateValue = function(tree, arrayDateNode, cu
|
||||
* This will check current date node with all date node in tree node.
|
||||
*
|
||||
* @method checkConditionDate
|
||||
* @param {array} currentNode The curent node.
|
||||
* @param {Y.Node} currentNode The curent node.
|
||||
*
|
||||
* @return {boolean} error Return true if the date is conflict.
|
||||
*/
|
||||
M.availability_date.form.checkConditionDate = function(currentNode) {
|
||||
var error = false;
|
||||
if (M.core_availability.form.rootList.getValue().op === '&') {
|
||||
var jsValue = M.core_availability.form.rootList.getValue().c;
|
||||
var arrayDateNode = M.availability_date.form.convertTreeDateValue(jsValue, [], currentNode);
|
||||
var currentNodeDirection = currentNode.one('select[name=direction]').get('value');
|
||||
var currentNodeTime = parseInt(currentNode.getData('time'), 10);
|
||||
arrayDateNode.forEach(function(checkNode) {
|
||||
var currentNodeUID = currentNode.getData('nodeUID');
|
||||
var currentNodeDirection = currentNode.one('select[name=direction]').get('value');
|
||||
var currentNodeTime = parseInt(currentNode.getData('time'), 10);
|
||||
var dateSiblings = M.availability_date.form.findAllDateSiblings(
|
||||
M.core_availability.form.rootList.getValue(),
|
||||
currentNodeUID);
|
||||
if (dateSiblings) {
|
||||
dateSiblings.forEach(function(dateSibling) {
|
||||
// Validate if the date is conflict.
|
||||
if (checkNode.d === '<') {
|
||||
if (currentNodeDirection === '>=' && currentNodeTime >= checkNode.t) {
|
||||
if (dateSibling.d === '<') {
|
||||
if (currentNodeDirection === '>=' && currentNodeTime >= dateSibling.t) {
|
||||
error = true;
|
||||
}
|
||||
} else {
|
||||
if (currentNodeDirection === '<' && currentNodeTime <= checkNode.t) {
|
||||
if (currentNodeDirection === '<' && currentNodeTime <= dateSibling.t) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
});
|
||||
return error;
|
||||
} else {
|
||||
if (currentNode.one('div > .badge-warning')) {
|
||||
currentNode.one('div > .badge-warning').remove();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
return error;
|
||||
};
|
||||
|
||||
M.availability_date.form.fillErrors = function(errors, node) {
|
||||
|
||||
+58
-42
@@ -63,6 +63,11 @@ M.availability_date.form.getNode = function(json) {
|
||||
// Set default time that corresponds to the HTML selectors.
|
||||
node.setData('time', this.defaultTime);
|
||||
}
|
||||
if (json.nodeUID === undefined) {
|
||||
var miliTime = new Date();
|
||||
json.nodeUID = miliTime.getTime();
|
||||
}
|
||||
node.setData('nodeUID', json.nodeUID);
|
||||
if (json.d !== undefined) {
|
||||
node.one('select[name=direction]').set('value', json.d);
|
||||
}
|
||||
@@ -112,7 +117,7 @@ M.availability_date.form.getNode = function(json) {
|
||||
* gets an AJAX response.
|
||||
*
|
||||
* @method updateTime
|
||||
* @param {Y.Node} component Node for plugin controls
|
||||
* @param {Y.Node} node Node for plugin controls
|
||||
*/
|
||||
M.availability_date.form.updateTime = function(node) {
|
||||
// After a change to the date/time we need to recompute the
|
||||
@@ -138,39 +143,53 @@ M.availability_date.form.updateTime = function(node) {
|
||||
M.availability_date.form.fillValue = function(value, node) {
|
||||
value.d = node.one('select[name=direction]').get('value');
|
||||
value.t = parseInt(node.getData('time'), 10);
|
||||
value.nodeUID = node.getData('nodeUID');
|
||||
};
|
||||
|
||||
/**
|
||||
* List out Date node value in an array node.
|
||||
* List out Date node value in the same branch.
|
||||
*
|
||||
* This will go through all array node and list from earlier date node to current date node.
|
||||
* This will go through all array node and list nodes that are sibling of the current node.
|
||||
*
|
||||
* @method convertTreeDateValue
|
||||
* @param {array} tree Tree node to convert
|
||||
* @param {array} arrayDateNode
|
||||
* @param {array} currentNode current node.
|
||||
*
|
||||
* @return {array} arrayDateNode
|
||||
* @method findAllDateSiblings
|
||||
* @param {Array} tree Tree items to convert
|
||||
* @param {Number} nodeUIDToFind node UID to find.
|
||||
* @return {Array|null} array of surrounding date avaiability values
|
||||
*/
|
||||
M.availability_date.form.convertTreeDateValue = function(tree, arrayDateNode, currentNode) {
|
||||
var shouldSkip = false;
|
||||
tree.forEach(function(node) {
|
||||
if (shouldSkip) {
|
||||
return;
|
||||
}
|
||||
if (node.type === 'date') {
|
||||
// We go through all tree node, if we meet the current node then return.
|
||||
if (node.t === parseInt(currentNode.getData('time'), 10)
|
||||
&& currentNode.one('select[name=direction]').get('value') == node.d) {
|
||||
shouldSkip = true;
|
||||
return;
|
||||
M.availability_date.form.findAllDateSiblings = function(tree, nodeUIDToFind) {
|
||||
var itemValue = null;
|
||||
var siblingsFinderRecursive = function(itemsTree) {
|
||||
var dateSiblings = [];
|
||||
var nodeFound = false;
|
||||
var index;
|
||||
var childDates;
|
||||
var currentOp = itemsTree.op !== undefined ? itemsTree.op : null;
|
||||
if (itemsTree.c !== undefined) {
|
||||
var children = itemsTree.c;
|
||||
for (index = 0; index < children.length; index++) {
|
||||
itemValue = children.at(index);
|
||||
if (itemValue.type === undefined) {
|
||||
childDates = siblingsFinderRecursive(itemValue);
|
||||
if (childDates) {
|
||||
return childDates;
|
||||
}
|
||||
}
|
||||
if (itemValue.type === 'date') {
|
||||
// We go through all tree node, if we meet the current node then we add all nodes in the current branch.
|
||||
if (nodeUIDToFind === itemValue.nodeUID) {
|
||||
nodeFound = true;
|
||||
} else if (currentOp === '&') {
|
||||
dateSiblings.push(itemValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodeFound) {
|
||||
return dateSiblings;
|
||||
}
|
||||
arrayDateNode.push(node);
|
||||
} else if (node.type === undefined) {
|
||||
M.availability_date.form.convertTreeDateValue(node.c, arrayDateNode, currentNode);
|
||||
}
|
||||
});
|
||||
return arrayDateNode;
|
||||
return null;
|
||||
};
|
||||
return siblingsFinderRecursive(tree);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -179,37 +198,34 @@ M.availability_date.form.convertTreeDateValue = function(tree, arrayDateNode, cu
|
||||
* This will check current date node with all date node in tree node.
|
||||
*
|
||||
* @method checkConditionDate
|
||||
* @param {array} currentNode The curent node.
|
||||
* @param {Y.Node} currentNode The curent node.
|
||||
*
|
||||
* @return {boolean} error Return true if the date is conflict.
|
||||
*/
|
||||
M.availability_date.form.checkConditionDate = function(currentNode) {
|
||||
var error = false;
|
||||
if (M.core_availability.form.rootList.getValue().op === '&') {
|
||||
var jsValue = M.core_availability.form.rootList.getValue().c;
|
||||
var arrayDateNode = M.availability_date.form.convertTreeDateValue(jsValue, [], currentNode);
|
||||
var currentNodeDirection = currentNode.one('select[name=direction]').get('value');
|
||||
var currentNodeTime = parseInt(currentNode.getData('time'), 10);
|
||||
arrayDateNode.forEach(function(checkNode) {
|
||||
var currentNodeUID = currentNode.getData('nodeUID');
|
||||
var currentNodeDirection = currentNode.one('select[name=direction]').get('value');
|
||||
var currentNodeTime = parseInt(currentNode.getData('time'), 10);
|
||||
var dateSiblings = M.availability_date.form.findAllDateSiblings(
|
||||
M.core_availability.form.rootList.getValue(),
|
||||
currentNodeUID);
|
||||
if (dateSiblings) {
|
||||
dateSiblings.forEach(function(dateSibling) {
|
||||
// Validate if the date is conflict.
|
||||
if (checkNode.d === '<') {
|
||||
if (currentNodeDirection === '>=' && currentNodeTime >= checkNode.t) {
|
||||
if (dateSibling.d === '<') {
|
||||
if (currentNodeDirection === '>=' && currentNodeTime >= dateSibling.t) {
|
||||
error = true;
|
||||
}
|
||||
} else {
|
||||
if (currentNodeDirection === '<' && currentNodeTime <= checkNode.t) {
|
||||
if (currentNodeDirection === '<' && currentNodeTime <= dateSibling.t) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
});
|
||||
return error;
|
||||
} else {
|
||||
if (currentNode.one('div > .badge-warning')) {
|
||||
currentNode.one('div > .badge-warning').remove();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
return error;
|
||||
};
|
||||
|
||||
M.availability_date.form.fillErrors = function(errors, node) {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?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/>.
|
||||
|
||||
require_once(__DIR__ . '/../../../lib/behat/behat_base.php');
|
||||
|
||||
/**
|
||||
* Availability related behat steps and selectors definitions.
|
||||
*
|
||||
* @package core_availability
|
||||
* @category test
|
||||
* @copyright 2023 Amaia Anabitarte <amaia@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_availability extends behat_base {
|
||||
|
||||
/**
|
||||
* Return the list of partial named selectors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_partial_named_selectors(): array {
|
||||
return [
|
||||
new behat_component_named_selector(
|
||||
'Activity availability', [
|
||||
".//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')]"
|
||||
. "[descendant::*[contains(normalize-space(.), %locator%)]]//div[@data-region='availabilityinfo']",
|
||||
]
|
||||
),
|
||||
new behat_component_named_selector(
|
||||
'Section availability', [".//li[@id = %locator%]//div[@data-region='availabilityinfo']"],
|
||||
),
|
||||
new behat_component_named_selector(
|
||||
'Set Of Restrictions', ["//div[h3[@data-restriction-order=%locator% and contains(text(), 'Set of')]]"],
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of exact named selectors
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_exact_named_selectors(): array {
|
||||
return [
|
||||
new behat_component_named_selector(
|
||||
'Availability Button Area',
|
||||
[
|
||||
"//h3[@data-restriction-order=%locator%]/following-sibling::div[contains(@class,'availability-inner')]/"
|
||||
. "div[contains(@class,'availability-button')]",
|
||||
],
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
Vendored
+2
-1
@@ -560,7 +560,7 @@ M.core_availability.List.prototype.renumber = function(parentNumber) {
|
||||
}
|
||||
var heading = M.util.get_string('setheading', 'availability', headingParams);
|
||||
this.node.one('> h3').set('innerHTML', heading);
|
||||
|
||||
this.node.one('> h3').getDOMNode().dataset.restrictionOrder = parentNumber ? parentNumber : 'root';
|
||||
// Do children.
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var child = this.children[i];
|
||||
@@ -1008,6 +1008,7 @@ M.core_availability.Item.prototype.renumber = function(number) {
|
||||
headingParams.number = number + ':';
|
||||
var heading = M.util.get_string('itemheading', 'availability', headingParams);
|
||||
this.node.one('> h3').set('innerHTML', heading);
|
||||
this.node.one('> h3').getDOMNode().dataset.restrictionOrder = number ? number : 'root';
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
File diff suppressed because one or more lines are too long
+2
-1
@@ -560,7 +560,7 @@ M.core_availability.List.prototype.renumber = function(parentNumber) {
|
||||
}
|
||||
var heading = M.util.get_string('setheading', 'availability', headingParams);
|
||||
this.node.one('> h3').set('innerHTML', heading);
|
||||
|
||||
this.node.one('> h3').getDOMNode().dataset.restrictionOrder = parentNumber ? parentNumber : 'root';
|
||||
// Do children.
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var child = this.children[i];
|
||||
@@ -1008,6 +1008,7 @@ M.core_availability.Item.prototype.renumber = function(number) {
|
||||
headingParams.number = number + ':';
|
||||
var heading = M.util.get_string('itemheading', 'availability', headingParams);
|
||||
this.node.one('> h3').set('innerHTML', heading);
|
||||
this.node.one('> h3').getDOMNode().dataset.restrictionOrder = number ? number : 'root';
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Vendored
+2
-1
@@ -558,7 +558,7 @@ M.core_availability.List.prototype.renumber = function(parentNumber) {
|
||||
}
|
||||
var heading = M.util.get_string('setheading', 'availability', headingParams);
|
||||
this.node.one('> h3').set('innerHTML', heading);
|
||||
|
||||
this.node.one('> h3').getDOMNode().dataset.restrictionOrder = parentNumber ? parentNumber : 'root';
|
||||
// Do children.
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var child = this.children[i];
|
||||
@@ -1006,6 +1006,7 @@ M.core_availability.Item.prototype.renumber = function(number) {
|
||||
headingParams.number = number + ':';
|
||||
var heading = M.util.get_string('itemheading', 'availability', headingParams);
|
||||
this.node.one('> h3').set('innerHTML', heading);
|
||||
this.node.one('> h3').getDOMNode().dataset.restrictionOrder = number ? number : 'root';
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -867,7 +867,9 @@ class moodle1_course_outline_handler extends moodle1_xml_handler {
|
||||
$plugin->version = null;
|
||||
$module = $plugin;
|
||||
include($versionfile);
|
||||
$data['version'] = $plugin->version;
|
||||
// Have to hardcode - since quiz uses some hardcoded version numbers when restoring.
|
||||
// This is the lowest number used minus one.
|
||||
$data['version'] = 2011010099;
|
||||
} else {
|
||||
$data['version'] = null;
|
||||
}
|
||||
|
||||
@@ -1602,7 +1602,13 @@ class backup_block_instance_structure_step extends backup_structure_step {
|
||||
// Transform configdata information if needed (process links and friends)
|
||||
$blockrec = $DB->get_record('block_instances', array('id' => $this->task->get_blockid()));
|
||||
if ($attrstotransform = $this->task->get_configdata_encoded_attributes()) {
|
||||
$configdata = (array)unserialize(base64_decode($blockrec->configdata));
|
||||
$configdata = array_filter(
|
||||
(array) unserialize_object(base64_decode($blockrec->configdata)),
|
||||
static function($value): bool {
|
||||
return !($value instanceof __PHP_Incomplete_Class);
|
||||
}
|
||||
);
|
||||
|
||||
foreach ($configdata as $attribute => $value) {
|
||||
if (in_array($attribute, $attrstotransform)) {
|
||||
$configdata[$attribute] = $this->contenttransformer->process($value);
|
||||
|
||||
@@ -4340,7 +4340,13 @@ class restore_block_instance_structure_step extends restore_structure_step {
|
||||
// Let's look for anything within configdata neededing processing
|
||||
// (nulls and uses of legacy file.php)
|
||||
if ($attrstotransform = $this->task->get_configdata_encoded_attributes()) {
|
||||
$configdata = (array) unserialize_object(base64_decode($data->configdata));
|
||||
$configdata = array_filter(
|
||||
(array) unserialize_object(base64_decode($data->configdata)),
|
||||
static function($value): bool {
|
||||
return !($value instanceof __PHP_Incomplete_Class);
|
||||
}
|
||||
);
|
||||
|
||||
foreach ($configdata as $attribute => $value) {
|
||||
if (in_array($attribute, $attrstotransform)) {
|
||||
$configdata[$attribute] = $this->contentprocessor->process_cdata($value);
|
||||
|
||||
@@ -160,12 +160,16 @@ if ($context->contextlevel == CONTEXT_MODULE) {
|
||||
$renderer = $PAGE->get_renderer('core', 'backup');
|
||||
echo $renderer->backup_files_viewer($treeview_options);
|
||||
echo $OUTPUT->container_end();
|
||||
// Update the course context with the proper value, because $context contains the module context.
|
||||
$coursecontext = \context_course::instance($course->id);
|
||||
} else {
|
||||
$coursecontext = $context;
|
||||
}
|
||||
|
||||
echo $OUTPUT->heading_with_help(get_string('choosefilefromcoursebackup', 'backup'), 'choosefilefromcoursebackup', 'backup');
|
||||
echo $OUTPUT->container_start();
|
||||
$treeview_options = array();
|
||||
$treeview_options['filecontext'] = $context;
|
||||
$treeview_options['filecontext'] = $coursecontext;
|
||||
$treeview_options['currentcontext'] = $context;
|
||||
$treeview_options['component'] = 'backup';
|
||||
$treeview_options['context'] = $context;
|
||||
|
||||
@@ -72,7 +72,7 @@ abstract class backup_structure_dbops extends backup_dbops {
|
||||
throw new base_element_struct_exception('valueofparamelementnotset', $param->get_name());
|
||||
}
|
||||
|
||||
} else if ($param < 0) { // Possibly one processor variable, let's process it
|
||||
} else if (is_int($param) && $param < 0) { // Possibly one processor variable, let's process it
|
||||
// See @backup class for all the VAR_XXX variables available.
|
||||
// Note1: backup::VAR_PARENTID is handled by nested elements themselves
|
||||
// Note2: trying to use one non-existing var will throw exception
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core_backup;
|
||||
|
||||
use backup_structure_dbops;
|
||||
|
||||
/**
|
||||
* Tests for backup_structure_dbops
|
||||
*
|
||||
* @package core_backup
|
||||
* @category test
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \backup_structure_dbops
|
||||
*/
|
||||
class backup_structure_dbops_test extends \advanced_testcase {
|
||||
public static function setUpBeforeClass(): void {
|
||||
global $CFG;
|
||||
parent::setUpBeforeClass();
|
||||
require_once("{$CFG->dirroot}/backup/util/includes/backup_includes.php");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for convert_params_to_values.
|
||||
*
|
||||
* @dataProvider convert_params_to_values_provider
|
||||
* @param array $params
|
||||
* @param mixed $processor
|
||||
* @param array $expected
|
||||
*/
|
||||
public function test_convert_params_to_values(
|
||||
array $params,
|
||||
$processor,
|
||||
array $expected
|
||||
): void {
|
||||
if (is_callable($processor)) {
|
||||
$newprocessor = $this->createMock(\backup_structure_processor::class);
|
||||
$newprocessor->method('get_var')->willReturnCallback($processor);
|
||||
$processor = $newprocessor;
|
||||
}
|
||||
|
||||
$result = backup_structure_dbops::convert_params_to_values($params, $processor);
|
||||
|
||||
$this->assertEqualsCanonicalizing($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for convert_params_to_values_provider.
|
||||
*/
|
||||
public static function convert_params_to_values_provider(): array {
|
||||
return [
|
||||
'String value is not processed' => [
|
||||
['/0/1/2/345'],
|
||||
null,
|
||||
['/0/1/2/345'],
|
||||
],
|
||||
'Positive integer' => [
|
||||
[123, 456],
|
||||
null,
|
||||
[123, 456],
|
||||
],
|
||||
'Negative integer' => [
|
||||
[-42],
|
||||
function () {
|
||||
return 'Life, the Universe, and Everything';
|
||||
},
|
||||
['Life, the Universe, and Everything'],
|
||||
],
|
||||
'Mix of strings, and ints with a processor' => [
|
||||
['foo', 123, 'bar', -42],
|
||||
function () {
|
||||
return 'Life, the Universe, and Everything';
|
||||
},
|
||||
['foo', 123, 'bar', 'Life, the Universe, and Everything'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for convert_params_to_values with an atom.
|
||||
*/
|
||||
public function test_convert_params_to_values_with_atom(): void {
|
||||
$atom = $this->createMock(\base_atom::class);
|
||||
$atom->method('is_set')->willReturn(true);
|
||||
$atom->method('get_value')->willReturn('Some atomised value');
|
||||
|
||||
$result = backup_structure_dbops::convert_params_to_values([$atom], null);
|
||||
|
||||
$this->assertEqualsCanonicalizing(['Some atomised value'], $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for convert_params_to_values with an atom without any value.
|
||||
*/
|
||||
public function test_convert_params_to_values_with_atom_no_value(): void {
|
||||
$atom = $this->createMock(\base_atom::class);
|
||||
$atom->method('is_set')->willReturn(false);
|
||||
$atom->method('get_name')->willReturn('Atomisd name');
|
||||
|
||||
$this->expectException(\base_element_struct_exception::class);
|
||||
backup_structure_dbops::convert_params_to_values([$atom], null);
|
||||
}
|
||||
}
|
||||
@@ -639,6 +639,8 @@ class backpack_api {
|
||||
$DB->delete_records('badge_external', array('backpackid' => $backpackid));
|
||||
$DB->delete_records('badge_backpack', array('userid' => $userid));
|
||||
$badgescache->delete($userid);
|
||||
$this->clear_system_user_session();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,20 +14,17 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use \core_badges\badge;
|
||||
|
||||
/**
|
||||
* Local stuff for category enrolment plugin.
|
||||
* Event observer for badges.
|
||||
*
|
||||
* @package core_badges
|
||||
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use \core_badges\badge;
|
||||
/**
|
||||
* Event observer for badges.
|
||||
*/
|
||||
class core_badges_observer {
|
||||
/**
|
||||
* Triggered when 'course_module_completion_updated' event is triggered.
|
||||
|
||||
@@ -188,8 +188,6 @@ class award_criteria_activity extends award_criteria {
|
||||
* @return bool Whether criteria is complete
|
||||
*/
|
||||
public function review($userid, $filtered = false) {
|
||||
$completionstates = array(COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS, COMPLETION_COMPLETE_FAIL);
|
||||
|
||||
if ($this->course->startdate > time()) {
|
||||
return false;
|
||||
}
|
||||
@@ -209,6 +207,15 @@ class award_criteria_activity extends award_criteria {
|
||||
$check_date = ($date <= $param['bydate']);
|
||||
}
|
||||
|
||||
// Successfull completion states depend on the completion settings.
|
||||
if (isset($data->passgrade)) {
|
||||
// Passing grade is required. Don't issue a badge when state is COMPLETION_COMPLETE_FAIL.
|
||||
$completionstates = [COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS];
|
||||
} else {
|
||||
// Any grade is required. Issue a badge even when state is COMPLETION_COMPLETE_FAIL.
|
||||
$completionstates = [COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS, COMPLETION_COMPLETE_FAIL];
|
||||
}
|
||||
|
||||
if ($this->method == BADGE_CRITERIA_AGGREGATION_ALL) {
|
||||
if (in_array($data->completionstate, $completionstates) && $check_date) {
|
||||
$overall = true;
|
||||
|
||||
@@ -54,6 +54,8 @@ $badge = new badge($badgeid);
|
||||
$context = $badge->get_context();
|
||||
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type));
|
||||
|
||||
require_capability('moodle/badges:viewawarded', $context);
|
||||
|
||||
if ($badge->type == BADGE_TYPE_COURSE) {
|
||||
if (empty($CFG->badges_allowcoursebadges)) {
|
||||
throw new \moodle_exception('coursebadgesdisabled', 'badges');
|
||||
|
||||
@@ -229,12 +229,19 @@ Feature: Award badges
|
||||
|
||||
@javascript
|
||||
Scenario: Award badge on course completion
|
||||
Given I log in as "teacher1"
|
||||
Given the following "activity" exists:
|
||||
| activity | chat |
|
||||
| course | C1 |
|
||||
| name | Music history |
|
||||
| section | 1 |
|
||||
| completion | 2 |
|
||||
| completionview | 1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Course completion" in current page administration
|
||||
And I set the field "id_overall_aggregation" to "2"
|
||||
And I click on "Condition: Activity completion" "link"
|
||||
And I set the field "Assignment - Test assignment name" to "1"
|
||||
And I set the field "Chat - Music history" to "1"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Badges > Add a new badge" in current page administration
|
||||
@@ -253,8 +260,7 @@ Feature: Award badges
|
||||
And I follow "Profile" in the user menu
|
||||
And I click on "Course 1" "link" in the "region-main" "region"
|
||||
Then I should not see "badges"
|
||||
And I am on "Course 1" course homepage
|
||||
And I toggle the manual completion state of "Test assignment name"
|
||||
When I am on the "Music history" "chat activity" page
|
||||
And I log out
|
||||
# Completion cron won't mark the whole course completed unless the
|
||||
# individual criteria was marked completed more than a second ago. So
|
||||
@@ -265,6 +271,7 @@ Feature: Award badges
|
||||
# The student should now see their badge.
|
||||
And I log in as "student1"
|
||||
And I follow "Profile" in the user menu
|
||||
And I click on "Course 1" "link" in the "region-main" "region"
|
||||
Then I should see "Course Badge"
|
||||
|
||||
@javascript
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
@mod @mod_quiz @core @core_badges @javascript
|
||||
@mod @mod_quiz @core @core_badges @core_completion @javascript
|
||||
Feature: Award badges based on activity completion
|
||||
In order to ensure a student has learned the material before being marked complete
|
||||
As a teacher
|
||||
I need to set a quiz to award a badge when upon completion when the student receives a passing grade, or completed_fail if they use all attempts without passing
|
||||
I need to configure an activity to grant a badge only when the student achieves a passing grade upon completion.
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| student2 | Student | 1 | student2@example.com |
|
||||
| student2 | Student | 2 | student2@example.com |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category | enablecompletion |
|
||||
@@ -27,96 +27,103 @@ Feature: Award badges based on activity completion
|
||||
| questioncategory | qtype | name | questiontext |
|
||||
| Test questions | truefalse | First question | Answer the first question |
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | idnumber | attempts | gradepass | completion | completionattemptsexhausted | completionpassgrade | completionusegrade |
|
||||
| quiz | Test quiz name | C1 | quiz1 | 2 | 5.00 | 2 | 1 | 1 | 1 |
|
||||
And quiz "Test quiz name" contains the following questions:
|
||||
| activity | name | course | idnumber | attempts | gradepass | completion | completionpassgrade | completionusegrade |
|
||||
| quiz | Test quiz name 1 | C1 | quiz1 | 2 | 5.00 | 2 | 1 | 1 |
|
||||
| quiz | Test quiz name 2 | C1 | quiz2 | 2 | 5.00 | 2 | 0 | 1 |
|
||||
And quiz "Test quiz name 1" contains the following questions:
|
||||
| question | page |
|
||||
| First question | 1 |
|
||||
And quiz "Test quiz name 2" contains the following questions:
|
||||
| question | page |
|
||||
| First question | 1 |
|
||||
And user "student1" has attempted "Test quiz name" with responses:
|
||||
| slot | response |
|
||||
| 1 | False |
|
||||
And user "student2" has attempted "Test quiz name" with responses:
|
||||
| slot | response |
|
||||
| 1 | False |
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Course Badge |
|
||||
| name | Course Badge 1 |
|
||||
| status | 0 |
|
||||
| type | 2 |
|
||||
| course | C1 |
|
||||
| description | Course badge description |
|
||||
| description | Course badge 1 description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Course Badge 2 |
|
||||
| status | 0 |
|
||||
| type | 2 |
|
||||
| course | C1 |
|
||||
| description | Course badge 2 description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
|
||||
Scenario: Student earns a badge using activity completion, but does not get passing grade
|
||||
Given I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to "Badges" in current page administration
|
||||
Scenario: Student does not earn a badge using activity completion when does not get passing grade
|
||||
Given I navigate to "Badges" in current page administration
|
||||
And I press "Manage badges"
|
||||
And I follow "Course Badge"
|
||||
And I follow "Course Badge 1"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Activity completion"
|
||||
And I set the field "Quiz - Test quiz name" to "1"
|
||||
And I set the field "Quiz - Test quiz name 1" to "1"
|
||||
And I press "Save"
|
||||
And I press "Enable access"
|
||||
And I press "Continue"
|
||||
And I should see "Recipients (0)"
|
||||
And I log out
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "failed"
|
||||
And the "Receive a pass grade or complete all available attempts" completion condition of "Test quiz name" is displayed as "todo"
|
||||
When I am on the "Test quiz name" "quiz activity" page
|
||||
And I press "Re-attempt quiz"
|
||||
And I set the field "False" to "1"
|
||||
And I press "Finish attempt ..."
|
||||
And I press "Submit all and finish"
|
||||
And I click on "Submit" "button" in the "Submit all your answers and finish?" "dialogue"
|
||||
And I log out
|
||||
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
# Pass grade for student1. Activity is considered complete because student1 got a passing grade.
|
||||
And user "student1" has attempted "Test quiz name 1" with responses:
|
||||
| slot | response |
|
||||
| 1 | True |
|
||||
# Fail grade for student2. Activity is considered incomplete because student2 got a failing grade.
|
||||
And user "student2" has attempted "Test quiz name 1" with responses:
|
||||
| slot | response |
|
||||
| 1 | False |
|
||||
And I navigate to "Badges > Manage badges" in current page administration
|
||||
And I follow "Course Badge"
|
||||
And I follow "Course Badge 1"
|
||||
Then I should see "Recipients (1)"
|
||||
And I select "Recipients (1)" from the "jump" singleselect
|
||||
And I should see "Student 1"
|
||||
And I should not see "Student 2"
|
||||
|
||||
Scenario Outline: Previously graded pass/fail students should earn a badge after enabling a badge
|
||||
Given I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to "Badges" in current page administration
|
||||
Scenario: Students with any grades in an activity will receive a badge if the completion condition is set to receive any grade
|
||||
Given I navigate to "Badges" in current page administration
|
||||
And I press "Manage badges"
|
||||
And I follow "Course Badge"
|
||||
And I follow "Course Badge 2"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Activity completion"
|
||||
And I click on "Expand all" "link"
|
||||
And I set the field "Quiz - Test quiz name" to "1"
|
||||
And I set the field "<aggregationcriteria>" to "1"
|
||||
And I set the field "Quiz - Test quiz name 2" to "1"
|
||||
And I press "Save"
|
||||
|
||||
# Fail grade with student2
|
||||
And I am on the "Course 1" course page logged in as student2
|
||||
And I am on the "Test quiz name" "quiz activity" page
|
||||
And I press "Re-attempt quiz"
|
||||
And I set the field "False" to "1"
|
||||
And I press "Finish attempt ..."
|
||||
And I press "Submit all and finish"
|
||||
And I click on "Submit" "button" in the "Submit all your answers and finish?" "dialogue"
|
||||
And I log out
|
||||
|
||||
# Pass grade with student1
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And I am on the "Test quiz name" "quiz activity" page
|
||||
And I press "Re-attempt quiz"
|
||||
And I set the field "False" to "0"
|
||||
And I press "Finish attempt ..."
|
||||
And I press "Submit all and finish"
|
||||
And I click on "Submit" "button" in the "Submit all your answers and finish?" "dialogue"
|
||||
And I log out
|
||||
|
||||
# Enable badge access once all students have completed an activity.
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I press "Enable access"
|
||||
And I press "Continue"
|
||||
# Pass grade for student1.
|
||||
And user "student1" has attempted "Test quiz name 2" with responses:
|
||||
| slot | response |
|
||||
| 1 | True |
|
||||
# Fail grade for student2. Activity is considered complete even if student2 got a failing grade.
|
||||
And user "student2" has attempted "Test quiz name 2" with responses:
|
||||
| slot | response |
|
||||
| 1 | False |
|
||||
And I navigate to "Badges > Manage badges" in current page administration
|
||||
And I follow "Course Badge"
|
||||
And I follow "Course Badge 2"
|
||||
Then I should see "Recipients (2)"
|
||||
And I select "Recipients (2)" from the "jump" singleselect
|
||||
And I should see "Student 1"
|
||||
And I should see "Student 2"
|
||||
|
||||
Scenario: Previously graded pass/fail students should earn a badge after enabling a badge
|
||||
# Pass grade for student1.
|
||||
Given user "student1" has attempted "Test quiz name 1" with responses:
|
||||
| slot | response |
|
||||
| 1 | True |
|
||||
# Fail grade for student2.
|
||||
And user "student2" has attempted "Test quiz name 1" with responses:
|
||||
| slot | response |
|
||||
| 1 | False |
|
||||
And I navigate to "Badges" in current page administration
|
||||
And I press "Manage badges"
|
||||
And I follow "Course Badge 1"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Activity completion"
|
||||
And I set the field "Quiz - Test quiz name 1" to "1"
|
||||
And I press "Save"
|
||||
# Enable badge access once students have completed the activity.
|
||||
When I press "Enable access"
|
||||
And I press "Continue"
|
||||
Then I should see "Recipients (2)"
|
||||
|
||||
Examples:
|
||||
| aggregationcriteria |
|
||||
| Any of the selected activities is complete |
|
||||
| All of the selected activities are complete |
|
||||
# Only student1 should earn the badge because student2 did not pass the quiz.
|
||||
Then I should see "Recipients (1)"
|
||||
And I select "Recipients (1)" from the "jump" singleselect
|
||||
And I should see "Student 1"
|
||||
And I should not see "Student 2"
|
||||
|
||||
@@ -32,18 +32,15 @@ Feature: The activity results block displays student scores
|
||||
And the following "activities" exist:
|
||||
| activity | name | content | course | section | idnumber |
|
||||
| page | Test page name | This is a page | C1 | 1 | page1 |
|
||||
And the following "grade grades" exist:
|
||||
| gradeitem | user | grade |
|
||||
| Test assignment 1 | student1 | 90.00 |
|
||||
| Test assignment 1 | student2 | 80.00 |
|
||||
| Test assignment 1 | student3 | 70.00 |
|
||||
| Test assignment 1 | student4 | 60.00 |
|
||||
| Test assignment 1 | student5 | 50.00 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I should see "Test page name"
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I change window size to "large"
|
||||
And I give the grade "90.00" to the user "Student 1" for the grade item "Test assignment 1"
|
||||
And I give the grade "80.00" to the user "Student 2" for the grade item "Test assignment 1"
|
||||
And I give the grade "70.00" to the user "Student 3" for the grade item "Test assignment 1"
|
||||
And I give the grade "60.00" to the user "Student 4" for the grade item "Test assignment 1"
|
||||
And I give the grade "50.00" to the user "Student 5" for the grade item "Test assignment 1"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
|
||||
Scenario: Configure the block on a non-graded activity to show 3 high scores
|
||||
Given I am on the "Test page name" "page activity" page
|
||||
|
||||
@@ -27,16 +27,15 @@ Feature: The activity results block displays student high scores
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | section | idnumber | assignsubmission_file_enabled |
|
||||
| assign | Test assignment | Offline text | C1 | 1 | assign1 | 0 |
|
||||
And the following "grade grades" exist:
|
||||
| gradeitem | user | grade |
|
||||
| Test assignment | student1 | 90.00 |
|
||||
| Test assignment | student2 | 80.00 |
|
||||
| Test assignment | student3 | 70.00 |
|
||||
| Test assignment | student4 | 60.00 |
|
||||
| Test assignment | student5 | 50.00 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I give the grade "90.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "60.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "50.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
|
||||
Scenario: Configure the block on the course page to show 0 high scores
|
||||
Given I add the "Activity results" block
|
||||
|
||||
@@ -31,23 +31,15 @@ Feature: The activity results block displays students high scores in group as sc
|
||||
| name | Test assignment |
|
||||
| intro | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Scales" in the course gradebook
|
||||
And I press "Add a new scale"
|
||||
And I set the following fields to these values:
|
||||
| Name | My Scale |
|
||||
| Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment"
|
||||
And I navigate to "Settings" in current page administration
|
||||
And the following "scales" exist:
|
||||
| name | scale |
|
||||
| My Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
|
||||
And I am on the "Test assignment" "assign activity editing" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| id_grade_modgrade_type | Scale |
|
||||
| id_grade_modgrade_scale | My Scale |
|
||||
And I press "Save and return to course"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I am on the "Course 1" "grades > Grader report > View" page
|
||||
And I turn editing mode on
|
||||
And I give the grade "Excellent!" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "Very good" to the user "Student 2" for the grade item "Test assignment"
|
||||
|
||||
@@ -44,25 +44,19 @@ Feature: The activity results block displays student in group high scores as sca
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | section | idnumber |
|
||||
| assign | Test assignment | Offline text | C1 | 1 | assign1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I navigate to "Scales" in the course gradebook
|
||||
And I press "Add a new scale"
|
||||
And I set the following fields to these values:
|
||||
| Name | My Scale |
|
||||
| Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Test assignment" "assign activity" page
|
||||
And I navigate to "Settings" in current page administration
|
||||
And the following "scales" exist:
|
||||
| name | scale |
|
||||
| My Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
|
||||
And I change window size to "large"
|
||||
And I am on the "Test assignment" "assign activity editing" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| id_grade_modgrade_type | Scale |
|
||||
| id_grade_modgrade_scale | My Scale |
|
||||
| Group mode | Separate groups |
|
||||
And I press "Save and return to course"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I turn editing mode on
|
||||
And I am on the "Course 1" "grades > Grader report > View" page
|
||||
And I give the grade "Excellent!" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "Very good" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "Very good" to the user "Student 3" for the grade item "Test assignment"
|
||||
@@ -83,9 +77,7 @@ Feature: The activity results block displays student in group high scores as sca
|
||||
And I press "Save changes"
|
||||
Then I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Student 1" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
|
||||
@@ -104,9 +96,7 @@ Feature: The activity results block displays student in group high scores as sca
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student3"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student3
|
||||
And I should see "Student 3" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Student 4" in the "Activity results" "block"
|
||||
@@ -127,10 +117,8 @@ Feature: The activity results block displays student in group high scores as sca
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
# Students cannot see user identity fields.
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And I should see "User" in the "Activity results" "block"
|
||||
And I should not see "User S1" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
@@ -150,9 +138,7 @@ Feature: The activity results block displays student in group high scores as sca
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And I should see "User" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
|
||||
@@ -46,21 +46,19 @@ Feature: The activity results block displays student in separate groups scores
|
||||
| course | C1 |
|
||||
| idnumber | 0001 |
|
||||
| name | Test assignment |
|
||||
| intro | Offline text |
|
||||
| section | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| groupmode | 1 |
|
||||
And the following "grade grades" exist:
|
||||
| gradeitem | user | grade |
|
||||
| Test assignment | student1 | 100.00 |
|
||||
| Test assignment | student2 | 90.00 |
|
||||
| Test assignment | student3 | 90.00 |
|
||||
| Test assignment | student4 | 80.00 |
|
||||
| Test assignment | student5 | 80.00 |
|
||||
| Test assignment | student6 | 70.00 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
|
||||
Scenario: Configure the block on the course page to show 1 high score
|
||||
Given I add the "Activity results" block
|
||||
@@ -88,9 +86,7 @@ Feature: The activity results block displays student in separate groups scores
|
||||
And I press "Save changes"
|
||||
Then I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "95.00/100.00" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Student 1" in the "Activity results" "block"
|
||||
And I should see "100.00/100.00" in the "Activity results" "block"
|
||||
|
||||
@@ -106,9 +102,7 @@ Feature: The activity results block displays student in separate groups scores
|
||||
And I press "Save changes"
|
||||
Then I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "95.00" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Student 1" in the "Activity results" "block"
|
||||
And I should see "100.00" in the "Activity results" "block"
|
||||
|
||||
@@ -129,9 +123,7 @@ Feature: The activity results block displays student in separate groups scores
|
||||
And I should see "85%" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75%" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Student 1" in the "Activity results" "block"
|
||||
And I should see "100%" in the "Activity results" "block"
|
||||
And I should see "Student 2" in the "Activity results" "block"
|
||||
@@ -153,9 +145,7 @@ Feature: The activity results block displays student in separate groups scores
|
||||
And I should see "85.00/100.00" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00/100.00" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student3"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student3
|
||||
And I should see "Student 3" in the "Activity results" "block"
|
||||
And I should see "90.00/100.00" in the "Activity results" "block"
|
||||
And I should see "Student 4" in the "Activity results" "block"
|
||||
@@ -177,9 +167,7 @@ Feature: The activity results block displays student in separate groups scores
|
||||
And I should see "85.00" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Student 1" in the "Activity results" "block"
|
||||
And I should see "100.00" in the "Activity results" "block"
|
||||
And I should see "Student 2" in the "Activity results" "block"
|
||||
@@ -201,10 +189,8 @@ Feature: The activity results block displays student in separate groups scores
|
||||
And I should see "95.00%" in the "Activity results" "block"
|
||||
And I should see "85.00%" in the "Activity results" "block"
|
||||
And I should see "75.00%" in the "Activity results" "block"
|
||||
And I log out
|
||||
# Students cannot see user identity fields.
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And I should see "User" in the "Activity results" "block"
|
||||
And I should not see "User S1" in the "Activity results" "block"
|
||||
And I should see "100.00%" in the "Activity results" "block"
|
||||
@@ -225,9 +211,7 @@ Feature: The activity results block displays student in separate groups scores
|
||||
And I should see "95.00%" in the "Activity results" "block"
|
||||
And I should see "85.00%" in the "Activity results" "block"
|
||||
And I should see "75.00%" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And I should see "User" in the "Activity results" "block"
|
||||
And I should see "100.00%" in the "Activity results" "block"
|
||||
And I should see "90.00%" in the "Activity results" "block"
|
||||
|
||||
@@ -42,17 +42,13 @@ Feature: The activity results block displays student in visible groups scores
|
||||
| student5 | G3 |
|
||||
| student6 | G3 |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section | assignsubmission_file_enabled |
|
||||
| assign | Test assignment | Test assignment | C1 | assign1 | 1 | 0 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I am on the "Test assignment" "assign activity" page
|
||||
And I navigate to "Settings" in current page administration
|
||||
| activity | name | course | idnumber | section | assignsubmission_file_enabled |
|
||||
| assign | Test assignment | C1 | assign1 | 1 | 0 |
|
||||
And I am on the "Test assignment" "assign activity editing" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| Group mode | Visible groups |
|
||||
And I press "Save and return to course"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I am on the "Course 1" "grades > Grader report > View" page
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
@@ -61,7 +57,7 @@ Feature: The activity results block displays student in visible groups scores
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
|
||||
Scenario: Configure the block on the course page to show 1 high score
|
||||
Given I add the "Activity results" block
|
||||
@@ -87,9 +83,7 @@ Feature: The activity results block displays student in visible groups scores
|
||||
| config_nameformat | Display full names |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "95.00/100.00" in the "Activity results" "block"
|
||||
|
||||
@@ -103,9 +97,7 @@ Feature: The activity results block displays student in visible groups scores
|
||||
| config_nameformat | Display full names |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "95.00" in the "Activity results" "block"
|
||||
|
||||
@@ -120,9 +112,7 @@ Feature: The activity results block displays student in visible groups scores
|
||||
| config_decimalpoints | 0 |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "95%" in the "Activity results" "block"
|
||||
And I should see "Group 2" in the "Activity results" "block"
|
||||
@@ -140,9 +130,7 @@ Feature: The activity results block displays student in visible groups scores
|
||||
| config_nameformat | Display full names |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "95.00/100.00" in the "Activity results" "block"
|
||||
And I should see "Group 2" in the "Activity results" "block"
|
||||
@@ -160,9 +148,7 @@ Feature: The activity results block displays student in visible groups scores
|
||||
| config_nameformat | Display full names |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "95.00" in the "Activity results" "block"
|
||||
And I should see "Group 2" in the "Activity results" "block"
|
||||
@@ -182,9 +168,7 @@ Feature: The activity results block displays student in visible groups scores
|
||||
| config_nameformat | Display only ID numbers |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group" in the "Activity results" "block"
|
||||
And I should see "95.00%" in the "Activity results" "block"
|
||||
And I should see "85.00%" in the "Activity results" "block"
|
||||
@@ -200,9 +184,7 @@ Feature: The activity results block displays student in visible groups scores
|
||||
| config_nameformat | Anonymous results |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group" in the "Activity results" "block"
|
||||
And I should see "95.00%" in the "Activity results" "block"
|
||||
And I should see "85.00%" in the "Activity results" "block"
|
||||
|
||||
@@ -29,19 +29,16 @@ Feature: The activity results block displays student low scores
|
||||
| course | C1 |
|
||||
| idnumber | 0001 |
|
||||
| name | Test assignment |
|
||||
| intro | Offline text |
|
||||
| section | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
And the following "grade grades" exist:
|
||||
| gradeitem | user | grade |
|
||||
| Test assignment | student1 | 90.00 |
|
||||
| Test assignment | student2 | 80.00 |
|
||||
| Test assignment | student3 | 70.00 |
|
||||
| Test assignment | student4 | 60.00 |
|
||||
| Test assignment | student5 | 50.00 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I give the grade "90.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "60.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "50.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
|
||||
Scenario: Configure the block on the course page to show 1 low score
|
||||
Given I add the "Activity results" block
|
||||
|
||||
@@ -32,23 +32,16 @@ Feature: The activity results block displays student low scores as scales
|
||||
| idnumber | 0001 |
|
||||
| section | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Scales" in the course gradebook
|
||||
And I press "Add a new scale"
|
||||
And I set the following fields to these values:
|
||||
| Name | My Scale |
|
||||
| Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I am on the "Test assignment" "assign activity" page
|
||||
And I navigate to "Settings" in current page administration
|
||||
And the following "scales" exist:
|
||||
| name | scale |
|
||||
| My Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
|
||||
And I am on the "Test assignment" "assign activity editing" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| id_grade_modgrade_type | Scale |
|
||||
| id_grade_modgrade_scale | My Scale |
|
||||
And I press "Save and return to course"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I turn editing mode on
|
||||
And I am on the "Course 1" "grades > Grader report > View" page
|
||||
And I give the grade "Excellent!" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "Very good" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "Good" to the user "Student 3" for the grade item "Test assignment"
|
||||
|
||||
@@ -49,23 +49,16 @@ Feature: The activity results block displays students in groups low scores as sc
|
||||
| description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| groupmode | 1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Scales" in the course gradebook
|
||||
And I press "Add a new scale"
|
||||
And I set the following fields to these values:
|
||||
| Name | My Scale |
|
||||
| Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment"
|
||||
And I navigate to "Settings" in current page administration
|
||||
And the following "scales" exist:
|
||||
| name | scale |
|
||||
| My Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
|
||||
And I change window size to "large"
|
||||
And I am on the "Test assignment" "assign activity editing" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| id_grade_modgrade_type | Scale |
|
||||
| id_grade_modgrade_scale | My Scale |
|
||||
And I press "Save and return to course"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I am on the "Course 1" "grades > Grader report > View" page
|
||||
And I turn editing mode on
|
||||
And I give the grade "Excellent!" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "Very good" to the user "Student 2" for the grade item "Test assignment"
|
||||
@@ -87,9 +80,7 @@ Feature: The activity results block displays students in groups low scores as sc
|
||||
And I press "Save changes"
|
||||
Then I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student5"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student5
|
||||
And I should see "Student 6" in the "Activity results" "block"
|
||||
And I should see "Average" in the "Activity results" "block"
|
||||
|
||||
@@ -106,9 +97,7 @@ Feature: The activity results block displays students in groups low scores as sc
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student3"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student3
|
||||
And I should see "Student 3" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Student 4" in the "Activity results" "block"
|
||||
@@ -128,10 +117,8 @@ Feature: The activity results block displays students in groups low scores as sc
|
||||
Then I should see "Group" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
# Students cannot see user identity fields.
|
||||
And I log in as "student5"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student5
|
||||
And I should see "User" in the "Activity results" "block"
|
||||
And I should not see "User S5" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
@@ -150,9 +137,7 @@ Feature: The activity results block displays students in groups low scores as sc
|
||||
Then I should see "Group" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student5"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student5
|
||||
And I should see "User" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I should see "Average" in the "Activity results" "block"
|
||||
|
||||
@@ -42,19 +42,18 @@ Feature: The activity results block displays students in separate groups scores
|
||||
| student5 | G3 |
|
||||
| student6 | G3 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro | assignsubmission_file_enabled | groupmode |
|
||||
| assign | C1 | a1 | Test assignment | Offline text | 0 | 1 |
|
||||
| activity | course | idnumber | name | assignsubmission_file_enabled | groupmode |
|
||||
| assign | C1 | a1 | Test assignment | 0 | 1 |
|
||||
And the following "grade grades" exist:
|
||||
| gradeitem | user | grade |
|
||||
| Test assignment | student1 | 100.00 |
|
||||
| Test assignment | student2 | 90.00 |
|
||||
| Test assignment | student3 | 90.00 |
|
||||
| Test assignment | student4 | 80.00 |
|
||||
| Test assignment | student5 | 80.00 |
|
||||
| Test assignment | student6 | 70.00 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
|
||||
Scenario: Configure the block on the course page to show 1 low score
|
||||
Given I add the "Activity results" block
|
||||
@@ -82,9 +81,7 @@ Feature: The activity results block displays students in separate groups scores
|
||||
And I press "Save changes"
|
||||
Then I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00/100.00" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student5"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student5
|
||||
And I should see "Student 6" in the "Activity results" "block"
|
||||
And I should see "70.00/100.00" in the "Activity results" "block"
|
||||
|
||||
@@ -100,9 +97,7 @@ Feature: The activity results block displays students in separate groups scores
|
||||
And I press "Save changes"
|
||||
Then I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student5"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student5
|
||||
And I should see "Student 6" in the "Activity results" "block"
|
||||
And I should see "70.00" in the "Activity results" "block"
|
||||
|
||||
@@ -121,9 +116,7 @@ Feature: The activity results block displays students in separate groups scores
|
||||
And I should see "85%" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75%" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student5"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student5
|
||||
And I should see "Student 6" in the "Activity results" "block"
|
||||
And I should see "70%" in the "Activity results" "block"
|
||||
And I should see "Student 5" in the "Activity results" "block"
|
||||
@@ -143,9 +136,7 @@ Feature: The activity results block displays students in separate groups scores
|
||||
And I should see "85.00/100.00" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00/100.00" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student3"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student3
|
||||
And I should see "Student 3" in the "Activity results" "block"
|
||||
And I should see "90.00/100.00" in the "Activity results" "block"
|
||||
And I should see "Student 4" in the "Activity results" "block"
|
||||
@@ -165,9 +156,7 @@ Feature: The activity results block displays students in separate groups scores
|
||||
And I should see "85.00" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student5"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student5
|
||||
And I should see "Student 5" in the "Activity results" "block"
|
||||
And I should see "80.00" in the "Activity results" "block"
|
||||
And I should see "Student 6" in the "Activity results" "block"
|
||||
@@ -188,10 +177,8 @@ Feature: The activity results block displays students in separate groups scores
|
||||
Then I should see "Group" in the "Activity results" "block"
|
||||
And I should see "85.00%" in the "Activity results" "block"
|
||||
And I should see "75.00%" in the "Activity results" "block"
|
||||
And I log out
|
||||
# Students cannot see user identity fields.
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And I should see "User" in the "Activity results" "block"
|
||||
And I should not see "User S1" in the "Activity results" "block"
|
||||
And I should see "100.00%" in the "Activity results" "block"
|
||||
@@ -211,9 +198,7 @@ Feature: The activity results block displays students in separate groups scores
|
||||
Then I should see "Group" in the "Activity results" "block"
|
||||
And I should see "85.00%" in the "Activity results" "block"
|
||||
And I should see "75.00%" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And I should see "User" in the "Activity results" "block"
|
||||
And I should see "100.00%" in the "Activity results" "block"
|
||||
And I should see "90.00%" in the "Activity results" "block"
|
||||
|
||||
@@ -46,21 +46,18 @@ Feature: The activity results block displays student in visible groups low score
|
||||
| course | C1 |
|
||||
| idnumber | 0001 |
|
||||
| name | Test assignment |
|
||||
| intro | Offline text |
|
||||
| section | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| groupmode | 2 |
|
||||
And the following "grade grades" exist:
|
||||
| gradeitem | user | grade |
|
||||
| Test assignment | student1 | 100.00 |
|
||||
| Test assignment | student2 | 90.00 |
|
||||
| Test assignment | student3 | 90.00 |
|
||||
| Test assignment | student4 | 80.00 |
|
||||
| Test assignment | student5 | 80.00 |
|
||||
| Test assignment | student6 | 70.00 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
|
||||
Scenario: Configure the block on the course page to show 1 low score
|
||||
Given I add the "Activity results" block
|
||||
@@ -86,9 +83,7 @@ Feature: The activity results block displays student in visible groups low score
|
||||
| config_nameformat | Display full names |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00/100.00" in the "Activity results" "block"
|
||||
|
||||
@@ -102,9 +97,7 @@ Feature: The activity results block displays student in visible groups low score
|
||||
| config_nameformat | Display full names |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00" in the "Activity results" "block"
|
||||
|
||||
@@ -123,9 +116,7 @@ Feature: The activity results block displays student in visible groups low score
|
||||
And I should see "85%" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75%" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student5"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student5
|
||||
Then I should see "Group 2" in the "Activity results" "block"
|
||||
And I should see "85%" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
@@ -141,9 +132,7 @@ Feature: The activity results block displays student in visible groups low score
|
||||
| config_nameformat | Display full names |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group 2" in the "Activity results" "block"
|
||||
And I should see "85.00/100.00" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
@@ -159,9 +148,7 @@ Feature: The activity results block displays student in visible groups low score
|
||||
| config_nameformat | Display full names |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group 2" in the "Activity results" "block"
|
||||
And I should see "85.00" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
@@ -179,9 +166,7 @@ Feature: The activity results block displays student in visible groups low score
|
||||
| config_nameformat | Display only ID numbers |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group" in the "Activity results" "block"
|
||||
And I should see "85.00%" in the "Activity results" "block"
|
||||
And I should see "75.00%" in the "Activity results" "block"
|
||||
@@ -196,9 +181,7 @@ Feature: The activity results block displays student in visible groups low score
|
||||
| config_nameformat | Anonymous results |
|
||||
| config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I am on the "Course 1" course page logged in as student1
|
||||
And I should see "Group" in the "Activity results" "block"
|
||||
And I should see "85.00%" in the "Activity results" "block"
|
||||
And I should see "75.00%" in the "Activity results" "block"
|
||||
|
||||
+28
-76
@@ -1,4 +1,4 @@
|
||||
@block @block_completionstatus
|
||||
@block @block_completionstatus @core_completion
|
||||
Feature: Enable Block Completion in a course using activity completion
|
||||
In order to view the completion block in a course
|
||||
As a teacher
|
||||
@@ -17,117 +17,69 @@ Feature: Enable Block Completion in a course using activity completion
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro |
|
||||
| page | C1 | page1 | Test page name | Test page description |
|
||||
| assign | C1 | assign1 | Test assign name | Test page description |
|
||||
| activity | course | idnumber | name | gradepass | completion | completionview | completionusegrade | completionpassgrade |
|
||||
| page | C1 | page1 | Test page name | | 2 | 1 | 0 | 0 |
|
||||
| assign | C1 | assign1 | Test assign name | 50 | 2 | 0 | 1 | 1 |
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| completionstatus | Course | C1 | course-view-* | side-pre |
|
||||
|
||||
Scenario: Add the block to a the course and add course completion items
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "Test page name"
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| Require view | 1 |
|
||||
And I press "Save and return to course"
|
||||
And I add the "Course completion status" block
|
||||
Scenario: Completion status block when student has not started any activities
|
||||
Given I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to "Course completion" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Test page name | 1 |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I am on the "Course 1" course page logged in as student1
|
||||
Then I should see "Status: Not yet started" in the "Course completion status" "block"
|
||||
And I should see "0 of 1" in the "Activity completion" "table_row"
|
||||
|
||||
Scenario: Add the block to a the course and add course completion items
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "Test page name"
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| Require view | 1 |
|
||||
And I press "Save and return to course"
|
||||
And I add the "Course completion status" block
|
||||
Scenario: Completion status block when student has completed a page
|
||||
Given I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to "Course completion" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Test page name | 1 |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test page name"
|
||||
When I am on the "Test page name" "page activity" page logged in as student1
|
||||
And I am on "Course 1" course homepage
|
||||
Then I should see "Status: Complete" in the "Course completion status" "block"
|
||||
And I should see "1 of 1" in the "Activity completion" "table_row"
|
||||
And I follow "More details"
|
||||
And I should see "Yes" in the "Activity completion" "table_row"
|
||||
|
||||
@javascript
|
||||
Scenario: Add the block to a the course and add course completion items with passing grade
|
||||
Given I am on the "Test assign name" "assign activity" page logged in as teacher1
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| completionusegrade | 1 |
|
||||
| completionpassgrade | 1 |
|
||||
| gradepass | 50 |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test assign name" "assign activity" page
|
||||
And I follow "View all submissions"
|
||||
And I click on "Grade" "link" in the "Student" "table_row"
|
||||
And I set the field "Grade out of 100" to "53"
|
||||
And I set the field "Notify student" to "0"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Course completion status" block
|
||||
Scenario: Completion status block with items with passing grade
|
||||
Given I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to "Course completion" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Test assign name | 1 |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I am on the "Test assign name" "assign activity" page logged in as student1
|
||||
And I am on "Course 1" course homepage
|
||||
Then I should see "Status: Pending" in the "Course completion status" "block"
|
||||
And I should see "0 of 1" in the "Activity completion" "table_row"
|
||||
And the following "grade grades" exist:
|
||||
| gradeitem | user | grade |
|
||||
| Test assign name | student1 | 53 |
|
||||
When I am on the "Course 1" course page logged in as student1
|
||||
Then I should see "Status: Complete" in the "Course completion status" "block"
|
||||
And I should see "1 of 1" in the "Activity completion" "table_row"
|
||||
And I trigger cron
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "More details"
|
||||
And I should see "Achieving grade, Achieving passing grade" in the "Activity completion" "table_row"
|
||||
And I should see "Yes" in the "Activity completion" "table_row"
|
||||
|
||||
@javascript
|
||||
Scenario: Add the block to a the course and add course completion items with failing grade.
|
||||
Given I am on the "Test assign name" "assign activity" page logged in as teacher1
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| completionusegrade | 1 |
|
||||
| completionpassgrade | 1 |
|
||||
| gradepass | 50 |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test assign name" "assign activity" page
|
||||
And I follow "View all submissions"
|
||||
And I click on "Grade" "link" in the "Student" "table_row"
|
||||
And I set the field "Grade out of 100" to "49"
|
||||
And I set the field "Notify student" to "0"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Course completion status" block
|
||||
Scenario: Completion status block with items with failing grade
|
||||
Given I am on the "Course 1" course page logged in as teacher1
|
||||
And the following "grade grades" exist:
|
||||
| gradeitem | user | grade |
|
||||
| Test assign name | student1 | 49 |
|
||||
And I navigate to "Course completion" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Test assign name | 1 |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I am on the "Test assign name" "assign activity" page logged in as student1
|
||||
And I am on "Course 1" course homepage
|
||||
Then I should see "Status: Pending" in the "Course completion status" "block"
|
||||
When I am on the "Course 1" course page logged in as student1
|
||||
Then I should see "Status: Not yet started" in the "Course completion status" "block"
|
||||
And I should see "0 of 1" in the "Activity completion" "table_row"
|
||||
And I trigger cron
|
||||
And I am on "Course 1" course homepage
|
||||
|
||||
@@ -30,7 +30,7 @@ $string['aria:allcoursesincludinghidden'] = 'Show all courses';
|
||||
$string['aria:allcourses'] = 'Show all courses except courses removed from view';
|
||||
$string['aria:card'] = 'Switch to card view';
|
||||
$string['aria:controls'] = 'Course overview controls';
|
||||
$string['aria:courseactions'] = 'Actions for current course';
|
||||
$string['aria:courseactions'] = 'Actions for course';
|
||||
$string['aria:coursesummary'] = 'Course summary text:';
|
||||
$string['aria:courseprogress'] = 'Course progress:';
|
||||
$string['aria:customfield'] = 'Show {$a} courses';
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"name": "Assignment due 1",
|
||||
"viewurl": "https://moodlesite/course/view.php?id=2",
|
||||
"courseimage": "https://moodlesite/pluginfile/123/course/overviewfiles/123.jpg",
|
||||
"fullname": "course 3",
|
||||
"fullname": "Course 3 for \"Statistical and Computational Tools\" ",
|
||||
"hasprogress": true,
|
||||
"progress": 10,
|
||||
"coursecategory": "Category 1",
|
||||
@@ -50,8 +50,11 @@
|
||||
{{/hasprogress}}
|
||||
{{/progress}}
|
||||
{{$coursename}}
|
||||
<span class="multiline">
|
||||
{{#shortentext}}50, {{{fullname}}} {{/shortentext}}
|
||||
<span class="multiline" title="{{fullname}}">
|
||||
<span class="sr-only">{{{fullname}}}</span>
|
||||
<span aria-hidden="true">
|
||||
{{#shortentext}}55, {{{fullname}}} {{/shortentext}}
|
||||
</span>
|
||||
</span>
|
||||
{{/coursename}}
|
||||
{{$coursecategory}}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<div class="col-md-2 d-flex align-items-center mb-sm-3 mb-md-0">
|
||||
<a href="{{viewurl}}" tabindex="-1" class="mw-100 w-100">
|
||||
<div class="card-img dashboard-list-img mw-100" style='background-image: url("{{{courseimage}}}");'>
|
||||
<span class="sr-only">{{#str}}aria:courseimage, core_course{{/str}}</span>
|
||||
<span class="sr-only">{{fullname}}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user