Compare commits
590 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cd71612cf6 | |||
| a4874cb9c5 | |||
| 90818a22ad | |||
| 28bb2b50d6 | |||
| 28d6953d48 | |||
| c7b3edf823 | |||
| 880e150587 | |||
| 760a316679 | |||
| 525f816567 | |||
| 40b1954431 | |||
| 9f152581f0 | |||
| 1a624afb87 | |||
| f80a3bce0a | |||
| 4deb1eea56 | |||
| 77c72b0bd7 | |||
| a15df02640 | |||
| e5dd087852 | |||
| f46643fd61 | |||
| 426e58d35d | |||
| be86e18ff1 | |||
| d33aa94074 | |||
| 47fcb7c012 | |||
| 7fd65d8896 | |||
| 4ad6481a77 | |||
| 40d01acce6 | |||
| f5daf410af | |||
| 40510605e4 | |||
| b436508b24 | |||
| 98bbce7011 | |||
| 04d74da325 | |||
| 90c5358680 | |||
| 882b9d67f5 | |||
| 591ffa267d | |||
| 7c10813e02 | |||
| a099b1d893 | |||
| 39ab1182d9 | |||
| 9e5bf8d4d5 | |||
| fc2ed595d9 | |||
| 86f1bf85c4 | |||
| 4e858410ea | |||
| dd581ff3f5 | |||
| 1a70b72b41 | |||
| c7b2f34748 | |||
| ee828d828a | |||
| 499f651729 | |||
| 0a95429dce | |||
| 35ef8a9e40 | |||
| 51dae0b04e | |||
| bc41f92872 | |||
| 430b3e7043 | |||
| f6debec437 | |||
| c4d91b4e42 | |||
| 98317ff91a | |||
| 21c5f2d453 | |||
| 42ec6014c4 | |||
| 45b81544c5 | |||
| f055b84644 | |||
| 8d6e0dc416 | |||
| 0ebccd5bb4 | |||
| a22e2aa0d7 | |||
| dfea25b3d7 | |||
| 173b61bf69 | |||
| c920bb6db5 | |||
| 9899fc0a0f | |||
| d01eba812b | |||
| 811526b0a6 | |||
| fb8fa74655 | |||
| 36e2f7d5a3 | |||
| 4fa6354d89 | |||
| 7ed2a79297 | |||
| 65731963bc | |||
| 63c6f278a7 | |||
| 474ee8524a | |||
| 5956302d76 | |||
| 9121d889f5 | |||
| af0aee7d2a | |||
| 76fc2573ce | |||
| d611739b3f | |||
| f638a5bbae | |||
| 2079ba1387 | |||
| c12e3b46de | |||
| bdb1aefaad | |||
| 6c48aaf4d9 | |||
| a745135867 | |||
| 2674350a47 | |||
| 16cee3894e | |||
| 5e943bf6ba | |||
| 4d29785724 | |||
| 733b90eef0 | |||
| 00385e7580 | |||
| 3b757a24eb | |||
| c56edaa116 | |||
| 6b54bd46f2 | |||
| 31f13cd315 | |||
| a45ccc464b | |||
| 604d8c291f | |||
| c5fdf320cd | |||
| 0fd5993afb | |||
| ec56eeb9a9 | |||
| fa6c77adc7 | |||
| dca46bcab8 | |||
| cc045cc27d | |||
| 980a265718 | |||
| 6ad9dcae1c | |||
| 2ebc453c99 | |||
| 5cbd545cd3 | |||
| e988445521 | |||
| b08f86b258 | |||
| 58213db159 | |||
| c34dc466b6 | |||
| 2b7ede20b5 | |||
| 4c64f49a88 | |||
| 0baa1aa391 | |||
| a9b87fa989 | |||
| cdcfb84d18 | |||
| 52046c52b1 | |||
| 9eccbb590e | |||
| 2b7f887245 | |||
| 3dd63e8149 | |||
| 78e5dd6284 | |||
| f14dc52adc | |||
| aab571ca2c | |||
| eadfbd21e9 | |||
| b5eb437fcd | |||
| 16e5b999ce | |||
| 7d596ff339 | |||
| d02bcbb963 | |||
| c01344a0e7 | |||
| e9439d064b | |||
| f21e1443dc | |||
| 860bfb6f25 | |||
| 388c5731fa | |||
| dc93055e28 | |||
| d57db03d20 | |||
| bd5bcec3f1 | |||
| 261fe42c05 | |||
| 6f622e2393 | |||
| 00b9fe36c1 | |||
| e4b27dd81b | |||
| 5c9704b210 | |||
| f6f2dd5022 | |||
| 9fc5f273e0 | |||
| dd63b85ed4 | |||
| f164d03df5 | |||
| e32d27e1ff | |||
| 2f826724c8 | |||
| 00ccb3a314 | |||
| 88d4939f25 | |||
| e3be2fcfb6 | |||
| 3585ab5afa | |||
| b7bfc77b52 | |||
| 72d98b0dd5 | |||
| 15916a6f3b | |||
| 48256e0242 | |||
| 18013b2153 | |||
| 9da4095949 | |||
| dc399cd841 | |||
| e4a8272d9c | |||
| 6832ac123d | |||
| e892c66058 | |||
| 48637c438d | |||
| 0e64a10ecf | |||
| 0dd5b86d3f | |||
| b0f89e5b92 | |||
| c4c67cd975 | |||
| 9ae06b8dc7 | |||
| e59e39c78f | |||
| 99e20baa54 | |||
| 7c04ccfdf9 | |||
| 2f8a56eaf0 | |||
| 0a774cefb8 | |||
| 6257ac4de7 | |||
| 5f34ca7b01 | |||
| 624d027753 | |||
| b492fa8255 | |||
| 2d1c45a40e | |||
| 13000ae319 | |||
| 81dee5182b | |||
| 44ec3591c0 | |||
| 7f638dac59 | |||
| 3ad36ca4f9 | |||
| ffc0155eab | |||
| 42e3f4d696 | |||
| ff446d05f6 | |||
| a213654a08 | |||
| b7947e03ff | |||
| 2c18225da4 | |||
| 67edcbd16f | |||
| a6154a1cab | |||
| eb7a2e3070 | |||
| 29a6589b8d | |||
| 219206d83e | |||
| 7391010aac | |||
| 713048a0c9 | |||
| 9f018ab557 | |||
| 8e6aeda4ba | |||
| 8af4bb6a40 | |||
| 804ae9ad72 | |||
| 75a49ff1b2 | |||
| 3931e6fe5c | |||
| 8e195adb84 | |||
| 44ab3ba8f1 | |||
| 91de19a803 | |||
| fcbd95d16d | |||
| ccb7bb2767 | |||
| 09be924480 | |||
| 9d9a626038 | |||
| 9a3cf47a77 | |||
| 1fb8bedf50 | |||
| 92b909033e | |||
| becbdd847d | |||
| 6ac3dd457c | |||
| cd97da9c5c | |||
| 759b2670a0 | |||
| 3f90e29e39 | |||
| 257a8126ad | |||
| d32320beac | |||
| 1352a23354 | |||
| 46a8a3bb75 | |||
| 79d1331384 | |||
| cd72578917 | |||
| 72e9f115ab | |||
| 01011e49dd | |||
| fcf7d12a4b | |||
| f44d6ba340 | |||
| 15632be78d | |||
| 53a0fbecd2 | |||
| 832261f49b | |||
| 2378fc0117 | |||
| cd754d3b44 | |||
| 8307ce8f18 | |||
| 4225940caa | |||
| 2ce1ed7247 | |||
| f21c892997 | |||
| 0b8ab4fcef | |||
| 8ec49b09e5 | |||
| fd9ab3efbd | |||
| acdca038df | |||
| dd6f0debcc | |||
| 8f93e88387 | |||
| 17fccfcf64 | |||
| 0cdb9169cb | |||
| a110b34a5a | |||
| 252d0faac1 | |||
| 1802410629 | |||
| 89cba33e91 | |||
| 2a36ff8dfb | |||
| b86162544d | |||
| 2135ff7c19 | |||
| d0e63f5a60 | |||
| ec65857de0 | |||
| d34d35d2b6 | |||
| 0742fb7b44 | |||
| 0e7caf93b5 | |||
| e876654d1f | |||
| a11e590324 | |||
| 5ff8f06f64 | |||
| 8a1c8f8bb3 | |||
| 671849b2db | |||
| 8341244903 | |||
| 02d251294c | |||
| b490d511d6 | |||
| 2d08d7d2c0 | |||
| 016d123034 | |||
| 2e4c5f9c12 | |||
| e7b463af6d | |||
| 314c9671fc | |||
| b8c4c975e0 | |||
| f3952dc29f | |||
| 71841556aa | |||
| 575fabe57a | |||
| 5cf3b78855 | |||
| a84b1f1307 | |||
| c435b7896f | |||
| e740fa9c3b | |||
| 243eb04a85 | |||
| 88c757cef0 | |||
| 8f06e62409 | |||
| 0eda72ec4f | |||
| 68ff5f0ce0 | |||
| deb5150786 | |||
| 15521655a3 | |||
| 3a2703c9f5 | |||
| f48d31f0d4 | |||
| 38da2c3a61 | |||
| 583b655e37 | |||
| 28f06c0f27 | |||
| 4e1e916ca6 | |||
| 0c2426d207 | |||
| 3f17ea00e7 | |||
| 565fe67086 | |||
| 97f67db36d | |||
| e2b085c81b | |||
| 91bb1805d9 | |||
| 4d36e008dd | |||
| e57d9506af | |||
| 779cd5b40c | |||
| 98fd15d75b | |||
| 552ec1b547 | |||
| 977cbaf239 | |||
| a68be3c7fa | |||
| a123645de3 | |||
| 29191eeff2 | |||
| b9701a8bb8 | |||
| 1fe901e1ab | |||
| 24bc7e9a19 | |||
| c352ec94a8 | |||
| 91c7b05b05 | |||
| a9e12e1d84 | |||
| 33eaae5569 | |||
| aaedf21a31 | |||
| 658c7e9ef5 | |||
| 7ef51203c6 | |||
| 6591971e8a | |||
| 58bc68b0bc | |||
| 93c53ea726 | |||
| 73eec5d12d | |||
| ee36b4146f | |||
| 6180b175d4 | |||
| e083dae38e | |||
| 42be9c33eb | |||
| 8ba4d8be17 | |||
| 78910334ff | |||
| 6af53fa8c0 | |||
| d0b8656cb5 | |||
| 9c93fbe3a4 | |||
| a97f8d6720 | |||
| 7ceb1466e9 | |||
| 5d0b1f0ed3 | |||
| 180bf41216 | |||
| 509578453a | |||
| 8be7ac509a | |||
| fcfd012b6a | |||
| a778af133e | |||
| 1ff07992ec | |||
| 8cbcbc094c | |||
| a35c9aab6d | |||
| bef4181788 | |||
| abcbc42139 | |||
| f65577ef3a | |||
| fdc7349577 | |||
| 0ee24af3cd | |||
| 815419ad12 | |||
| b92f5e00aa | |||
| 54263aa1f6 | |||
| 100fad08fe | |||
| 14f87ce4b5 | |||
| b4b650f9cd | |||
| efc6d19ac2 | |||
| a887e577a4 | |||
| 5b9f243378 | |||
| 1900cadd4f | |||
| f55fd1b49c | |||
| 575358c0f0 | |||
| 83a1703746 | |||
| 5c74434dfa | |||
| 72e2a0dfb5 | |||
| 8c30413ba8 | |||
| ce2a901414 | |||
| 811fc31904 | |||
| 25efc9e7aa | |||
| c29ba27942 | |||
| 125065e488 | |||
| 613ba34b07 | |||
| 975ef5c540 | |||
| 1db7e78c8b | |||
| 37fa9f51e9 | |||
| 4eed9bd261 | |||
| ec6c3cd9a0 | |||
| 133b7b700d | |||
| c269c67830 | |||
| 8d09620c14 | |||
| 94327ba15f | |||
| 8e1353f39d | |||
| 342c6367d0 | |||
| fe6c455b51 | |||
| 777025b298 | |||
| 1545abb21d | |||
| d70b73345c | |||
| fbc97ebdcd | |||
| 95b4682d3c | |||
| 27f7c54d58 | |||
| 459da610c6 | |||
| 930a0d2944 | |||
| e881dee5b4 | |||
| f525194ea2 | |||
| d18f60bd3f | |||
| 01643574c5 | |||
| 0268bbd07b | |||
| 4f5d221749 | |||
| 8ca4a0087d | |||
| 357ab40ff4 | |||
| a0518068fb | |||
| 5ef68db33a | |||
| 2914d47171 | |||
| e79b14e2a9 | |||
| b97ed6d75a | |||
| f4d830d7e4 | |||
| 2974880afe | |||
| 4ed21af7df | |||
| e1d80935a3 | |||
| f40424cd25 | |||
| 47f85d5da1 | |||
| ac0444bff4 | |||
| bb7955546c | |||
| 0fd522dd1f | |||
| a09f258f70 | |||
| b193122b29 | |||
| 10d39a1feb | |||
| d51a14792b | |||
| 074307ebba | |||
| aeacebf383 | |||
| 51c22d1e3f | |||
| e5bf98ab9d | |||
| 1b1758caa2 | |||
| a71341c693 | |||
| b21541294a | |||
| 806a667b3a | |||
| 7311810970 | |||
| c8773b698a | |||
| e446e2b6a9 | |||
| 6a6344e268 | |||
| bcdee74ae9 | |||
| dacd86c23c | |||
| bb6c03a252 | |||
| b37a074180 | |||
| 64e570d0ab | |||
| 0a4af5f771 | |||
| d288aea421 | |||
| a9edf3962a | |||
| 6087c2a835 | |||
| 6fd68977ac | |||
| 94f6eefb86 | |||
| d03da85cef | |||
| 3e789e5d6d | |||
| b16eb4c432 | |||
| f533978709 | |||
| 53846820df | |||
| 65c8839157 | |||
| 0561f8c5b5 | |||
| 8684cd6a76 | |||
| fa10357f57 | |||
| d463e0d8f6 | |||
| 54b614ca7e | |||
| 9f7d92de62 | |||
| 4125c3c470 | |||
| 258cdfaa6a | |||
| 8c2792cb5d | |||
| 25d4bc7ffc | |||
| d98b39a597 | |||
| 191badf5ad | |||
| c4ba598a0b | |||
| f77ea5bffa | |||
| 3d11b25cce | |||
| 8a55673463 | |||
| 230f7a2d1b | |||
| 87344d03e1 | |||
| e237e83dfb | |||
| aa392ce73a | |||
| 6220f712ab | |||
| 714b88a1b8 | |||
| bbadf7a02c | |||
| 57b97b29b7 | |||
| 6fe4eb2a86 | |||
| 8a0274423d | |||
| ddd80a5d2c | |||
| 50bf83fede | |||
| cafbfc6076 | |||
| 2b22716dc2 | |||
| 3498aeaf1e | |||
| c59d4f9612 | |||
| e3ce532831 | |||
| 87e0d39e19 | |||
| 90aceb5e6c | |||
| 7d1996fb3a | |||
| cb9583c21c | |||
| 633c6d7e80 | |||
| 76ed3885a9 | |||
| f4456f6afe | |||
| 21384101e1 | |||
| 61cedbd56e | |||
| 376e57d267 | |||
| 9de11ea641 | |||
| d793ac8e5e | |||
| 3828f4b484 | |||
| e5e8bc4b22 | |||
| 911fafd9a9 | |||
| 4c5288b32c | |||
| 284b201a28 | |||
| 31c078e183 | |||
| 6b8961b7ae | |||
| 7ef79076fe | |||
| 1bf4ac0c11 | |||
| 739b551fa8 | |||
| 2c4cc3caf6 | |||
| 3fd34dd999 | |||
| 4dcb3b244c | |||
| 6272227934 | |||
| 36e0a49c00 | |||
| 1ee3d6323c | |||
| 4ed613fbc2 | |||
| 123fc91eea | |||
| 83c9f41a47 | |||
| 3bec78df9b | |||
| 6793732790 | |||
| a9ce394b63 | |||
| a8c9e82653 | |||
| 9ceb538216 | |||
| f8351de05e | |||
| 5073d3542b | |||
| 34f352ded2 | |||
| 1125231af0 | |||
| 8a147fee4b | |||
| 1d4a1bc258 | |||
| 4119bd99a9 | |||
| a287546036 | |||
| 6102f8553a | |||
| 982dda9417 | |||
| e5744719c9 | |||
| 1b513e8c42 | |||
| 1aa9a5b11f | |||
| a313e53b54 | |||
| 983a79347b | |||
| f6a3cbe339 | |||
| cccef66f0c | |||
| ad58a4c3c3 | |||
| 2eb859a839 | |||
| 3583300da5 | |||
| 2d9ee56211 | |||
| 5ba22c14a1 | |||
| b3fab1d80e | |||
| d5cd3c95b0 | |||
| 0448a7b267 | |||
| 7b841a0f39 | |||
| 25519bc4d8 | |||
| 5f6923adf1 | |||
| a08fcb8d13 | |||
| 9fbbdc8a0a | |||
| 56781dec40 | |||
| 15b31bfb39 | |||
| fc65a2e4a2 | |||
| 3436523f17 | |||
| 8062e43941 | |||
| a28e929a74 | |||
| 838f1bfa7b | |||
| 88a18df37f | |||
| cad3403e71 | |||
| 34b551b4e7 | |||
| a62e36a9f6 | |||
| 7dd9098338 | |||
| a69d81beaa | |||
| 4434756fd6 | |||
| 08e64ba626 | |||
| caa944907a | |||
| 19815c2c2c | |||
| 8de4b14be7 | |||
| 2016d64b83 | |||
| 3eedb8a9c9 | |||
| 7f8d209ba1 | |||
| 3f2ffcce08 | |||
| 18f46b32a2 | |||
| ffb762aae0 | |||
| 9b6a36114c | |||
| 8ef1574c47 | |||
| 09a93cb6eb | |||
| b1fa2a9976 | |||
| 310da5eee7 | |||
| f9e7aa5820 | |||
| 91c1bba220 | |||
| 8984ffef4f | |||
| 419e169fa5 | |||
| 73003c7c96 | |||
| 4619b5128d | |||
| 9a5389830e | |||
| 44cd084562 | |||
| ca6f1479ad | |||
| 2e592749aa | |||
| e261c7ed25 | |||
| 57c492a6a5 | |||
| 442e1f33c9 | |||
| 9cde5a75bb | |||
| 191351d2a3 | |||
| fec4afdbd3 | |||
| 02daea22d5 | |||
| df61870abc | |||
| 2571dcf012 | |||
| cb42a0ad6a | |||
| 23f0472514 | |||
| 9b3be75879 | |||
| 1b9df59e3c |
@@ -13,14 +13,14 @@ env:
|
||||
|
||||
jobs:
|
||||
Grunt:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checking out code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Configuring node & npm
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
@@ -54,11 +54,11 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
php: 7.3
|
||||
extensions:
|
||||
db: mysqli
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
php: 8.0
|
||||
db: pgsql
|
||||
extensions: xmlrpc-beta
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
steps:
|
||||
- name: Setting up DB mysql
|
||||
if: ${{ matrix.db == 'mysqli' }}
|
||||
uses: johanmeiring/mysql-action@tmpfs-patch
|
||||
uses: moodlehq/mysql-action@v1
|
||||
with:
|
||||
collation server: utf8mb4_bin
|
||||
mysql version: 5.7
|
||||
@@ -74,6 +74,8 @@ jobs:
|
||||
mysql user: test
|
||||
mysql password: test
|
||||
use tmpfs: true
|
||||
tmpfs size: '1024M'
|
||||
extra conf: --skip-log-bin
|
||||
|
||||
- name: Setting up DB pgsql
|
||||
if: ${{ matrix.db == 'pgsql' }}
|
||||
@@ -85,7 +87,7 @@ jobs:
|
||||
postgresql password: test
|
||||
|
||||
- name: Configuring git vars
|
||||
uses: rlespinasse/github-slug-action@v3.x
|
||||
uses: rlespinasse/github-slug-action@v4
|
||||
|
||||
- name: Setting up PHP ${{ matrix.php }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
@@ -96,7 +98,7 @@ jobs:
|
||||
coverage: none
|
||||
|
||||
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setting up PHPUnit
|
||||
env:
|
||||
|
||||
+2
-1
@@ -51,4 +51,5 @@ moodle-plugin-ci.phar
|
||||
.eslintignore
|
||||
.stylelintignore
|
||||
/jsdoc
|
||||
.phpcs.xml
|
||||
phpcs.xml
|
||||
jsconfig.json
|
||||
|
||||
@@ -233,6 +233,7 @@ const getOwningComponentDirectory = checkPath => {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
fetchComponentData,
|
||||
getAmdSrcGlobList,
|
||||
getComponentFromPath,
|
||||
getComponentPaths,
|
||||
|
||||
@@ -39,7 +39,7 @@ module.exports = grunt => {
|
||||
{
|
||||
rule: {
|
||||
_attrs: {
|
||||
ref: './.phpcs.xml.dist',
|
||||
ref: './phpcs.xml.dist',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -52,7 +52,7 @@ module.exports = grunt => {
|
||||
});
|
||||
});
|
||||
|
||||
grunt.file.write('.phpcs.xml', toXML(config, {
|
||||
grunt.file.write('phpcs.xml', toXML(config, {
|
||||
header: true,
|
||||
indent: ' ',
|
||||
}) + "\n");
|
||||
|
||||
@@ -47,6 +47,9 @@ module.exports = grunt => {
|
||||
// Load ESLint.
|
||||
require('./eslint')(grunt);
|
||||
|
||||
// Load jsconfig.
|
||||
require('./jsconfig')(grunt);
|
||||
|
||||
// Load JSDoc.
|
||||
require('./jsdoc')(grunt);
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// 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/>.
|
||||
/* jshint node: true, browser: false */
|
||||
/* eslint-env node */
|
||||
|
||||
/**
|
||||
* @copyright 2022 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
const configuration = {
|
||||
compilerOptions: {
|
||||
baseUrl: ".",
|
||||
paths: {
|
||||
},
|
||||
target: "es2015",
|
||||
allowSyntheticDefaultImports: false,
|
||||
},
|
||||
exclude: [
|
||||
"node_modules",
|
||||
],
|
||||
include: [],
|
||||
};
|
||||
|
||||
module.exports = (grunt) => {
|
||||
const handler = () => {
|
||||
const jsconfigData = Object.assign({}, configuration);
|
||||
|
||||
const path = require('path');
|
||||
const {fetchComponentData} = require(path.join(process.cwd(), '.grunt', 'components.js'));
|
||||
|
||||
const componentData = fetchComponentData().components;
|
||||
for (const [thisPath, component] of Object.entries(componentData)) {
|
||||
jsconfigData.compilerOptions.paths[`${component}/*`] = [`${thisPath}/amd/src/*`];
|
||||
jsconfigData.include.push(`${thisPath}/amd/src/**/*`);
|
||||
}
|
||||
|
||||
grunt.file.write('jsconfig.json', JSON.stringify(jsconfigData, null, " ") + "\n");
|
||||
};
|
||||
grunt.registerTask('jsconfig', 'Generate a jsconfig configuration compatible with the LSP', handler);
|
||||
};
|
||||
+3
-1
@@ -81,7 +81,8 @@ install:
|
||||
sudo service mysql stop
|
||||
sudo mv /var/lib/mysql /mnt/ramdisk
|
||||
sudo ln -s /mnt/ramdisk/mysql /var/lib/mysql
|
||||
sudo service mysql restart
|
||||
echo -e "[mysqld]\nskip-log-bin" | sudo tee -a /etc/mysql/my.cnf
|
||||
sudo service mysql start
|
||||
fi
|
||||
- >
|
||||
if [ "$DB" = 'pgsql' ];
|
||||
@@ -92,6 +93,7 @@ install:
|
||||
sudo mv /var/lib/postgresql /mnt/ramdisk
|
||||
sudo ln -s /mnt/ramdisk/postgresql /var/lib/postgresql
|
||||
sudo service postgresql start 9.6
|
||||
sh -c 'until pg_isready -p 5432; do echo "Waiting for the DB to be up..."; sleep 2; done'
|
||||
fi
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
|
||||
+53
-35
@@ -1,48 +1,66 @@
|
||||
MOODLE TRADEMARKS POLICY
|
||||
========================
|
||||
|
||||
The word "Moodle" is trademarked in many countries around the world. The word
|
||||
was originally coined as an acronym: Modular Object-Oriented Dynamic Learning
|
||||
Environment. The trademark is owned by Martin Dougiamas, Founder and Director
|
||||
of Moodle.
|
||||
The Moodle Trademark
|
||||
--------------------
|
||||
|
||||
The law obligates trademark owners to police their marks and prevent the use of
|
||||
confusingly similar names by third parties. Through this policy we’d like to
|
||||
make it clear how Moodle-related projects, organisations, and people can use
|
||||
the Moodle trademark. We’d also like to be clear about how use of the word is
|
||||
restricted when used to promote commercial Moodle services. We do this to
|
||||
protect the very business model that allows us to continue developing Moodle
|
||||
for you.
|
||||
The brand and word "Moodle" has trade mark protection in many countries around
|
||||
the world. Various Moodle™ trade marks are owned by either Moodle Pty Ltd or
|
||||
one of its associated entities. The law obligates trade mark owners to police
|
||||
their trade marks and prevent the use of confusingly similar names by
|
||||
third parties.
|
||||
|
||||
Allowed uses
|
||||
------------
|
||||
We have created a more concise and thorough set of Trademark Guidelines
|
||||
(https://moodle.com/wp-content/uploads/2023/02/Moodle-Trademark-Guidelines-2023-4.pdf)
|
||||
to help you understand how to comply with Moodle's trade mark requirements.
|
||||
The Trademark Guidelines will also assist our Moodle Certified Partners and the
|
||||
community to understand some of the principles that inform Moodle's stance
|
||||
whenever potential infringement has been detected by us or our community.
|
||||
|
||||
The following uses don’t require any permission at all:
|
||||
We need to be clear about use of the word "Moodle" and how we restrict its use
|
||||
when promoting commercial Moodle™ branded services. The proper use of
|
||||
trade marks reliably assures consumers about the quality of the associated
|
||||
products or services and where they have been derived from. Because the
|
||||
Moodle LMS is made available under the open source ‘GNU General Public License'
|
||||
that permits you to modify the copyrighted software, the distribution of such
|
||||
modified software in combination with Moodle trade marks can potentially
|
||||
mislead others in the community. To be clear, the GNU GPL does not include an
|
||||
implied right or licence to use Moodle's trade marks.
|
||||
|
||||
* Referring to the software or the Moodle project.
|
||||
* Describing your own Moodle implementation (including within corporate
|
||||
settings).
|
||||
We do all this to protect the very business model that allows us to continue
|
||||
developing various Moodle software solutions for you.
|
||||
|
||||
Allowed uses of "Moodle"
|
||||
------------------------
|
||||
|
||||
The following uses don't require any permission at all:
|
||||
|
||||
* Referring to the software or the Moodle project as the "Moodle™ software"
|
||||
or the "Moodle™ project"
|
||||
* Describing your own implementation of the Moodle™ software platform
|
||||
(including within corporate settings).
|
||||
* Describing a Moodle-based community hub.
|
||||
* Describing some software you’ve made that integrates with Moodle
|
||||
(eg a Moodle integration feature on another system).
|
||||
* Describing certain software you've made that integrates with Moodle™
|
||||
branded software (e.g. a Moodle™ integration feature on another system).
|
||||
|
||||
Restricted uses
|
||||
---------------
|
||||
Restricted uses of "Moodle"
|
||||
---------------------------
|
||||
|
||||
The following uses are generally prohibited without explicit and direct
|
||||
permission being granted to you by Moodle Pty Ltd. We do this to protect the
|
||||
Moodle project from software and sites which could confuse people. Please
|
||||
contact us to ask for permission in writing.
|
||||
Moodle™ project from software and sites which could confuse people. If in
|
||||
doubt, reach out for clarification at <trademarks@moodle.com>
|
||||
|
||||
* You can’t use "Moodle" in the name of your software (including Mobile apps)
|
||||
* You can’t use "Moodle" in your company name
|
||||
* You can’t use "Moodle" in your domain name
|
||||
* You can’t use "Moodle" in advertising-related keywords (such as Adsense)
|
||||
* You can’t use "Moodle" to describe services around Moodle (such as hosting,
|
||||
training, support, consulting, course creation services, theme development,
|
||||
customisation, installation, integration and certification). This applies
|
||||
even if you do not charge for the services. Note that usually only Moodle
|
||||
Partners have this permission.
|
||||
|
||||
For information about the Moodle Partner Certification Mark as well as for how
|
||||
to contact us, please see <https://moodle.com/trademarks/>.
|
||||
* You can't use the word "Moodle" or any Moodle logos for commercial purposes
|
||||
without prior written permission from Moodle HQ.
|
||||
* You can't use "Moodle" in the name of your software (including Mobile apps).
|
||||
* You can't use "Moodle" in your company name.
|
||||
* You can't use "Moodle" in your domain name.
|
||||
* You can't use "Moodle" in advertising-related keywords (such as Adsense).
|
||||
* You can't use "Moodle" to describe services around Moodle
|
||||
(such as hosting, training, support, consulting, course creation services,
|
||||
theme development, customisation, installation, integration, analytics
|
||||
and certification) that cause consumers to be confused that you are
|
||||
associated with Moodle HQ if you are not.
|
||||
This applies even if you do not charge for the services.
|
||||
Note that usually only Moodle Partners have this permission.
|
||||
|
||||
@@ -3371,6 +3371,7 @@
|
||||
<VENDOR name="oracle" version="11.2" />
|
||||
</DATABASE>
|
||||
<PHP version="7.3.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_81" message="unsupportedphpversion81" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -3539,6 +3540,8 @@
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.0" requires="3.6">
|
||||
@@ -3555,6 +3558,7 @@
|
||||
<VENDOR name="oracle" version="11.2" />
|
||||
</DATABASE>
|
||||
<PHP version="7.3.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_81" message="unsupportedphpversion81" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -3729,6 +3733,382 @@
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.1" requires="3.9">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.4" />
|
||||
<VENDOR name="mysql" version="5.7" />
|
||||
<VENDOR name="postgres" version="12" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="7.4.0" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="optional"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="sixtyfourbitswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.2" requires="3.11.8">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.6.7" />
|
||||
<VENDOR name="mysql" version="8.0" />
|
||||
<VENDOR name="postgres" version="13" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.0.0" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="sixtyfourbitsrequired" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -59,9 +59,8 @@ class mnet_simple_host_form extends moodleform {
|
||||
$wwwroot = 'http://'.$wwwroot;
|
||||
}
|
||||
if ($host = $DB->get_record('mnet_host', array('wwwroot' => $wwwroot))) {
|
||||
global $CFG;
|
||||
return array('wwwroot' => get_string('hostexists', 'mnet',
|
||||
new moodle_url('/admin/mnet/peers.php', array('hostid' => $host->id))));
|
||||
$str = get_string('hostexists', 'mnet', (new moodle_url('/admin/mnet/peers.php', ['hostid' => $host->id]))->out());
|
||||
return array('wwwroot' => $str);
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
@@ -51,12 +51,12 @@
|
||||
<div class="form-password">
|
||||
<span data-passwordunmask="wrapper" data-passwordunmaskid="{{ id }}">
|
||||
<span data-passwordunmask="editor">
|
||||
<input type="hidden"
|
||||
<input type="password"
|
||||
name="{{ name }}"
|
||||
id="{{ id }}"
|
||||
value="{{ value }}"
|
||||
data-size="{{ size }}"
|
||||
class="form-control d-inline-block"
|
||||
class="form-control d-none"
|
||||
>
|
||||
</span>
|
||||
<a href="#" data-passwordunmask="edit" title="{{ edithint }}">
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
define("tool_behat/steps",["exports","core/ajax","core/templates","core/pending"],(function(_exports,_ajax,_templates,_pending){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_templates=_interopRequireDefault(_templates),_pending=_interopRequireDefault(_pending);
|
||||
/**
|
||||
* Enhancements for the step definitions page.
|
||||
*
|
||||
* @module tool_behat/steps
|
||||
* @copyright 2022 Catalyst IT EU
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
var getRequiredFieldsContent=function(entityData){var _entityData$required;return null!==(_entityData$required=entityData.required)&&void 0!==_entityData$required&&_entityData$required.length?_templates.default.renderForPromise("tool_behat/steprequiredfields",{fields:entityData.required}):Promise.resolve({html:"",js:""})};_exports.init=function(){var fn,_ref;document.addEventListener("change",(fn=regeneratorRuntime.mark((function _callee(e){var entityElement,stepElement,pendingPromise,entityData,_yield$getRequiredFie,html,js,stepRequiredFields;return regeneratorRuntime.wrap((function(_context){for(;;)switch(_context.prev=_context.next){case 0:if(entityElement=e.target.closest(".entities"),stepElement=e.target.closest(".stepcontent"),entityElement&&stepElement){_context.next=4;break}return _context.abrupt("return");case 4:return pendingPromise=new _pending.default("tool_behat/steps:change"),_context.next=7,entityType=e.target.value,_ajax.default.call([{methodname:"tool_behat_get_entity_generator",args:{entitytype:entityType}}])[0];case 7:return entityData=_context.sent,_context.next=10,getRequiredFieldsContent(entityData);case 10:if(_yield$getRequiredFie=_context.sent,html=_yield$getRequiredFie.html,js=_yield$getRequiredFie.js,!(stepRequiredFields=stepElement.querySelector(".steprequiredfields"))){_context.next=19;break}return _context.next=17,_templates.default.replaceNode(stepRequiredFields,html,js);case 17:_context.next=21;break;case 19:return _context.next=21,_templates.default.appendNodeContents(stepElement,html,js);case 21:pendingPromise.resolve();case 22:case"end":return _context.stop()}var entityType}),_callee)})),_ref=function(){var self=this,args=arguments;return new Promise((function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)}))},function(_x){return _ref.apply(this,arguments)}))}}));
|
||||
|
||||
//# sourceMappingURL=steps.min.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"steps.min.js","sources":["../src/steps.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\nimport Ajax from 'core/ajax';\nimport Templates from 'core/templates';\nimport PendingJS from 'core/pending';\n\n/**\n * Enhancements for the step definitions page.\n *\n * @module tool_behat/steps\n * @copyright 2022 Catalyst IT EU\n * @author Mark Johnson <mark.johnson@catalyst-eu.net>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Call the get_entity_generator web service function\n *\n * Takes the name of an entity generator and returns an object containing a list of the required fields.\n *\n * @param {String} entityType\n * @returns {Promise}\n */\nconst getGeneratorEntities = (entityType) => Ajax.call([{\n methodname: 'tool_behat_get_entity_generator',\n args: {entitytype: entityType}\n}])[0];\n\n/**\n * Render HTML for required fields\n *\n * Takes the entity data returned from getGeneratorEntities and renders the HTML to display the required fields.\n *\n * @param {String} entityData\n * @return {Promise}\n */\nconst getRequiredFieldsContent = (entityData) => {\n if (!entityData.required?.length) {\n return Promise.resolve({\n html: '',\n js: ''\n });\n }\n return Templates.renderForPromise('tool_behat/steprequiredfields', {fields: entityData.required});\n};\n\nexport const init = () => {\n // When an entity is selected in the \"the following exist\" step, fetch and display the required fields.\n document.addEventListener('change', async(e) => {\n const entityElement = e.target.closest('.entities');\n const stepElement = e.target.closest('.stepcontent');\n if (!entityElement || !stepElement) {\n return;\n }\n\n const pendingPromise = new PendingJS('tool_behat/steps:change');\n\n const entityData = await getGeneratorEntities(e.target.value);\n const {html, js} = await getRequiredFieldsContent(entityData);\n\n const stepRequiredFields = stepElement.querySelector('.steprequiredfields');\n if (stepRequiredFields) {\n await Templates.replaceNode(stepRequiredFields, html, js);\n } else {\n await Templates.appendNodeContents(stepElement, html, js);\n }\n pendingPromise.resolve();\n });\n};\n"],"names":["getRequiredFieldsContent","entityData","required","_entityData$required","length","Templates","renderForPromise","fields","Promise","resolve","html","js","document","addEventListener","e","entityElement","target","closest","stepElement","pendingPromise","PendingJS","entityType","value","Ajax","call","methodname","args","entitytype","stepRequiredFields","querySelector","replaceNode","appendNodeContents"],"mappings":";;;;;;;;;IAiDMA,yBAA2B,SAACC,yEACzBA,WAAWC,0CAAXC,qBAAqBC,OAMnBC,mBAAUC,iBAAiB,gCAAiC,CAACC,OAAQN,WAAWC,WAL5EM,QAAQC,QAAQ,CACnBC,KAAM,GACNC,GAAI,oBAMI,uBAEhBC,SAASC,iBAAiB,sCAAU,iBAAMC,oNAChCC,cAAgBD,EAAEE,OAAOC,QAAQ,aACjCC,YAAcJ,EAAEE,OAAOC,QAAQ,gBAChCF,eAAkBG,kFAIjBC,eAAiB,IAAIC,iBAAU,2CAhCfC,WAkCwBP,EAAEE,OAAOM,MAlClBC,cAAKC,KAAK,CAAC,CACpDC,WAAY,kCACZC,KAAM,CAACC,WAAYN,eACnB,iBA+BUpB,0CACmBD,yBAAyBC,2DAA3CS,2BAAAA,KAAMC,yBAAAA,KAEPiB,mBAAqBV,YAAYW,cAAc,wEAE3CxB,mBAAUyB,YAAYF,mBAAoBlB,KAAMC,mEAEhDN,mBAAU0B,mBAAmBb,YAAaR,KAAMC,YAE1DQ,eAAeV,mDA3CM,IAACY"}
|
||||
@@ -0,0 +1,82 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import Ajax from 'core/ajax';
|
||||
import Templates from 'core/templates';
|
||||
import PendingJS from 'core/pending';
|
||||
|
||||
/**
|
||||
* Enhancements for the step definitions page.
|
||||
*
|
||||
* @module tool_behat/steps
|
||||
* @copyright 2022 Catalyst IT EU
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Call the get_entity_generator web service function
|
||||
*
|
||||
* Takes the name of an entity generator and returns an object containing a list of the required fields.
|
||||
*
|
||||
* @param {String} entityType
|
||||
* @returns {Promise}
|
||||
*/
|
||||
const getGeneratorEntities = (entityType) => Ajax.call([{
|
||||
methodname: 'tool_behat_get_entity_generator',
|
||||
args: {entitytype: entityType}
|
||||
}])[0];
|
||||
|
||||
/**
|
||||
* Render HTML for required fields
|
||||
*
|
||||
* Takes the entity data returned from getGeneratorEntities and renders the HTML to display the required fields.
|
||||
*
|
||||
* @param {String} entityData
|
||||
* @return {Promise}
|
||||
*/
|
||||
const getRequiredFieldsContent = (entityData) => {
|
||||
if (!entityData.required?.length) {
|
||||
return Promise.resolve({
|
||||
html: '',
|
||||
js: ''
|
||||
});
|
||||
}
|
||||
return Templates.renderForPromise('tool_behat/steprequiredfields', {fields: entityData.required});
|
||||
};
|
||||
|
||||
export const init = () => {
|
||||
// When an entity is selected in the "the following exist" step, fetch and display the required fields.
|
||||
document.addEventListener('change', async(e) => {
|
||||
const entityElement = e.target.closest('.entities');
|
||||
const stepElement = e.target.closest('.stepcontent');
|
||||
if (!entityElement || !stepElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pendingPromise = new PendingJS('tool_behat/steps:change');
|
||||
|
||||
const entityData = await getGeneratorEntities(e.target.value);
|
||||
const {html, js} = await getRequiredFieldsContent(entityData);
|
||||
|
||||
const stepRequiredFields = stepElement.querySelector('.steprequiredfields');
|
||||
if (stepRequiredFields) {
|
||||
await Templates.replaceNode(stepRequiredFields, html, js);
|
||||
} else {
|
||||
await Templates.appendNodeContents(stepElement, html, js);
|
||||
}
|
||||
pendingPromise.resolve();
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Return data about an entity generator.
|
||||
*
|
||||
* @package tool_behat
|
||||
* @copyright 2022 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_behat\external;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
/**
|
||||
* External function for getting properties of entity generators.
|
||||
*/
|
||||
class get_entity_generator extends \external_api {
|
||||
|
||||
/**
|
||||
* Define parameters for external function.
|
||||
*
|
||||
* The parameter is either in the format 'entity' or 'component_name > entity'. There is no appropriate param type for a
|
||||
* string like this containing angle brackets, so we will do PARAM_RAW. The value will be parsed by
|
||||
* behat_data_generators::parse_entity_type, which validates the format of the parameter and throws an exception if it is not
|
||||
* correct.
|
||||
*
|
||||
* @return \external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): \external_function_parameters {
|
||||
return new \external_function_parameters([
|
||||
'entitytype' => new \external_value(PARAM_RAW, 'Entity type that can be created by a generator.'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the required fields for a given entity type.
|
||||
*
|
||||
* @param string $entitytype
|
||||
* @return array
|
||||
*/
|
||||
public static function execute(string $entitytype): array {
|
||||
global $CFG;
|
||||
|
||||
// Ensure we can load Behat and Facebook namespaces in behat libraries.
|
||||
require_once("{$CFG->dirroot}/vendor/autoload.php");
|
||||
require_once("{$CFG->libdir}/tests/behat/behat_data_generators.php");
|
||||
|
||||
$params = self::validate_parameters(self::execute_parameters(), ['entitytype' => $entitytype]);
|
||||
$context = \context_system::instance();
|
||||
self::validate_context($context);
|
||||
require_capability('moodle/site:config', $context);
|
||||
|
||||
$generators = new \behat_data_generators();
|
||||
$entity = $generators->get_entity($params['entitytype']);
|
||||
return ['required' => $entity['required']];
|
||||
}
|
||||
|
||||
/**
|
||||
* Define return values.
|
||||
*
|
||||
* Return required fields
|
||||
*
|
||||
* @return \external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): \external_single_structure {
|
||||
return new \external_single_structure([
|
||||
'required' => new \external_multiple_structure(
|
||||
new \external_value(PARAM_TEXT, 'Required field'),
|
||||
'Required fields',
|
||||
VALUE_OPTIONAL
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Define web service functions for tool_behat
|
||||
*
|
||||
* @package tool_behat
|
||||
* @copyright 2022 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$functions = [
|
||||
'tool_behat_get_entity_generator' => [
|
||||
'classname' => 'tool_behat\\external\\get_entity_generator',
|
||||
'methodname' => 'execute',
|
||||
'description' => 'Get the generator details for an entity',
|
||||
'type' => 'read',
|
||||
'ajax' => true,
|
||||
'capabilities' => 'moodle/site:config'
|
||||
]
|
||||
];
|
||||
@@ -56,6 +56,7 @@ if ($components) {
|
||||
$form = new steps_definitions_form(null, array('components' => $componentswithsteps));
|
||||
|
||||
// Output contents.
|
||||
$PAGE->requires->js_call_amd('tool_behat/steps', 'init');
|
||||
$renderer = $PAGE->get_renderer('tool_behat');
|
||||
echo $renderer->render_stepsdefinitions($steps, $form);
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/behat/classes/behat_generator_base.php');
|
||||
|
||||
/**
|
||||
* Renderer for behat tool web features
|
||||
*
|
||||
@@ -106,6 +108,32 @@ class tool_behat_renderer extends plugin_renderer_base {
|
||||
},
|
||||
$stepsdefinitions
|
||||
);
|
||||
|
||||
$elementstrings = [];
|
||||
$count = 1;
|
||||
$stepsdefinitions = preg_replace_callback('/(the following ")ELEMENT\d?_STRING(" exist:)/',
|
||||
function($matches) use (&$elementstrings, &$count) {
|
||||
// Replace element type arguments with a user-friendly select.
|
||||
if (empty($elementstrings)) {
|
||||
$behatgenerators = new behat_data_generators();
|
||||
$componententities = $behatgenerators->get_all_entities();
|
||||
ksort($componententities);
|
||||
$elementstrings = [];
|
||||
foreach ($componententities as $component => $entities) {
|
||||
asort($entities);
|
||||
foreach ($entities as $entity) {
|
||||
$string = ($component === 'core') ? $entity : $component . ' > ' . $entity;
|
||||
$elementstrings[$string] = $string;
|
||||
}
|
||||
}
|
||||
}
|
||||
$select = html_writer::select($elementstrings, 'entities' . $count, '', ['' => 'choosedots'],
|
||||
['class' => 'entities']);
|
||||
$count++;
|
||||
return $matches[1] . $select . $matches[2];
|
||||
},
|
||||
$stepsdefinitions
|
||||
);
|
||||
}
|
||||
|
||||
// Steps definitions.
|
||||
|
||||
@@ -29,3 +29,9 @@
|
||||
#page-admin-tool-behat-index .steps-definitions .stepregex {
|
||||
color: #060;
|
||||
}
|
||||
|
||||
#page-admin-tool-behat-index .steprequiredfields {
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
{{!
|
||||
This file is part of Moodle - https://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template tool_behat/steprequiredfields
|
||||
|
||||
Display a Gherkin-style table row showing required columns for a step.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"fields": [
|
||||
"user",
|
||||
"role",
|
||||
"context"
|
||||
]
|
||||
}
|
||||
}}
|
||||
<pre class="steprequiredfields">
|
||||
|{{#fields}} {{{.}}} |{{/fields}}
|
||||
</pre>
|
||||
@@ -30,10 +30,9 @@ Feature: Verify that all form fields values can be get and set
|
||||
| student2 | G2 |
|
||||
| student3 | G2 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro | firstpagetitle | wikimode | visible |
|
||||
| wiki | C1 | wiki1 | Test this one | Test this one | Test this one | collaborative | 0 |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
| activity | course | idnumber | name | firstpagetitle | wikimode | visible |
|
||||
| wiki | C1 | wiki1 | Test this one | Test this one | collaborative | 0 |
|
||||
And I am on the "Course 1" course page logged in as admin
|
||||
And I navigate to "Reset" in current page administration
|
||||
# Select (multi-select) - Checking "the select box should contain".
|
||||
And I expand all fieldsets
|
||||
@@ -61,16 +60,14 @@ Feature: Verify that all form fields values can be get and set
|
||||
# Checkbox - Checking "I set the field" and "The field matches value" ticked.
|
||||
And I set the field "Force format" to "1"
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I expand all fieldsets
|
||||
And the field "Force format" matches value "1"
|
||||
And the field "Force format" does not match value ""
|
||||
# Checkbox - Checking "I set the field" and "The field matches value" unticked.
|
||||
And I set the field "Force format" to ""
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I expand all fieldsets
|
||||
And the field "Force format" matches value ""
|
||||
And the field "Force format" does not match value "1"
|
||||
@@ -78,8 +75,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I set the following fields to these values:
|
||||
| Force format | 1 |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I expand all fieldsets
|
||||
And the following fields match these values:
|
||||
| Force format | 1 |
|
||||
@@ -89,8 +85,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I set the following fields to these values:
|
||||
| Force format | |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I expand all fieldsets
|
||||
And the following fields match these values:
|
||||
| Force format | |
|
||||
@@ -143,10 +138,11 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And the field "Course ID number" matches value "Course id number"
|
||||
|
||||
Scenario: with JS disabled all form fields getters and setters works as expected
|
||||
|
||||
@javascript
|
||||
Scenario: with JS enabled all form fields getters and setters works as expected
|
||||
Given the following "activities" exist:
|
||||
| activity | course | name |
|
||||
| lesson | C1 | Test lesson |
|
||||
Then I am on "Course 1" course homepage
|
||||
And I navigate to "Users > Groups" in current page administration
|
||||
# Select (multi-select & AJAX) - Checking "I set the field" and "select box should contain".
|
||||
@@ -159,11 +155,8 @@ Feature: Verify that all form fields values can be get and set
|
||||
And the "members" select box should contain "Student 2 (s2@example.com)"
|
||||
And the "members" select box should not contain "Student 3 (s3@example.com)"
|
||||
# Checkbox (AJAX) - Checking "I set the field" and "I set the following fields to these values".
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a "Lesson" to section "1"
|
||||
And I am on the "Test lesson" "lesson activity editing" page
|
||||
And I set the following fields to these values:
|
||||
| Name | Test lesson |
|
||||
| Description | Test lesson description |
|
||||
| available[enabled] | 1 |
|
||||
And I set the field "deadline[enabled]" to "1"
|
||||
# Checkbox (AJAX) - Checking "the field matches value" before saving.
|
||||
|
||||
@@ -7,8 +7,8 @@ Feature: Behat steps for interacting with form work
|
||||
@javascript
|
||||
Scenario: Test fields in containers
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
| fullname | shortname | summary | summaryformat |
|
||||
| Course 1 | C1 | Red | 1 |
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
# Just get to any form.
|
||||
@@ -17,11 +17,15 @@ Feature: Behat steps for interacting with form work
|
||||
And I set the following fields in the "Appearance" "fieldset" to these values:
|
||||
| Show activity reports | Yes |
|
||||
| Number of announcements | 1 |
|
||||
And I set the following fields in the "Description" "fieldset" to these values:
|
||||
| Course summary | Green |
|
||||
Then the field "Show activity reports" in the "Appearance" "fieldset" matches value "Yes"
|
||||
And the field "Show activity reports" in the "Appearance" "fieldset" does not match value "No"
|
||||
And the following fields in the "region-main" "region" match these values:
|
||||
| Course full name | Frog |
|
||||
| Number of announcements | 1 |
|
||||
| Course summary | Green |
|
||||
And the following fields in the "region-main" "region" do not match these values:
|
||||
| Course full name | Course 1 |
|
||||
| Number of announcements | 5 |
|
||||
| Course summary | Red |
|
||||
|
||||
@@ -13,6 +13,10 @@ Feature: List the system steps definitions
|
||||
Scenario: Accessing the list
|
||||
Then I should see "Step definitions"
|
||||
And I should not see "There aren't steps definitions matching this filter"
|
||||
And I should not see "the following \"ELEMENT_STRING\" exist:"
|
||||
And "entities1" "select" should exist
|
||||
And the "entities1" select box should contain "users"
|
||||
And the "entities1" select box should contain "mod_assign > submissions"
|
||||
|
||||
@javascript
|
||||
Scenario: Filtering by type
|
||||
@@ -34,3 +38,11 @@ Feature: List the system steps definitions
|
||||
Then I should not see "There aren't steps definitions matching this filter"
|
||||
And I should see "Checks the provided element and selector type exists in the current page."
|
||||
And I should see "Checks that an element and selector type exists in another element and selector type on the current page."
|
||||
|
||||
@javascript
|
||||
Scenario: Get required fields
|
||||
Given I set the field "entities1" to "users"
|
||||
And I should see "| username |"
|
||||
When I set the field "entities1" to "mod_quiz > user overrides"
|
||||
Then I should not see "| username |"
|
||||
And I should see "| quiz | user |"
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for get_entity_generator web service
|
||||
*
|
||||
* @package tool_behat
|
||||
* @copyright 2022 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_behat\external;
|
||||
|
||||
/**
|
||||
* Tests for get_entity_generator web service
|
||||
*
|
||||
* @covers \tool_behat\external\get_entity_generator
|
||||
*/
|
||||
class get_entity_generator_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Log in as admin
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator for a core entity.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_core_entity(): void {
|
||||
$generator = get_entity_generator::execute('users');
|
||||
$this->assertEquals(['required' => ['username']], $generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator for the plugin entity.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_plugin_entity(): void {
|
||||
$generator = get_entity_generator::execute('mod_book > chapters');
|
||||
$this->assertEquals(['required' => ['book', 'title', 'content']], $generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator for an entity with no required fields.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_no_requried(): void {
|
||||
$generator = get_entity_generator::execute('mod_forum > posts');
|
||||
$this->assertEquals(['required' => []], $generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get the generator for a core entity that does not exist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_invalid_entity(): void {
|
||||
$this->expectException('coding_exception');
|
||||
get_entity_generator::execute('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get a generator form a plugin that does not exist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_invalid_plugin(): void {
|
||||
$this->expectException('coding_exception');
|
||||
get_entity_generator::execute('foo > bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get a generator for an entity that does not exist, from a plugin that does.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_invalid_plugin_entity(): void {
|
||||
$this->expectException('coding_exception');
|
||||
get_entity_generator::execute('mod_book > bar');
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2021051700; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2021051701; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2021051100; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_behat'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -323,7 +323,7 @@ class accessibility {
|
||||
/**
|
||||
* This function runs one specified check on the html item
|
||||
*
|
||||
* @param string $html The html string to be analysed; might be NULL.
|
||||
* @param string|null $html The html string to be analysed; might be NULL.
|
||||
* @param int $contentid The content area ID
|
||||
* @param int $errid The error ID
|
||||
* @param string $check The check name to run
|
||||
@@ -333,7 +333,7 @@ class accessibility {
|
||||
* @throws \dml_exception
|
||||
*/
|
||||
public static function run_one_check(
|
||||
string $html = null,
|
||||
?string $html,
|
||||
int $contentid,
|
||||
int $errid,
|
||||
string $check,
|
||||
|
||||
@@ -36,7 +36,7 @@ Useful for uploading custom langstrings to AMOS or importing or syncing them to
|
||||
Options:
|
||||
-l, --lang Comma seperated language ids to export, default: all
|
||||
-c, --components Comma seperated components to export, default: all
|
||||
-t, --target Target to copy the zip files to, default: $CFG->tempdir/customlang
|
||||
-t, --target Target directory to copy the zip files to, default: $CFG->tempdir/customlang
|
||||
-o, --overwrite Overwrite existing files in the target folder.
|
||||
Note: If the target is not set, the files are always overwritten!
|
||||
-h, --help Print out this help
|
||||
@@ -73,9 +73,10 @@ if ($options['help']) {
|
||||
echo $usage;
|
||||
die;
|
||||
}
|
||||
if (!file_exists($options['target'])) {
|
||||
mkdir($options['target'], 0777, true);
|
||||
}
|
||||
|
||||
// Ensure target directory exists.
|
||||
$options['target'] = rtrim($options['target'], '/') . '/';
|
||||
check_dir_exists($options['target']);
|
||||
|
||||
cli_writeln(get_string('cliexportheading', 'tool_customlang'));
|
||||
$langs = [];
|
||||
@@ -90,7 +91,7 @@ foreach ($langs as $lang) {
|
||||
$filename = $options['target'] . get_string('exportzipfilename', 'tool_customlang', ['lang' => $lang]);
|
||||
// If the file exists and we are not using the temp folder it requires an ovewrite.
|
||||
if ($options['target'] != $dafaulttarget && file_exists($filename) && !$options['overwrite']) {
|
||||
cli_problem(get_string('cliexportfileexists', 'tool_customlang', $lang));
|
||||
cli_problem(get_string('cliexportfileexists', 'tool_customlang', ['lang' => $lang]));
|
||||
continue;
|
||||
}
|
||||
cli_heading(get_string('cliexportstartexport', 'tool_customlang', $lang));
|
||||
|
||||
@@ -160,6 +160,16 @@ foreach ($langfiles as $lng => $files) {
|
||||
|
||||
cli_heading(get_string('clifiles', 'tool_customlang', $lng));
|
||||
|
||||
// If we intend to check in any changes, we must first check them out.
|
||||
if ($checkin) {
|
||||
cli_writeln(get_string('checkout', 'tool_customlang'));
|
||||
|
||||
$progressbar = new progress_bar();
|
||||
$progressbar->create();
|
||||
|
||||
tool_customlang_utils::checkout($lng, $progressbar);
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
// Generate a valid stored_file from this file.
|
||||
$record = (object)[
|
||||
|
||||
@@ -50,6 +50,7 @@ $string['customlang:export'] = 'Export local translation';
|
||||
$string['customlang:view'] = 'View local translation';
|
||||
$string['export'] = 'Export custom strings';
|
||||
$string['exportfilter'] = 'Select component(s) to export';
|
||||
$string['exportzipfilename'] = 'customlang-export-{$a->lang}.zip';
|
||||
$string['filter'] = 'Filter strings';
|
||||
$string['filtercomponent'] = 'Show strings of these components';
|
||||
$string['filtercustomized'] = 'Customised only';
|
||||
|
||||
@@ -89,7 +89,9 @@ class tool_customlang_utils {
|
||||
* @param progress_bar $progressbar optionally, the given progress bar can be updated
|
||||
*/
|
||||
public static function checkout($lang, progress_bar $progressbar = null) {
|
||||
global $DB;
|
||||
global $DB, $CFG;
|
||||
|
||||
require_once("{$CFG->libdir}/adminlib.php");
|
||||
|
||||
// For behat executions we are going to load only a few components in the
|
||||
// language customisation structures. Using the whole "en" langpack is
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_httpsreplace\tests;
|
||||
|
||||
namespace tool_httpsreplace;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
@@ -124,6 +124,12 @@ class controller {
|
||||
}
|
||||
|
||||
if ($rm1 or $rm2) {
|
||||
// Set the default site language to en if the deleted language pack is the default site language.
|
||||
if ($CFG->lang === $lang) {
|
||||
set_config('lang', 'en');
|
||||
// Fix the user's current language to the default site language.
|
||||
fix_current_language($CFG->lang);
|
||||
}
|
||||
$this->info[] = get_string('langpackremoved', 'tool_langimport', $lang);
|
||||
event\langpack_removed::event_with_langcode($lang)->trigger();
|
||||
return true;
|
||||
|
||||
@@ -79,6 +79,19 @@ class locale {
|
||||
* @return string|false Returns the new current locale, or FALSE on error.
|
||||
*/
|
||||
protected function set_locale(int $category = LC_ALL, string $locale = '0') {
|
||||
return setlocale($category, $locale);
|
||||
if (strlen($locale) <= 255 || PHP_OS_FAMILY === 'BSD' || PHP_OS_FAMILY === 'Darwin') {
|
||||
// We can set the whole locale all together.
|
||||
return setlocale($category, $locale);
|
||||
}
|
||||
|
||||
// Too long locale with linux or windows, let's split it into known and supported categories.
|
||||
$split = explode(';', $locale);
|
||||
foreach ($split as $element) {
|
||||
[$category, $value] = explode('=', $element);
|
||||
if (defined($category)) { // Only if the category exists, there are OS differences.
|
||||
setlocale(constant($category), $value);
|
||||
}
|
||||
}
|
||||
return setlocale(LC_ALL, 0); // Finally, return the complete configured locale.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tests for \tool_langimport\locale class.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2018 Université Rennes 2 {@link https://www.univ-rennes2.fr}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_langimport;
|
||||
|
||||
/**
|
||||
@@ -29,6 +21,7 @@ namespace tool_langimport;
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @category test
|
||||
* @coversDefaultClass \tool_langimport\locale
|
||||
* @copyright 2018 Université Rennes 2 {@link https://www.univ-rennes2.fr}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
@@ -36,6 +29,7 @@ class locale_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test that \tool_langimport\locale::check_locale_availability() works as expected.
|
||||
*
|
||||
* @covers ::check_locale_availability
|
||||
* @return void
|
||||
*/
|
||||
public function test_check_locale_availability() {
|
||||
@@ -43,7 +37,7 @@ class locale_test extends \advanced_testcase {
|
||||
// - first setlocale() call which backup current locale
|
||||
// - second setlocale() call which try to set new 'es' locale
|
||||
// - third setlocale() call which restore locale.
|
||||
$mock = $this->getMockBuilder(\tool_langimport\locale::class)
|
||||
$mock = $this->getMockBuilder(locale::class)
|
||||
->onlyMethods(['set_locale'])
|
||||
->getMock();
|
||||
$mock->method('set_locale')->will($this->onConsecutiveCalls('en', 'es', 'en'));
|
||||
@@ -56,7 +50,7 @@ class locale_test extends \advanced_testcase {
|
||||
// - first setlocale() call which backup current locale
|
||||
// - second setlocale() call which fail to set new locale
|
||||
// - third setlocale() call which restore locale.
|
||||
$mock = $this->getMockBuilder(\tool_langimport\locale::class)
|
||||
$mock = $this->getMockBuilder(locale::class)
|
||||
->onlyMethods(['set_locale'])
|
||||
->getMock();
|
||||
$mock->method('set_locale')->will($this->onConsecutiveCalls('en', false, 'en'));
|
||||
@@ -66,8 +60,104 @@ class locale_test extends \advanced_testcase {
|
||||
$this->assertFalse($result);
|
||||
|
||||
// Test an invalid parameter.
|
||||
$locale = new \tool_langimport\locale();
|
||||
$locale = new locale();
|
||||
$this->expectException(\coding_exception::class);
|
||||
$locale->check_locale_availability('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test \tool_langimport\locale::set_locale() own logic.
|
||||
*
|
||||
* We have to explicitly test set_locale() own logic and results,
|
||||
* that effectively sets the current locale, so we need to restore
|
||||
* the original locale after every test (ugly, from a purist unit test
|
||||
* point of view, but needed).
|
||||
*
|
||||
* @dataProvider set_locale_provider
|
||||
* @covers ::set_locale
|
||||
*
|
||||
* @param string $set locale string to be set.
|
||||
* @param string $ret expected results returned after setting the locale.
|
||||
*/
|
||||
public function test_set_locale(string $set, string $ret) {
|
||||
// Make set_locale() public.
|
||||
$loc = new locale();
|
||||
$rc = new \ReflectionClass(locale::class);
|
||||
$rm = $rc->getMethod('set_locale');
|
||||
$rm->setAccessible(true);
|
||||
|
||||
// Capture current locale for later restore (funnily, using the set_locale() method itself.
|
||||
$originallocale = $rm->invokeArgs($loc, [LC_ALL, 0]);
|
||||
|
||||
// Assert we get the locale defined as expected.
|
||||
$this->assertEquals($ret, $rm->invokeArgs($loc, [LC_ALL, $set]));
|
||||
|
||||
// We have finished, restore the original locale, so this doesn't affect other tests at distance.
|
||||
// (again, funnily, using the very same set_locale() method).
|
||||
$rm->invokeArgs($loc, [LC_ALL, $originallocale]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_set_locale().
|
||||
*
|
||||
* Provides a locale to be set (as 'set') and a expected return value (as 'ret'). Note that
|
||||
* some of the locales are OS dependent, so only the ones matching the OS will be provided.
|
||||
*
|
||||
* We make extensive use of the en_AU.UTF-8/English_Australia.1252 locale that is mandatory to
|
||||
* be installed in any system running PHPUnit tests.
|
||||
*/
|
||||
public function set_locale_provider(): array {
|
||||
// Let's list the allowed categories by OS.
|
||||
$bsdallowed = ['LC_COLLATE', 'LC_CTYPE', 'LC_MESSAGES', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME'];
|
||||
$winallowed = ['LC_COLLATE', 'LC_CTYPE', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME'];
|
||||
$linuxallowed = [
|
||||
'LC_COLLATE', 'LC_CTYPE', 'LC_MESSAGES', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME',
|
||||
'LC_PAPER', 'LC_NAME', 'LC_ADDRESS', 'LC_TELEPHONE', 'LC_MEASUREMENT', 'LC_IDENTIFICATION'
|
||||
];
|
||||
|
||||
// The base locale name is also OS dependent.
|
||||
$baselocale = get_string('locale', 'langconfig');
|
||||
if (PHP_OS_FAMILY === 'Windows') {
|
||||
$baselocale = get_string('localewin', 'langconfig');
|
||||
}
|
||||
|
||||
// Here we'll go accumulating cases to be provided.
|
||||
$cases = [];
|
||||
|
||||
// First, the simplest case, just pass a locale name, without categories.
|
||||
$cases['rawlocale'] = [
|
||||
'set' => $baselocale,
|
||||
'ret' => $baselocale,
|
||||
];
|
||||
|
||||
// Now, let's fill ALL LC categories, we should get back the locale name if all them are set with same value.
|
||||
// Note that this case is the one that, under Linux only, covers the changes performed to the set_locale() method.
|
||||
// Pick the correct categories depending on the OS.
|
||||
$oscategories = $bsdallowed; // Default to BSD/Dawrwin ones because they are the standard 6 supported by PHP.
|
||||
if (PHP_OS_FAMILY === 'Windows') {
|
||||
$oscategories = $winallowed;
|
||||
} else if (PHP_OS_FAMILY === 'Linux') {
|
||||
$oscategories = $linuxallowed;
|
||||
}
|
||||
|
||||
$localestr = '';
|
||||
foreach ($oscategories as $category) {
|
||||
// Format is different by OS too, so let build the string conditionally.
|
||||
if (PHP_OS_FAMILY === 'BSD' || PHP_OS_FAMILY === 'Darwin') {
|
||||
// BSD uses slashes (/) separated list of the 6 values in exact order.
|
||||
$localestr .= '/' . $baselocale;
|
||||
} else {
|
||||
// Linux/Windows use semicolon (;) separated list of category=value pairs.
|
||||
$localestr .= ';' . $category . '=' . $baselocale;
|
||||
}
|
||||
}
|
||||
$cases['allcategories'] = [
|
||||
'set' => trim($localestr, ';/'),
|
||||
'ret' => $baselocale,
|
||||
];
|
||||
|
||||
// Return all the built cases.
|
||||
return $cases;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,3 +33,27 @@ Feature: Licence manager
|
||||
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 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 |
|
||||
| rememberuserlicensepref | <rememberuserlicensepref> |
|
||||
And I log in as "admin"
|
||||
And I follow "Manage private files..."
|
||||
And I follow "Add..."
|
||||
And I follow "Upload a file"
|
||||
And the field with xpath "//select[@name='license']" matches value "Creative Commons"
|
||||
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 |
|
||||
| license | Public domain |
|
||||
And I press "Save changes"
|
||||
And I follow "Manage private files..."
|
||||
And I follow "Add..."
|
||||
Then the field with xpath "//select[@name='license']" matches value "<expectedlicence>"
|
||||
|
||||
Examples:
|
||||
| rememberuserlicensepref | expectedlicence |
|
||||
| 0 | Creative Commons |
|
||||
| 1 | Public domain |
|
||||
|
||||
@@ -33,8 +33,7 @@ class store_test extends \advanced_testcase {
|
||||
* Tests log writing.
|
||||
*
|
||||
* @param bool $jsonformat True to test with JSON format
|
||||
* @dataProvider test_log_writing_provider
|
||||
* @throws moodle_exception
|
||||
* @dataProvider log_writing_provider
|
||||
*/
|
||||
public function test_log_writing(bool $jsonformat) {
|
||||
global $DB, $CFG;
|
||||
@@ -252,9 +251,9 @@ class store_test extends \advanced_testcase {
|
||||
* Returns different JSON format settings so the test can be run with JSON format either on or
|
||||
* off.
|
||||
*
|
||||
* @return [bool] Array of true/false
|
||||
* @return bool[] Array of true/false
|
||||
*/
|
||||
public static function test_log_writing_provider(): array {
|
||||
public static function log_writing_provider(): array {
|
||||
return [
|
||||
[false],
|
||||
[true]
|
||||
@@ -311,17 +310,16 @@ class store_test extends \advanced_testcase {
|
||||
$logmanager = get_log_manager();
|
||||
$allreports = \core_component::get_plugin_list('report');
|
||||
|
||||
$supportedreports = array(
|
||||
'report_log' => '/report/log',
|
||||
'report_loglive' => '/report/loglive'
|
||||
);
|
||||
|
||||
// Make sure all supported reports are installed.
|
||||
$expectedreports = array_keys(array_intersect_key($allreports, $supportedreports));
|
||||
$reports = $logmanager->get_supported_reports('logstore_database');
|
||||
$reports = array_keys($reports);
|
||||
$expectedreports = array_intersect_key([
|
||||
'log' => 'report_log',
|
||||
'loglive' => 'report_loglive',
|
||||
], $allreports);
|
||||
|
||||
$supportedreports = $logmanager->get_supported_reports('logstore_database');
|
||||
|
||||
foreach ($expectedreports as $expectedreport) {
|
||||
$this->assertContains($expectedreport, $reports);
|
||||
$this->assertArrayHasKey($expectedreport, $supportedreports);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,20 +217,19 @@ class store_test extends \advanced_testcase {
|
||||
$logmanager = get_log_manager();
|
||||
$allreports = \core_component::get_plugin_list('report');
|
||||
|
||||
$supportedreports = array(
|
||||
'report_log' => '/report/log',
|
||||
'report_loglive' => '/report/loglive',
|
||||
'report_outline' => '/report/outline',
|
||||
'report_participation' => '/report/participation',
|
||||
'report_stats' => '/report/stats'
|
||||
);
|
||||
|
||||
// Make sure all supported reports are installed.
|
||||
$expectedreports = array_keys(array_intersect_key($allreports, $supportedreports));
|
||||
$reports = $logmanager->get_supported_reports('logstore_legacy');
|
||||
$reports = array_keys($reports);
|
||||
$expectedreports = array_intersect_key([
|
||||
'log' => 'report_log',
|
||||
'loglive' => 'report_loglive',
|
||||
'outline' => 'report_outline',
|
||||
'participation' => 'report_participation',
|
||||
'stats' => 'report_stats'
|
||||
], $allreports);
|
||||
|
||||
$supportedreports = $logmanager->get_supported_reports('logstore_legacy');
|
||||
|
||||
foreach ($expectedreports as $expectedreport) {
|
||||
$this->assertContains($expectedreport, $reports);
|
||||
$this->assertArrayHasKey($expectedreport, $supportedreports);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,7 @@ class store_test extends \advanced_testcase {
|
||||
* Tests log writing.
|
||||
*
|
||||
* @param bool $jsonformat True to test with JSON format
|
||||
* @dataProvider test_log_writing_provider
|
||||
* @throws moodle_exception
|
||||
* @dataProvider log_writing_provider
|
||||
*/
|
||||
public function test_log_writing(bool $jsonformat) {
|
||||
global $DB;
|
||||
@@ -223,9 +222,9 @@ class store_test extends \advanced_testcase {
|
||||
* Returns different JSON format settings so the test can be run with JSON format either on or
|
||||
* off.
|
||||
*
|
||||
* @return [bool] Array of true/false
|
||||
* @return bool[] Array of true/false
|
||||
*/
|
||||
public static function test_log_writing_provider(): array {
|
||||
public static function log_writing_provider(): array {
|
||||
return [
|
||||
[false],
|
||||
[true]
|
||||
@@ -239,20 +238,19 @@ class store_test extends \advanced_testcase {
|
||||
$logmanager = get_log_manager();
|
||||
$allreports = \core_component::get_plugin_list('report');
|
||||
|
||||
$supportedreports = array(
|
||||
'report_log' => '/report/log',
|
||||
'report_loglive' => '/report/loglive',
|
||||
'report_outline' => '/report/outline',
|
||||
'report_participation' => '/report/participation',
|
||||
'report_stats' => '/report/stats'
|
||||
);
|
||||
|
||||
// Make sure all supported reports are installed.
|
||||
$expectedreports = array_keys(array_intersect_key($allreports, $supportedreports));
|
||||
$reports = $logmanager->get_supported_reports('logstore_standard');
|
||||
$reports = array_keys($reports);
|
||||
$expectedreports = array_intersect_key([
|
||||
'log' => 'report_log',
|
||||
'loglive' => 'report_loglive',
|
||||
'outline' => 'report_outline',
|
||||
'participation' => 'report_participation',
|
||||
'stats' => 'report_stats'
|
||||
], $allreports);
|
||||
|
||||
$supportedreports = $logmanager->get_supported_reports('logstore_standard');
|
||||
|
||||
foreach ($expectedreports as $expectedreport) {
|
||||
$this->assertContains($expectedreport, $reports);
|
||||
$this->assertArrayHasKey($expectedreport, $supportedreports);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +366,7 @@ class store_test extends \advanced_testcase {
|
||||
* Tests the decode_other function can cope with both JSON and PHP serialized format.
|
||||
*
|
||||
* @param mixed $value Value to encode and decode
|
||||
* @dataProvider test_decode_other_provider
|
||||
* @dataProvider decode_other_provider
|
||||
*/
|
||||
public function test_decode_other($value) {
|
||||
$this->assertEquals($value, \logstore_standard\log\store::decode_other(serialize($value)));
|
||||
@@ -387,7 +385,7 @@ class store_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array Array of parameters
|
||||
*/
|
||||
public function test_decode_other_provider(): array {
|
||||
public function decode_other_provider(): array {
|
||||
return [
|
||||
[['info' => 'd2819896', 'logurl' => 'discuss.php?d=2819896']],
|
||||
[null],
|
||||
@@ -400,8 +398,7 @@ class store_test extends \advanced_testcase {
|
||||
* Checks that backup and restore of log data works correctly.
|
||||
*
|
||||
* @param bool $jsonformat True to test with JSON format
|
||||
* @dataProvider test_log_writing_provider
|
||||
* @throws moodle_exception
|
||||
* @dataProvider log_writing_provider
|
||||
*/
|
||||
public function test_backup_restore(bool $jsonformat) {
|
||||
global $DB;
|
||||
|
||||
@@ -77,9 +77,10 @@
|
||||
ucw.registerEvents('[data-region="user-competency-status"]');
|
||||
ucw.on('status-changed', infoReloader.reload.bind(infoReloader));
|
||||
ucw.on('error-occured', infoReloader.reload.bind(infoReloader));
|
||||
|
||||
var inlineGrader = new mod('#rate_{{uniqid}}', '{{competency.scaleid}}', '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}', '', '{{#str}}chooserating, tool_lp{{/str}}');
|
||||
inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader));
|
||||
{{#cangrade}}
|
||||
var inlineGrader = new mod('#rate_{{uniqid}}', '{{competency.scaleid}}', '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}', '', '{{#str}}chooserating, tool_lp{{/str}}');
|
||||
inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader));
|
||||
{{/cangrade}}
|
||||
});
|
||||
{{/js}}
|
||||
{{/usercompetency}}
|
||||
|
||||
@@ -95,13 +95,14 @@
|
||||
{{#js}}
|
||||
require(['jquery', 'tool_lp/grade_user_competency_inline', 'tool_lp/user_competency_info'], function($, mod, info) {
|
||||
|
||||
var inlineGrader = new mod('#rate_{{uniqid}}', '{{competency.scaleid}}', '{{competency.competency.id}}', '{{user.id}}', '', '{{course.id}}', '{{#str}}chooserating, tool_lp{{/str}}');
|
||||
var competencyElement = $('[data-region-id="{{uniqid}}"]');
|
||||
|
||||
var displayuser = ('{{displayuser}}' == 'true') ? true : false;
|
||||
var infoReloader = new info(competencyElement, '{{competency.competency.id}}', '{{user.id}}', '', '{{course.id}}', displayuser);
|
||||
|
||||
inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader));
|
||||
{{#cangrade}}
|
||||
var inlineGrader = new mod('#rate_{{uniqid}}', '{{competency.scaleid}}', '{{competency.competency.id}}', '{{user.id}}', '', '{{course.id}}', '{{#str}}chooserating, tool_lp{{/str}}');
|
||||
inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader));
|
||||
{{/cangrade}}
|
||||
});
|
||||
|
||||
{{/js}}
|
||||
|
||||
@@ -63,4 +63,67 @@ class behat_tool_lp extends behat_base {
|
||||
$this->execute('behat_general::i_click_on', [$xpathtarget, 'xpath_element']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert page names to URLs for steps like 'When I am on the "[identifier]" "[page type]" page'.
|
||||
*
|
||||
* Recognised page names are:
|
||||
* | pagetype | name meaning | description |
|
||||
* | Course competencies | Course name | The course competencies page |
|
||||
*
|
||||
* @param string $page identifies which type of page this is, e.g. 'Course competencies'.
|
||||
* @param string $identifier identifies the particular page, e.g. 'C1'.
|
||||
* @return moodle_url the corresponding URL.
|
||||
* @throws Exception with a meaningful error message if the specified page cannot be found.
|
||||
*/
|
||||
protected function resolve_page_instance_url(string $page, string $identifier): moodle_url {
|
||||
switch (strtolower($page)) {
|
||||
case 'course competencies':
|
||||
$courseid = $this->get_course_id($identifier);
|
||||
return new moodle_url('/admin/tool/lp/coursecompetencies.php', [
|
||||
'courseid' => $courseid,
|
||||
]);
|
||||
default:
|
||||
throw new Exception("Unrecognised page type '{$page}'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the exact named selectors for the component.
|
||||
*
|
||||
* @return behat_component_named_selector[]
|
||||
*/
|
||||
public static function get_exact_named_selectors(): array {
|
||||
return [
|
||||
new behat_component_named_selector('competency', [
|
||||
"//*[@data-region='coursecompetencies']//table[contains(@class,'managecompetencies')]".
|
||||
"//tr[contains(., //a[@title='View details'][contains(., %locator%)])]",
|
||||
]),
|
||||
new behat_component_named_selector('learning plan', [
|
||||
"//*[@data-region='plan-competencies']//table[contains(@class,'managecompetencies')]".
|
||||
"//tr[@data-node='user-competency'][contains(., //a[@data-usercompetency='true'][contains(., %locator%)])]",
|
||||
]),
|
||||
new behat_component_named_selector('competency description', [
|
||||
"//td/p[contains(., %locator%)]",
|
||||
]),
|
||||
new behat_component_named_selector('competency grade', [
|
||||
"//span[contains(concat(' ', normalize-space(@class), ' '), ' badge ')][contains(., %locator%)]",
|
||||
]),
|
||||
new behat_component_named_selector('learning plan rating', [
|
||||
"//td[position()=2][contains(., %locator%)]",
|
||||
]),
|
||||
new behat_component_named_selector('learning plan proficiency', [
|
||||
"//td[position()=3][contains(., %locator%)]",
|
||||
]),
|
||||
new behat_component_named_selector('competency page proficiency', [
|
||||
"//dt[contains(., 'Proficient')]/following-sibling::dd[1][contains(., %locator%)]",
|
||||
]),
|
||||
new behat_component_named_selector('competency page rating', [
|
||||
"//dt[contains(., 'Rating')]/following-sibling::dd[1][contains(., %locator%)]",
|
||||
]),
|
||||
new behat_component_named_selector('competency page related competency', [
|
||||
"//*[@data-region='relatedcompetencies']//a[contains(., %locator%)]",
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
@tool @tool_lp @javascript
|
||||
Feature: View competencies
|
||||
In order to access competency information
|
||||
As a user
|
||||
I need to view user competencies
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| student1 | Student | first |
|
||||
| teacher1 | Teacher | first |
|
||||
And the following "system role assigns" exist:
|
||||
| user | role | contextlevel |
|
||||
| teacher1 | editingteacher | System |
|
||||
And the following "permission overrides" exist:
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| moodle/competency:planview | Allow | editingteacher | System | |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "scales" exist:
|
||||
| name | scale |
|
||||
| Test Scale | Bad, Good, Great |
|
||||
And the following "core_competency > frameworks" exist:
|
||||
| shortname | idnumber | scale |
|
||||
| Cookery | cookery | Test Scale |
|
||||
| Literacy | literacy | Test Scale |
|
||||
And the following "core_competency > competencies" exist:
|
||||
| shortname | idnumber | description | competencyframework |
|
||||
| Salads | salads | Salads are important | cookery |
|
||||
| Desserts | desserts | Desserts are important | cookery |
|
||||
| Cakes | cakes | Cakes are important | cookery |
|
||||
| Reading | reading | Reading is important | literacy |
|
||||
| Writing | writing | Writing is important | literacy |
|
||||
And the following "core_competency > related_competencies" exist:
|
||||
| competency | relatedcompetency |
|
||||
| desserts | cakes |
|
||||
And the following "core_competency > plans" exist:
|
||||
| name | description | competencies | user |
|
||||
| Cookery | Cookery is important | salads, desserts, cakes | student1 |
|
||||
| Literacy | Literacy is important | reading, writing | student1 |
|
||||
And the following "core_competency > course_competencies" exist:
|
||||
| course | competency |
|
||||
| C1 | salads |
|
||||
| C1 | desserts |
|
||||
| C1 | cakes |
|
||||
| C1 | reading |
|
||||
| C1 | writing |
|
||||
And the following "core_competency > user_competency" exist:
|
||||
| competency | user | grade |
|
||||
| salads | student1 | Good |
|
||||
| desserts | student1 | Great |
|
||||
| cakes | student1 | Great |
|
||||
And the following "core_competency > user_competency_courses" exist:
|
||||
| course | competency | user | grade |
|
||||
| C1 | salads | student1 | Good |
|
||||
| C1 | desserts | student1 | Great |
|
||||
| C1 | cakes | student1 | Great |
|
||||
|
||||
Scenario: Student view
|
||||
# Course competencies
|
||||
Given I am on the "C1" "tool_lp > course competencies" page logged in as "student1"
|
||||
Then I should see "You are proficient in 3 out of 5 competencies in this course"
|
||||
|
||||
And "Salads are important" "tool_lp > competency description" should exist in the "Salads" "tool_lp > competency"
|
||||
And "Good" "tool_lp > competency grade" should exist in the "Salads" "tool_lp > competency"
|
||||
|
||||
And "Desserts are important" "tool_lp > competency description" should exist in the "Desserts" "tool_lp > competency"
|
||||
And "Great" "tool_lp > competency grade" should exist in the "Desserts" "tool_lp > competency"
|
||||
|
||||
And "Cakes are important" "tool_lp > competency description" should exist in the "Cakes" "tool_lp > competency"
|
||||
And "Great" "tool_lp > competency grade" should exist in the "Cakes" "tool_lp > competency"
|
||||
|
||||
And "Reading is important" "tool_lp > competency description" should exist in the "Reading" "tool_lp > competency"
|
||||
And "Good" "tool_lp > competency grade" should not exist in the "Reading" "tool_lp > competency"
|
||||
And "Great" "tool_lp > competency grade" should not exist in the "Reading" "tool_lp > competency"
|
||||
And "Bad" "tool_lp > competency grade" should not exist in the "Reading" "tool_lp > competency"
|
||||
|
||||
And "Writing is important" "tool_lp > competency description" should exist in the "Writing" "tool_lp > competency"
|
||||
And "Good" "tool_lp > competency grade" should not exist in the "Writing" "tool_lp > competency"
|
||||
And "Great" "tool_lp > competency grade" should not exist in the "Writing" "tool_lp > competency"
|
||||
And "Bad" "tool_lp > competency grade" should not exist in the "Writing" "tool_lp > competency"
|
||||
|
||||
# Course competencies details
|
||||
And I click on "Desserts" "link" in the "Desserts" "tool_lp > competency"
|
||||
And I should see "Desserts are important"
|
||||
And "Yes" "tool_lp > competency page proficiency" should exist
|
||||
And "Great" "tool_lp > competency page rating" should exist
|
||||
|
||||
# Course competencies summary
|
||||
And I click on "Cakes" "link"
|
||||
And I should see "Cakes are important"
|
||||
|
||||
# Learning plans
|
||||
And I click on "Close" "button" in the "Cakes" "dialogue"
|
||||
And I follow "Profile" in the user menu
|
||||
And I click on "Learning plans" "link"
|
||||
And I should see "Cookery"
|
||||
And I should see "Literacy"
|
||||
|
||||
# Learning plans details
|
||||
And I click on "Cookery" "link"
|
||||
And I should see "Cookery is important"
|
||||
And I should see "3 out of 3 competencies are proficient"
|
||||
|
||||
And "Good" "tool_lp > learning plan rating" should exist in the "Salads" "tool_lp > learning plan"
|
||||
And "Yes" "tool_lp > learning plan proficiency" should exist in the "Salads" "tool_lp > learning plan"
|
||||
|
||||
And "Great" "tool_lp > learning plan rating" should exist in the "Desserts" "tool_lp > learning plan"
|
||||
And "Yes" "tool_lp > learning plan proficiency" should exist in the "Desserts" "tool_lp > learning plan"
|
||||
|
||||
And "Great" "tool_lp > learning plan rating" should exist in the "Cakes" "tool_lp > learning plan"
|
||||
And "Yes" "tool_lp > learning plan proficiency" should exist in the "Cakes" "tool_lp > learning plan"
|
||||
|
||||
And I should not see "Literacy"
|
||||
And I should not see "Reading"
|
||||
And I should not see "Writing"
|
||||
|
||||
# Learning plans competency details
|
||||
And I click on "Desserts" "link" in the "Desserts" "tool_lp > learning plan"
|
||||
And I should see "Desserts are important"
|
||||
And "Yes" "tool_lp > competency page proficiency" should exist
|
||||
And "Great" "tool_lp > competency page rating" should exist
|
||||
|
||||
# Learning plans competency summary
|
||||
And I click on "Cakes cakes" "link"
|
||||
And I should see "Cakes are important"
|
||||
|
||||
Scenario: Teacher view
|
||||
# Participant competencies
|
||||
Given I am on the "C1" "report_competency > breakdown" page logged in as "teacher1"
|
||||
Then I should see "Student first"
|
||||
And "Good" "report_competency > breakdown rating" should exist in the "Salads" "report_competency > breakdown"
|
||||
And "Great" "report_competency > breakdown rating" should exist in the "Desserts" "report_competency > breakdown"
|
||||
And "Great" "report_competency > breakdown rating" should exist in the "Cakes" "report_competency > breakdown"
|
||||
And "Not rated" "report_competency > breakdown rating" should exist in the "Reading" "report_competency > breakdown"
|
||||
And "Not rated" "report_competency > breakdown rating" should exist in the "Writing" "report_competency > breakdown"
|
||||
|
||||
# Participant competencies details
|
||||
And I click on "Great" "report_competency > breakdown rating" in the "Desserts" "report_competency > breakdown"
|
||||
And "Yes" "tool_lp > competency page proficiency" should exist
|
||||
And "Great" "tool_lp > competency page rating" should exist
|
||||
|
||||
# Participant competencies summary
|
||||
And I click on "Cakes" "tool_lp > competency page related competency"
|
||||
And I should see "Cakes are important"
|
||||
|
||||
# Participant learning plans
|
||||
And I click on "Close" "button" in the "Cakes" "dialogue"
|
||||
And I click on "Close" "button" in the "User competency summary" "dialogue"
|
||||
And I navigate to course participants
|
||||
And I click on "Student first" "link"
|
||||
And I click on "Learning plans" "link"
|
||||
And I should see "Cookery"
|
||||
And I should see "Literacy"
|
||||
|
||||
# Participant learning plans details
|
||||
And I click on "Cookery" "link"
|
||||
And I should see "Cookery is important"
|
||||
And I should see "3 out of 3 competencies are proficient"
|
||||
|
||||
And "Good" "tool_lp > learning plan rating" should exist in the "Salads" "tool_lp > learning plan"
|
||||
And "Yes" "tool_lp > learning plan proficiency" should exist in the "Salads" "tool_lp > learning plan"
|
||||
|
||||
And "Great" "tool_lp > learning plan rating" should exist in the "Desserts" "tool_lp > learning plan"
|
||||
And "Yes" "tool_lp > learning plan proficiency" should exist in the "Desserts" "tool_lp > learning plan"
|
||||
|
||||
And "Great" "tool_lp > learning plan rating" should exist in the "Cakes" "tool_lp > learning plan"
|
||||
And "Yes" "tool_lp > learning plan proficiency" should exist in the "Cakes" "tool_lp > learning plan"
|
||||
|
||||
And I should not see "Literacy"
|
||||
And I should not see "Reading"
|
||||
And I should not see "Writing"
|
||||
|
||||
# Learning plans competency details
|
||||
And I click on "Desserts" "link"
|
||||
And I should see "Desserts are important"
|
||||
And "Yes" "tool_lp > competency page proficiency" should exist
|
||||
And "Great" "tool_lp > competency page rating" should exist
|
||||
|
||||
# Learning plans competency summary
|
||||
And I click on "Cakes" "tool_lp > competency page related competency"
|
||||
And I should see "Cakes are important"
|
||||
@@ -59,22 +59,26 @@ class api_test extends \externallib_advanced_testcase {
|
||||
*/
|
||||
public function test_get_potential_config_issues() {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/message/lib.php');
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$CFG->userquota = '73289234723498234723423489273423497234234';
|
||||
// Set non-SSL wwwroot, to avoid spurious certificate checking.
|
||||
$CFG->wwwroot = 'http://www.example.com';
|
||||
$CFG->debugdisplay = 1;
|
||||
|
||||
set_config('debugauthdb', 1, 'auth_db');
|
||||
set_config('debugdb', 1, 'enrol_database');
|
||||
$expectedissues = array('adodbdebugwarning', 'displayerrorswarning');
|
||||
|
||||
// Get potential issues, obtain their keys for comparison.
|
||||
$issues = api::get_potential_config_issues();
|
||||
$this->assertCount(count($expectedissues), $issues);
|
||||
foreach ($issues as $issue) {
|
||||
$this->assertTrue(in_array($issue[0], $expectedissues));
|
||||
}
|
||||
$issuekeys = array_column($issues, 0);
|
||||
|
||||
$this->assertEqualsCanonicalizing([
|
||||
'nohttpsformobilewarning',
|
||||
'adodbdebugwarning',
|
||||
'displayerrorswarning',
|
||||
], $issuekeys);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-11
@@ -14,24 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the import_handler_info class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_moodlenet\local\tests;
|
||||
namespace tool_moodlenet\local;
|
||||
|
||||
use tool_moodlenet\local\import_handler_info;
|
||||
use tool_moodlenet\local\import_strategy;
|
||||
use tool_moodlenet\local\import_strategy_file;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class tool_moodlenet_import_handler_info_testcase, providing test cases for the import_handler_info class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class import_handler_info_test extends \advanced_testcase {
|
||||
|
||||
+6
-11
@@ -14,15 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the import_handler_registry class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_moodlenet\local\tests;
|
||||
namespace tool_moodlenet\local;
|
||||
|
||||
use tool_moodlenet\local\import_handler_registry;
|
||||
use tool_moodlenet\local\import_handler_info;
|
||||
@@ -31,10 +23,13 @@ use tool_moodlenet\local\import_strategy_link;
|
||||
use tool_moodlenet\local\remote_resource;
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class tool_moodlenet_import_handler_registry_testcase, providing test cases for the import_handler_registry class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class import_handler_registry_test extends \advanced_testcase {
|
||||
|
||||
+6
-11
@@ -14,24 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the import_info class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_moodlenet\local\tests;
|
||||
namespace tool_moodlenet\local;
|
||||
|
||||
use tool_moodlenet\local\import_info;
|
||||
use tool_moodlenet\local\remote_resource;
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class tool_moodlenet_import_info_testcase, providing test cases for the import_info class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class import_info_test extends \advanced_testcase {
|
||||
|
||||
+6
-11
@@ -14,15 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the import_processor class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_moodlenet\local\tests;
|
||||
namespace tool_moodlenet\local;
|
||||
|
||||
use tool_moodlenet\local\import_handler_registry;
|
||||
use tool_moodlenet\local\import_processor;
|
||||
@@ -31,10 +23,13 @@ use tool_moodlenet\local\import_strategy_link;
|
||||
use tool_moodlenet\local\remote_resource;
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class tool_moodlenet_import_processor_testcase, providing test cases for the import_processor class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class import_processor_test extends \advanced_testcase {
|
||||
|
||||
+6
-11
@@ -14,24 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace tool_moodlenet\local;
|
||||
|
||||
use tool_moodlenet\local\remote_resource;
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
/**
|
||||
* Unit tests for the remote_resource class.
|
||||
* Class tool_moodlenet_remote_resource_testcase, providing test cases for the remote_resource class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_moodlenet\local\tests;
|
||||
|
||||
use tool_moodlenet\local\remote_resource;
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class tool_moodlenet_remote_resource_testcase, providing test cases for the remote_resource class.
|
||||
*/
|
||||
class remote_resource_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
+5
-10
@@ -14,23 +14,18 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace tool_moodlenet\local;
|
||||
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
/**
|
||||
* Unit tests for the url class.
|
||||
* Class tool_moodlenet_url_testcase, providing test cases for the url class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_moodlenet\local\tests;
|
||||
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class tool_moodlenet_url_testcase, providing test cases for the url class.
|
||||
*/
|
||||
class url_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
@@ -134,7 +134,6 @@ Feature: Basic OAuth2 functionality
|
||||
And I set the following fields to these values:
|
||||
| Name | Testing service modified |
|
||||
And I press "Save changes"
|
||||
And I should see "Could not discover service endpoints"
|
||||
And I should see "Testing service modified"
|
||||
And I click on "Delete" "link" in the "Testing service modified" "table_row"
|
||||
And I should see "Are you sure you want to delete the identity issuer \"Testing service modified\"?"
|
||||
@@ -239,13 +238,12 @@ Feature: Basic OAuth2 functionality
|
||||
And I press "Save changes"
|
||||
And "Do not allow login" "icon" should exist in the "Valid custom" "table_row"
|
||||
And "Allow services" "icon" should exist in the "Valid custom" "table_row"
|
||||
And "Service discovery successful" "icon" should exist in the "Valid custom" "table_row"
|
||||
And I should see "-" in the "Valid custom" "table_row"
|
||||
And I click on "Edit" "link" in the "Valid custom service" "table_row"
|
||||
And I set the following fields to these values:
|
||||
| Name | Invalid custom service |
|
||||
| Service base URL | https://dc.imsglobal.org/ |
|
||||
And I press "Save changes"
|
||||
Then I should see "Could not discover end points for identity issuer: Invalid custom service"
|
||||
And I should see "-" in the "Invalid custom service" "table_row"
|
||||
And I click on "Delete" "link" in the "Invalid custom service" "table_row"
|
||||
And I should see "Are you sure you want to delete the identity issuer \"Invalid custom service\"?"
|
||||
@@ -281,13 +279,12 @@ Feature: Basic OAuth2 functionality
|
||||
And I press "Save changes"
|
||||
And "Do not allow login" "icon" should exist in the "Valid custom" "table_row"
|
||||
And "Allow services" "icon" should exist in the "Valid custom" "table_row"
|
||||
And "Service discovery successful" "icon" should exist in the "Valid custom" "table_row"
|
||||
And I should see "-" in the "Valid custom" "table_row"
|
||||
And I click on "Edit" "link" in the "Valid custom service" "table_row"
|
||||
And I set the following fields to these values:
|
||||
| Name | Invalid custom service |
|
||||
| Service base URL | https://dc.imsglobal.org/ |
|
||||
And I press "Save changes"
|
||||
Then I should see "Could not discover end points for identity issuer: Invalid custom service"
|
||||
And I should see "-" in the "Invalid custom service" "table_row"
|
||||
And I click on "Edit" "link" in the "Invalid custom service" "table_row"
|
||||
And I set the following fields to these values:
|
||||
@@ -351,9 +348,12 @@ Feature: Basic OAuth2 functionality
|
||||
And I should see "Custom display name" in the "Empty custom service" "table_row"
|
||||
And "Not configured" "icon" should exist in the "Empty custom service" "table_row"
|
||||
And "Do not allow services" "icon" should exist in the "Empty custom service" "table_row"
|
||||
And I click on "Edit" "link" in the "Empty custom service" "table_row"
|
||||
And I click on "Configure endpoints" "link" in the "Empty custom service" "table_row"
|
||||
And I press "Create new endpoint for issuer \"Empty custom service\""
|
||||
And I set the following fields to these values:
|
||||
| Service base URL | https://accounts.google.com |
|
||||
| Name | userinfo_endpoint |
|
||||
| URL | https://example.com/userinfo |
|
||||
And I press "Save changes"
|
||||
And I navigate to "Server > OAuth 2 services" in site administration
|
||||
And "Allow login" "icon" should exist in the "Empty custom service" "table_row"
|
||||
And "Do not allow services" "icon" should exist in the "Empty custom service" "table_row"
|
||||
|
||||
@@ -67,14 +67,10 @@ Feature: Upload users
|
||||
@javascript
|
||||
Scenario: Upload users with custom profile fields
|
||||
# Create user profile field.
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Users > Accounts > User profile fields" in site administration
|
||||
And I click on "Create a new profile field" "link"
|
||||
And I click on "Text area" "link"
|
||||
And I set the following fields to these values:
|
||||
| Short name | superfield |
|
||||
| Name | Super field |
|
||||
And I click on "Save changes" "button"
|
||||
Given the following "custom profile fields" exist:
|
||||
| datatype | shortname | name |
|
||||
| text | superfield | Super field |
|
||||
And I log in as "admin"
|
||||
# Upload users.
|
||||
When I navigate to "Users > Accounts > Upload users" in site administration
|
||||
And I upload "lib/tests/fixtures/upload_users_profile.csv" file to "File" filemanager
|
||||
|
||||
@@ -152,14 +152,11 @@ Feature: Apply tour filters to a tour
|
||||
| fullname | shortname | format | enablecompletion |
|
||||
| Course 1 | C1 | topics | 1 |
|
||||
| Course 2 | C2 | topics | 1 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | name | firstpagetitle | wikimode |
|
||||
| wiki | C1 | Test wiki name | First page | collaborative |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Wiki" to section "1" and I fill the form with:
|
||||
| Wiki name | Test wiki name |
|
||||
| Description | Test wiki description |
|
||||
| First page name | First page |
|
||||
| Wiki mode | Collaborative wiki |
|
||||
And I am on "Course 2" course homepage
|
||||
And I am on "Course 2" course homepage with editing mode on
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Forum type | Standard forum for general use |
|
||||
|
||||
@@ -14,17 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the analysis class.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2019 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/fixtures/test_timesplitting_upcoming_seconds.php');
|
||||
namespace core_analytics;
|
||||
|
||||
/**
|
||||
* Unit tests for the analysis class.
|
||||
@@ -33,18 +23,19 @@ require_once(__DIR__ . '/fixtures/test_timesplitting_upcoming_seconds.php');
|
||||
* @copyright 2019 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class analytics_analysis_testcase extends advanced_testcase {
|
||||
class analysis_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test fill_firstanalyses_cache.
|
||||
* @return null
|
||||
*/
|
||||
public function test_fill_firstanalyses_cache() {
|
||||
require_once(__DIR__ . '/fixtures/test_timesplitting_upcoming_seconds.php');
|
||||
$this->resetAfterTest();
|
||||
|
||||
$modelid = 1;
|
||||
|
||||
$params = ['startdate' => (new DateTimeImmutable('-5 seconds'))->getTimestamp()];
|
||||
$params = ['startdate' => (new \DateTimeImmutable('-5 seconds'))->getTimestamp()];
|
||||
$course1 = $this->getDataGenerator()->create_course($params);
|
||||
$course2 = $this->getDataGenerator()->create_course($params);
|
||||
$analysable1 = new \core_analytics\course($course1);
|
||||
@@ -72,7 +63,7 @@ class analytics_analysis_testcase extends advanced_testcase {
|
||||
$this->assertEquals($earliest, $firstanalyses[$modelid . '_' . $course1->id]);
|
||||
|
||||
// Upcoming periodic time-splitting methods can read and process the cached data.
|
||||
$seconds = new test_timesplitting_upcoming_seconds();
|
||||
$seconds = new \test_timesplitting_upcoming_seconds();
|
||||
$seconds->set_modelid($modelid);
|
||||
$seconds->set_analysable($analysable1);
|
||||
|
||||
|
||||
@@ -14,18 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the calculation info cache.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2019 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/fixtures/test_indicator_max.php');
|
||||
require_once(__DIR__ . '/fixtures/test_indicator_min.php');
|
||||
namespace core_analytics;
|
||||
|
||||
/**
|
||||
* Unit tests for the calculation info cache.
|
||||
@@ -34,7 +23,7 @@ require_once(__DIR__ . '/fixtures/test_indicator_min.php');
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class analytics_calculation_info_testcase extends advanced_testcase {
|
||||
class calculation_info_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* test_calculation_info description
|
||||
@@ -47,12 +36,14 @@ class analytics_calculation_info_testcase extends advanced_testcase {
|
||||
* @return null
|
||||
*/
|
||||
public function test_calculation_info_add_pull($info1, $info2, $info3, $info4) {
|
||||
require_once(__DIR__ . '/fixtures/test_indicator_max.php');
|
||||
require_once(__DIR__ . '/fixtures/test_indicator_min.php');
|
||||
$this->resetAfterTest();
|
||||
|
||||
$atimesplitting = new \core\analytics\time_splitting\quarters();
|
||||
|
||||
$indicator1 = new test_indicator_min();
|
||||
$indicator2 = new test_indicator_max();
|
||||
$indicator1 = new \test_indicator_min();
|
||||
$indicator2 = new \test_indicator_max();
|
||||
|
||||
$calculationinfo = new \core_analytics\calculation_info();
|
||||
$calculationinfo->add_shared(111, [111 => $info1]);
|
||||
|
||||
@@ -14,15 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the dataset manager.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
namespace core_analytics;
|
||||
|
||||
/**
|
||||
* Unit tests for the dataset manager.
|
||||
@@ -31,7 +23,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class dataset_manager_testcase extends advanced_testcase {
|
||||
class dataset_manager_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* setUp
|
||||
|
||||
@@ -14,13 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the indicator API.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2019 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_analytics;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -35,7 +29,7 @@ require_once(__DIR__ . '/fixtures/test_indicator_min.php');
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class analytics_indicator_testcase extends advanced_testcase {
|
||||
class indicator_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* test_validate_calculated_value
|
||||
@@ -79,7 +73,7 @@ class analytics_indicator_testcase extends advanced_testcase {
|
||||
->onlyMethods(['calculate_sample'])
|
||||
->getMock();
|
||||
$indicatormock->method('calculate_sample')->willReturn($willreturn);
|
||||
$this->expectException(coding_exception::class);
|
||||
$this->expectException(\coding_exception::class);
|
||||
list($values, $unused) = $indicatormock->calculate([1], 'notrelevanthere');
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_analytics;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/fixtures/test_indicator_max.php');
|
||||
@@ -39,7 +41,7 @@ require_once(__DIR__ . '/fixtures/test_analysis.php');
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class analytics_model_testcase extends advanced_testcase {
|
||||
class model_test extends \advanced_testcase {
|
||||
|
||||
public function setUp(): void {
|
||||
|
||||
@@ -183,7 +185,7 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$statictarget = new test_static_target_shortname();
|
||||
$statictarget = new \test_static_target_shortname();
|
||||
$indicators['test_indicator_max'] = \core_analytics\manager::get_indicator('test_indicator_max');
|
||||
$model = \core_analytics\model::create($statictarget, $indicators, '\core\analytics\time_splitting\quarters');
|
||||
$modelobj = $model->get_model_obj();
|
||||
@@ -301,11 +303,11 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
$courses[$analysable->get_id()] = $course;
|
||||
}
|
||||
|
||||
$target = new test_target_course_level_shortname();
|
||||
$target = new \test_target_course_level_shortname();
|
||||
$analyser = new \core\analytics\analyser\courses(1, $target, [], [], []);
|
||||
|
||||
$result = new \core_analytics\local\analysis\result_array(1, false, []);
|
||||
$analysis = new test_analysis($analyser, false, $result);
|
||||
$analysis = new \test_analysis($analyser, false, $result);
|
||||
|
||||
// Each analysable element takes 0.5 secs minimum (test_analysis), so the max (and likely) number of analysable
|
||||
// elements that will be processed is 2.
|
||||
@@ -342,7 +344,7 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
|
||||
// Training and prediction data do not get mixed.
|
||||
$result = new \core_analytics\local\analysis\result_array(1, false, []);
|
||||
$analysis = new test_analysis($analyser, false, $result);
|
||||
$analysis = new \test_analysis($analyser, false, $result);
|
||||
$analysis->run();
|
||||
$params = array('modelid' => 1, 'action' => 'training');
|
||||
$this->assertLessThanOrEqual(2, $DB->count_records('analytics_used_analysables', $params));
|
||||
@@ -402,7 +404,7 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
$this->model->update(true, [], false);
|
||||
$this->assertFalse($this->model->can_export_configuration());
|
||||
|
||||
$statictarget = new test_static_target_shortname();
|
||||
$statictarget = new \test_static_target_shortname();
|
||||
$indicators['test_indicator_max'] = \core_analytics\manager::get_indicator('test_indicator_max');
|
||||
$model = \core_analytics\model::create($statictarget, $indicators, '\\core\\analytics\\time_splitting\\quarters');
|
||||
$this->assertFalse($model->can_export_configuration());
|
||||
@@ -418,7 +420,7 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
|
||||
$modelconfig = new \core_analytics\model_config($this->model);
|
||||
|
||||
$method = new ReflectionMethod('\\core_analytics\\model_config', 'export_model_data');
|
||||
$method = new \ReflectionMethod('\\core_analytics\\model_config', 'export_model_data');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$modeldata = $method->invoke($modelconfig);
|
||||
@@ -566,7 +568,7 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
private function add_fake_log() {
|
||||
global $DB, $USER;
|
||||
|
||||
$log = new stdClass();
|
||||
$log = new \stdClass();
|
||||
$log->modelid = $this->modelobj->id;
|
||||
$log->version = $this->modelobj->version;
|
||||
$log->target = $this->modelobj->target;
|
||||
|
||||
@@ -14,13 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for prediction actions.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_analytics;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -34,7 +28,7 @@ require_once(__DIR__ . '/fixtures/test_target_shortname.php');
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class analytics_prediction_actions_testcase extends advanced_testcase {
|
||||
class prediction_actions_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Common startup tasks
|
||||
|
||||
@@ -14,21 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for evaluation, training and prediction.
|
||||
*
|
||||
* NOTE: in order to execute this test using a separate server for the
|
||||
* python ML backend you need to define these variables in your config.php file:
|
||||
*
|
||||
* define('TEST_MLBACKEND_PYTHON_HOST', '127.0.0.1');
|
||||
* define('TEST_MLBACKEND_PYTHON_PORT', 5000);
|
||||
* define('TEST_MLBACKEND_PYTHON_USERNAME', 'default');
|
||||
* define('TEST_MLBACKEND_PYTHON_PASSWORD', 'sshhhh');
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_analytics;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -48,11 +34,19 @@ require_once(__DIR__ . '/../../course/lib.php');
|
||||
/**
|
||||
* Unit tests for evaluation, training and prediction.
|
||||
*
|
||||
* NOTE: in order to execute this test using a separate server for the
|
||||
* python ML backend you need to define these variables in your config.php file:
|
||||
*
|
||||
* define('TEST_MLBACKEND_PYTHON_HOST', '127.0.0.1');
|
||||
* define('TEST_MLBACKEND_PYTHON_PORT', 5000);
|
||||
* define('TEST_MLBACKEND_PYTHON_USERNAME', 'default');
|
||||
* define('TEST_MLBACKEND_PYTHON_PASSWORD', 'sshhhh');
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_analytics_prediction_testcase extends advanced_testcase {
|
||||
class prediction_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Purge all the mlbackend outputs.
|
||||
@@ -746,7 +740,7 @@ class core_analytics_prediction_testcase extends advanced_testcase {
|
||||
$samples,
|
||||
$ranges
|
||||
);
|
||||
$dataset = phpunit_util::call_internal_method($analysis, 'calculate_indicators', $params,
|
||||
$dataset = \phpunit_util::call_internal_method($analysis, 'calculate_indicators', $params,
|
||||
'\core_analytics\analysis');
|
||||
$this->assertArrayHasKey('123-0', $dataset);
|
||||
$this->assertArrayHasKey('123-1', $dataset);
|
||||
@@ -770,7 +764,7 @@ class core_analytics_prediction_testcase extends advanced_testcase {
|
||||
$samples,
|
||||
$ranges
|
||||
);
|
||||
$dataset = phpunit_util::call_internal_method($analysis, 'calculate_indicators', $params,
|
||||
$dataset = \phpunit_util::call_internal_method($analysis, 'calculate_indicators', $params,
|
||||
'\core_analytics\analysis');
|
||||
$this->assertArrayNotHasKey('123-0', $dataset);
|
||||
$this->assertArrayNotHasKey('123-1', $dataset);
|
||||
|
||||
@@ -14,14 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Provides the {@link analytics_stats_testcase} class.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @category test
|
||||
* @copyright 2019 David Mudrák <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_analytics;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -31,10 +24,12 @@ require_once(__DIR__ . '/fixtures/test_target_shortname.php');
|
||||
/**
|
||||
* Unit tests for the analytics stats.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @category test
|
||||
* @copyright 2019 David Mudrák <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class analytics_stats_testcase extends advanced_testcase {
|
||||
class stats_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Set up the test environment.
|
||||
|
||||
@@ -14,30 +14,26 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for core time splitting methods.
|
||||
*
|
||||
* @package core
|
||||
* @category analytics
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_analytics;
|
||||
|
||||
use test_timesplitting_seconds;
|
||||
use test_timesplitting_upcoming_seconds;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/../../analytics/tests/fixtures/test_timesplitting_seconds.php');
|
||||
require_once(__DIR__ . '/../../analytics/tests/fixtures/test_timesplitting_upcoming_seconds.php');
|
||||
require_once(__DIR__ . '/fixtures/test_timesplitting_seconds.php');
|
||||
require_once(__DIR__ . '/fixtures/test_timesplitting_upcoming_seconds.php');
|
||||
require_once(__DIR__ . '/../../lib/enrollib.php');
|
||||
|
||||
/**
|
||||
* Unit tests for core time splitting methods.
|
||||
*
|
||||
* @package core
|
||||
* @category analytics
|
||||
* @category test
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_analytics_time_splittings_testcase extends advanced_testcase {
|
||||
class time_splittings_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* setUp
|
||||
@@ -214,7 +210,7 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
|
||||
|
||||
// We now use an ongoing course not yet ready to generate predictions.
|
||||
|
||||
$threedaysago = new DateTime('-3 days');
|
||||
$threedaysago = new \DateTime('-3 days');
|
||||
$params = array(
|
||||
'startdate' => $threedaysago->getTimestamp(),
|
||||
);
|
||||
@@ -229,7 +225,7 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
|
||||
|
||||
// We now use a ready-to-predict ongoing course.
|
||||
|
||||
$onemonthago = new DateTime('-30 days');
|
||||
$onemonthago = new \DateTime('-30 days');
|
||||
$params = array(
|
||||
'startdate' => $onemonthago->getTimestamp(),
|
||||
);
|
||||
@@ -284,10 +280,10 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
|
||||
|
||||
// We now check how new ranges get added as time passes.
|
||||
|
||||
$fewsecsago = new DateTime('-5 seconds');
|
||||
$fewsecsago = new \DateTime('-5 seconds');
|
||||
$params = array(
|
||||
'startdate' => $fewsecsago->getTimestamp(),
|
||||
'enddate' => (new DateTimeImmutable('+1 year'))->getTimestamp(),
|
||||
'enddate' => (new \DateTimeImmutable('+1 year'))->getTimestamp(),
|
||||
);
|
||||
$course = $this->getDataGenerator()->create_course($params);
|
||||
$analysable = new \core_analytics\course($course);
|
||||
+4
-9
@@ -866,11 +866,8 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
if (!empty($users)) {
|
||||
print_string('userentriestoupdate', 'auth_ldap', count($users));
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
$xcount = 0;
|
||||
$maxxcount = 100;
|
||||
|
||||
foreach ($users as $user) {
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
echo "\t"; print_string('auth_dbupdatinguser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id));
|
||||
$userinfo = $this->get_userinfo($user->username);
|
||||
if (!$this->update_user_record($user->username, $updatekeys, true,
|
||||
@@ -878,12 +875,11 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
echo ' - '.get_string('skipped');
|
||||
}
|
||||
echo "\n";
|
||||
$xcount++;
|
||||
|
||||
// Update system roles, if needed.
|
||||
$this->sync_roles($user);
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
$transaction->allow_commit();
|
||||
unset($users); // free mem
|
||||
}
|
||||
} else { // end do updates
|
||||
@@ -903,8 +899,8 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
if (!empty($add_users)) {
|
||||
print_string('userentriestoadd', 'auth_ldap', count($add_users));
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
foreach ($add_users as $user) {
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
$user = $this->get_userinfo_asobj($user->username);
|
||||
|
||||
// Prep a few params
|
||||
@@ -939,9 +935,8 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
|
||||
// Add roles if needed.
|
||||
$this->sync_roles($euser);
|
||||
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
$transaction->allow_commit();
|
||||
unset($add_users); // free mem
|
||||
} else {
|
||||
print_string('nouserstobeadded', 'auth_ldap');
|
||||
|
||||
@@ -482,13 +482,13 @@ class tree extends tree_node {
|
||||
*
|
||||
* @param bool $not True if there is a NOT in effect
|
||||
* @param info $info Information about location of condition tree
|
||||
* @param result $result Result object if this is a student display, else null
|
||||
* @param result|null $result Result object if this is a student display, else null
|
||||
* @param bool $root True if this is the root item
|
||||
* @param bool $hidden Staff display; true if this tree has show=false (from parent)
|
||||
* @return string|renderable Information to render
|
||||
*/
|
||||
protected function get_full_information_recursive(
|
||||
$not, info $info, result $result = null, $root, $hidden = false) {
|
||||
$not, info $info, ?result $result, $root, $hidden = false) {
|
||||
// Get list of children - either full list, or those which are shown.
|
||||
$children = $this->children;
|
||||
$staff = true;
|
||||
|
||||
@@ -378,7 +378,7 @@ class condition_test extends \advanced_testcase {
|
||||
/**
|
||||
* Tests the is_available and get_description functions for previous activity option.
|
||||
*
|
||||
* @dataProvider test_previous_activity_data
|
||||
* @dataProvider previous_activity_data
|
||||
* @param int $grade the current assign grade (0 for none)
|
||||
* @param int $condition true for complete, false for incomplete
|
||||
* @param string $mark activity to mark as complete
|
||||
@@ -467,7 +467,7 @@ class condition_test extends \advanced_testcase {
|
||||
$this->assertMatchesRegularExpression($description, $information);
|
||||
}
|
||||
|
||||
public function test_previous_activity_data(): array {
|
||||
public function previous_activity_data(): array {
|
||||
// Assign grade, condition, activity to complete, activity to test, result, resultnot, description.
|
||||
return [
|
||||
'Missing previous activity complete' => [
|
||||
@@ -559,7 +559,7 @@ class condition_test extends \advanced_testcase {
|
||||
* Tests the is_available and get_description functions for
|
||||
* previous activity option in course sections.
|
||||
*
|
||||
* @dataProvider test_section_previous_activity_data
|
||||
* @dataProvider section_previous_activity_data
|
||||
* @param int $condition condition value
|
||||
* @param bool $mark if Page 1 must be mark as completed
|
||||
* @param string $section section to add the availability
|
||||
@@ -632,7 +632,7 @@ class condition_test extends \advanced_testcase {
|
||||
|
||||
}
|
||||
|
||||
public function test_section_previous_activity_data(): array {
|
||||
public function section_previous_activity_data(): array {
|
||||
return [
|
||||
// Condition, Activity completion, section to test, result, resultnot, description.
|
||||
'Completion complete Section with no previous activity' => [
|
||||
|
||||
@@ -49,7 +49,7 @@ class frontend extends \core_availability\frontend {
|
||||
|
||||
protected function get_javascript_strings() {
|
||||
return array('ajaxerror', 'direction_before', 'direction_from', 'direction_until',
|
||||
'direction_label');
|
||||
'direction_label', 'error_dateconflict');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,7 @@ $string['direction_from'] = 'from';
|
||||
$string['direction_label'] = 'Direction';
|
||||
$string['direction_until'] = 'until';
|
||||
$string['description'] = 'Prevent access until (or from) a specified date and time.';
|
||||
$string['error_dateconflict'] = 'Conflicts with other date restrictions';
|
||||
$string['full_from'] = 'It is after <strong>{$a}</strong>';
|
||||
$string['full_from_date'] = 'It is on or after <strong>{$a}</strong>';
|
||||
$string['full_until'] = 'It is before <strong>{$a}</strong>';
|
||||
|
||||
+79
@@ -142,5 +142,84 @@ M.availability_date.form.fillValue = function(value, node) {
|
||||
value.t = parseInt(node.getData('time'), 10);
|
||||
};
|
||||
|
||||
/**
|
||||
* List out Date node value in an array node.
|
||||
*
|
||||
* This will go through all array node and list from earlier date node to current date node.
|
||||
*
|
||||
* @method convertTreeDateValue
|
||||
* @param {array} tree Tree node to convert
|
||||
* @param {array} arrayDateNode
|
||||
* @param {array} currentNode current node.
|
||||
*
|
||||
* @return {array} arrayDateNode
|
||||
*/
|
||||
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;
|
||||
}
|
||||
arrayDateNode.push(node);
|
||||
} else if (node.type === undefined) {
|
||||
M.availability_date.form.convertTreeDateValue(node.c, arrayDateNode, currentNode);
|
||||
}
|
||||
});
|
||||
return arrayDateNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check current node.
|
||||
*
|
||||
* This will check current date node with all date node in tree node.
|
||||
*
|
||||
* @method checkConditionDate
|
||||
* @param {array} 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) {
|
||||
// Validate if the date is conflict.
|
||||
if (checkNode.d === '<') {
|
||||
if (currentNodeDirection === '>=' && currentNodeTime >= checkNode.t) {
|
||||
error = true;
|
||||
}
|
||||
} else {
|
||||
if (currentNodeDirection === '<' && currentNodeTime <= checkNode.t) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
});
|
||||
return error;
|
||||
} else {
|
||||
if (currentNode.one('div > .badge-warning')) {
|
||||
currentNode.one('div > .badge-warning').remove();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
M.availability_date.form.fillErrors = function(errors, node) {
|
||||
var error = M.availability_date.form.checkConditionDate(node);
|
||||
if (error) {
|
||||
errors.push('availability_date:error_dateconflict');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["base", "node", "event", "io", "moodle-core_availability-form"]});
|
||||
|
||||
+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)}},"@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,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"]});
|
||||
availability/condition/date/yui/build/moodle-availability_date-form/moodle-availability_date-form.js
Vendored
+79
@@ -142,5 +142,84 @@ M.availability_date.form.fillValue = function(value, node) {
|
||||
value.t = parseInt(node.getData('time'), 10);
|
||||
};
|
||||
|
||||
/**
|
||||
* List out Date node value in an array node.
|
||||
*
|
||||
* This will go through all array node and list from earlier date node to current date node.
|
||||
*
|
||||
* @method convertTreeDateValue
|
||||
* @param {array} tree Tree node to convert
|
||||
* @param {array} arrayDateNode
|
||||
* @param {array} currentNode current node.
|
||||
*
|
||||
* @return {array} arrayDateNode
|
||||
*/
|
||||
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;
|
||||
}
|
||||
arrayDateNode.push(node);
|
||||
} else if (node.type === undefined) {
|
||||
M.availability_date.form.convertTreeDateValue(node.c, arrayDateNode, currentNode);
|
||||
}
|
||||
});
|
||||
return arrayDateNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check current node.
|
||||
*
|
||||
* This will check current date node with all date node in tree node.
|
||||
*
|
||||
* @method checkConditionDate
|
||||
* @param {array} 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) {
|
||||
// Validate if the date is conflict.
|
||||
if (checkNode.d === '<') {
|
||||
if (currentNodeDirection === '>=' && currentNodeTime >= checkNode.t) {
|
||||
error = true;
|
||||
}
|
||||
} else {
|
||||
if (currentNodeDirection === '<' && currentNodeTime <= checkNode.t) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
});
|
||||
return error;
|
||||
} else {
|
||||
if (currentNode.one('div > .badge-warning')) {
|
||||
currentNode.one('div > .badge-warning').remove();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
M.availability_date.form.fillErrors = function(errors, node) {
|
||||
var error = M.availability_date.form.checkConditionDate(node);
|
||||
if (error) {
|
||||
errors.push('availability_date:error_dateconflict');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["base", "node", "event", "io", "moodle-core_availability-form"]});
|
||||
|
||||
@@ -139,3 +139,82 @@ M.availability_date.form.fillValue = function(value, node) {
|
||||
value.d = node.one('select[name=direction]').get('value');
|
||||
value.t = parseInt(node.getData('time'), 10);
|
||||
};
|
||||
|
||||
/**
|
||||
* List out Date node value in an array node.
|
||||
*
|
||||
* This will go through all array node and list from earlier date node to current date node.
|
||||
*
|
||||
* @method convertTreeDateValue
|
||||
* @param {array} tree Tree node to convert
|
||||
* @param {array} arrayDateNode
|
||||
* @param {array} currentNode current node.
|
||||
*
|
||||
* @return {array} arrayDateNode
|
||||
*/
|
||||
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;
|
||||
}
|
||||
arrayDateNode.push(node);
|
||||
} else if (node.type === undefined) {
|
||||
M.availability_date.form.convertTreeDateValue(node.c, arrayDateNode, currentNode);
|
||||
}
|
||||
});
|
||||
return arrayDateNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check current node.
|
||||
*
|
||||
* This will check current date node with all date node in tree node.
|
||||
*
|
||||
* @method checkConditionDate
|
||||
* @param {array} 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) {
|
||||
// Validate if the date is conflict.
|
||||
if (checkNode.d === '<') {
|
||||
if (currentNodeDirection === '>=' && currentNodeTime >= checkNode.t) {
|
||||
error = true;
|
||||
}
|
||||
} else {
|
||||
if (currentNodeDirection === '<' && currentNodeTime <= checkNode.t) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
});
|
||||
return error;
|
||||
} else {
|
||||
if (currentNode.one('div > .badge-warning')) {
|
||||
currentNode.one('div > .badge-warning').remove();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
M.availability_date.form.fillErrors = function(errors, node) {
|
||||
var error = M.availability_date.form.checkConditionDate(node);
|
||||
if (error) {
|
||||
errors.push('availability_date:error_dateconflict');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -197,7 +197,12 @@ class condition extends \core_availability\condition {
|
||||
$this->customfield);
|
||||
}
|
||||
} else {
|
||||
$translatedfieldname = \core_user\fields::get_display_name($this->standardfield);
|
||||
$standardfields = self::get_standard_profile_fields();
|
||||
if (array_key_exists($this->standardfield, $standardfields)) {
|
||||
$translatedfieldname = $standardfields[$this->standardfield];
|
||||
} else {
|
||||
$translatedfieldname = get_string('missing', 'availability_profile', $this->standardfield);
|
||||
}
|
||||
}
|
||||
$a = new \stdClass();
|
||||
// Not safe to call format_string here; use the special function to call it later.
|
||||
@@ -321,6 +326,27 @@ class condition extends \core_availability\condition {
|
||||
return $fieldconditionmet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of standard user profile fields used by the condition
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_standard_profile_fields(): array {
|
||||
return [
|
||||
'firstname' => \core_user\fields::get_display_name('firstname'),
|
||||
'lastname' => \core_user\fields::get_display_name('lastname'),
|
||||
'email' => \core_user\fields::get_display_name('email'),
|
||||
'city' => \core_user\fields::get_display_name('city'),
|
||||
'country' => \core_user\fields::get_display_name('country'),
|
||||
'idnumber' => \core_user\fields::get_display_name('idnumber'),
|
||||
'institution' => \core_user\fields::get_display_name('institution'),
|
||||
'department' => \core_user\fields::get_display_name('department'),
|
||||
'phone1' => \core_user\fields::get_display_name('phone1'),
|
||||
'phone2' => \core_user\fields::get_display_name('phone2'),
|
||||
'address' => \core_user\fields::get_display_name('address'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data about custom profile fields. Cached statically in current
|
||||
* request.
|
||||
@@ -472,6 +498,11 @@ class condition extends \core_availability\condition {
|
||||
$valuefield = 'data';
|
||||
$default = $customfield->defaultdata;
|
||||
} else {
|
||||
$standardfields = self::get_standard_profile_fields();
|
||||
if (!array_key_exists($this->standardfield, $standardfields)) {
|
||||
// If the field isn't found, nobody matches.
|
||||
return [];
|
||||
}
|
||||
$values = $DB->get_records_select('user', 'id ' . $sql, $params,
|
||||
'', 'id, '. $this->standardfield);
|
||||
$valuefield = $this->standardfield;
|
||||
@@ -595,6 +626,11 @@ class condition extends \core_availability\condition {
|
||||
$where = "(ud.data IS NOT NULL AND $condition)";
|
||||
}
|
||||
} else {
|
||||
$standardfields = self::get_standard_profile_fields();
|
||||
if (!array_key_exists($this->standardfield, $standardfields)) {
|
||||
// If the field isn't found, nobody matches.
|
||||
return ['SELECT id FROM {user} WHERE 0 = 1', []];
|
||||
}
|
||||
$tablesql = "JOIN {user} u ON u.id = userids.id";
|
||||
list ($where, $mainparams) = $this->get_condition_sql(
|
||||
'u.' . $this->standardfield);
|
||||
|
||||
@@ -42,20 +42,9 @@ class frontend extends \core_availability\frontend {
|
||||
|
||||
protected function get_javascript_init_params($course, \cm_info $cm = null,
|
||||
\section_info $section = null) {
|
||||
|
||||
// Standard user fields.
|
||||
$standardfields = array(
|
||||
'firstname' => \core_user\fields::get_display_name('firstname'),
|
||||
'lastname' => \core_user\fields::get_display_name('lastname'),
|
||||
'email' => \core_user\fields::get_display_name('email'),
|
||||
'city' => \core_user\fields::get_display_name('city'),
|
||||
'country' => \core_user\fields::get_display_name('country'),
|
||||
'idnumber' => \core_user\fields::get_display_name('idnumber'),
|
||||
'institution' => \core_user\fields::get_display_name('institution'),
|
||||
'department' => \core_user\fields::get_display_name('department'),
|
||||
'phone1' => \core_user\fields::get_display_name('phone1'),
|
||||
'phone2' => \core_user\fields::get_display_name('phone2'),
|
||||
'address' => \core_user\fields::get_display_name('address')
|
||||
);
|
||||
$standardfields = condition::get_standard_profile_fields();
|
||||
\core_collator::asort($standardfields);
|
||||
|
||||
// Custom fields.
|
||||
|
||||
@@ -39,7 +39,7 @@ $string['requires_notendswith'] = 'Your <strong>{$a->field}</strong> does not en
|
||||
$string['requires_notisequalto'] = 'Your <strong>{$a->field}</strong> is not <strong>{$a->value}</strong>';
|
||||
$string['requires_notstartswith'] = 'Your <strong>{$a->field}</strong> does not start with <strong>{$a->value}</strong>';
|
||||
$string['requires_startswith'] = 'Your <strong>{$a->field}</strong> starts with <strong>{$a->value}</strong>';
|
||||
$string['missing'] = '(Missing custom field: {$a})';
|
||||
$string['missing'] = '(Missing field: {$a})';
|
||||
$string['title'] = 'User profile';
|
||||
$string['op_contains'] = 'contains';
|
||||
$string['op_doesnotcontain'] = 'doesn\'t contain';
|
||||
|
||||
@@ -62,15 +62,10 @@ Feature: availability_profile
|
||||
|
||||
@javascript
|
||||
Scenario: Test with custom user profile field
|
||||
# Add custom field.
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Users > Accounts > User profile fields" in site administration
|
||||
And I click on "Create a new profile field" "link"
|
||||
And I click on "Text input" "link"
|
||||
And I set the following fields to these values:
|
||||
| Short name | superfield |
|
||||
| Name | Super field |
|
||||
And I click on "Save changes" "button"
|
||||
Given the following "custom profile fields" exist:
|
||||
| datatype | shortname | name |
|
||||
| text | superfield | Super field |
|
||||
And I log in as "admin"
|
||||
|
||||
# Set field value for user.
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
|
||||
Vendored
+15
-1
@@ -971,7 +971,21 @@ M.core_availability.Item.prototype.fillErrors = function(errors) {
|
||||
// If any errors were added, add the marker to this item.
|
||||
var errorLabel = this.node.one('> .badge-warning');
|
||||
if (errors.length !== before && !errorLabel.get('firstChild')) {
|
||||
errorLabel.appendChild(document.createTextNode(M.util.get_string('invalid', 'availability')));
|
||||
var errorString = '';
|
||||
// Fetch the last error code from the array of errors and split using the ':' delimiter.
|
||||
var langString = errors[errors.length - 1].split(':');
|
||||
var component = langString[0];
|
||||
var identifier = langString[1];
|
||||
// If get_string can't find the string, it will return the string in this format.
|
||||
var undefinedString = '[[' + identifier + ',' + component + ']]';
|
||||
// Get the lang string.
|
||||
errorString = M.util.get_string(identifier, component);
|
||||
if (errorString === undefinedString) {
|
||||
// Use a generic invalid input message when the error lang string cannot be loaded.
|
||||
errorString = M.util.get_string('invalid', 'availability');
|
||||
}
|
||||
// Show the error string.
|
||||
errorLabel.appendChild(document.createTextNode(errorString));
|
||||
} else if (errors.length === before && errorLabel.get('firstChild')) {
|
||||
errorLabel.get('firstChild').remove();
|
||||
}
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+15
-1
@@ -971,7 +971,21 @@ M.core_availability.Item.prototype.fillErrors = function(errors) {
|
||||
// If any errors were added, add the marker to this item.
|
||||
var errorLabel = this.node.one('> .badge-warning');
|
||||
if (errors.length !== before && !errorLabel.get('firstChild')) {
|
||||
errorLabel.appendChild(document.createTextNode(M.util.get_string('invalid', 'availability')));
|
||||
var errorString = '';
|
||||
// Fetch the last error code from the array of errors and split using the ':' delimiter.
|
||||
var langString = errors[errors.length - 1].split(':');
|
||||
var component = langString[0];
|
||||
var identifier = langString[1];
|
||||
// If get_string can't find the string, it will return the string in this format.
|
||||
var undefinedString = '[[' + identifier + ',' + component + ']]';
|
||||
// Get the lang string.
|
||||
errorString = M.util.get_string(identifier, component);
|
||||
if (errorString === undefinedString) {
|
||||
// Use a generic invalid input message when the error lang string cannot be loaded.
|
||||
errorString = M.util.get_string('invalid', 'availability');
|
||||
}
|
||||
// Show the error string.
|
||||
errorLabel.appendChild(document.createTextNode(errorString));
|
||||
} else if (errors.length === before && errorLabel.get('firstChild')) {
|
||||
errorLabel.get('firstChild').remove();
|
||||
}
|
||||
|
||||
Vendored
+15
-1
@@ -969,7 +969,21 @@ M.core_availability.Item.prototype.fillErrors = function(errors) {
|
||||
// If any errors were added, add the marker to this item.
|
||||
var errorLabel = this.node.one('> .badge-warning');
|
||||
if (errors.length !== before && !errorLabel.get('firstChild')) {
|
||||
errorLabel.appendChild(document.createTextNode(M.util.get_string('invalid', 'availability')));
|
||||
var errorString = '';
|
||||
// Fetch the last error code from the array of errors and split using the ':' delimiter.
|
||||
var langString = errors[errors.length - 1].split(':');
|
||||
var component = langString[0];
|
||||
var identifier = langString[1];
|
||||
// If get_string can't find the string, it will return the string in this format.
|
||||
var undefinedString = '[[' + identifier + ',' + component + ']]';
|
||||
// Get the lang string.
|
||||
errorString = M.util.get_string(identifier, component);
|
||||
if (errorString === undefinedString) {
|
||||
// Use a generic invalid input message when the error lang string cannot be loaded.
|
||||
errorString = M.util.get_string('invalid', 'availability');
|
||||
}
|
||||
// Show the error string.
|
||||
errorLabel.appendChild(document.createTextNode(errorString));
|
||||
} else if (errors.length === before && errorLabel.get('firstChild')) {
|
||||
errorLabel.get('firstChild').remove();
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class backup_files_edit_form extends moodleform {
|
||||
$mform->setType('component', PARAM_COMPONENT);
|
||||
|
||||
$mform->addElement('hidden', 'returnurl', $this->_customdata['returnurl']);
|
||||
$mform->setType('returnurl', PARAM_URL);
|
||||
$mform->setType('returnurl', PARAM_LOCALURL);
|
||||
|
||||
$this->add_action_buttons(true, get_string('savechanges'));
|
||||
$this->set_data($this->_customdata['data']);
|
||||
|
||||
@@ -4239,7 +4239,8 @@ class restore_block_instance_structure_step extends restore_structure_step {
|
||||
|
||||
// Look for the parent contextid
|
||||
if (!$data->parentcontextid = $this->get_mappingid('context', $data->parentcontextid)) {
|
||||
throw new restore_step_exception('restore_block_missing_parent_ctx', $data->parentcontextid);
|
||||
// Parent contextid does not exist, ignore this block.
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: it would be nice to use standard plugin supports instead of this instance_allow_multiple()
|
||||
@@ -4285,14 +4286,17 @@ class restore_block_instance_structure_step extends restore_structure_step {
|
||||
$params['subpagepattern'] = $data->subpagepattern;
|
||||
}
|
||||
|
||||
$exists = $DB->record_exists_sql("SELECT bi.id
|
||||
$existingblock = $DB->get_records_sql("SELECT bi.id
|
||||
FROM {block_instances} bi
|
||||
JOIN {block} b ON b.name = bi.blockname
|
||||
WHERE bi.blockname = :blockname
|
||||
AND $contextsql
|
||||
AND bi.pagetypepattern $pagetypepatternsql
|
||||
AND $subpagepatternsql", $params);
|
||||
if ($exists) {
|
||||
if (!empty($existingblock)) {
|
||||
// Save the context mapping in case something else is linking to this block's context.
|
||||
$newcontext = context_block::instance(reset($existingblock)->id);
|
||||
$this->set_mapping('context', $oldcontextid, $newcontext->id);
|
||||
// There is at least one very similar block visible on the page where we
|
||||
// are trying to restore the block. In these circumstances the block API
|
||||
// would not allow the user to add another instance of the block, so we
|
||||
@@ -4311,6 +4315,9 @@ class restore_block_instance_structure_step extends restore_structure_step {
|
||||
if ($birecs = $DB->get_records('block_instances', $params)) {
|
||||
foreach($birecs as $birec) {
|
||||
if ($birec->configdata == $data->configdata) {
|
||||
// Save the context mapping in case something else is linking to this block's context.
|
||||
$newcontext = context_block::instance($birec->id);
|
||||
$this->set_mapping('context', $oldcontextid, $newcontext->id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -5296,7 +5303,8 @@ class restore_process_file_aliases_queue extends restore_execution_step {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($info->oldfile->repositorytype === 'local' or $info->oldfile->repositorytype === 'coursefiles') {
|
||||
if ($info->oldfile->repositorytype === 'local' || $info->oldfile->repositorytype === 'coursefiles'
|
||||
|| $info->oldfile->repositorytype === 'contentbank') {
|
||||
// Aliases to Server files and Legacy course files may refer to a file
|
||||
// contained in the backup file or to some existing file (if we are on the
|
||||
// same site).
|
||||
@@ -5459,7 +5467,8 @@ class restore_process_file_aliases_queue extends restore_execution_step {
|
||||
|
||||
// Both Server files and Legacy course files repositories have a single
|
||||
// instance at the system context to use. Let us try to find it.
|
||||
if ($info->oldfile->repositorytype === 'local' or $info->oldfile->repositorytype === 'coursefiles') {
|
||||
if ($info->oldfile->repositorytype === 'local' || $info->oldfile->repositorytype === 'coursefiles'
|
||||
|| $info->oldfile->repositorytype === 'contentbank') {
|
||||
$sql = "SELECT ri.id
|
||||
FROM {repository} r
|
||||
JOIN {repository_instances} ri ON ri.typeid = r.id
|
||||
|
||||
@@ -145,9 +145,11 @@ abstract class convert_helper {
|
||||
$firstchars = fread($handle, 200);
|
||||
$status = fclose($handle);
|
||||
|
||||
if (strpos($firstchars,'<?xml version="1.0" encoding="UTF-8"?>') !== false and
|
||||
strpos($firstchars,'<moodle_backup>') !== false and
|
||||
strpos($firstchars,'<information>') !== false) {
|
||||
// Look for expected XML elements (case-insensitive to account for encoding attribute).
|
||||
if (stripos($firstchars, '<?xml version="1.0" encoding="UTF-8"?>') !== false &&
|
||||
strpos($firstchars, '<moodle_backup>') !== false &&
|
||||
strpos($firstchars, '<information>') !== false) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -643,7 +643,7 @@ class backup_ui_stage_complete extends backup_ui_stage_final {
|
||||
}
|
||||
$output .= $renderer->get_samesite_notification();
|
||||
$output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess');
|
||||
$output .= $renderer->continue_button($restorerul);
|
||||
$output .= $renderer->continue_button($restorerul, 'get');
|
||||
$output .= $renderer->box_end();
|
||||
|
||||
return $output;
|
||||
|
||||
@@ -553,7 +553,8 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a continue button
|
||||
* Displays a continue button, overriding core renderer method of the same in order
|
||||
* to override submission method of the button form
|
||||
*
|
||||
* @param string|moodle_url $url
|
||||
* @param string $method
|
||||
@@ -566,7 +567,6 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
if ($method != 'post') {
|
||||
$method = 'get';
|
||||
}
|
||||
$url->param('sesskey', sesskey());
|
||||
$button = new single_button($url, get_string('continue'), $method, true);
|
||||
$button->class = 'continuebutton';
|
||||
return $this->render($button);
|
||||
|
||||
@@ -1161,8 +1161,10 @@ class restore_ui_stage_complete extends restore_ui_stage_process {
|
||||
$html .= $renderer->notification(get_string('restorefileweremissing', 'backup'), 'notifyproblem');
|
||||
}
|
||||
$html .= $renderer->notification(get_string('restoreexecutionsuccess', 'backup'), 'notifysuccess');
|
||||
$html .= $renderer->continue_button(new moodle_url('/course/view.php', array(
|
||||
'id' => $this->get_ui()->get_controller()->get_courseid())), 'get');
|
||||
|
||||
$courseurl = course_get_url($this->get_ui()->get_controller()->get_courseid());
|
||||
$html .= $renderer->continue_button($courseurl, 'get');
|
||||
|
||||
$html .= $renderer->box_end();
|
||||
|
||||
return $html;
|
||||
|
||||
@@ -12,9 +12,10 @@ Feature: Restore Moodle 2 course backups
|
||||
| Course 3 | C3 | 0 | topics | 2 | 0 |
|
||||
| Course 4 | C4 | 0 | topics | 20 | 0 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro | section |
|
||||
| assign | C3 | assign1 | Test assign name | Assign description | 1 |
|
||||
| data | C3 | data1 | Test database name | Database description | 2 |
|
||||
| activity | course | idnumber | name | intro | section | externalurl |
|
||||
| assign | C3 | assign1 | Test assign name | Assign description | 1 | |
|
||||
| data | C3 | data1 | Test database name | Database description | 2 | |
|
||||
| url | C1 | url1 | Test URL name | Test URL description | 3 | http://www.moodle.org |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
@@ -108,11 +109,7 @@ Feature: Restore Moodle 2 course backups
|
||||
|
||||
@javascript
|
||||
Scenario: Restore a backup in an existing course retaining the backup course settings
|
||||
Given I add a "URL" to section "3" and I fill the form with:
|
||||
| Name | Test URL name |
|
||||
| Description | Test URL description |
|
||||
| id_externalurl | http://www.moodle.org |
|
||||
And I hide section "3"
|
||||
Given I hide section "3"
|
||||
And I hide section "7"
|
||||
When I backup "Course 1" course using this options:
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
@@ -134,11 +131,7 @@ Feature: Restore Moodle 2 course backups
|
||||
|
||||
@javascript
|
||||
Scenario: Restore a backup in an existing course keeping the target course settings
|
||||
Given I add a "URL" to section "3" and I fill the form with:
|
||||
| Name | Test URL name |
|
||||
| Description | Test URL description |
|
||||
| id_externalurl | http://www.moodle.org |
|
||||
And I hide section "3"
|
||||
Given I hide section "3"
|
||||
And I hide section "7"
|
||||
When I backup "Course 1" course using this options:
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
@@ -160,11 +153,7 @@ Feature: Restore Moodle 2 course backups
|
||||
|
||||
@javascript
|
||||
Scenario: Restore a backup in an existing course deleting contents and retaining the backup course settings
|
||||
Given I add a "URL" to section "3" and I fill the form with:
|
||||
| Name | Test URL name |
|
||||
| Description | Test URL description |
|
||||
| id_externalurl | http://www.moodle.org |
|
||||
And I hide section "3"
|
||||
Given I hide section "3"
|
||||
And I hide section "7"
|
||||
When I backup "Course 1" course using this options:
|
||||
| Initial | Include enrolled users | 0 |
|
||||
@@ -189,11 +178,7 @@ Feature: Restore Moodle 2 course backups
|
||||
|
||||
@javascript
|
||||
Scenario: Restore a backup in an existing course deleting contents and keeping the current course settings
|
||||
Given I add a "URL" to section "3" and I fill the form with:
|
||||
| Name | Test URL name |
|
||||
| Description | Test URL description |
|
||||
| id_externalurl | http://www.moodle.org |
|
||||
And I hide section "3"
|
||||
Given I hide section "3"
|
||||
And I hide section "7"
|
||||
When I backup "Course 1" course using this options:
|
||||
| Initial | Include enrolled users | 0 |
|
||||
@@ -218,11 +203,7 @@ Feature: Restore Moodle 2 course backups
|
||||
|
||||
@javascript
|
||||
Scenario: Restore a backup in an existing course deleting contents decreasing the number of sections
|
||||
Given I add a "URL" to section "3" and I fill the form with:
|
||||
| Name | Test URL name |
|
||||
| Description | Test URL description |
|
||||
| id_externalurl | http://www.moodle.org |
|
||||
And I hide section "3"
|
||||
Given I hide section "3"
|
||||
And I hide section "7"
|
||||
When I backup "Course 1" course using this options:
|
||||
| Initial | Include enrolled users | 0 |
|
||||
|
||||
@@ -21,7 +21,7 @@ Feature: Restore Moodle 2 course backups with different user data settings
|
||||
| data | Test database name | n | C1 | data1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a "Text input" field to "Test database name" database and I fill the form with:
|
||||
And I add a "Short text" field to "Test database name" database and I fill the form with:
|
||||
| Field name | Test field name |
|
||||
| Field description | Test field description |
|
||||
And I follow "Templates"
|
||||
|
||||
@@ -207,7 +207,7 @@ class issued_badge implements renderable {
|
||||
$data->hasrelatedbadges = true;
|
||||
$data->relatedbadges = [];
|
||||
foreach ($relatedbadges as $related) {
|
||||
if (isloggedin() && !is_guest($context)) {
|
||||
if (isloggedin() && ($context instanceof context_course && !is_guest($context))) {
|
||||
$related->url = (new moodle_url('/badges/overview.php', ['id' => $related->id]))->out(false);
|
||||
}
|
||||
$data->relatedbadges[] = (array)$related;
|
||||
|
||||
@@ -30,9 +30,7 @@ Feature: Award badges with separate groups
|
||||
| teacher1 | CB |
|
||||
| student2 | CA |
|
||||
| teacher2 | CA |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Course 1" "course editing" page logged in as "teacher1"
|
||||
And I expand all fieldsets
|
||||
And I set the field "Group mode" to "Separate groups"
|
||||
And I press "Save and display"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace block_accessreview\tests;
|
||||
namespace block_accessreview;
|
||||
|
||||
use ReflectionClass;
|
||||
use advanced_testcase;
|
||||
|
||||
@@ -36,7 +36,7 @@ class moodle1_block_html_handler extends moodle1_block_handler {
|
||||
$contextid = $this->converter->get_contextid(CONTEXT_BLOCK, $olddata['id']);
|
||||
$decodeddata = base64_decode($olddata['configdata']);
|
||||
list($updated, $configdata) = upgrade_fix_serialized_objects($decodeddata);
|
||||
$configdata = unserialize($configdata);
|
||||
$configdata = unserialize_object($configdata);
|
||||
|
||||
// get a fresh new file manager for this instance
|
||||
$this->fileman = $this->converter->get_file_manager($contextid, 'block_html');
|
||||
@@ -44,7 +44,7 @@ class moodle1_block_html_handler extends moodle1_block_handler {
|
||||
// convert course files embedded in the block content
|
||||
$this->fileman->filearea = 'content';
|
||||
$this->fileman->itemid = 0;
|
||||
$configdata->text = moodle1_converter::migrate_referenced_files($configdata->text, $this->fileman);
|
||||
$configdata->text = moodle1_converter::migrate_referenced_files($configdata->text ?? '', $this->fileman);
|
||||
$configdata->format = FORMAT_HTML;
|
||||
|
||||
return base64_encode(serialize($configdata));
|
||||
|
||||
@@ -83,7 +83,8 @@ class content extends \core_search\base_block {
|
||||
|
||||
$context = \context::instance_by_id($document->get('contextid'));
|
||||
|
||||
$files = $fs->get_area_files($context->id, 'block_html', 'content');
|
||||
$files = $fs->get_area_files($context->id, 'block_html', 'content',
|
||||
false, 'itemid, filepath, filename', false);
|
||||
foreach ($files as $file) {
|
||||
$document->add_stored_file($file);
|
||||
}
|
||||
|
||||
@@ -137,11 +137,9 @@ class search_content_test extends \advanced_testcase {
|
||||
$this->assertCount(0, $doc->get_files());
|
||||
$area->attach_files($doc);
|
||||
$files = $doc->get_files();
|
||||
$this->assertCount(2, $files);
|
||||
// The directory entry should NOT be provided for indexing.
|
||||
$this->assertCount(1, $files);
|
||||
foreach ($files as $file) {
|
||||
if ($file->is_directory()) {
|
||||
continue;
|
||||
}
|
||||
$this->assertEquals('file.txt', $file->get_filename());
|
||||
$this->assertEquals('File content', $file->get_content());
|
||||
}
|
||||
|
||||
@@ -119,10 +119,19 @@ class block_news_items extends block_base {
|
||||
if (!empty($CFG->forum_enabletimedposts) && ($discussion->timestart > $posttime)) {
|
||||
$posttime = $discussion->timestart;
|
||||
}
|
||||
|
||||
// If the user who created the discussion post has been deleted, indicate so.
|
||||
if ($discussion->userdeleted) {
|
||||
$userfullname = get_string('deleteduser', 'mod_forum');
|
||||
} else {
|
||||
$userfullname = fullname($discussion, has_capability('moodle/site:viewfullnames', $context));
|
||||
}
|
||||
|
||||
$text .= '<li class="post">'.
|
||||
'<div class="head clearfix">'.
|
||||
'<div class="date">'.userdate($posttime, $strftimerecent).'</div>'.
|
||||
'<div class="name">'.fullname($discussion).'</div></div>'.
|
||||
'<div class="name">'.$userfullname.'</div>'.
|
||||
'</div>'.
|
||||
'<div class="info"><a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$discussion->discussion.'">'.$discussion->subject.'</a></div>'.
|
||||
"</li>\n";
|
||||
}
|
||||
|
||||
@@ -10,11 +10,18 @@ Feature: Add URL to main menu block
|
||||
And I am on site homepage
|
||||
And I turn editing mode on
|
||||
And I add the "Main menu" block
|
||||
When I add a "URL" to section "0" and I fill the form with:
|
||||
| Name | reference link |
|
||||
| Description | mooooooooodle |
|
||||
| External URL | http://www.moodle.com |
|
||||
| id_display | In pop-up |
|
||||
And the following "activity" exists:
|
||||
| activity | url |
|
||||
| course | Acceptance test site |
|
||||
| name | reference link |
|
||||
| intro | mooooooooodle |
|
||||
| externalurl | http://www.moodle.com |
|
||||
| section | 0 |
|
||||
When I am on the "reference link" "url activity editing" page
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| id_display | In pop-up |
|
||||
And I press "Save and return to course"
|
||||
Then "reference link" "link" should exist in the "Main menu" "block"
|
||||
And "Add an activity or resource" "button" should exist in the "Main menu" "block"
|
||||
|
||||
@@ -33,12 +40,18 @@ Feature: Add URL to main menu block
|
||||
And I set the following fields to these values:
|
||||
| Page contexts | Display throughout the entire site |
|
||||
And I press "Save changes"
|
||||
When I am on the "C1" Course page
|
||||
And I add a "URL" to section "0" and I fill the form with:
|
||||
| Name | reference link |
|
||||
| Description | mooooooooodle |
|
||||
| External URL | http://www.moodle.com |
|
||||
| Display description on course page | 1 |
|
||||
| id_display | In pop-up |
|
||||
When the following "activity" exists:
|
||||
| activity | url |
|
||||
| course | C1 |
|
||||
| name | reference link |
|
||||
| intro | mooooooooodle |
|
||||
| externalurl | http://www.moodle.com |
|
||||
| section | 0 |
|
||||
| showdescription | 1 |
|
||||
And I am on the "reference link" "url activity editing" page
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| id_display | In pop-up |
|
||||
And I press "Save and return to course"
|
||||
Then "reference link" "link" should not exist in the "Main menu" "block"
|
||||
And I should see "mooooooooodle" in the "region-main" "region"
|
||||
|
||||
@@ -15,25 +15,15 @@ Feature: Block appearances
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | name | description | course | idnumber | section |
|
||||
| survey | Test survey name | Test survey description | C1 | survey1 | 1 |
|
||||
| book | Test book name | Test book description | C1 | book1 | 1 |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test survey name"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Survey type | ATTLS (20 item version) |
|
||||
And I press "Save and return to course"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "Test book name"
|
||||
And I set the following fields to these values:
|
||||
| Chapter title | Book title |
|
||||
| Content | Book content test test |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
| activity | name | course | idnumber | section | template |
|
||||
| survey | Test survey name | C1 | survey1 | 1 | 4 |
|
||||
| book | Test book name | C1 | book1 | 1 | |
|
||||
And the following "mod_book > chapter" exists:
|
||||
| book | Test book name |
|
||||
| title | Book title |
|
||||
| content | Book content test test |
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I turn editing mode on
|
||||
And I add the "Comments" block
|
||||
And I configure the "Comments" block
|
||||
And I set the following fields to these values:
|
||||
|
||||
@@ -14,21 +14,14 @@ Feature: Block region moving
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Survey" to section "1" and I fill the form with:
|
||||
| Name | Test survey name |
|
||||
| Survey type | ATTLS (20 item version) |
|
||||
| Description | Test survey description |
|
||||
And I add a "Book" to section "1" and I fill the form with:
|
||||
| Name | Test book name |
|
||||
| Description | Test book description |
|
||||
And I follow "Test book name"
|
||||
And I set the following fields to these values:
|
||||
| Chapter title | Book title |
|
||||
| Content | Book content test test |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | template |
|
||||
| survey | Test survey name | C1 | 4 |
|
||||
| book | Test book name | C1 | |
|
||||
And the following "mod_book > chapter" exists:
|
||||
| book | Test book name |
|
||||
| title | Book title |
|
||||
| content | Book content test test |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Comments" block
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user