Compare commits
419 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 02e8cebdd2 | |||
| 024051b719 | |||
| 6423996066 | |||
| 490e544204 | |||
| 62395a5aca | |||
| 41ed00e59a | |||
| ba74b9be02 | |||
| 16f8d04930 | |||
| b389ec0b8b | |||
| 1c8ac6a361 | |||
| c748e7d7e9 | |||
| fcff77046d | |||
| d01b671f2d | |||
| 2d35e0a180 | |||
| a8b11d8923 | |||
| 6cc0eabc7e | |||
| 4a1811b769 | |||
| ffabf0b4b9 | |||
| 5e078e4a78 | |||
| 77c39c40e3 | |||
| 8ec9af05b5 | |||
| 0ecdb05ab9 | |||
| 54bc7d8197 | |||
| ea3848abe8 | |||
| 5f0201bd79 | |||
| 363941c247 | |||
| 60e0905018 | |||
| 987b7ef10d | |||
| fdb5d897de | |||
| 02d5efc450 | |||
| 4b2a950d08 | |||
| 899b4fa1f4 | |||
| 9ce7e40f2e | |||
| 84459c1ebf | |||
| 495654b92b | |||
| 6535a96989 | |||
| 8628fc8664 | |||
| 7da8af1006 | |||
| 4bce55d783 | |||
| e9cfb0ad02 | |||
| 73a35edc24 | |||
| 83c6906e75 | |||
| 3637e3db9f | |||
| 30d8c900a9 | |||
| 1d5e6e4e5d | |||
| 276c40500c | |||
| e7556aa106 | |||
| 68c96a97b9 | |||
| 213b37077c | |||
| e75b7d1e0d | |||
| 7a77eb18c3 | |||
| 5d5d2f8f49 | |||
| da00d28c2c | |||
| e778888ed2 | |||
| b058b6681c | |||
| e2928d531e | |||
| c3184e070a | |||
| cd7f36d194 | |||
| 6f97d3a89f | |||
| 4da7e5dec3 | |||
| 35b9ad6bbf | |||
| af68f3ca28 | |||
| ecf91e296e | |||
| ef09179d1e | |||
| 1ab37f0e63 | |||
| 286c3367c2 | |||
| d514c32c71 | |||
| 1d192cf19d | |||
| d805dde928 | |||
| 86e2e5882e | |||
| 505987af6c | |||
| 558b5aa693 | |||
| 888a4f23bb | |||
| e871b6fc71 | |||
| d032d75641 | |||
| 43a90e8197 | |||
| 25657e4be2 | |||
| 2f27619ffe | |||
| 80a77e7c74 | |||
| 761f169185 | |||
| a3b50194ee | |||
| 752b45d421 | |||
| 7d3a4aa37d | |||
| 55fb142c2f | |||
| d4a98e6cfb | |||
| 97b1dd2f2f | |||
| 626ea71299 | |||
| 98975c118e | |||
| 90409e8fa0 | |||
| d7898ee7da | |||
| c6942c9bb7 | |||
| 38688c0be6 | |||
| a88cbdae73 | |||
| ec498ce036 | |||
| 5f85ba1793 | |||
| 63205f03bb | |||
| b820c1c5c3 | |||
| 482d0cc1dc | |||
| 195a4ce781 | |||
| 785d70c2d7 | |||
| ab25803907 | |||
| 1a88833799 | |||
| 8e6355fc8c | |||
| 00fc817923 | |||
| c8f0796ca6 | |||
| afe848bcc6 | |||
| 89e18f1381 | |||
| 200fb340e6 | |||
| 364c27227a | |||
| a70bbb3628 | |||
| 5bbe044927 | |||
| a85c93018a | |||
| 3f9b9363d0 | |||
| 805ff1806a | |||
| 6ba656e2f5 | |||
| 91d352a085 | |||
| 27073a36b6 | |||
| e1b6c9be56 | |||
| fee929cdaf | |||
| a3a1e2184d | |||
| 2245a4c0bc | |||
| 803f72ef0f | |||
| 5ad4c9cf3b | |||
| 21fc25e46c | |||
| 962d7cfa55 | |||
| 37319d2c88 | |||
| be5b800a80 | |||
| c3bc783ff4 | |||
| 58c98e14d9 | |||
| ad201ba85a | |||
| 3203fb9ae7 | |||
| 84c2589c42 | |||
| 99b5729824 | |||
| 3134bf772a | |||
| db03f2a58e | |||
| 78cbc7cb16 | |||
| b784c144f8 | |||
| 94ab19f544 | |||
| 438ef558cf | |||
| 16c1a0494c | |||
| 9b0b39065c | |||
| 8b0afe2984 | |||
| 6fa7222f0f | |||
| f616472d63 | |||
| cc33999469 | |||
| 4736294b35 | |||
| cc86aa7f8d | |||
| 2f5145d704 | |||
| e62acd23e0 | |||
| 5bd5d08f7e | |||
| 7bec161984 | |||
| f960ce6d5b | |||
| 9ade28a977 | |||
| 93821b6024 | |||
| 731d5cc8b3 | |||
| 2bb85117e3 | |||
| dced24e7c3 | |||
| 62d0705cc1 | |||
| 62778bb1aa | |||
| 3d05070094 | |||
| 7b007b32af | |||
| 564de9d4a7 | |||
| da7c5d98ec | |||
| ff51c0bbf6 | |||
| 33bc3cd98c | |||
| dd2c9b56bf | |||
| a3bcf54428 | |||
| fb6ea9b0d6 | |||
| 599a3be74f | |||
| 23a60a1220 | |||
| b097840e33 | |||
| 04e7c65f0c | |||
| 7e3638ff2e | |||
| 540fda4055 | |||
| f44da13380 | |||
| c8d55cdc52 | |||
| d87999b89a | |||
| 6e617b9e46 | |||
| 5a237cfef2 | |||
| e05af64ecf | |||
| 1427cd178c | |||
| 6f6eae5d67 | |||
| f442e8d5ad | |||
| 0ccc87c617 | |||
| 92b27a6f07 | |||
| 07bc841860 | |||
| 0282a557d0 | |||
| d506b8f6e2 | |||
| 34495e01fc | |||
| cd06961249 | |||
| 7cdc137d8a | |||
| 8a6d6ef675 | |||
| b2cf67e4f5 | |||
| 62a0b21d27 | |||
| cee330362c | |||
| 9e7d54ebe6 | |||
| b51456d83a | |||
| 847ab7d072 | |||
| b48e64e2a1 | |||
| 71e219b7db | |||
| aa0fbc3f08 | |||
| 9ef5476361 | |||
| 2c363085af | |||
| 75573d11e9 | |||
| 35ca0b0616 | |||
| 1ff3797d8d | |||
| 666fffc680 | |||
| 6bbb0de4eb | |||
| 79dcd64b34 | |||
| 13e5a55ae9 | |||
| e5b03f9fb9 | |||
| 9a72cc8837 | |||
| 756a559024 | |||
| 0685bfdb24 | |||
| 6f73e436fb | |||
| b72b37c974 | |||
| dc2b113bca | |||
| a9d4d93b74 | |||
| d7e3bea9fa | |||
| f67240b70b | |||
| 5ce118a9c5 | |||
| cc27af1b7f | |||
| 2128d39ed7 | |||
| 3b8f6dee80 | |||
| 6c113ddc35 | |||
| b08fbf57fd | |||
| fce950a59a | |||
| 54e9ee4a9e | |||
| ba131ff29d | |||
| 6e61b34ac2 | |||
| 06666c60f5 | |||
| a0c341d039 | |||
| 6e77a2070d | |||
| 366d82ccd7 | |||
| c75ec7503c | |||
| 0f62b3d370 | |||
| 3100b07fb6 | |||
| 4a68972a4a | |||
| 1a219492f7 | |||
| d8de6025b2 | |||
| bdd79633d3 | |||
| 823e8d94de | |||
| 54da83f40a | |||
| 759bf6e3b6 | |||
| e3460d67f3 | |||
| a99970eeb5 | |||
| 96321d7b45 | |||
| 971fd1cf26 | |||
| c187fde227 | |||
| 7df5aeed41 | |||
| 21e23bef57 | |||
| 04d887ec89 | |||
| 12c97671bc | |||
| 3a1d250c27 | |||
| 3dadbe85af | |||
| 9f3174a32d | |||
| bba5ec68ec | |||
| 7b354279c7 | |||
| 78380cc2a3 | |||
| 0feec6d5f0 | |||
| 03edcc984e | |||
| 264e5dcb44 | |||
| 2f5e3d13b2 | |||
| 26d77f3735 | |||
| 4d1919014f | |||
| 2fad1f88f1 | |||
| 0bcf1e2dcc | |||
| 76ed1fd12a | |||
| d205a07d40 | |||
| 5670b0932c | |||
| 67cec533ea | |||
| 1550715d9b | |||
| 81e23f4c02 | |||
| d8a9c0b987 | |||
| a89faaf6e5 | |||
| 881d5fb544 | |||
| 3f8ed2a39c | |||
| e1f3a16764 | |||
| 8cb9876cf8 | |||
| 24dadc7a7f | |||
| 1cc03ca6b9 | |||
| 35fd32ffb4 | |||
| 5a010c604d | |||
| a646166319 | |||
| 6d65eb3a1f | |||
| 9a19ddfef4 | |||
| ffaed1fc50 | |||
| 2c111a05ea | |||
| e2712c4065 | |||
| 6865cf828b | |||
| 3202109780 | |||
| 0cd33e81ce | |||
| f5f2e79a72 | |||
| 4a4a42cdce | |||
| c36fe51c48 | |||
| 11fc78ed62 | |||
| a635c64779 | |||
| ff4f52ddcf | |||
| 3342532dfa | |||
| 931ac8545a | |||
| 4eed515242 | |||
| 32162a7fe4 | |||
| bc8b2d8b63 | |||
| ba94804e81 | |||
| ad913b65ee | |||
| 90fd319190 | |||
| 289f2b427a | |||
| ae73896f2b | |||
| 42be864b55 | |||
| 7fbbd368f6 | |||
| 003d6ee817 | |||
| 084dbef995 | |||
| ecceaffca1 | |||
| b0600e2954 | |||
| 0df6fd6b43 | |||
| e66e5955e7 | |||
| d73ad2127e | |||
| fdb513461b | |||
| 0e69b95fbb | |||
| 3792869ef7 | |||
| a290cc77a3 | |||
| 5ec04e7808 | |||
| f129cbbe62 | |||
| 9317b4d86e | |||
| 86a71669ee | |||
| 76d79b57c4 | |||
| 6aa7832084 | |||
| fbc8123eb4 | |||
| a4dd8fedf0 | |||
| fc1e46db15 | |||
| 26af25312c | |||
| 64c54d9510 | |||
| 62c4f8a76c | |||
| 237a803050 | |||
| 32ac490e77 | |||
| 54b01d1943 | |||
| 8069aeec1e | |||
| e715380d4b | |||
| 20c681e5f8 | |||
| cfcaf488be | |||
| 2a65efd9a3 | |||
| 46748714da | |||
| 846e242aec | |||
| 49d8babe8b | |||
| 5102249c52 | |||
| 37f5141f60 | |||
| b9e73bd65e | |||
| 4a0cb6e1b5 | |||
| bfe4d189cb | |||
| 4058934644 | |||
| ca8e5915e6 | |||
| 2247cd68a4 | |||
| 36c8faede8 | |||
| 31e1e17590 | |||
| d79acfdd59 | |||
| bc1324af4d | |||
| 367d1c7cb7 | |||
| 8346e2b912 | |||
| 09274be2e0 | |||
| d8f262e0b5 | |||
| 692f8031bf | |||
| f86b97fdd6 | |||
| faf0e0654d | |||
| bc3050ad0c | |||
| 2412b1278b | |||
| cb6904b002 | |||
| 2cf32c40e9 | |||
| a4ee77a654 | |||
| 15e04d6651 | |||
| 8ccba0808b | |||
| 9ecb8de2bb | |||
| 851c6d00b6 | |||
| 864bbf86db | |||
| 08127c83a7 | |||
| c4f9163dc0 | |||
| dfaa31d4f0 | |||
| f62ef26f37 | |||
| 3dc10958bc | |||
| 7901350509 | |||
| 298810e993 | |||
| 3c04cc40d0 | |||
| 125db05313 | |||
| c34b5f79cd | |||
| e4b96893b8 | |||
| 452d92d9bb | |||
| e55e9974b8 | |||
| fd5c2b3aa4 | |||
| 1fd5899e70 | |||
| b9a191dda8 | |||
| 89506cd08d | |||
| e8c5f37306 | |||
| 6a7b69a30a | |||
| ddbc161632 | |||
| 4b6b859ca0 | |||
| 66896b275a | |||
| 2558c6a9b9 | |||
| 890f2e7c57 | |||
| eb05d37e5b | |||
| b85b5dd74e | |||
| 230831bc70 | |||
| 60e11dc998 | |||
| 88730f6a8d | |||
| cd69894e95 | |||
| c83eaf4066 | |||
| e78fe25155 | |||
| 5f1db200b1 | |||
| c5ef86c3bf | |||
| faac67e2ea | |||
| 8caac3da44 | |||
| 67674462dd | |||
| f354ba61e6 | |||
| a7f5c1eb05 | |||
| 1ba60572b3 | |||
| c804789bbb | |||
| ddd99c03d2 | |||
| 8aa860d7b7 | |||
| b5519852fc | |||
| 731e8a1e01 | |||
| 375c921a69 |
@@ -4703,4 +4703,199 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="5.0" requires="4.2.3">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.11.0" />
|
||||
<VENDOR name="mysql" version="8.4" />
|
||||
<VENDOR name="postgres" version="14" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.2.0" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="sixtyfourbitsrequired" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_async_backup" level="recommended">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -180,7 +180,7 @@ class generator_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function create_preset_provider(): array {
|
||||
public static function create_preset_provider(): array {
|
||||
return [
|
||||
'Default values' => [
|
||||
],
|
||||
|
||||
@@ -84,7 +84,7 @@ class helper_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function create_preset_provider(): array {
|
||||
public static function create_preset_provider(): array {
|
||||
return [
|
||||
'Default values' => [
|
||||
],
|
||||
@@ -177,7 +177,7 @@ class helper_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_item_provider(): array {
|
||||
public static function add_item_provider(): array {
|
||||
return [
|
||||
'Setting without plugin' => [
|
||||
'name' => 'settingname',
|
||||
@@ -239,7 +239,7 @@ class helper_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_plugin_provider(): array {
|
||||
public static function add_plugin_provider(): array {
|
||||
return [
|
||||
'Plugin: enabled (using int)' => [
|
||||
'type' => 'plugintype',
|
||||
@@ -321,7 +321,7 @@ class helper_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function change_default_preset_provider(): array {
|
||||
public static function change_default_preset_provider(): array {
|
||||
return [
|
||||
'Starter preset' => [
|
||||
'preset' => 'starter',
|
||||
@@ -364,7 +364,7 @@ class helper_test extends \advanced_testcase {
|
||||
'preset' => 'unexisting',
|
||||
],
|
||||
'Valid XML file' => [
|
||||
'preset' => __DIR__ . '/fixtures/import_settings_plugins.xml',
|
||||
'preset' => self::get_fixture_path(__NAMESPACE__, 'import_settings_plugins.xml'),
|
||||
'settings' => [
|
||||
'allowemojipicker' => 1,
|
||||
'enableportfolios' => 1,
|
||||
@@ -377,7 +377,7 @@ class helper_test extends \advanced_testcase {
|
||||
],
|
||||
],
|
||||
'Invalid XML file' => [
|
||||
'preset' => __DIR__ . '/fixtures/invalid_xml_file.xml',
|
||||
'preset' => self::get_fixture_path(__NAMESPACE__, 'invalid_xml_file.xml'),
|
||||
],
|
||||
'Unexisting XML file' => [
|
||||
'preset' => __DIR__ . '/fixtures/unexisting.xml',
|
||||
|
||||
@@ -72,7 +72,7 @@ class adminpresets_admin_setting_bloglevel_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function save_value_provider(): array {
|
||||
public static function save_value_provider(): array {
|
||||
return [
|
||||
'Save the bloglevel and set blog_menu block visibility to true' => [
|
||||
'setttingvalue' => BLOG_USER_LEVEL,
|
||||
|
||||
@@ -66,7 +66,7 @@ class adminpresets_admin_setting_sitesettext_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function save_value_provider(): array {
|
||||
public static function save_value_provider(): array {
|
||||
return [
|
||||
'Fullname: different value' => [
|
||||
'settingname' => 'fullname',
|
||||
|
||||
@@ -77,7 +77,7 @@ class adminpresets_setting_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function save_value_provider(): array {
|
||||
public static function save_value_provider(): array {
|
||||
return [
|
||||
'Core setting with the same value is not saved' => [
|
||||
'category' => 'optionalsubsystems',
|
||||
@@ -167,7 +167,7 @@ class adminpresets_setting_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function save_attributes_values_provider(): array {
|
||||
public static function save_attributes_values_provider(): array {
|
||||
return [
|
||||
'Plugin setting with the same value is not saved' => [
|
||||
'category' => 'modsettinglesson',
|
||||
|
||||
@@ -367,7 +367,7 @@ class manager_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function export_preset_provider(): array {
|
||||
public static function export_preset_provider(): array {
|
||||
return [
|
||||
'Export settings and plugins, excluding sensible' => [
|
||||
'includesensible' => false,
|
||||
@@ -530,26 +530,32 @@ class manager_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function import_preset_provider(): array {
|
||||
public static function import_preset_provider(): array {
|
||||
return [
|
||||
'Import settings from an empty file' => [
|
||||
'filecontents' => '',
|
||||
'expectedpreset' => false,
|
||||
],
|
||||
'Import settings and plugins from a valid XML file' => [
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_settings_plugins.xml'),
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'import_settings_plugins.xml')
|
||||
),
|
||||
'expectedpreset' => true,
|
||||
'expectedsettings' => true,
|
||||
'expectedplugins' => true,
|
||||
],
|
||||
'Import only settings from a valid XML file' => [
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_settings.xml'),
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'import_settings.xml')
|
||||
),
|
||||
'expectedpreset' => true,
|
||||
'expectedsettings' => true,
|
||||
'expectedplugins' => false,
|
||||
],
|
||||
'Import settings and plugins from a valid XML file with Starter name, which will be marked as non-core' => [
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_starter_name.xml'),
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'import_starter_name.xml')
|
||||
),
|
||||
'expectedpreset' => true,
|
||||
'expectedsettings' => true,
|
||||
'expectedplugins' => true,
|
||||
@@ -558,7 +564,9 @@ class manager_test extends \advanced_testcase {
|
||||
'expectedpresetname' => 'Starter',
|
||||
],
|
||||
'Import settings from an invalid XML file' => [
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/invalid_xml_file.xml'),
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'invalid_xml_file.xml')
|
||||
),
|
||||
'expectedpreset' => false,
|
||||
'expectedsettings' => false,
|
||||
'expectedplugins' => false,
|
||||
@@ -566,20 +574,26 @@ class manager_test extends \advanced_testcase {
|
||||
'expectedexception' => \Exception::class,
|
||||
],
|
||||
'Import unexisting settings category' => [
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/unexisting_category.xml'),
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'unexisting_category.xml')
|
||||
),
|
||||
'expectedpreset' => false,
|
||||
'expectedsettings' => false,
|
||||
'expectedplugins' => false,
|
||||
],
|
||||
'Import unexisting setting' => [
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/unexisting_setting.xml'),
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'unexisting_setting.xml')
|
||||
),
|
||||
'expectedpreset' => false,
|
||||
'expectedsettings' => false,
|
||||
'expectedplugins' => false,
|
||||
'expecteddebugging' => true,
|
||||
],
|
||||
'Import valid settings with one unexisting setting too' => [
|
||||
'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_settings_with_unexisting_setting.xml'),
|
||||
'filecontents' => file_get_contents(
|
||||
filename: self::get_fixture_path(__NAMESPACE__, 'import_settings_with_unexisting_setting.xml'),
|
||||
),
|
||||
'expectedpreset' => true,
|
||||
'expectedsettings' => false,
|
||||
'expectedplugins' => false,
|
||||
|
||||
+2
-2
@@ -874,8 +874,8 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
protected function mobile_configuration_warning($mobileconfigured) {
|
||||
$output = '';
|
||||
if (!$mobileconfigured) {
|
||||
$settingslink = new moodle_url('/admin/settings.php', ['section' => 'mobilesettings']);
|
||||
$configurebutton = $this->single_button($settingslink, get_string('enablemobilewebservice', 'admin'));
|
||||
$settingslink = new moodle_url('/admin/search.php', ['query' => 'enablemobilewebservice']);
|
||||
$configurebutton = $this->single_button($settingslink, get_string('enablemobilewebservice', 'admin'), 'get');
|
||||
$output .= $this->warning(get_string('mobilenotconfiguredwarning', 'admin') . ' ' . $configurebutton);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ class preset_test extends \advanced_testcase {
|
||||
public function test_mixed_levels(): void {
|
||||
// The problem here is that we cannot guarantee plugin contexts
|
||||
// have unique short names, so we have to also support level numbers.
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/mixed_levels.xml');
|
||||
$xml = file_get_contents(self::get_fixture_path(__NAMESPACE__, 'mixed_levels.xml'));
|
||||
$this->assertTrue(\core_role_preset::is_valid_preset($xml));
|
||||
|
||||
$preset = \core_role_preset::parse_preset($xml);
|
||||
|
||||
@@ -420,6 +420,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
new lang_string('generalgroups', 'backup'), new lang_string('configgeneralgroups', 'backup'),
|
||||
array('value' => 1, 'locked' => 0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_competencies', new lang_string('generalcompetencies','backup'), new lang_string('configgeneralcompetencies','backup'), array('value'=>1, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock(
|
||||
'backup/backup_general_customfield',
|
||||
new lang_string('generalcustomfield', 'backup'),
|
||||
new lang_string('configgeneralcustomfield', 'backup'),
|
||||
['value' => 1, 'locked' => 0],
|
||||
));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_contentbankcontent',
|
||||
new lang_string('generalcontentbankcontent', 'backup'),
|
||||
new lang_string('configgeneralcontentbankcontent', 'backup'),
|
||||
@@ -431,7 +437,6 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
['value' => 1, 'locked' => 0])
|
||||
);
|
||||
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_legacyfiles',
|
||||
new lang_string('generallegacyfiles', 'backup'),
|
||||
new lang_string('configlegacyfiles', 'backup'), array('value' => 1, 'locked' => 0)));
|
||||
@@ -460,6 +465,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
new lang_string('generalgroups', 'backup'), new lang_string('configgeneralgroups', 'backup'),
|
||||
array('value' => 1, 'locked' => 0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_import_competencies', new lang_string('generalcompetencies','backup'), new lang_string('configgeneralcompetencies','backup'), array('value'=>1, 'locked'=>0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock(
|
||||
'backup/backup_import_customfield',
|
||||
new lang_string('generalcustomfield', 'backup'),
|
||||
new lang_string('configgeneralcustomfield', 'backup'),
|
||||
['value' => 1, 'locked' => 0],
|
||||
));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock(
|
||||
'backup/backup_import_contentbankcontent',
|
||||
new lang_string('generalcontentbankcontent', 'backup'),
|
||||
@@ -589,6 +600,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_groups', new lang_string('generalgroups', 'backup'),
|
||||
new lang_string('configgeneralgroups', 'backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_competencies', new lang_string('generalcompetencies','backup'), new lang_string('configgeneralcompetencies','backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox(
|
||||
'backup/backup_auto_customfield',
|
||||
new lang_string('generalcustomfield', 'backup'),
|
||||
new lang_string('configgeneralcustomfield', 'backup'),
|
||||
1,
|
||||
));
|
||||
$temp->add(new admin_setting_configcheckbox(
|
||||
'backup/backup_auto_contentbankcontent',
|
||||
new lang_string('generalcontentbankcontent', 'backup'),
|
||||
@@ -668,6 +685,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_competencies',
|
||||
new lang_string('generalcompetencies', 'backup'),
|
||||
new lang_string('configrestorecompetencies', 'backup'), array('value' => 1, 'locked' => 0)));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock(
|
||||
'restore/restore_general_customfield',
|
||||
new lang_string('generalcustomfield', 'backup'),
|
||||
new lang_string('configrestorecustomfield', 'backup'),
|
||||
['value' => 1, 'locked' => 0],
|
||||
));
|
||||
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_contentbankcontent',
|
||||
new lang_string('generalcontentbankcontent', 'backup'),
|
||||
new lang_string('configrestorecontentbankcontent', 'backup'), array('value' => 1, 'locked' => 0)));
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ class set_block_protection_test extends \externallib_advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function execute_provider(): array {
|
||||
public static function execute_provider(): array {
|
||||
return [
|
||||
[
|
||||
'block_login',
|
||||
|
||||
+2
-2
@@ -72,7 +72,7 @@ class set_plugin_order_test extends \externallib_advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function execute_editor_provider(): array {
|
||||
public static function execute_editor_provider(): array {
|
||||
$pluginmanager = \core_plugin_manager::instance();
|
||||
$allplugins = array_keys($pluginmanager->get_plugins_of_type('editor'));
|
||||
|
||||
@@ -142,7 +142,7 @@ class set_plugin_order_test extends \externallib_advanced_testcase {
|
||||
$this->assertIsArray(set_plugin_order::execute($plugin, 1));
|
||||
}
|
||||
|
||||
public function execute_non_orderable_provider(): array {
|
||||
public static function execute_non_orderable_provider(): array {
|
||||
return [
|
||||
// Activities do not support ordering.
|
||||
['mod_assign'],
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ class set_plugin_state_test extends \externallib_advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function execute_standard_provider(): array {
|
||||
public static function execute_standard_provider(): array {
|
||||
$generatetestsfor = function (string $plugin): array {
|
||||
return [
|
||||
[
|
||||
|
||||
@@ -110,7 +110,7 @@ class task_logs_test extends core_reportbuilder_testcase {
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function datasource_filters_provider(): array {
|
||||
public static function datasource_filters_provider(): array {
|
||||
return [
|
||||
'Filter name' => ['task_log:name', [
|
||||
'task_log:name_values' => [send_schedules::class],
|
||||
|
||||
@@ -5,16 +5,18 @@ Feature: I can download a preset
|
||||
| name |
|
||||
| Custom preset |
|
||||
|
||||
@javascript
|
||||
Scenario: Custom preset settings can be downloaded
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Site admin presets" in site administration
|
||||
When I open the action menu in "Custom preset" "table_row"
|
||||
Then following "Download" "link" in the "Custom preset" "table_row" should download between "0" and "5000" bytes
|
||||
Then following "Download" in the "Custom preset" "table_row" should download a file that:
|
||||
| Has mimetype | text/xml |
|
||||
| Contains text in xml element | Custom preset |
|
||||
|
||||
@javascript
|
||||
Scenario: Core preset settings can be downloaded
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Site admin presets" in site administration
|
||||
When I open the action menu in "Starter" "table_row"
|
||||
Then following "Download" "link" in the "Starter" "table_row" should download between "0" and "5000" bytes
|
||||
Then following "Download" in the "Starter" "table_row" should download a file that:
|
||||
| Has mimetype | text/xml |
|
||||
| Contains text in xml element | Starter |
|
||||
|
||||
@@ -70,7 +70,7 @@ class base_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function log_provider(): array {
|
||||
public static function log_provider(): array {
|
||||
return [
|
||||
// Action = base.
|
||||
'action=base and mode = show' => [
|
||||
|
||||
@@ -156,7 +156,7 @@ class export_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function export_execute_provider(): array {
|
||||
public static function export_execute_provider(): array {
|
||||
return [
|
||||
'Export settings and plugins, excluding sensible' => [
|
||||
'includesensible' => false,
|
||||
|
||||
@@ -190,7 +190,7 @@ class import_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function import_execute_provider(): array {
|
||||
public static function import_execute_provider(): array {
|
||||
$fixturesfolder = __DIR__ . '/../../../../../presets/tests/fixtures/';
|
||||
|
||||
return [
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
@tool @tool_behat
|
||||
Feature: Frozen clock in Behat
|
||||
In order to write tests that depend on the current system time
|
||||
As a test writer
|
||||
I need to set the time using a Behat step
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | name | idnumber | externalurl |
|
||||
| url | C1 | Fixture | url1 | #wwwroot#/admin/tool/behat/tests/fixtures/core/showtime.php |
|
||||
| forum | C1 | TestForum | forum1 | |
|
||||
|
||||
Scenario: Time has been frozen
|
||||
# Set up 2 forum discussions at different times. This tests the clock in the Behat CLI process.
|
||||
Given the time is frozen at "2024-03-01 12:34:56"
|
||||
And the following "mod_forum > discussions" exist:
|
||||
| user | forum | name | message |
|
||||
| admin | forum1 | Subject1 | Message1 |
|
||||
And the time is frozen at "2024-08-01 12:34:56"
|
||||
And the following "mod_forum > discussions" exist:
|
||||
| user | forum | name | message |
|
||||
| admin | forum1 | Subject2 | Message2 |
|
||||
When I am on the "TestForum" "forum activity" page logged in as admin
|
||||
Then I should see "1 Mar 2024" in the "Subject1" "table_row"
|
||||
And I should see "1 Aug 2024" in the "Subject2" "table_row"
|
||||
# Also view time on the fixture page. This tests the clock for Behat web server requests.
|
||||
And I am on the "Fixture" "url activity" page
|
||||
And I should see "Behat time is not the same as real time"
|
||||
# This Unix time corresponds to 12:34:56 in Perth time zone.
|
||||
And I should see "Unix time 1722486896"
|
||||
And I should see "Date-time 2024-08-01 12:34:56"
|
||||
|
||||
# This scenario is second, to verify that the clock automatically goes back to normal after test.
|
||||
Scenario: Time is normal
|
||||
Given the following "mod_forum > discussions" exist:
|
||||
| user | forum | name | message |
|
||||
| admin | forum1 | Subject1 | Message1 |
|
||||
When I am on the "TestForum" "forum activity" page logged in as admin
|
||||
# The time should be the real current time, not the frozen time.
|
||||
Then I should see "## today ##%d %b %Y##" in the "Subject1" "table_row"
|
||||
And I am on the "Fixture" "url activity" page
|
||||
And I should see "Behat time is the same as real time"
|
||||
|
||||
Scenario: Time is frozen and then unfrozen
|
||||
Given the time is frozen at "2024-03-01 12:34:56"
|
||||
And the following "mod_forum > discussions" exist:
|
||||
| user | forum | name | message |
|
||||
| admin | forum1 | Subject1 | Message1 |
|
||||
And the time is no longer frozen
|
||||
And the following "mod_forum > discussions" exist:
|
||||
| user | forum | name | message |
|
||||
| admin | forum1 | Subject2 | Message2 |
|
||||
When I am on the "TestForum" "forum activity" page logged in as admin
|
||||
Then I should see "1 Mar 2024" in the "Subject1" "table_row"
|
||||
# The time should be the real current time, not the frozen time for this entry.
|
||||
And I should see "## today ##%d %b %Y##" in the "Subject2" "table_row"
|
||||
And I am on the "Fixture" "url activity" page
|
||||
And I should see "Behat time is the same as real time"
|
||||
@@ -25,7 +25,7 @@ Feature: Confirm that we can open multiple browser tabs
|
||||
And I open a tab named "CourseViewer4" on the "My courses" page
|
||||
|
||||
# Switch between all the tabs and confirm their different contents.
|
||||
Then I should see "You're not enrolled in any course"
|
||||
Then I should see "You're not enrolled in any courses."
|
||||
And I switch to "CourseViewer2" tab
|
||||
And "Course 3" "heading" should exist
|
||||
And I switch to "CourseViewer1" tab
|
||||
|
||||
@@ -53,7 +53,7 @@ class behat_form_text_test extends \basic_testcase {
|
||||
*
|
||||
* @return array of value and expectation pairs to be tested.
|
||||
*/
|
||||
public function provider_test_set_get_value() {
|
||||
public static function provider_test_set_get_value(): array {
|
||||
return [
|
||||
'null' => [null, null],
|
||||
'int' => [3, 3],
|
||||
@@ -68,7 +68,7 @@ class behat_form_text_test extends \basic_testcase {
|
||||
*
|
||||
* @param mixed $value value to be set.
|
||||
* @param mixed $expectation value to be checked.
|
||||
* @dataProvider provider_test_set_get_value()
|
||||
* @dataProvider provider_test_set_get_value
|
||||
*/
|
||||
public function test_set_get_value($value, $expectation): void {
|
||||
$session = $this->createMock(Session::class);
|
||||
@@ -85,7 +85,7 @@ class behat_form_text_test extends \basic_testcase {
|
||||
*
|
||||
* @return array of decsep, value, match and result pairs to be tested.
|
||||
*/
|
||||
public function provider_test_matches() {
|
||||
public static function provider_test_matches(): array {
|
||||
return [
|
||||
'lazy true' => ['.', 'hello', 'hello', true],
|
||||
'lazy false' => ['.', 'hello', 'bye', false],
|
||||
@@ -113,7 +113,7 @@ class behat_form_text_test extends \basic_testcase {
|
||||
* @param mixed $value value to be set.
|
||||
* @param mixed $match value to be matched.
|
||||
* @param bool $result expected return status of the function.
|
||||
* @dataProvider provider_test_matches()
|
||||
* @dataProvider provider_test_matches
|
||||
*/
|
||||
public function test_matches($decsep, $value, $match, $result): void {
|
||||
global $CFG;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Fixture to show the current server time using \core\clock.
|
||||
*
|
||||
* @package tool_behat
|
||||
* @copyright 2024 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
// phpcs:disable moodle.Files.RequireLogin.Missing
|
||||
require(__DIR__ . '/../../../../../../config.php');
|
||||
|
||||
defined('BEHAT_SITE_RUNNING') || die('Behat fixture');
|
||||
|
||||
$PAGE->set_context(\context_system::instance());
|
||||
$PAGE->set_url(new \moodle_url('/admin/tool/behat/tests/fixtures/core/showtime.php'));
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
$clock = \core\di::get(\core\clock::class);
|
||||
$dt = $clock->now();
|
||||
$realbefore = time();
|
||||
$time = $clock->time();
|
||||
$realafter = time();
|
||||
|
||||
echo html_writer::div('Unix time ' . $time);
|
||||
echo html_writer::div('Date-time ' . $dt->format('Y-m-d H:i:s'));
|
||||
|
||||
echo html_writer::div('TZ ' . $dt->getTimezone()->getName());
|
||||
|
||||
if ($time >= $realbefore && $time <= $realafter) {
|
||||
echo html_writer::div('Behat time is the same as real time');
|
||||
} else {
|
||||
echo html_writer::div('Behat time is not the same as real time');
|
||||
}
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
@@ -107,11 +107,11 @@ class manager_util_test extends \advanced_testcase {
|
||||
*/
|
||||
private function get_behat_config_util($behatconfigutil, $notheme = false) {
|
||||
// Create a map of arguments to return values.
|
||||
$map = array(
|
||||
array('withfeatures', __DIR__.'/fixtures/theme/withfeatures'),
|
||||
array('nofeatures', __DIR__.'/fixtures/theme/nofeatures'),
|
||||
array('defaulttheme', __DIR__.'/fixtures/theme/defaulttheme'),
|
||||
);
|
||||
$map = [
|
||||
['withfeatures', self::get_fixture_path(__NAMESPACE__, 'theme/withfeatures')],
|
||||
['nofeatures', self::get_fixture_path(__NAMESPACE__, 'theme/nofeatures')],
|
||||
['defaulttheme', self::get_fixture_path(__NAMESPACE__, 'theme/defaulttheme')],
|
||||
];
|
||||
// List of themes is const for test.
|
||||
if ($notheme) {
|
||||
$themelist = array('defaulttheme');
|
||||
|
||||
+3
-3
@@ -410,13 +410,13 @@ class brickfield_accessibility_color_test extends brickfield_accessibility_test
|
||||
$pos3 = stripos($fontsize, 'px');
|
||||
if ($pos1 !== false) {
|
||||
$rem = substr($fontsize, 0, -3);
|
||||
$newfontsize = $newfontsize * $rem;
|
||||
$newfontsize = is_numeric($rem) ? $newfontsize * $rem : $newfontsize;
|
||||
} else if ($pos2 !== false) {
|
||||
$em = substr($fontsize, 0, -2);
|
||||
$newfontsize = $newfontsize * $em;
|
||||
$newfontsize = is_numeric($em) ? $newfontsize * $em : $newfontsize;
|
||||
} else if ($pos3 !== false) {
|
||||
$px = substr($fontsize, 0, -2);
|
||||
$newfontsize = 0.75 * $px;
|
||||
$newfontsize = is_numeric($px) ? 0.75 * $px : $newfontsize;
|
||||
} else if (in_array($fontsize, array_keys($this->fontsizenames))) {
|
||||
$newfontsize = $this->fontsizenames[$fontsize];
|
||||
} else {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
namespace tool_brickfield\local\htmlchecker\common\checks;
|
||||
|
||||
use tool_brickfield\local\htmlchecker\common\brickfield_accessibility_tag_test;
|
||||
use tool_brickfield\local\htmlchecker\common\brickfield_accessibility_test;
|
||||
|
||||
/**
|
||||
* Brickfield accessibility HTML checker library.
|
||||
@@ -28,11 +28,25 @@ use tool_brickfield\local\htmlchecker\common\brickfield_accessibility_tag_test;
|
||||
* @copyright 2020 onward: Brickfield Education Labs, www.brickfield.ie
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class i_is_not_used extends brickfield_accessibility_tag_test {
|
||||
class i_is_not_used extends brickfield_accessibility_test {
|
||||
|
||||
/** @var int The default severity code for this test. */
|
||||
public $defaultseverity = \tool_brickfield\local\htmlchecker\brickfield_accessibility::BA_TEST_SEVERE;
|
||||
|
||||
/** @var string The tag this test will fire on. */
|
||||
public $tag = 'i';
|
||||
|
||||
/**
|
||||
* Check for any i elements and flag them as errors
|
||||
* while allowing font awesome icons to be used.
|
||||
*/
|
||||
public function check(): void {
|
||||
foreach ($this->get_all_elements('i') as $element) {
|
||||
// Ensure this is not a font awesome icon with aria-hidden.
|
||||
if (str_contains($element->getAttribute('class'), 'fa-') && $element->getAttribute('aria-hidden') === 'true') {
|
||||
continue;
|
||||
}
|
||||
$this->add_report($element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -46,7 +46,7 @@ class table_data_should_have_th extends brickfield_accessibility_table_test {
|
||||
foreach ($tr->childNodes as $th) {
|
||||
if ($this->property_is_equal($th, 'tagName', 'th')) {
|
||||
break 3;
|
||||
} else {
|
||||
} else if ($th->nodeName != '#text') {
|
||||
$this->add_report($table);
|
||||
break 3;
|
||||
}
|
||||
@@ -57,7 +57,7 @@ class table_data_should_have_th extends brickfield_accessibility_table_test {
|
||||
foreach ($child->childNodes as $th) {
|
||||
if ($this->property_is_equal($th, 'tagName', 'th')) {
|
||||
break 2;
|
||||
} else {
|
||||
} else if ($th->nodeName != '#text') {
|
||||
$this->add_report($table);
|
||||
break 2;
|
||||
}
|
||||
|
||||
+29
-1
@@ -32,7 +32,7 @@ require_once('all_checks.php');
|
||||
* Class test_css_text_has_contrast_test
|
||||
* @covers \tool_brickfield\local\htmlchecker\brickfield_accessibility
|
||||
*/
|
||||
class css_text_has_contrast_test extends all_checks {
|
||||
final class css_text_has_contrast_test extends all_checks {
|
||||
/** @var string The check type. */
|
||||
protected $checktype = 'css_text_has_contrast';
|
||||
|
||||
@@ -227,6 +227,18 @@ EOD;
|
||||
This is contrasty enough.</p></body>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML with calculated size colour values. */
|
||||
private $calculatedfail = <<<EOD
|
||||
<body><p style="color:#EF0000; background-color:white; font-size: calc(0.90375rem + 0.045vw)">
|
||||
This is not contrasty enough.</p></body>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML with calculated size colour values. */
|
||||
private $calculatedpass = <<<EOD
|
||||
<body><p style="color:#E60000; background-color:white; font-size: calc(0.90375rem + 0.045vw);">
|
||||
This is contrasty enough.</p></body>
|
||||
EOD;
|
||||
|
||||
/**
|
||||
* Test for the area assign intro
|
||||
*/
|
||||
@@ -458,4 +470,20 @@ EOD;
|
||||
$results = $this->get_checker_results($html);
|
||||
$this->assertEmpty($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for calculated (12pt) text with insufficient contrast of 4.49.
|
||||
*/
|
||||
public function test_check_for_calculated_fail(): void {
|
||||
$results = $this->get_checker_results($this->calculatedfail);
|
||||
$this->assertTrue($results[0]->element->tagName == 'p');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for calculated (12pt) text with sufficient contrast of 4.81.
|
||||
*/
|
||||
public function test_check_for_calculated_pass(): void {
|
||||
$results = $this->get_checker_results($this->calculatedpass);
|
||||
$this->assertEmpty($results);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ require_once('all_checks.php');
|
||||
|
||||
/**
|
||||
* Class i_is_not_used_testcase
|
||||
*
|
||||
* @covers \tool_brickfield\local\htmlchecker\common\checks\i_is_not_used
|
||||
*/
|
||||
class i_is_not_used_test extends all_checks {
|
||||
/** @var string Check type */
|
||||
@@ -71,4 +73,13 @@ EOD;
|
||||
$results = $this->get_checker_results($this->htmlpass);
|
||||
$this->assertEmpty($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for font awesome icon.
|
||||
*/
|
||||
public function test_fa_icon(): void {
|
||||
$html = '<div><i class="fa fa-user"></i><i>Hello there</i><i class="fa fa-address-book" aria-hidden="true"></i></div>';
|
||||
$results = $this->get_checker_results($html);
|
||||
$this->assertCount(2, $results);
|
||||
}
|
||||
}
|
||||
|
||||
+125
@@ -30,6 +30,8 @@ require_once('all_checks.php');
|
||||
|
||||
/**
|
||||
* Class table_data_should_have_th_test
|
||||
*
|
||||
* @covers \tool_brickfield\local\htmlchecker\common\checks\table_data_should_have_th
|
||||
*/
|
||||
class table_data_should_have_th_test extends all_checks {
|
||||
/** @var string Check type */
|
||||
@@ -113,6 +115,117 @@ EOD;
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML that should not get flagged. */
|
||||
private $htmlpass3 = <<<EOD
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Table should have at least one th - pass</title>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
This is table heading
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
This is a tables data
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML that should not get flagged. */
|
||||
private $htmlpass4 = <<<EOD
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Table should have at least one th - pass</title>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<th>
|
||||
This is table heading
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
This is a tables data
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML that should not get flagged. */
|
||||
private $htmlpass5 = <<<EOD
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Table should have at least one th - pass</title>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
This is table heading
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
This is a table heading in table data
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
This is a tables data
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
EOD;
|
||||
|
||||
/** @var string HTML that should not get flagged. */
|
||||
private $htmlpass6 = <<<EOD
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Table should have at least one th - pass</title>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
This is a table heading in table data
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
This is a tables data
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
EOD;
|
||||
/**
|
||||
* Test that th does not exist
|
||||
@@ -134,5 +247,17 @@ EOD;
|
||||
|
||||
$results = $this->get_checker_results($this->htmlpass2);
|
||||
$this->assertEmpty($results);
|
||||
|
||||
$results = $this->get_checker_results($this->htmlpass3);
|
||||
$this->assertEmpty($results);
|
||||
|
||||
$results = $this->get_checker_results($this->htmlpass4);
|
||||
$this->assertEmpty($results);
|
||||
|
||||
$results = $this->get_checker_results($this->htmlpass5);
|
||||
$this->assertEmpty($results);
|
||||
|
||||
$results = $this->get_checker_results($this->htmlpass6);
|
||||
$this->assertEmpty($results);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ use tool_brickfield\local\tool\tool;
|
||||
class tool_test extends \advanced_testcase {
|
||||
|
||||
/** @var string base 64 image */
|
||||
protected $base64img = <<<EOF
|
||||
protected static string $base64img = <<<EOF
|
||||
<img src="data:image/gif;base64,R0lGODlhPQBEAPeoAJosM//AwO/AwHVYZ/z595kzAP/s7P+goOXMv8+fhw/v739/f+8PD98fH/
|
||||
8mJl+fn/9ZWb8/PzWlwv///6wWGbImAPgTEMImIN9gUFCEm/gDALULDN8PAD6atYdCTX9gUNKlj8wZAKUsAOzZz+UMAOsJAP/Z2ccMDA8PD/95eX5N
|
||||
WvsJCOVNQPtfX/8zM8+QePLl38MGBr8JCP+zs9myn/8GBqwpAP/GxgwJCPny78lzYLgjAJ8vAP9fX/+MjMUcAN8zM/9wcM8ZGcATEL+QePdZWf/29u
|
||||
@@ -118,11 +118,11 @@ EOF;
|
||||
* Base64 image provider.
|
||||
* @return array
|
||||
*/
|
||||
public function base64_img_provider(): array {
|
||||
public static function base64_img_provider(): array {
|
||||
$img = '<img src="myimage.jpg" />';
|
||||
return [
|
||||
'Image tag alone (base64)' => [
|
||||
$this->base64img,
|
||||
self::$base64img,
|
||||
true,
|
||||
],
|
||||
'Image tag alone (link)' => [
|
||||
@@ -130,7 +130,7 @@ EOF;
|
||||
false,
|
||||
],
|
||||
'Image tag in string (base64)' => [
|
||||
"This is my image {$this->base64img}.",
|
||||
"This is my image " . self::$base64img,
|
||||
true,
|
||||
],
|
||||
'Image tag in string (link)' => [
|
||||
@@ -162,7 +162,7 @@ EOF;
|
||||
}
|
||||
|
||||
public function test_truncate_base64(): void {
|
||||
$truncated = tool::truncate_base64($this->base64img);
|
||||
$truncated = tool::truncate_base64(self::$base64img);
|
||||
$this->assertStringContainsString('<img src="data:image/gif;base64..."', $truncated);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,11 +63,9 @@ class assign_role_cohort extends moodleform {
|
||||
$mform->addElement('select', 'roleid', get_string('selectrole', 'tool_cohortroles'), $options);
|
||||
$mform->addRule('roleid', null, 'required');
|
||||
|
||||
$context = context_system::instance();
|
||||
$options = array(
|
||||
'multiple' => true,
|
||||
'data-contextid' => $context->id,
|
||||
'data-includes' => 'all'
|
||||
'includes' => 'all',
|
||||
);
|
||||
$mform->addElement('cohort', 'cohortids', get_string('selectcohorts', 'tool_cohortroles'), $options);
|
||||
$mform->addRule('cohortids', null, 'required');
|
||||
|
||||
@@ -60,7 +60,7 @@ class langstring_test extends advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fix_syntax_data(): array {
|
||||
public static function fix_syntax_data(): array {
|
||||
return [
|
||||
// Syntax sanity v1 strings.
|
||||
[
|
||||
|
||||
@@ -79,7 +79,7 @@ class phpparser_test extends advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parse_provider(): array {
|
||||
public static function parse_provider(): array {
|
||||
return [
|
||||
'Invalid PHP code' => [
|
||||
'No PHP code', [], false
|
||||
|
||||
@@ -633,7 +633,7 @@ class api_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function data_request_creation_provider() {
|
||||
public static function data_request_creation_provider(): array {
|
||||
return [
|
||||
'Export request by user, automatic approval off' => [
|
||||
false, api::DATAREQUEST_TYPE_EXPORT, 'automaticdataexportapproval', false, 0,
|
||||
@@ -815,7 +815,7 @@ class api_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_data_requests_provider() {
|
||||
public static function get_data_requests_provider(): array {
|
||||
$completeonly = [api::DATAREQUEST_STATUS_COMPLETE, api::DATAREQUEST_STATUS_DOWNLOAD_READY, api::DATAREQUEST_STATUS_DELETED];
|
||||
$completeandcancelled = array_merge($completeonly, [api::DATAREQUEST_STATUS_CANCELLED]);
|
||||
|
||||
@@ -1000,7 +1000,7 @@ class api_test extends \advanced_testcase {
|
||||
/**
|
||||
* Data provider for test_has_ongoing_request.
|
||||
*/
|
||||
public function status_provider() {
|
||||
public static function status_provider(): array {
|
||||
return [
|
||||
[api::DATAREQUEST_STATUS_AWAITING_APPROVAL, true],
|
||||
[api::DATAREQUEST_STATUS_APPROVED, true],
|
||||
@@ -1090,7 +1090,7 @@ class api_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function notify_dpo_provider() {
|
||||
public static function notify_dpo_provider(): array {
|
||||
return [
|
||||
[false, api::DATAREQUEST_TYPE_EXPORT, 'requesttypeexport', 'Export my user data'],
|
||||
[false, api::DATAREQUEST_TYPE_DELETE, 'requesttypedelete', 'Delete my user data'],
|
||||
@@ -1442,7 +1442,7 @@ class api_test extends \advanced_testcase {
|
||||
/**
|
||||
* Data provider for invalid contextlevel fetchers.
|
||||
*/
|
||||
public function invalid_effective_contextlevel_provider() {
|
||||
public static function invalid_effective_contextlevel_provider(): array {
|
||||
return [
|
||||
[CONTEXT_COURSECAT],
|
||||
[CONTEXT_COURSE],
|
||||
@@ -2002,7 +2002,7 @@ class api_test extends \advanced_testcase {
|
||||
/**
|
||||
* Data provider for \tool_dataprivacy_api_testcase::test_set_context_defaults
|
||||
*/
|
||||
public function set_context_defaults_provider() {
|
||||
public static function set_context_defaults_provider(): array {
|
||||
$contextlevels = [
|
||||
[CONTEXT_COURSECAT],
|
||||
[CONTEXT_COURSE],
|
||||
@@ -2477,7 +2477,7 @@ class api_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function queue_data_request_task_provider() {
|
||||
public static function queue_data_request_task_provider(): array {
|
||||
return [
|
||||
'With user ID provided' => [true],
|
||||
'Without user ID provided' => [false],
|
||||
@@ -2514,7 +2514,7 @@ class api_test extends \advanced_testcase {
|
||||
/**
|
||||
* Data provider for test_is_automatic_request_approval_on().
|
||||
*/
|
||||
public function automatic_request_approval_setting_provider() {
|
||||
public static function automatic_request_approval_setting_provider(): array {
|
||||
return [
|
||||
'Data export, not set' => [
|
||||
'automaticdataexportapproval', api::DATAREQUEST_TYPE_EXPORT, null, false
|
||||
|
||||
@@ -55,7 +55,8 @@ Feature: Data export from the privacy API
|
||||
And I reload the page
|
||||
And I should see "Download ready" in the "Victim User 1" "table_row"
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And following "Download" should download between "1" and "200000" bytes
|
||||
And following "Download" should download a file that:
|
||||
| Contains file in zip | index.html |
|
||||
And the following config values are set as admin:
|
||||
| privacyrequestexpiry | 1 | tool_dataprivacy |
|
||||
And I wait "1" seconds
|
||||
@@ -90,7 +91,8 @@ Feature: Data export from the privacy API
|
||||
And I reload the page
|
||||
And I should see "Download ready" in the "Export all of my personal data" "table_row"
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And following "Download" should download between "1" and "200000" bytes
|
||||
And following "Download" should download a file that:
|
||||
| Contains file in zip | index.html |
|
||||
|
||||
And the following config values are set as admin:
|
||||
| privacyrequestexpiry | 1 | tool_dataprivacy |
|
||||
@@ -128,7 +130,8 @@ Feature: Data export from the privacy API
|
||||
And I reload the page
|
||||
And I should see "Download ready" in the "Victim User 1" "table_row"
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And following "Download" should download between "1" and "200000" bytes
|
||||
And following "Download" should download a file that:
|
||||
| Contains file in zip | index.html |
|
||||
|
||||
And the following config values are set as admin:
|
||||
| privacyrequestexpiry | 1 | tool_dataprivacy |
|
||||
@@ -187,7 +190,8 @@ Feature: Data export from the privacy API
|
||||
And I reload the page
|
||||
And I should see "Download ready" in the "Victim User 1" "table_row"
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And following "Download" should download between "1" and "172000" bytes
|
||||
And following "Download" should download a file that:
|
||||
| Contains file in zip | index.html |
|
||||
And the following config values are set as admin:
|
||||
| privacyrequestexpiry | 1 | tool_dataprivacy |
|
||||
And I wait "1" seconds
|
||||
@@ -231,7 +235,8 @@ Feature: Data export from the privacy API
|
||||
And I reload the page
|
||||
And I should see "Download ready" in the "Victim User 1" "table_row"
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And following "Download" should download between "1" and "180000" bytes
|
||||
And following "Download" should download a file that:
|
||||
| Contains file in zip | index.html |
|
||||
|
||||
@javascript
|
||||
Scenario: Filter before export data for a user and download it in the view request action
|
||||
@@ -264,4 +269,5 @@ Feature: Data export from the privacy API
|
||||
And I reload the page
|
||||
And I should see "Download ready" in the "Victim User 1" "table_row"
|
||||
And I open the action menu in "Victim User 1" "table_row"
|
||||
And following "Download" should download between "1" and "180000" bytes
|
||||
And following "Download" should download a file that:
|
||||
| Contains file in zip | index.html |
|
||||
|
||||
@@ -35,7 +35,7 @@ class data_request_test extends data_privacy_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function status_state_provider(): array {
|
||||
public static function status_state_provider(): array {
|
||||
return [
|
||||
[
|
||||
'state' => api::DATAREQUEST_STATUS_PENDING,
|
||||
@@ -138,9 +138,9 @@ class data_request_test extends data_privacy_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function non_resettable_provider(): array {
|
||||
public static function non_resettable_provider(): array {
|
||||
$states = [];
|
||||
foreach ($this->status_state_provider() as $thisstatus) {
|
||||
foreach (self::status_state_provider() as $thisstatus) {
|
||||
if (!$thisstatus['resettable']) {
|
||||
$states[] = $thisstatus;
|
||||
}
|
||||
|
||||
@@ -1370,12 +1370,20 @@ class expired_contexts_test extends \advanced_testcase {
|
||||
])
|
||||
->getMock();
|
||||
$mockprivacymanager->expects($this->atLeastOnce())->method('delete_data_for_user');
|
||||
$mockprivacymanager->expects($this->exactly(2))
|
||||
$deleteinvocations = $this->exactly(2);
|
||||
$mockprivacymanager->expects($deleteinvocations)
|
||||
->method('delete_data_for_all_users_in_context')
|
||||
->withConsecutive(
|
||||
[$blockcontext],
|
||||
[$usercontext]
|
||||
);
|
||||
->willReturnCallback(function ($context) use (
|
||||
$deleteinvocations,
|
||||
$blockcontext,
|
||||
$usercontext,
|
||||
): void {
|
||||
match (self::getInvocationCount($deleteinvocations)) {
|
||||
1 => $this->assertEquals($blockcontext, $context),
|
||||
2 => $this->assertEquals($usercontext, $context),
|
||||
default => $this->fail('Unexpected invocation count'),
|
||||
};
|
||||
});
|
||||
|
||||
$manager = $this->getMockBuilder(\tool_dataprivacy\expired_contexts_manager::class)
|
||||
->onlyMethods(['get_privacy_manager'])
|
||||
@@ -1588,12 +1596,20 @@ class expired_contexts_test extends \advanced_testcase {
|
||||
])
|
||||
->getMock();
|
||||
$mockprivacymanager->expects($this->atLeastOnce())->method('delete_data_for_user');
|
||||
$mockprivacymanager->expects($this->exactly(2))
|
||||
$deleteinvocations = $this->exactly(2);
|
||||
$mockprivacymanager->expects($deleteinvocations)
|
||||
->method('delete_data_for_all_users_in_context')
|
||||
->withConsecutive(
|
||||
[$blockcontext],
|
||||
[$usercontext]
|
||||
);
|
||||
->willReturnCallback(function ($context) use (
|
||||
$deleteinvocations,
|
||||
$blockcontext,
|
||||
$usercontext,
|
||||
): void {
|
||||
match (self::getInvocationCount($deleteinvocations)) {
|
||||
1 => $this->assertEquals($blockcontext, $context),
|
||||
2 => $this->assertEquals($usercontext, $context),
|
||||
default => $this->fail('Unexpected invocation count'),
|
||||
};
|
||||
});
|
||||
|
||||
$manager = $this->getMockBuilder(\tool_dataprivacy\expired_contexts_manager::class)
|
||||
->onlyMethods(['get_privacy_manager'])
|
||||
@@ -1641,12 +1657,20 @@ class expired_contexts_test extends \advanced_testcase {
|
||||
])
|
||||
->getMock();
|
||||
$mockprivacymanager->expects($this->atLeastOnce())->method('delete_data_for_user');
|
||||
$mockprivacymanager->expects($this->exactly(2))
|
||||
$deleteinvocations = $this->exactly(2);
|
||||
$mockprivacymanager->expects($deleteinvocations)
|
||||
->method('delete_data_for_all_users_in_context')
|
||||
->withConsecutive(
|
||||
[$blockcontext],
|
||||
[$usercontext]
|
||||
);
|
||||
->willReturnCallback(function ($context) use (
|
||||
$deleteinvocations,
|
||||
$blockcontext,
|
||||
$usercontext,
|
||||
): void {
|
||||
match (self::getInvocationCount($deleteinvocations)) {
|
||||
1 => $this->assertEquals($blockcontext, $context),
|
||||
2 => $this->assertEquals($usercontext, $context),
|
||||
default => $this->fail('Unexpected invocation count'),
|
||||
};
|
||||
});
|
||||
|
||||
$manager = $this->getMockBuilder(\tool_dataprivacy\expired_contexts_manager::class)
|
||||
->onlyMethods(['get_privacy_manager'])
|
||||
@@ -1860,12 +1884,20 @@ class expired_contexts_test extends \advanced_testcase {
|
||||
])
|
||||
->getMock();
|
||||
$mockprivacymanager->expects($this->never())->method('delete_data_for_user');
|
||||
$mockprivacymanager->expects($this->exactly(2))
|
||||
$deleteinvocations = $this->exactly(2);
|
||||
$mockprivacymanager->expects($deleteinvocations)
|
||||
->method('delete_data_for_all_users_in_context')
|
||||
->withConsecutive(
|
||||
[$forumcontext],
|
||||
[$coursecontext]
|
||||
);
|
||||
->willReturnCallback(function ($context) use (
|
||||
$deleteinvocations,
|
||||
$forumcontext,
|
||||
$coursecontext,
|
||||
): void {
|
||||
match (self::getInvocationCount($deleteinvocations)) {
|
||||
1 => $this->assertEquals($forumcontext, $context),
|
||||
2 => $this->assertEquals($coursecontext, $context),
|
||||
default => $this->fail('Unexpected invocation count'),
|
||||
};
|
||||
});
|
||||
|
||||
$manager = $this->getMockBuilder(\tool_dataprivacy\expired_contexts_manager::class)
|
||||
->onlyMethods(['get_privacy_manager'])
|
||||
@@ -1918,7 +1950,7 @@ class expired_contexts_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function can_process_deletion_provider(): array {
|
||||
public static function can_process_deletion_provider(): array {
|
||||
return [
|
||||
'Pending' => [
|
||||
expired_context::STATUS_EXPIRED,
|
||||
@@ -1956,7 +1988,7 @@ class expired_contexts_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function is_complete_provider(): array {
|
||||
public static function is_complete_provider(): array {
|
||||
return [
|
||||
'Pending' => [
|
||||
expired_context::STATUS_EXPIRED,
|
||||
@@ -1991,7 +2023,7 @@ class expired_contexts_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function is_fully_expired_provider(): array {
|
||||
public static function is_fully_expired_provider(): array {
|
||||
return [
|
||||
'Fully expired' => [
|
||||
[
|
||||
|
||||
+2
-2
@@ -580,7 +580,7 @@ class external_test extends externallib_advanced_testcase {
|
||||
/**
|
||||
* Data provider for \tool_dataprivacy_external_testcase::test_XX_options().
|
||||
*/
|
||||
public function get_options_provider() {
|
||||
public static function get_options_provider(): array {
|
||||
return [
|
||||
[false, false],
|
||||
[false, true],
|
||||
@@ -705,7 +705,7 @@ class external_test extends externallib_advanced_testcase {
|
||||
/**
|
||||
* Data provider for \tool_dataprivacy_external_testcase::get_activity_options().
|
||||
*/
|
||||
public function get_activity_options_provider() {
|
||||
public static function get_activity_options_provider(): array {
|
||||
return [
|
||||
[false, false, true],
|
||||
[false, true, true],
|
||||
|
||||
@@ -57,7 +57,7 @@ class filtered_userlist_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function apply_expired_contexts_filters_provider(): array {
|
||||
public static function apply_expired_contexts_filters_provider(): array {
|
||||
return [
|
||||
// Entire list should be preserved.
|
||||
'No overrides' => [
|
||||
|
||||
@@ -38,20 +38,20 @@ class httpsreplace_test extends \advanced_testcase {
|
||||
/**
|
||||
* Data provider for test_upgrade_http_links
|
||||
*/
|
||||
public function upgrade_http_links_provider() {
|
||||
public static function upgrade_http_links_provider(): array {
|
||||
global $CFG;
|
||||
// Get the http url, since the default test wwwroot is https.
|
||||
$wwwroothttp = preg_replace('/^https:/', 'http:', $CFG->wwwroot);
|
||||
return [
|
||||
"Test image from another site should be replaced" => [
|
||||
"content" => '<img src="' . $this->getExternalTestFileUrl('/test.jpg', false) . '">',
|
||||
"content" => '<img src="' . self::getExternalTestFileUrl('/test.jpg', false) . '">',
|
||||
"outputregex" => '/UPDATE/',
|
||||
"expectedcontent" => '<img src="' . $this->get_converted_http_link('/test.jpg') . '">',
|
||||
"expectedcontent" => '<img src="' . self::get_converted_http_link('/test.jpg') . '">',
|
||||
],
|
||||
"Test object from another site should be replaced" => [
|
||||
"content" => '<object data="' . $this->getExternalTestFileUrl('/test.swf', false) . '">',
|
||||
"content" => '<object data="' . self::getExternalTestFileUrl('/test.swf', false) . '">',
|
||||
"outputregex" => '/UPDATE/',
|
||||
"expectedcontent" => '<object data="' . $this->get_converted_http_link('/test.swf') . '">',
|
||||
"expectedcontent" => '<object data="' . self::get_converted_http_link('/test.swf') . '">',
|
||||
],
|
||||
"Test image from a site with international name should be replaced" => [
|
||||
"content" => '<img src="http://中国互联网络信息中心.中国/logosy/201706/W01.png">',
|
||||
@@ -79,9 +79,9 @@ class httpsreplace_test extends \advanced_testcase {
|
||||
"expectedcontent" => '<img src="https://anothersite.com?param=http://asdf.com">',
|
||||
],
|
||||
"Search for params should be case insensitive" => [
|
||||
"content" => '<object DATA="' . $this->getExternalTestFileUrl('/test.swf', false) . '">',
|
||||
"content" => '<object DATA="' . self::getExternalTestFileUrl('/test.swf', false) . '">',
|
||||
"outputregex" => '/UPDATE/',
|
||||
"expectedcontent" => '<object DATA="' . $this->get_converted_http_link('/test.swf') . '">',
|
||||
"expectedcontent" => '<object DATA="' . self::get_converted_http_link('/test.swf') . '">',
|
||||
],
|
||||
"URL should be case insensitive" => [
|
||||
"content" => '<object data="HTTP://some.site/path?query">',
|
||||
@@ -89,30 +89,30 @@ class httpsreplace_test extends \advanced_testcase {
|
||||
"expectedcontent" => '<object data="https://some.site/path?query">',
|
||||
],
|
||||
"More params should not interfere" => [
|
||||
"content" => '<img alt="A picture" src="' . $this->getExternalTestFileUrl('/test.png', false) .
|
||||
"content" => '<img alt="A picture" src="' . self::getExternalTestFileUrl('/test.png', false) .
|
||||
'" width="1”><p style="font-size: \'20px\'"></p>',
|
||||
"outputregex" => '/UPDATE/',
|
||||
"expectedcontent" => '<img alt="A picture" src="' . $this->get_converted_http_link('/test.png') .
|
||||
"expectedcontent" => '<img alt="A picture" src="' . self::get_converted_http_link('/test.png') .
|
||||
'" width="1”><p style="font-size: \'20px\'"></p>',
|
||||
],
|
||||
"Broken URL should not be changed" => [
|
||||
"content" => '<img src="broken.' . $this->getExternalTestFileUrl('/test.png', false) . '">',
|
||||
"content" => '<img src="broken.' . self::getExternalTestFileUrl('/test.png', false) . '">',
|
||||
"outputregex" => '/^$/',
|
||||
"expectedcontent" => '<img src="broken.' . $this->getExternalTestFileUrl('/test.png', false) . '">',
|
||||
"expectedcontent" => '<img src="broken.' . self::getExternalTestFileUrl('/test.png', false) . '">',
|
||||
],
|
||||
"Link URL should not be changed" => [
|
||||
"content" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '">' .
|
||||
$this->getExternalTestFileUrl('/test.png', false) . '</a>',
|
||||
"content" => '<a href="' . self::getExternalTestFileUrl('/test.png', false) . '">' .
|
||||
self::getExternalTestFileUrl('/test.png', false) . '</a>',
|
||||
"outputregex" => '/^$/',
|
||||
"expectedcontent" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '">' .
|
||||
$this->getExternalTestFileUrl('/test.png', false) . '</a>',
|
||||
"expectedcontent" => '<a href="' . self::getExternalTestFileUrl('/test.png', false) . '">' .
|
||||
self::getExternalTestFileUrl('/test.png', false) . '</a>',
|
||||
],
|
||||
"Test image from another site should be replaced but link should not" => [
|
||||
"content" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '"><img src="' .
|
||||
$this->getExternalTestFileUrl('/test.jpg', false) . '"></a>',
|
||||
"content" => '<a href="' . self::getExternalTestFileUrl('/test.png', false) . '"><img src="' .
|
||||
self::getExternalTestFileUrl('/test.jpg', false) . '"></a>',
|
||||
"outputregex" => '/UPDATE/',
|
||||
"expectedcontent" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '"><img src="' .
|
||||
$this->get_converted_http_link('/test.jpg') . '"></a>',
|
||||
"expectedcontent" => '<a href="' . self::getExternalTestFileUrl('/test.png', false) . '"><img src="' .
|
||||
self::get_converted_http_link('/test.jpg') . '"></a>',
|
||||
],
|
||||
];
|
||||
}
|
||||
@@ -127,8 +127,8 @@ class httpsreplace_test extends \advanced_testcase {
|
||||
* @param string $path Path to be rewritten
|
||||
* @return string
|
||||
*/
|
||||
protected function get_converted_http_link($path) {
|
||||
return preg_replace('/^http:/', 'https:', $this->getExternalTestFileUrl($path, false));
|
||||
protected static function get_converted_http_link($path) {
|
||||
return preg_replace('/^http:/', 'https:', self::getExternalTestFileUrl($path, false));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,15 +160,15 @@ class httpsreplace_test extends \advanced_testcase {
|
||||
/**
|
||||
* Data provider for test_http_link_stats
|
||||
*/
|
||||
public function http_link_stats_provider() {
|
||||
public static function http_link_stats_provider(): array {
|
||||
global $CFG;
|
||||
// Get the http url, since the default test wwwroot is https.
|
||||
$wwwrootdomain = 'www.example.com';
|
||||
$wwwroothttp = preg_replace('/^https:/', 'http:', $CFG->wwwroot);
|
||||
$testdomain = $this->get_converted_http_link('');
|
||||
$testdomain = self::get_converted_http_link('');
|
||||
return [
|
||||
"Test image from an available site so shouldn't be reported" => [
|
||||
"content" => '<img src="' . $this->getExternalTestFileUrl('/test.jpg', false) . '">',
|
||||
"content" => '<img src="' . self::getExternalTestFileUrl('/test.jpg', false) . '">',
|
||||
"domain" => $testdomain,
|
||||
"expectedcount" => 0,
|
||||
],
|
||||
|
||||
@@ -48,7 +48,7 @@ class controller_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function uninstall_lang_invalid_provider(): array {
|
||||
public static function uninstall_lang_invalid_provider(): array {
|
||||
return [
|
||||
'Empty string' => [''],
|
||||
'Meaningless empty string' => [' '],
|
||||
|
||||
@@ -55,8 +55,14 @@ final class locale_test extends \advanced_testcase {
|
||||
'set_locale',
|
||||
])
|
||||
->getMock();
|
||||
$mock->method('get_locale')->will($this->onConsecutiveCalls('en'));
|
||||
$mock->method('set_locale')->will($this->onConsecutiveCalls('es', 'en'));
|
||||
$mock->method('get_locale')->will($this->returnValue('en'));
|
||||
$setinvocations = $this->exactly(2);
|
||||
$mock
|
||||
->expects($setinvocations)
|
||||
->method('set_locale')->willReturnCallback(fn () => match (self::getInvocationCount($setinvocations)) {
|
||||
1 => 'es',
|
||||
2 => 'en',
|
||||
});
|
||||
|
||||
// Test what happen when locale is available on system.
|
||||
$result = $mock->check_locale_availability('en');
|
||||
@@ -72,8 +78,14 @@ final class locale_test extends \advanced_testcase {
|
||||
'set_locale',
|
||||
])
|
||||
->getMock();
|
||||
$mock->method('get_locale')->will($this->onConsecutiveCalls('en'));
|
||||
$mock->method('set_locale')->will($this->onConsecutiveCalls(false, 'en'));
|
||||
$mock->expects($this->exactly(1))->method('get_locale')->will($this->returnValue('en'));
|
||||
$setinvocations = $this->exactly(2);
|
||||
$mock
|
||||
->expects($setinvocations)
|
||||
->method('set_locale')->willReturnCallback(fn () => match (self::getInvocationCount($setinvocations)) {
|
||||
1 => false,
|
||||
2 => 'en',
|
||||
});
|
||||
|
||||
// Test what happen when locale is not available on system.
|
||||
$result = $mock->check_locale_availability('en');
|
||||
|
||||
@@ -389,7 +389,7 @@ class store_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array Array of parameters
|
||||
*/
|
||||
public function decode_other_provider(): array {
|
||||
public static function decode_other_provider(): array {
|
||||
return [
|
||||
[['info' => 'd2819896', 'logurl' => 'discuss.php?d=2819896']],
|
||||
[null],
|
||||
|
||||
@@ -864,6 +864,8 @@ class external extends external_api {
|
||||
|
||||
$context = context_system::instance();
|
||||
self::validate_context($context);
|
||||
require_capability('moodle/competency:templatemanage', $context);
|
||||
|
||||
$output = $PAGE->get_renderer('tool_lp');
|
||||
|
||||
list($filtercapsql, $filtercapparams) = api::filter_users_with_capability_on_user_context_sql($cap,
|
||||
|
||||
@@ -128,7 +128,7 @@ $functions = array(
|
||||
'classpath' => '',
|
||||
'description' => 'Search for users.',
|
||||
'type' => 'read',
|
||||
'capabilities' => '',
|
||||
'capabilities' => 'moodle/competency:templatemanage',
|
||||
'ajax' => true,
|
||||
),
|
||||
// This function was originally in this plugin but has been moved to core.
|
||||
|
||||
@@ -141,17 +141,14 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
'email' => 'bobbyyy@dyyylan.com', 'phone1' => '123456', 'phone2' => '78910', 'department' => 'Marketing',
|
||||
'institution' => 'HQ'));
|
||||
|
||||
// First we search with no capability assigned.
|
||||
// Assign capability required to perform the search.
|
||||
$this->setUser($ux);
|
||||
$result = external::search_users('yyylan', 'moodle/competency:planmanage');
|
||||
$result = external_api::clean_returnvalue(external::search_users_returns(), $result);
|
||||
$this->assertCount(0, $result['users']);
|
||||
$this->assertEquals(0, $result['count']);
|
||||
$systemcontext = \context_system::instance();
|
||||
$customrole = $this->assignUserCapability('moodle/competency:templatemanage', $systemcontext->id);
|
||||
|
||||
// Now we assign a different capability.
|
||||
$usercontext = \context_user::instance($u1->id);
|
||||
$systemcontext = \context_system::instance();
|
||||
$customrole = $this->assignUserCapability('moodle/competency:planview', $usercontext->id);
|
||||
$this->assignUserCapability('moodle/competency:templatemanage', $usercontext->id, $customrole);
|
||||
|
||||
$result = external::search_users('yyylan', 'moodle/competency:planmanage');
|
||||
$result = external_api::clean_returnvalue(external::search_users_returns(), $result);
|
||||
@@ -187,6 +184,8 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$ux3 = $dg->create_user();
|
||||
role_assign($this->creatorrole, $ux3->id, $usercontext->id);
|
||||
$this->setUser($ux3);
|
||||
$systemcontext = \context_system::instance();
|
||||
$customrole = $this->assignUserCapability('moodle/competency:templatemanage', $systemcontext->id, $customrole);
|
||||
$result = external::search_users('yyylan', 'moodle/competency:planmanage');
|
||||
$result = external_api::clean_returnvalue(external::search_users_returns(), $result);
|
||||
$this->assertCount(1, $result['users']);
|
||||
@@ -262,6 +261,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
|
||||
// Now do the test.
|
||||
$this->setUser($master);
|
||||
$dummyrole = $this->assignUserCapability('moodle/competency:templatemanage', $syscontext->id);
|
||||
$result = external::search_users('MOODLER', 'moodle/site:config');
|
||||
$this->assertCount(2, $result['users']);
|
||||
$this->assertEquals(2, $result['count']);
|
||||
@@ -269,6 +269,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$this->assertArrayHasKey($slave3->id, $result['users']);
|
||||
|
||||
$this->setUser($manager);
|
||||
$this->assignUserCapability('moodle/competency:templatemanage', $syscontext->id, $dummyrole);
|
||||
$result = external::search_users('MOODLER', 'moodle/site:config');
|
||||
$this->assertCount(1, $result['users']);
|
||||
$this->assertEquals(1, $result['count']);
|
||||
@@ -377,6 +378,8 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
|
||||
// Switch to a user that cannot view identity fields.
|
||||
$this->setUser($ux);
|
||||
$systemcontext = \context_system::instance();
|
||||
$this->assignUserCapability('moodle/competency:templatemanage', $systemcontext->id, $dummyrole);
|
||||
$CFG->showuseridentity = 'idnumber,email,phone1,phone2,department,institution';
|
||||
|
||||
// Only names are included.
|
||||
|
||||
@@ -25,6 +25,6 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
$plugin->version = 2024042200; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2024042201; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2024041600; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_lp'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -31,7 +31,9 @@ class import_test extends \advanced_testcase {
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$importer = new framework_importer(file_get_contents(__DIR__ . '/fixtures/example.csv'));
|
||||
$importer = new framework_importer(
|
||||
file_get_contents(self::get_fixture_path(__NAMESPACE__, 'example.csv')),
|
||||
);
|
||||
|
||||
$this->assertEquals('', $importer->get_error());
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
define("tool_mfa/autosubmit_verification_code",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0;_exports.init=()=>{const codeInput=document.querySelector("#id_verificationcode"),codeForm=codeInput.closest("form"),submitButton=codeForm.querySelector("#id_submitbutton");codeInput.addEventListener("keyup",(function(){this.value.length>=6&&codeForm.submit()})),codeInput.disabled&&(submitButton.disabled=!0)}}));
|
||||
define("tool_mfa/autosubmit_verification_code",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0;_exports.init=()=>{const codeInput=document.querySelector("#id_verificationcode"),codeForm=codeInput.closest("form"),submitButton=codeForm.querySelector("#id_submitbutton");codeInput.addEventListener("input",(function(){this.value.length>=6&&(codeForm.submit(),codeInput.readOnly=!0,submitButton.disabled=!0)})),codeInput.disabled&&(submitButton.disabled=!0)}}));
|
||||
|
||||
//# sourceMappingURL=autosubmit_verification_code.min.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"autosubmit_verification_code.min.js","sources":["../src/autosubmit_verification_code.js"],"sourcesContent":["\n// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module to autosubmit the verification code element when it reaches 6 characters.\n *\n * @module tool_mfa/autosubmit_verification_code\n * @copyright 2020 Peter Burnett <peterburnett@catalyst-au.net>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport const init = () => {\n const codeInput = document.querySelector(\"#id_verificationcode\");\n const codeForm = codeInput.closest(\"form\");\n const submitButton = codeForm.querySelector(\"#id_submitbutton\");\n\n // Event listener for code input field.\n codeInput.addEventListener('keyup', function() {\n if (this.value.length >= 6) {\n // Submits the closes form (parent).\n codeForm.submit();\n }\n });\n\n // Disable the submit button if the input field is disabled.\n // This occurs if there are no more attempts left for the factor.\n if (codeInput.disabled) {\n submitButton.disabled = true;\n }\n};\n"],"names":["codeInput","document","querySelector","codeForm","closest","submitButton","addEventListener","this","value","length","submit","disabled"],"mappings":"0KAwBoB,WACVA,UAAYC,SAASC,cAAc,wBACnCC,SAAWH,UAAUI,QAAQ,QAC7BC,aAAeF,SAASD,cAAc,oBAG5CF,UAAUM,iBAAiB,SAAS,WAC5BC,KAAKC,MAAMC,QAAU,GAErBN,SAASO,YAMbV,UAAUW,WACVN,aAAaM,UAAW"}
|
||||
{"version":3,"file":"autosubmit_verification_code.min.js","sources":["../src/autosubmit_verification_code.js"],"sourcesContent":["\n// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module to autosubmit the verification code element when it reaches 6 characters.\n *\n * @module tool_mfa/autosubmit_verification_code\n * @copyright 2020 Peter Burnett <peterburnett@catalyst-au.net>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport const init = () => {\n const codeInput = document.querySelector(\"#id_verificationcode\");\n const codeForm = codeInput.closest(\"form\");\n const submitButton = codeForm.querySelector(\"#id_submitbutton\");\n\n // Event listener for code input field.\n codeInput.addEventListener('input', function() {\n if (this.value.length >= 6) {\n // Submits the closest form (parent) and prevents accidental resubmission.\n codeForm.submit();\n codeInput.readOnly = true;\n submitButton.disabled = true;\n }\n });\n\n // Disable the submit button if the input field is disabled.\n // This occurs if there are no more attempts left for the factor.\n if (codeInput.disabled) {\n submitButton.disabled = true;\n }\n};\n"],"names":["codeInput","document","querySelector","codeForm","closest","submitButton","addEventListener","this","value","length","submit","readOnly","disabled"],"mappings":"0KAwBoB,WACVA,UAAYC,SAASC,cAAc,wBACnCC,SAAWH,UAAUI,QAAQ,QAC7BC,aAAeF,SAASD,cAAc,oBAG5CF,UAAUM,iBAAiB,SAAS,WAC5BC,KAAKC,MAAMC,QAAU,IAErBN,SAASO,SACTV,UAAUW,UAAW,EACrBN,aAAaO,UAAW,MAM5BZ,UAAUY,WACVP,aAAaO,UAAW"}
|
||||
@@ -28,10 +28,12 @@ export const init = () => {
|
||||
const submitButton = codeForm.querySelector("#id_submitbutton");
|
||||
|
||||
// Event listener for code input field.
|
||||
codeInput.addEventListener('keyup', function() {
|
||||
codeInput.addEventListener('input', function() {
|
||||
if (this.value.length >= 6) {
|
||||
// Submits the closes form (parent).
|
||||
// Submits the closest form (parent) and prevents accidental resubmission.
|
||||
codeForm.submit();
|
||||
codeInput.readOnly = true;
|
||||
submitButton.disabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class factor_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array of different country codes and phone numbers.
|
||||
*/
|
||||
public function format_number_provider(): array {
|
||||
public static function format_number_provider(): array {
|
||||
|
||||
return [
|
||||
'Phone number with local format' => [
|
||||
@@ -88,7 +88,7 @@ class factor_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array with different phone numebr tests
|
||||
*/
|
||||
public function is_valid_phonenumber_provider(): array {
|
||||
public static function is_valid_phonenumber_provider(): array {
|
||||
return [
|
||||
['+919367788755', true],
|
||||
['8989829304', false],
|
||||
|
||||
@@ -275,7 +275,7 @@ class factor_test extends \advanced_testcase {
|
||||
* Increments by 30 minutes to cover half hour and hour cases.
|
||||
* Starting timestamp: 2022-01-15 07:30:00 Australia/Melbourne time.
|
||||
*/
|
||||
public function timestamp_provider() {
|
||||
public static function timestamp_provider(): array {
|
||||
$starttimestamp = 1642192200;
|
||||
foreach (range(0, 23) as $i) {
|
||||
$timestamps[] = [$starttimestamp + ($i * HOURSECS)];
|
||||
|
||||
@@ -51,7 +51,7 @@ class admin_setting_managemfa_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_factor_combinations_provider() {
|
||||
public static function get_factor_combinations_provider(): array {
|
||||
$provider = [];
|
||||
|
||||
$factors = [];
|
||||
|
||||
@@ -157,7 +157,7 @@ class manager_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function should_redirect_urls_provider() {
|
||||
public static function should_redirect_urls_provider(): array {
|
||||
$badurl1 = new \moodle_url('/');
|
||||
$badparam1 = $badurl1->out();
|
||||
$badurl2 = new \moodle_url('admin/tool/mfa/auth.php');
|
||||
|
||||
@@ -76,7 +76,9 @@ class hook_callbacks {
|
||||
return;
|
||||
}
|
||||
$hook->add_html(
|
||||
html_writer::link($url, get_string('getmoodleonyourmobile', 'tool_mobile'), ['class' => 'mobilelink']),
|
||||
html_writer::div(
|
||||
html_writer::link($url, get_string('getmoodleonyourmobile', 'tool_mobile'), ['class' => 'mobilelink']),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class lib_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_endpoints_provider() {
|
||||
public static function get_endpoints_provider(): array {
|
||||
global $CFG;
|
||||
return [
|
||||
[
|
||||
|
||||
@@ -59,7 +59,7 @@ class import_handler_info_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array the data for creation of the info object.
|
||||
*/
|
||||
public function handler_info_data_provider() {
|
||||
public static function handler_info_data_provider(): array {
|
||||
return [
|
||||
'All data present' => ['label', 'Add a label to the course', false],
|
||||
'Empty module name' => ['', 'Add a file resource to the course', true],
|
||||
|
||||
@@ -53,10 +53,10 @@ class remote_resource_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function remote_resource_data_provider() {
|
||||
public static function remote_resource_data_provider(): array {
|
||||
return [
|
||||
'With filename and extension' => [
|
||||
$this->getExternalTestFileUrl('/test.html'),
|
||||
self::getExternalTestFileUrl('/test.html'),
|
||||
(object) [
|
||||
'name' => 'Test html file',
|
||||
'description' => 'Full description of the html file'
|
||||
@@ -78,8 +78,8 @@ class remote_resource_test extends \advanced_testcase {
|
||||
* Test confirming the network based operations of a remote_resource.
|
||||
*/
|
||||
public function test_network_features(): void {
|
||||
$url = $this->getExternalTestFileUrl('/test.html');
|
||||
$nonexistenturl = $this->getExternalTestFileUrl('/test.htmlzz');
|
||||
$url = self::getExternalTestFileUrl('/test.html');
|
||||
$nonexistenturl = self::getExternalTestFileUrl('/test.htmlzz');
|
||||
|
||||
$remoteres = new remote_resource(
|
||||
new \curl(),
|
||||
|
||||
@@ -55,7 +55,7 @@ class url_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function url_provider() {
|
||||
public static function url_provider(): array {
|
||||
return [
|
||||
'No path' => [
|
||||
'url' => 'https://example.moodle.net',
|
||||
|
||||
@@ -79,7 +79,10 @@ class hook_callbacks {
|
||||
if (!empty($policies)) {
|
||||
$url = new moodle_url('/admin/tool/policy/viewall.php', ['returnurl' => $PAGE->url]);
|
||||
$hook->add_html(
|
||||
html_writer::link($url, get_string('userpolicysettings', 'tool_policy'), ['class' => 'policiesfooter']),
|
||||
html_writer::div(
|
||||
html_writer::link($url, get_string('userpolicysettings', 'tool_policy')),
|
||||
'policiesfooter',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<ul>
|
||||
{{#policies}}
|
||||
<li>
|
||||
<a href=\"{{pluginbaseurl}}/view.php?versionid={{id}}{{#returnurl}}&returnurl={{.}}{{/returnurl}} {{!
|
||||
<a href="{{pluginbaseurl}}/view.php?versionid={{id}}{{#returnurl}}&returnurl={{.}}{{/returnurl}}" {{!
|
||||
}}data-action="view-guest" data-versionid="{{id}}" data-behalfid="1">
|
||||
{{{name}}}
|
||||
</a>
|
||||
|
||||
@@ -117,7 +117,7 @@ class category_bin extends base_bin {
|
||||
// This hack will be removed once recycle bin switches to use its own backup mode, with
|
||||
// own preferences and 100% separate from MOODLE_AUTOMATED.
|
||||
// TODO: Remove this as part of MDL-65228.
|
||||
$forcedbackupsettings = $CFG->forced_plugin_settings['backup'] ?? null;
|
||||
$forcedbackupsettings = $CFG->forced_plugin_settings['backup'] ?? [];
|
||||
$CFG->forced_plugin_settings['backup']['backup_auto_storage'] = 0;
|
||||
$CFG->forced_plugin_settings['backup']['backup_auto_files'] = 1;
|
||||
|
||||
@@ -253,7 +253,7 @@ class category_bin extends base_bin {
|
||||
// This hack will be removed once recycle bin switches to use its own backup mode, with
|
||||
// own preferences and 100% separate from MOODLE_AUTOMATED.
|
||||
// TODO: Remove this as part of MDL-65228.
|
||||
$forcedrestoresettings = $CFG->forced_plugin_settings['restore'] ?? null;
|
||||
$forcedrestoresettings = $CFG->forced_plugin_settings['restore'] ?? [];
|
||||
$CFG->forced_plugin_settings['restore']['restore_general_users'] = 1;
|
||||
$CFG->forced_plugin_settings['restore']['restore_general_groups'] = 1;
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ class course_bin extends base_bin {
|
||||
// This hack will be removed once recycle bin switches to use its own backup mode, with
|
||||
// own preferences and 100% separate from MOODLE_AUTOMATED.
|
||||
// TODO: Remove this as part of MDL-65228.
|
||||
$forcedbackupsettings = $CFG->forced_plugin_settings['backup'] ?? null;
|
||||
$forcedbackupsettings = $CFG->forced_plugin_settings['backup'] ?? [];
|
||||
$CFG->forced_plugin_settings['backup']['backup_auto_storage'] = 0;
|
||||
$CFG->forced_plugin_settings['backup']['backup_auto_files'] = 1;
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ class category_bin_test extends \advanced_testcase {
|
||||
* Used to verify that recycle bin is immune to various settings. Provides plugin, name, value for
|
||||
* direct usage with set_config()
|
||||
*/
|
||||
public function recycle_bin_settings_provider() {
|
||||
public static function recycle_bin_settings_provider(): array {
|
||||
return [
|
||||
'backup/backup_auto_storage moodle' => [[
|
||||
(object)['plugin' => 'backup', 'name' => 'backup_auto_storage', 'value' => 0],
|
||||
|
||||
@@ -175,7 +175,7 @@ class course_bin_test extends \advanced_testcase {
|
||||
* Used to verify that recycle bin is immune to various settings. Provides plugin, name, value for
|
||||
* direct usage with set_config()
|
||||
*/
|
||||
public function recycle_bin_settings_provider() {
|
||||
public static function recycle_bin_settings_provider(): array {
|
||||
return [
|
||||
'backup/backup_auto_storage moodle' => [[
|
||||
(object)['plugin' => 'backup', 'name' => 'backup_auto_storage', 'value' => 0],
|
||||
|
||||
@@ -967,8 +967,14 @@ class course_test extends \advanced_testcase {
|
||||
// Restore from a file, checking that the file takes priority over the templatecourse.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => 'A1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz',
|
||||
'summary' => 'A', 'category' => 1, 'fullname' => 'A1', 'templatecourse' => $c1->shortname);
|
||||
$data = [
|
||||
'shortname' => 'A1',
|
||||
'backupfile' => self::get_fixture_path(__NAMESPACE__, 'backup.mbz'),
|
||||
'summary' => 'A',
|
||||
'category' => 1,
|
||||
'fullname' => 'A1',
|
||||
'templatecourse' => $c1->shortname,
|
||||
];
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
@@ -986,8 +992,13 @@ class course_test extends \advanced_testcase {
|
||||
$this->assertTrue($found);
|
||||
|
||||
// Restoring twice from the same file should work.
|
||||
$data = array('shortname' => 'B1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz',
|
||||
'summary' => 'B', 'category' => 1, 'fullname' => 'B1');
|
||||
$data = [
|
||||
'shortname' => 'B1',
|
||||
'backupfile' => self::get_fixture_path(__NAMESPACE__, 'backup.mbz'),
|
||||
'summary' => 'B',
|
||||
'category' => 1,
|
||||
'fullname' => 'B1',
|
||||
];
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
@@ -1020,8 +1031,14 @@ class course_test extends \advanced_testcase {
|
||||
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => 'A1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz',
|
||||
'summary' => 'A', 'category' => 1, 'fullname' => 'A1', 'templatecourse' => $c1->shortname);
|
||||
$data = [
|
||||
'shortname' => 'A1',
|
||||
'backupfile' => self::get_fixture_path(__NAMESPACE__, 'backup.mbz'),
|
||||
'summary' => 'A',
|
||||
'category' => 1,
|
||||
'fullname' => 'A1',
|
||||
'templatecourse' => $c1->shortname,
|
||||
];
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
@@ -1259,7 +1276,7 @@ class course_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function enrolment_uploaddata_error_provider(): array {
|
||||
public static function enrolment_uploaddata_error_provider(): array {
|
||||
return [
|
||||
['errorcannotcreateorupdateenrolment', [
|
||||
'shortname' => 'C1',
|
||||
@@ -1487,7 +1504,7 @@ class course_test extends \advanced_testcase {
|
||||
// Create our custom field.
|
||||
$category = $this->get_customfield_generator()->create_category();
|
||||
$this->create_custom_field($category, 'date', 'mydate',
|
||||
['mindate' => strtotime('2020-04-01'), 'maxdate' => '2020-04-30']);
|
||||
['mindate' => strtotime('2020-04-01'), 'maxdate' => strtotime('2020-04-30')]);
|
||||
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
|
||||
@@ -110,11 +110,11 @@ class processor_test extends \advanced_testcase {
|
||||
$cir->load_csv_content($content, 'utf-8', 'comma');
|
||||
$cir->init();
|
||||
|
||||
$options = array(
|
||||
$options = [
|
||||
'mode' => tool_uploadcourse_processor::MODE_CREATE_NEW,
|
||||
'restorefile' => __DIR__ . '/fixtures/backup.mbz',
|
||||
'templatecourse' => 'DoesNotExist' // Restorefile takes priority.
|
||||
);
|
||||
'restorefile' => self::get_fixture_path(__NAMESPACE__, 'backup.mbz'),
|
||||
'templatecourse' => 'DoesNotExist', // Restorefile takes priority.
|
||||
];
|
||||
$defaults = array('category' => '1');
|
||||
|
||||
$p = new tool_uploadcourse_processor($cir, $options, $defaults);
|
||||
|
||||
@@ -30,7 +30,7 @@ class field_value_validators_test extends \advanced_testcase {
|
||||
/**
|
||||
* Data provider for \field_value_validators_testcase::test_validate_theme().
|
||||
*/
|
||||
public function themes_provider() {
|
||||
public static function themes_provider(): array {
|
||||
return [
|
||||
'User themes disabled' => [
|
||||
false, 'boost', 'warning', get_string('userthemesnotallowed', 'tool_uploaduser')
|
||||
|
||||
@@ -562,7 +562,8 @@ class step {
|
||||
* @return $this
|
||||
*/
|
||||
public function persist($force = false) {
|
||||
global $DB;
|
||||
global $CFG, $DB;
|
||||
require_once("{$CFG->libdir}/filelib.php");
|
||||
|
||||
if (!$this->dirty && !$force) {
|
||||
return $this;
|
||||
@@ -719,6 +720,9 @@ class step {
|
||||
* @return object
|
||||
*/
|
||||
public function prepare_data_for_form() {
|
||||
global $CFG;
|
||||
require_once("{$CFG->libdir}/filelib.php");
|
||||
|
||||
$data = $this->to_record();
|
||||
foreach (self::get_config_keys() as $key) {
|
||||
$data->$key = $this->get_config($key, configuration::get_step_default_value($key));
|
||||
|
||||
@@ -106,7 +106,7 @@ final class helper_test extends \advanced_testcase {
|
||||
\core\di::set(
|
||||
\core\hook\manager::class,
|
||||
\core\hook\manager::phpunit_get_instance([
|
||||
'test_plugin1' => __DIR__ . '/fixtures/invalid_serverside_hook_fixture.php',
|
||||
'test_plugin1' => self::get_fixture_path(__NAMESPACE__, 'invalid_serverside_hook_fixture.php'),
|
||||
]),
|
||||
);
|
||||
|
||||
@@ -118,7 +118,7 @@ final class helper_test extends \advanced_testcase {
|
||||
\core\di::set(
|
||||
\core\hook\manager::class,
|
||||
\core\hook\manager::phpunit_get_instance([
|
||||
'test_plugin1' => __DIR__ . '/fixtures/clientside_filter_for_serverside_hook.php',
|
||||
'test_plugin1' => self::get_fixture_path(__NAMESPACE__, 'clientside_filter_for_serverside_hook.php'),
|
||||
]),
|
||||
);
|
||||
|
||||
@@ -130,7 +130,7 @@ final class helper_test extends \advanced_testcase {
|
||||
\core\di::set(
|
||||
\core\hook\manager::class,
|
||||
\core\hook\manager::phpunit_get_instance([
|
||||
'test_plugin1' => __DIR__ . '/fixtures/serverside_filter_for_clientside_hook.php',
|
||||
'test_plugin1' => self::get_fixture_path(__NAMESPACE__, 'serverside_filter_for_clientside_hook.php'),
|
||||
]),
|
||||
);
|
||||
|
||||
@@ -142,7 +142,7 @@ final class helper_test extends \advanced_testcase {
|
||||
\core\di::set(
|
||||
\core\hook\manager::class,
|
||||
\core\hook\manager::phpunit_get_instance([
|
||||
'test_plugin1' => __DIR__ . '/fixtures/hook_fixtures.php',
|
||||
'test_plugin1' => self::get_fixture_path(__NAMESPACE__, 'hook_fixtures.php'),
|
||||
]),
|
||||
);
|
||||
|
||||
@@ -175,7 +175,7 @@ final class helper_test extends \advanced_testcase {
|
||||
\core\di::set(
|
||||
\core\hook\manager::class,
|
||||
\core\hook\manager::phpunit_get_instance([
|
||||
'test_plugin1' => __DIR__ . '/fixtures/invalid_clientside_hook_fixture.php',
|
||||
'test_plugin1' => self::get_fixture_path(__NAMESPACE__, 'invalid_clientside_hook_fixture.php'),
|
||||
]),
|
||||
);
|
||||
|
||||
|
||||
@@ -524,14 +524,30 @@ class tour_test extends \advanced_testcase {
|
||||
// Mock the database.
|
||||
$DB = $this->mock_database();
|
||||
|
||||
$DB->expects($this->exactly(3))
|
||||
$deleteinvocations = $this->exactly(3);
|
||||
$DB->expects($deleteinvocations)
|
||||
->method('delete_records')
|
||||
->withConsecutive(
|
||||
[$this->equalTo('tool_usertours_tours'), $this->equalTo(['id' => $id])],
|
||||
[$this->equalTo('user_preferences'), $this->equalTo(['name' => tour::TOUR_LAST_COMPLETED_BY_USER . $id])],
|
||||
[$this->equalTo('user_preferences'), $this->equalTo(['name' => tour::TOUR_REQUESTED_BY_USER . $id])]
|
||||
)
|
||||
->willReturn(null);
|
||||
->willReturnCallback(function ($table, $conditions) use ($deleteinvocations, $id) {
|
||||
switch (self::getInvocationCount($deleteinvocations)) {
|
||||
case 1:
|
||||
$this->assertEquals('tool_usertours_tours', $table);
|
||||
$this->assertEquals(['id' => $id], $conditions);
|
||||
return null;
|
||||
break;
|
||||
case 2:
|
||||
$this->assertEquals('user_preferences', $table);
|
||||
$this->assertEquals(['name' => tour::TOUR_LAST_COMPLETED_BY_USER . $id], $conditions);
|
||||
return null;
|
||||
break;
|
||||
case 3:
|
||||
$this->assertEquals('user_preferences', $table);
|
||||
$this->assertEquals(['name' => tour::TOUR_REQUESTED_BY_USER . $id], $conditions);
|
||||
return null;
|
||||
break;
|
||||
default:
|
||||
$this->fail('Unexpected call to delete_records');
|
||||
}
|
||||
});
|
||||
|
||||
$DB->expects($this->once())
|
||||
->method('get_records')
|
||||
@@ -551,7 +567,7 @@ class tour_test extends \advanced_testcase {
|
||||
for ($i = 4; $i >= 0; $i--) {
|
||||
$id = rand($i * 10, ($i * 10) + 9);
|
||||
$mockdata[] = (object) ['id' => $id];
|
||||
$expectations[] = [$this->equalTo('tool_usertours_steps'), $this->equalTo('sortorder'), 4 - $i, ['id' => $id]];
|
||||
$expectations[] = [4 - $i, ['id' => $id]];
|
||||
}
|
||||
|
||||
// Mock the database.
|
||||
@@ -560,9 +576,19 @@ class tour_test extends \advanced_testcase {
|
||||
->method('get_records')
|
||||
->willReturn($mockdata);
|
||||
|
||||
$setfield = $DB->expects($this->exactly(5))
|
||||
->method('set_field');
|
||||
call_user_func_array([$setfield, 'withConsecutive'], $expectations);
|
||||
$setfieldinvocations = $this->exactly(5);
|
||||
$DB->expects($setfieldinvocations)
|
||||
->method('set_field')
|
||||
->willReturnCallback(function ($table, $field, $value, $conditions) use (
|
||||
$setfieldinvocations,
|
||||
$expectations,
|
||||
): void {
|
||||
$expectation = $expectations[self::getInvocationCount($setfieldinvocations) - 1];
|
||||
$this->assertEquals('tool_usertours_steps', $table);
|
||||
$this->assertEquals('sortorder', $field);
|
||||
$this->assertEquals($expectation[0], $value);
|
||||
$this->assertEquals($expectation[1], $conditions);
|
||||
});
|
||||
|
||||
$tour->reset_step_sortorder();
|
||||
}
|
||||
@@ -761,9 +787,12 @@ class tour_test extends \advanced_testcase {
|
||||
->getMock();
|
||||
|
||||
if ($getconfig) {
|
||||
$tour->expects($this->exactly(count($getconfig)))
|
||||
$getinvocations = $this->exactly(count($getconfig));
|
||||
$tour->expects($getinvocations)
|
||||
->method('get_config')
|
||||
->will(call_user_func_array([$this, 'onConsecutiveCalls'], $getconfig));
|
||||
->willReturnCallback(function () use ($getinvocations, $getconfig) {
|
||||
return $getconfig[self::getInvocationCount($getinvocations) - 1];
|
||||
});
|
||||
}
|
||||
|
||||
if ($setconfig) {
|
||||
|
||||
@@ -30,7 +30,7 @@ class analysis_test extends \advanced_testcase {
|
||||
* @return null
|
||||
*/
|
||||
public function test_fill_firstanalyses_cache(): void {
|
||||
require_once(__DIR__ . '/fixtures/test_timesplitting_upcoming_seconds.php');
|
||||
require_once(self::get_fixture_path(__NAMESPACE__, 'test_timesplitting_upcoming_seconds.php'));
|
||||
$this->resetAfterTest();
|
||||
|
||||
$modelid = 1;
|
||||
|
||||
@@ -148,7 +148,8 @@ Feature: Manage analytics models
|
||||
When I open the action menu in "Students at risk of not meeting the course completion conditions" "table_row"
|
||||
And I choose "Export" in the open action menu
|
||||
And I click on "Actions" "link" in the "Students at risk of not meeting the course completion conditions" "table_row"
|
||||
And following "Export" should download between "100" and "500" bytes
|
||||
And following "Export" should download a file that:
|
||||
| Contains file in zip | model-config.json |
|
||||
|
||||
Scenario: Check invalid site elements
|
||||
When I open the action menu in "Students at risk of not meeting the course completion conditions" "table_row"
|
||||
|
||||
@@ -23,8 +23,7 @@ namespace 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 calculation_info_test extends \advanced_testcase {
|
||||
|
||||
final class calculation_info_test extends \advanced_testcase {
|
||||
/**
|
||||
* test_calculation_info description
|
||||
*
|
||||
@@ -88,7 +87,7 @@ class calculation_info_test extends \advanced_testcase {
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function provider_test_calculation_info_add_pull() {
|
||||
public static function provider_test_calculation_info_add_pull(): array {
|
||||
return [
|
||||
'mixed-types' => ['asd', true, [123, 123, 123], (object)['asd' => 'fgfg']],
|
||||
];
|
||||
|
||||
@@ -50,7 +50,7 @@ final class community_of_inquiry_activities_completed_by_test extends advanced_t
|
||||
* @param string $availabilitylevel
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_activities_with_availability($availabilitylevel) {
|
||||
public function test_get_activities_with_availability($availabilitylevel): void {
|
||||
|
||||
list($course, $stu1) = $this->setup_course();
|
||||
|
||||
@@ -113,7 +113,7 @@ final class community_of_inquiry_activities_completed_by_test extends advanced_t
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_activities_with_weeks() {
|
||||
public function test_get_activities_with_weeks(): void {
|
||||
|
||||
$startdate = gmmktime('0', '0', '0', 10, 24, 2015);
|
||||
$record = array(
|
||||
@@ -156,7 +156,7 @@ final class community_of_inquiry_activities_completed_by_test extends advanced_t
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_activities_by_section() {
|
||||
public function test_get_activities_by_section(): void {
|
||||
|
||||
// This makes debugging easier, sorry WA's +8 :).
|
||||
$this->setTimezone('UTC');
|
||||
@@ -226,7 +226,7 @@ final class community_of_inquiry_activities_completed_by_test extends advanced_t
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_activities_with_specific_restrictions() {
|
||||
public function test_get_activities_with_specific_restrictions(): void {
|
||||
|
||||
list($course, $stu1) = $this->setup_course();
|
||||
|
||||
|
||||
@@ -29,8 +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 indicator_test extends \advanced_testcase {
|
||||
|
||||
final class indicator_test extends \advanced_testcase {
|
||||
/**
|
||||
* test_validate_calculated_value
|
||||
*
|
||||
@@ -50,7 +49,7 @@ class indicator_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate_calculated_value() {
|
||||
public static function validate_calculated_value(): array {
|
||||
return [
|
||||
'max' => ['test_indicator_max', [1]],
|
||||
'min' => ['test_indicator_min', [-1]],
|
||||
@@ -83,7 +82,7 @@ class indicator_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate_calculated_value_exceptions() {
|
||||
public static function validate_calculated_value_exceptions(): array {
|
||||
return [
|
||||
'max' => ['test_indicator_max', 2],
|
||||
'min' => ['test_indicator_min', -2],
|
||||
|
||||
@@ -31,8 +31,7 @@ require_once(__DIR__ . '/fixtures/test_target_course_level_shortname.php');
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \core_analytics\manager
|
||||
*/
|
||||
class manager_test extends \advanced_testcase {
|
||||
|
||||
final class manager_test extends \advanced_testcase {
|
||||
/**
|
||||
* test_deleted_context
|
||||
*/
|
||||
@@ -44,7 +43,7 @@ class manager_test extends \advanced_testcase {
|
||||
set_config('enabled_stores', 'logstore_standard', 'tool_log');
|
||||
|
||||
$target = \core_analytics\manager::get_target('test_target_course_level_shortname');
|
||||
$indicators = array('test_indicator_max', 'test_indicator_min', 'test_indicator_fullname');
|
||||
$indicators = ['test_indicator_max', 'test_indicator_min', 'test_indicator_fullname'];
|
||||
foreach ($indicators as $key => $indicator) {
|
||||
$indicators[$key] = \core_analytics\manager::get_indicator($indicator);
|
||||
}
|
||||
@@ -52,10 +51,10 @@ class manager_test extends \advanced_testcase {
|
||||
$model = \core_analytics\model::create($target, $indicators);
|
||||
$modelobj = $model->get_model_obj();
|
||||
|
||||
$coursepredict1 = $this->getDataGenerator()->create_course(array('visible' => 0));
|
||||
$coursepredict2 = $this->getDataGenerator()->create_course(array('visible' => 0));
|
||||
$coursetrain1 = $this->getDataGenerator()->create_course(array('visible' => 1));
|
||||
$coursetrain2 = $this->getDataGenerator()->create_course(array('visible' => 1));
|
||||
$coursepredict1 = $this->getDataGenerator()->create_course(['visible' => 0]);
|
||||
$coursepredict2 = $this->getDataGenerator()->create_course(['visible' => 0]);
|
||||
$coursetrain1 = $this->getDataGenerator()->create_course(['visible' => 1]);
|
||||
$coursetrain2 = $this->getDataGenerator()->create_course(['visible' => 1]);
|
||||
|
||||
$model->enable('\core\analytics\time_splitting\no_splitting');
|
||||
|
||||
@@ -65,25 +64,33 @@ class manager_test extends \advanced_testcase {
|
||||
// Generate a prediction action to confirm that it is deleted when there is an important update.
|
||||
$predictions = $DB->get_records('analytics_predictions');
|
||||
$prediction = reset($predictions);
|
||||
$prediction = new \core_analytics\prediction($prediction, array('whatever' => 'not used'));
|
||||
$prediction = new \core_analytics\prediction($prediction, ['whatever' => 'not used']);
|
||||
$prediction->action_executed(\core_analytics\prediction::ACTION_USEFUL, $model->get_target());
|
||||
|
||||
$predictioncontextid = $prediction->get_prediction_data()->contextid;
|
||||
|
||||
$npredictions = $DB->count_records('analytics_predictions', array('contextid' => $predictioncontextid));
|
||||
$npredictionactions = $DB->count_records('analytics_prediction_actions',
|
||||
array('predictionid' => $prediction->get_prediction_data()->id));
|
||||
$nindicatorcalc = $DB->count_records('analytics_indicator_calc', array('contextid' => $predictioncontextid));
|
||||
$npredictions = $DB->count_records('analytics_predictions', ['contextid' => $predictioncontextid]);
|
||||
$npredictionactions = $DB->count_records(
|
||||
'analytics_prediction_actions',
|
||||
['predictionid' => $prediction->get_prediction_data()->id]
|
||||
);
|
||||
$nindicatorcalc = $DB->count_records('analytics_indicator_calc', ['contextid' => $predictioncontextid]);
|
||||
|
||||
\core_analytics\manager::cleanup();
|
||||
|
||||
// Nothing is incorrectly deleted.
|
||||
$this->assertEquals($npredictions, $DB->count_records('analytics_predictions',
|
||||
array('contextid' => $predictioncontextid)));
|
||||
$this->assertEquals($npredictionactions, $DB->count_records('analytics_prediction_actions',
|
||||
array('predictionid' => $prediction->get_prediction_data()->id)));
|
||||
$this->assertEquals($nindicatorcalc, $DB->count_records('analytics_indicator_calc',
|
||||
array('contextid' => $predictioncontextid)));
|
||||
$this->assertEquals($npredictions, $DB->count_records(
|
||||
'analytics_predictions',
|
||||
['contextid' => $predictioncontextid]
|
||||
));
|
||||
$this->assertEquals($npredictionactions, $DB->count_records(
|
||||
'analytics_prediction_actions',
|
||||
['predictionid' => $prediction->get_prediction_data()->id]
|
||||
));
|
||||
$this->assertEquals($nindicatorcalc, $DB->count_records(
|
||||
'analytics_indicator_calc',
|
||||
['contextid' => $predictioncontextid]
|
||||
));
|
||||
|
||||
// Now we delete a context, the course predictions and prediction actions should be deleted.
|
||||
$deletedcontext = \context::instance_by_id($predictioncontextid);
|
||||
@@ -91,10 +98,12 @@ class manager_test extends \advanced_testcase {
|
||||
|
||||
\core_analytics\manager::cleanup();
|
||||
|
||||
$this->assertEmpty($DB->count_records('analytics_predictions', array('contextid' => $predictioncontextid)));
|
||||
$this->assertEmpty($DB->count_records('analytics_prediction_actions',
|
||||
array('predictionid' => $prediction->get_prediction_data()->id)));
|
||||
$this->assertEmpty($DB->count_records('analytics_indicator_calc', array('contextid' => $predictioncontextid)));
|
||||
$this->assertEmpty($DB->count_records('analytics_predictions', ['contextid' => $predictioncontextid]));
|
||||
$this->assertEmpty($DB->count_records(
|
||||
'analytics_prediction_actions',
|
||||
['predictionid' => $prediction->get_prediction_data()->id]
|
||||
));
|
||||
$this->assertEmpty($DB->count_records('analytics_indicator_calc', ['contextid' => $predictioncontextid]));
|
||||
|
||||
set_config('enabled_stores', '', 'tool_log');
|
||||
get_log_manager(true);
|
||||
@@ -111,7 +120,7 @@ class manager_test extends \advanced_testcase {
|
||||
set_config('enabled_stores', 'logstore_standard', 'tool_log');
|
||||
|
||||
$target = \core_analytics\manager::get_target('test_target_course_level_shortname');
|
||||
$indicators = array('test_indicator_max', 'test_indicator_min', 'test_indicator_fullname');
|
||||
$indicators = ['test_indicator_max', 'test_indicator_min', 'test_indicator_fullname'];
|
||||
foreach ($indicators as $key => $indicator) {
|
||||
$indicators[$key] = \core_analytics\manager::get_indicator($indicator);
|
||||
}
|
||||
@@ -119,10 +128,10 @@ class manager_test extends \advanced_testcase {
|
||||
$model = \core_analytics\model::create($target, $indicators);
|
||||
$modelobj = $model->get_model_obj();
|
||||
|
||||
$coursepredict1 = $this->getDataGenerator()->create_course(array('visible' => 0));
|
||||
$coursepredict2 = $this->getDataGenerator()->create_course(array('visible' => 0));
|
||||
$coursetrain1 = $this->getDataGenerator()->create_course(array('visible' => 1));
|
||||
$coursetrain2 = $this->getDataGenerator()->create_course(array('visible' => 1));
|
||||
$coursepredict1 = $this->getDataGenerator()->create_course(['visible' => 0]);
|
||||
$coursepredict2 = $this->getDataGenerator()->create_course(['visible' => 0]);
|
||||
$coursetrain1 = $this->getDataGenerator()->create_course(['visible' => 1]);
|
||||
$coursetrain2 = $this->getDataGenerator()->create_course(['visible' => 1]);
|
||||
|
||||
$model->enable('\core\analytics\time_splitting\no_splitting');
|
||||
|
||||
@@ -139,9 +148,9 @@ class manager_test extends \advanced_testcase {
|
||||
|
||||
\core_analytics\manager::cleanup();
|
||||
|
||||
$this->assertEmpty($DB->count_records('analytics_predict_samples', array('analysableid' => $coursepredict1->id)));
|
||||
$this->assertEmpty($DB->count_records('analytics_train_samples', array('analysableid' => $coursepredict1->id)));
|
||||
$this->assertEmpty($DB->count_records('analytics_used_analysables', array('analysableid' => $coursepredict1->id)));
|
||||
$this->assertEmpty($DB->count_records('analytics_predict_samples', ['analysableid' => $coursepredict1->id]));
|
||||
$this->assertEmpty($DB->count_records('analytics_train_samples', ['analysableid' => $coursepredict1->id]));
|
||||
$this->assertEmpty($DB->count_records('analytics_used_analysables', ['analysableid' => $coursepredict1->id]));
|
||||
|
||||
set_config('enabled_stores', '', 'tool_log');
|
||||
get_log_manager(true);
|
||||
@@ -190,7 +199,7 @@ class manager_test extends \advanced_testcase {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// This is expected to run without an exception.
|
||||
$models = $this->load_models_from_fixture_file('no_teaching');
|
||||
$models = self::load_models_from_fixture_file('no_teaching');
|
||||
\core_analytics\manager::validate_models_declaration($models);
|
||||
}
|
||||
|
||||
@@ -214,34 +223,34 @@ class manager_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array of (string)testcase => [(array)models, (string)expected exception message]
|
||||
*/
|
||||
public function validate_models_declaration_exceptions_provider() {
|
||||
public static function validate_models_declaration_exceptions_provider(): array {
|
||||
return [
|
||||
'missing_target' => [
|
||||
$this->load_models_from_fixture_file('missing_target'),
|
||||
self::load_models_from_fixture_file('missing_target'),
|
||||
'Missing target declaration',
|
||||
],
|
||||
'invalid_target' => [
|
||||
$this->load_models_from_fixture_file('invalid_target'),
|
||||
self::load_models_from_fixture_file('invalid_target'),
|
||||
'Invalid target classname',
|
||||
],
|
||||
'missing_indicators' => [
|
||||
$this->load_models_from_fixture_file('missing_indicators'),
|
||||
self::load_models_from_fixture_file('missing_indicators'),
|
||||
'Missing indicators declaration',
|
||||
],
|
||||
'invalid_indicators' => [
|
||||
$this->load_models_from_fixture_file('invalid_indicators'),
|
||||
self::load_models_from_fixture_file('invalid_indicators'),
|
||||
'Invalid indicator classname',
|
||||
],
|
||||
'invalid_time_splitting' => [
|
||||
$this->load_models_from_fixture_file('invalid_time_splitting'),
|
||||
self::load_models_from_fixture_file('invalid_time_splitting'),
|
||||
'Invalid time splitting classname',
|
||||
],
|
||||
'invalid_time_splitting_fq' => [
|
||||
$this->load_models_from_fixture_file('invalid_time_splitting_fq'),
|
||||
self::load_models_from_fixture_file('invalid_time_splitting_fq'),
|
||||
'Expecting fully qualified time splitting classname',
|
||||
],
|
||||
'invalid_enabled' => [
|
||||
$this->load_models_from_fixture_file('invalid_enabled'),
|
||||
self::load_models_from_fixture_file('invalid_enabled'),
|
||||
'Cannot enable a model without time splitting method specified',
|
||||
],
|
||||
];
|
||||
@@ -253,12 +262,12 @@ class manager_test extends \advanced_testcase {
|
||||
* @param string $filename
|
||||
* @return array
|
||||
*/
|
||||
protected function load_models_from_fixture_file(string $filename) {
|
||||
protected static function load_models_from_fixture_file(string $filename) {
|
||||
global $CFG;
|
||||
|
||||
$models = null;
|
||||
|
||||
require($CFG->dirroot.'/analytics/tests/fixtures/db_analytics_php/'.$filename.'.php');
|
||||
require("{$CFG->dirroot}/analytics/tests/fixtures/db_analytics_php/{$filename}.php");
|
||||
|
||||
return $models;
|
||||
}
|
||||
@@ -430,9 +439,9 @@ class manager_test extends \advanced_testcase {
|
||||
*/
|
||||
public function test_model_declaration_identifier(): void {
|
||||
|
||||
$noteaching1 = $this->load_models_from_fixture_file('no_teaching');
|
||||
$noteaching2 = $this->load_models_from_fixture_file('no_teaching');
|
||||
$noteaching3 = $this->load_models_from_fixture_file('no_teaching');
|
||||
$noteaching1 = self::load_models_from_fixture_file('no_teaching');
|
||||
$noteaching2 = self::load_models_from_fixture_file('no_teaching');
|
||||
$noteaching3 = self::load_models_from_fixture_file('no_teaching');
|
||||
|
||||
// Same model declaration should always lead to same identifier.
|
||||
$this->assertEquals(
|
||||
@@ -474,9 +483,9 @@ class manager_test extends \advanced_testcase {
|
||||
public function test_get_declared_target_and_indicators_instances(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$definition = $this->load_models_from_fixture_file('no_teaching');
|
||||
$definition = self::load_models_from_fixture_file('no_teaching');
|
||||
|
||||
list($target, $indicators) = \core_analytics\manager::get_declared_target_and_indicators_instances($definition[0]);
|
||||
[$target, $indicators] = \core_analytics\manager::get_declared_target_and_indicators_instances($definition[0]);
|
||||
|
||||
$this->assertTrue($target instanceof \core_analytics\local\target\base);
|
||||
$this->assertNotEmpty($indicators);
|
||||
|
||||
@@ -135,7 +135,7 @@ class prediction_actions_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function execute_actions_provider(): array {
|
||||
public static function execute_actions_provider(): array {
|
||||
return [
|
||||
'Empty actions with no filter' => [
|
||||
[],
|
||||
|
||||
@@ -341,14 +341,14 @@ class prediction_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function provider_ml_training_and_prediction() {
|
||||
public static function provider_ml_training_and_prediction(): array {
|
||||
$cases = array(
|
||||
'no_splitting' => array('\core\analytics\time_splitting\no_splitting', 0, 1),
|
||||
'quarters' => array('\core\analytics\time_splitting\quarters', 3, 4)
|
||||
);
|
||||
|
||||
// We need to test all system prediction processors.
|
||||
return $this->add_prediction_processors($cases);
|
||||
return static::add_prediction_processors($cases);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -417,13 +417,13 @@ class prediction_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function provider_ml_processors() {
|
||||
public static function provider_ml_processors(): array {
|
||||
$cases = [
|
||||
'case' => [],
|
||||
];
|
||||
|
||||
// We need to test all system prediction processors.
|
||||
return $this->add_prediction_processors($cases);
|
||||
return static::add_prediction_processors($cases);
|
||||
}
|
||||
/**
|
||||
* Test the system classifiers returns.
|
||||
@@ -507,7 +507,7 @@ class prediction_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function provider_ml_classifiers_return() {
|
||||
public static function provider_ml_classifiers_return(): array {
|
||||
// Using verbose options as the first argument for readability.
|
||||
$cases = array(
|
||||
'1-samples' => array('maybe', 1, [0]),
|
||||
@@ -517,7 +517,7 @@ class prediction_test extends \advanced_testcase {
|
||||
);
|
||||
|
||||
// We need to test all system prediction processors.
|
||||
return $this->add_prediction_processors($cases);
|
||||
return static::add_prediction_processors($cases);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -581,13 +581,13 @@ class prediction_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function provider_test_multi_classifier() {
|
||||
public static function provider_test_multi_classifier(): array {
|
||||
$cases = array(
|
||||
'notimesplitting' => array('\core\analytics\time_splitting\no_splitting'),
|
||||
);
|
||||
|
||||
// Add all system prediction processors.
|
||||
return $this->add_prediction_processors($cases);
|
||||
return static::add_prediction_processors($cases);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -777,8 +777,7 @@ class prediction_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function provider_ml_test_evaluation_configuration() {
|
||||
|
||||
public static function provider_ml_test_evaluation_configuration(): array {
|
||||
$cases = array(
|
||||
'bad' => array(
|
||||
'modelquality' => 'random',
|
||||
@@ -797,7 +796,7 @@ class prediction_test extends \advanced_testcase {
|
||||
)
|
||||
)
|
||||
);
|
||||
return $this->add_prediction_processors($cases);
|
||||
return static::add_prediction_processors($cases);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -955,8 +954,7 @@ class prediction_test extends \advanced_testcase {
|
||||
* @param array $cases
|
||||
* @return array
|
||||
*/
|
||||
protected function add_prediction_processors($cases) {
|
||||
|
||||
protected static function add_prediction_processors($cases): array {
|
||||
$return = array();
|
||||
|
||||
if (defined('TEST_MLBACKEND_PYTHON_HOST') && defined('TEST_MLBACKEND_PYTHON_PORT')
|
||||
|
||||
@@ -66,7 +66,7 @@ class auth_ldap_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function auth_ldap_provider() {
|
||||
public static function auth_ldap_provider(): array {
|
||||
$pagesizes = [1, 3, 5, 1000];
|
||||
$subcontexts = [0, 1];
|
||||
$combinations = [];
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace auth_lti;
|
||||
class auth_test extends \advanced_testcase {
|
||||
|
||||
/** @var string issuer URL used for test cases. */
|
||||
protected $issuer = 'https://lms.example.org';
|
||||
protected static string $issuer = 'https://lms.example.org';
|
||||
|
||||
/** @var int const representing cases where no PII is present. */
|
||||
protected const PII_NONE = 0;
|
||||
@@ -70,10 +70,13 @@ class auth_test extends \advanced_testcase {
|
||||
* @param bool $includepicture whether to include a profile picture or not (slows tests, so defaults to false).
|
||||
* @return array the users list.
|
||||
*/
|
||||
protected function get_mock_users_with_ids(array $ids,
|
||||
string $role = 'http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor', bool $includenames = true,
|
||||
bool $includeemail = true, bool $includepicture = false): array {
|
||||
|
||||
protected static function get_mock_users_with_ids(
|
||||
array $ids,
|
||||
string $role = 'http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor',
|
||||
bool $includenames = true,
|
||||
bool $includeemail = true,
|
||||
bool $includepicture = false,
|
||||
): array {
|
||||
$users = [];
|
||||
foreach ($ids as $id) {
|
||||
$user = [
|
||||
@@ -91,7 +94,7 @@ class auth_test extends \advanced_testcase {
|
||||
unset($user['email']);
|
||||
}
|
||||
if ($includepicture) {
|
||||
$user['picture'] = $this->getExternalTestFileUrl('/test.jpg');
|
||||
$user['picture'] = self::getExternalTestFileUrl('/test.jpg');
|
||||
}
|
||||
$users[] = $user;
|
||||
}
|
||||
@@ -137,7 +140,7 @@ class auth_test extends \advanced_testcase {
|
||||
*/
|
||||
protected function get_mock_launchdata_for_user(array $mockuser, array $mockmigration = []): array {
|
||||
$data = [
|
||||
'iss' => $this->issuer, // Must match registration in create_test_environment.
|
||||
'iss' => self::$issuer, // Must match registration in create_test_environment.
|
||||
'aud' => '123', // Must match registration in create_test_environment.
|
||||
'sub' => $mockuser['user_id'], // User id on the platform site.
|
||||
'exp' => time() + 60,
|
||||
@@ -286,12 +289,12 @@ class auth_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array the test case data.
|
||||
*/
|
||||
public function launch_data_provider(): array {
|
||||
public static function launch_data_provider(): array {
|
||||
return [
|
||||
'New (unlinked) platform learner including PII, no legacy user, no migration claim' => [
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
@@ -301,7 +304,7 @@ class auth_test extends \advanced_testcase {
|
||||
'New (unlinked) platform learner excluding names, no legacy user, no migration claim' => [
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
false
|
||||
@@ -312,7 +315,7 @@ class auth_test extends \advanced_testcase {
|
||||
'New (unlinked) platform learner excluding emails, no legacy user, no migration claim' => [
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
true,
|
||||
@@ -324,7 +327,7 @@ class auth_test extends \advanced_testcase {
|
||||
'New (unlinked) platform learner excluding all PII, no legacy user, no migration claim' => [
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
false,
|
||||
@@ -345,7 +348,7 @@ class auth_test extends \advanced_testcase {
|
||||
]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
@@ -374,7 +377,7 @@ class auth_test extends \advanced_testcase {
|
||||
]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
@@ -396,7 +399,7 @@ class auth_test extends \advanced_testcase {
|
||||
]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
@@ -425,7 +428,7 @@ class auth_test extends \advanced_testcase {
|
||||
]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
@@ -454,7 +457,7 @@ class auth_test extends \advanced_testcase {
|
||||
]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
@@ -483,7 +486,7 @@ class auth_test extends \advanced_testcase {
|
||||
]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
@@ -512,7 +515,7 @@ class auth_test extends \advanced_testcase {
|
||||
]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
@@ -540,7 +543,7 @@ class auth_test extends \advanced_testcase {
|
||||
]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
@@ -569,7 +572,7 @@ class auth_test extends \advanced_testcase {
|
||||
]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
false,
|
||||
@@ -591,7 +594,7 @@ class auth_test extends \advanced_testcase {
|
||||
'New (unlinked) platform instructor including PII, no legacy user, no migration claim' => [
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor'
|
||||
)[0],
|
||||
@@ -601,7 +604,7 @@ class auth_test extends \advanced_testcase {
|
||||
'New (unlinked) platform instructor excluding PII, no legacy user, no migration claim' => [
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor',
|
||||
false,
|
||||
@@ -622,7 +625,7 @@ class auth_test extends \advanced_testcase {
|
||||
]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor'
|
||||
)[0],
|
||||
@@ -643,7 +646,7 @@ class auth_test extends \advanced_testcase {
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'has_authenticated_before' => true,
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
@@ -654,7 +657,7 @@ class auth_test extends \advanced_testcase {
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'has_authenticated_before' => true,
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
false,
|
||||
@@ -667,7 +670,7 @@ class auth_test extends \advanced_testcase {
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'has_authenticated_before' => true,
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor'
|
||||
)[0],
|
||||
@@ -678,7 +681,7 @@ class auth_test extends \advanced_testcase {
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'has_authenticated_before' => true,
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor',
|
||||
false,
|
||||
@@ -691,7 +694,7 @@ class auth_test extends \advanced_testcase {
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'has_authenticated_before' => false,
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor',
|
||||
false,
|
||||
@@ -810,17 +813,17 @@ class auth_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array the test case data.
|
||||
*/
|
||||
public function membership_data_provider(): array {
|
||||
public static function membership_data_provider(): array {
|
||||
return [
|
||||
'New (unlinked) platform learner including PII, no legacy data, no consumer key bound, no legacy id' => [
|
||||
'legacy_data' => null,
|
||||
'membership_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => null,
|
||||
'expected' => [
|
||||
'PII' => self::PII_ALL,
|
||||
@@ -830,14 +833,14 @@ class auth_test extends \advanced_testcase {
|
||||
'New (unlinked) platform learner excluding PII, no legacy data, no consumer key bound, no legacy id' => [
|
||||
'legacy_data' => null,
|
||||
'membership_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
false,
|
||||
false
|
||||
)[0],
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => null,
|
||||
'expected' => [
|
||||
'PII' => self::PII_NONE,
|
||||
@@ -847,13 +850,13 @@ class auth_test extends \advanced_testcase {
|
||||
'New (unlinked) platform learner excluding names, no legacy data, no consumer key bound, no legacy id' => [
|
||||
'legacy_data' => null,
|
||||
'membership_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
false,
|
||||
)[0],
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => null,
|
||||
'expected' => [
|
||||
'PII' => self::PII_EMAILS_ONLY,
|
||||
@@ -863,14 +866,14 @@ class auth_test extends \advanced_testcase {
|
||||
'New (unlinked) platform learner excluding email, no legacy data, no consumer key bound, no legacy id' => [
|
||||
'legacy_data' => null,
|
||||
'membership_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
true,
|
||||
false
|
||||
)[0],
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => null,
|
||||
'expected' => [
|
||||
'PII' => self::PII_NAMES_ONLY,
|
||||
@@ -885,13 +888,13 @@ class auth_test extends \advanced_testcase {
|
||||
'consumer_key' => 'CONSUMER_1',
|
||||
],
|
||||
'membership_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
'legacy_user_id' => '123-abc'
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => 'CONSUMER_1',
|
||||
'expected' => [
|
||||
'PII' => self::PII_ALL,
|
||||
@@ -906,12 +909,12 @@ class auth_test extends \advanced_testcase {
|
||||
'consumer_key' => 'CONSUMER_1',
|
||||
],
|
||||
'membership_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => 'CONSUMER_1',
|
||||
'expected' => [
|
||||
'PII' => self::PII_ALL,
|
||||
@@ -926,12 +929,12 @@ class auth_test extends \advanced_testcase {
|
||||
'consumer_key' => 'CONSUMER_1',
|
||||
],
|
||||
'membership_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['123-abc'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => 'CONSUMER_1',
|
||||
'expected' => [
|
||||
'PII' => self::PII_ALL,
|
||||
@@ -946,12 +949,12 @@ class auth_test extends \advanced_testcase {
|
||||
'consumer_key' => 'CONSUMER_1',
|
||||
],
|
||||
'membership_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['123-abc'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => 'CONSUMER_ABCDEF',
|
||||
'expected' => [
|
||||
'PII' => self::PII_ALL,
|
||||
@@ -966,13 +969,13 @@ class auth_test extends \advanced_testcase {
|
||||
'consumer_key' => 'CONSUMER_1',
|
||||
],
|
||||
'membership_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
'legacy_user_id' => '123-abc'
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => null,
|
||||
'expected' => [
|
||||
'PII' => self::PII_ALL,
|
||||
@@ -982,13 +985,13 @@ class auth_test extends \advanced_testcase {
|
||||
'New (unlinked) platform learner including PII, no legacy data, consumer key bound, legacy user id sent' => [
|
||||
'legacy_data' => null,
|
||||
'membership_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
'legacy_user_id' => '123-abc'
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => 'CONSUMER_1',
|
||||
'expected' => [
|
||||
'PII' => self::PII_ALL,
|
||||
@@ -998,12 +1001,12 @@ class auth_test extends \advanced_testcase {
|
||||
'New (unlinked) platform instructor including PII, no legacy data, no consumer key bound, no legacy id' => [
|
||||
'legacy_data' => null,
|
||||
'membership_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor'
|
||||
)[0],
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => null,
|
||||
'expected' => [
|
||||
'PII' => self::PII_ALL,
|
||||
@@ -1013,14 +1016,14 @@ class auth_test extends \advanced_testcase {
|
||||
'New (unlinked) platform instructor excluding PII, no legacy data, no consumer key bound, no legacy id' => [
|
||||
'legacy_data' => null,
|
||||
'membership_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor',
|
||||
false,
|
||||
false
|
||||
)[0],
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => null,
|
||||
'expected' => [
|
||||
'PII' => self::PII_NONE,
|
||||
@@ -1031,12 +1034,12 @@ class auth_test extends \advanced_testcase {
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'has_authenticated_before' => true,
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'iss' => self::$issuer,
|
||||
'legacy_consumer_key' => null,
|
||||
'expected' => [
|
||||
'PII' => self::PII_ALL,
|
||||
@@ -1056,7 +1059,7 @@ class auth_test extends \advanced_testcase {
|
||||
global $DB;
|
||||
$auth = get_auth_plugin('lti');
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$mockiss = $this->issuer;
|
||||
$mockiss = self::$issuer;
|
||||
$mocksub = '1';
|
||||
|
||||
// Create a binding and verify it exists.
|
||||
@@ -1068,7 +1071,7 @@ class auth_test extends \advanced_testcase {
|
||||
$numusersbefore = $DB->count_records('user');
|
||||
$matcheduser = $auth->find_or_create_user_from_launch(
|
||||
$this->get_mock_launchdata_for_user(
|
||||
$this->get_mock_users_with_ids([$mocksub])[0]
|
||||
self::get_mock_users_with_ids([$mocksub])[0]
|
||||
)
|
||||
);
|
||||
$numusersafter = $DB->count_records('user');
|
||||
@@ -1148,17 +1151,17 @@ class auth_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array the test case data.
|
||||
*/
|
||||
public function update_user_account_provider(): array {
|
||||
public static function update_user_account_provider(): array {
|
||||
return [
|
||||
'Full PII included in both auths, no picture in either' => [
|
||||
'first_launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
@@ -1171,7 +1174,7 @@ class auth_test extends \advanced_testcase {
|
||||
],
|
||||
'No PII included in both auths, no picture in either' => [
|
||||
'first_launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
false,
|
||||
@@ -1179,7 +1182,7 @@ class auth_test extends \advanced_testcase {
|
||||
)[0]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
false,
|
||||
@@ -1194,7 +1197,7 @@ class auth_test extends \advanced_testcase {
|
||||
],
|
||||
'First auth no PII, second auth including PII, no picture in either' => [
|
||||
'first_launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
false,
|
||||
@@ -1202,7 +1205,7 @@ class auth_test extends \advanced_testcase {
|
||||
)[0]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
@@ -1215,13 +1218,13 @@ class auth_test extends \advanced_testcase {
|
||||
],
|
||||
'First auth full PII, second auth no PII, no picture in either' => [
|
||||
'first_launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
)[0]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
false,
|
||||
@@ -1236,13 +1239,13 @@ class auth_test extends \advanced_testcase {
|
||||
],
|
||||
'First auth full PII, second auth emails only, no picture in either' => [
|
||||
'first_launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
)[0]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
false
|
||||
@@ -1256,13 +1259,13 @@ class auth_test extends \advanced_testcase {
|
||||
],
|
||||
'First auth full PII, second auth names only, no picture in either' => [
|
||||
'first_launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
)[0]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
true,
|
||||
@@ -1277,13 +1280,13 @@ class auth_test extends \advanced_testcase {
|
||||
],
|
||||
'Full PII included in both auths, picture included in the second auth' => [
|
||||
'first_launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0]
|
||||
],
|
||||
'launch_data' => [
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
'user' => self::get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner',
|
||||
true,
|
||||
|
||||
@@ -469,7 +469,7 @@ class condition_test extends \advanced_testcase {
|
||||
$this->assertMatchesRegularExpression($description, $information);
|
||||
}
|
||||
|
||||
public function previous_activity_data(): array {
|
||||
public static function previous_activity_data(): array {
|
||||
// Assign grade, condition, activity to complete, activity to test, result, resultnot, description.
|
||||
return [
|
||||
'Missing previous activity complete' => [
|
||||
@@ -634,7 +634,7 @@ class condition_test extends \advanced_testcase {
|
||||
|
||||
}
|
||||
|
||||
public function section_previous_activity_data(): array {
|
||||
public static function section_previous_activity_data(): array {
|
||||
return [
|
||||
// Condition, Activity completion, section to test, result, resultnot, description.
|
||||
'Completion complete Section with no previous activity' => [
|
||||
|
||||
@@ -72,7 +72,7 @@ class frontend extends \core_availability\frontend {
|
||||
require_once($CFG->libdir . '/grouplib.php');
|
||||
|
||||
if ($courseid != $this->allgroupscourseid) {
|
||||
$this->allgroups = groups_get_all_groups($courseid, 0, 0, 'g.id, g.name');
|
||||
$this->allgroups = groups_get_all_groups($courseid, 0, 0, 'g.id, g.name, g.visibility');
|
||||
$this->allgroupscourseid = $courseid;
|
||||
}
|
||||
return $this->allgroups;
|
||||
|
||||
@@ -557,10 +557,13 @@ class backup_course_structure_step extends backup_structure_step {
|
||||
FROM {course_format_options}
|
||||
WHERE courseid = ? AND sectionid = 0', [ backup::VAR_PARENTID ]);
|
||||
|
||||
$handler = core_course\customfield\course_handler::create();
|
||||
$fieldsforbackup = $handler->get_instance_data_for_backup($this->task->get_courseid());
|
||||
$handler->backup_define_structure($this->task->get_courseid(), $customfield);
|
||||
$customfield->set_source_array($fieldsforbackup);
|
||||
// Custom fields.
|
||||
if ($this->get_setting_value('customfield')) {
|
||||
$handler = core_course\customfield\course_handler::create();
|
||||
$fieldsforbackup = $handler->get_instance_data_for_backup($this->task->get_courseid());
|
||||
$handler->backup_define_structure($this->task->get_courseid(), $customfield);
|
||||
$customfield->set_source_array($fieldsforbackup);
|
||||
}
|
||||
|
||||
// Some annotations
|
||||
|
||||
@@ -1409,14 +1412,19 @@ class backup_groups_structure_step extends backup_structure_step {
|
||||
FROM {groups} g
|
||||
JOIN {backup_ids_temp} bi ON g.id = bi.itemid
|
||||
WHERE bi.backupid = ?
|
||||
AND bi.itemname = 'groupfinal'", array(backup::VAR_BACKUPID));
|
||||
AND bi.itemname = 'groupfinal'",
|
||||
[backup_helper::is_sqlparam($this->get_backupid())]
|
||||
);
|
||||
|
||||
$grouping->set_source_sql("
|
||||
SELECT g.*
|
||||
FROM {groupings} g
|
||||
JOIN {backup_ids_temp} bi ON g.id = bi.itemid
|
||||
WHERE bi.backupid = ?
|
||||
AND bi.itemname = 'groupingfinal'", array(backup::VAR_BACKUPID));
|
||||
AND bi.itemname = 'groupingfinal'",
|
||||
[backup_helper::is_sqlparam($this->get_backupid())]
|
||||
);
|
||||
|
||||
$groupinggroup->set_source_table('groupings_groups', array('groupingid' => backup::VAR_PARENTID));
|
||||
|
||||
// This only happens if we are including users.
|
||||
@@ -1424,9 +1432,20 @@ class backup_groups_structure_step extends backup_structure_step {
|
||||
$member->set_source_table('groups_members', array('groupid' => backup::VAR_PARENTID));
|
||||
}
|
||||
|
||||
$courseid = $this->task->get_courseid();
|
||||
$groupcustomfield->set_source_array($this->get_group_custom_fields_for_backup($courseid));
|
||||
$groupingcustomfield->set_source_array($this->get_grouping_custom_fields_for_backup($courseid));
|
||||
// Custom fields.
|
||||
if ($this->get_setting_value('customfield')) {
|
||||
$groupcustomfieldarray = $this->get_group_custom_fields_for_backup(
|
||||
$group->get_source_sql(),
|
||||
[$this->get_backupid()]
|
||||
);
|
||||
$groupcustomfield->set_source_array($groupcustomfieldarray);
|
||||
|
||||
$groupingcustomfieldarray = $this->get_grouping_custom_fields_for_backup(
|
||||
$grouping->get_source_sql(),
|
||||
[$this->get_backupid()]
|
||||
);
|
||||
$groupingcustomfield->set_source_array($groupingcustomfieldarray);
|
||||
}
|
||||
}
|
||||
|
||||
// Define id annotations (as final)
|
||||
@@ -1445,14 +1464,16 @@ class backup_groups_structure_step extends backup_structure_step {
|
||||
|
||||
/**
|
||||
* Get custom fields array for group
|
||||
* @param int $courseid
|
||||
*
|
||||
* @param string $groupsourcesql
|
||||
* @param array $groupsourceparams
|
||||
* @return array
|
||||
*/
|
||||
protected function get_group_custom_fields_for_backup(int $courseid): array {
|
||||
protected function get_group_custom_fields_for_backup(string $groupsourcesql, array $groupsourceparams): array {
|
||||
global $DB;
|
||||
$handler = \core_group\customfield\group_handler::create();
|
||||
$fieldsforbackup = [];
|
||||
if ($groups = $DB->get_records('groups', ['courseid' => $courseid], '', 'id')) {
|
||||
if ($groups = $DB->get_records_sql($groupsourcesql, $groupsourceparams)) {
|
||||
foreach ($groups as $group) {
|
||||
$fieldsforbackup = array_merge($fieldsforbackup, $handler->get_instance_data_for_backup($group->id));
|
||||
}
|
||||
@@ -1462,14 +1483,16 @@ class backup_groups_structure_step extends backup_structure_step {
|
||||
|
||||
/**
|
||||
* Get custom fields array for grouping
|
||||
* @param int $courseid
|
||||
*
|
||||
* @param string $groupingsourcesql
|
||||
* @param array $groupingsourceparams
|
||||
* @return array
|
||||
*/
|
||||
protected function get_grouping_custom_fields_for_backup(int $courseid): array {
|
||||
protected function get_grouping_custom_fields_for_backup(string $groupingsourcesql, array $groupingsourceparams): array {
|
||||
global $DB;
|
||||
$handler = \core_group\customfield\grouping_handler::create();
|
||||
$fieldsforbackup = [];
|
||||
if ($groupings = $DB->get_records('groupings', ['courseid' => $courseid], '', 'id')) {
|
||||
if ($groupings = $DB->get_records_sql($groupingsourcesql, $groupingsourceparams)) {
|
||||
foreach ($groupings as $grouping) {
|
||||
$fieldsforbackup = array_merge($fieldsforbackup, $handler->get_instance_data_for_backup($grouping->id));
|
||||
}
|
||||
|
||||
@@ -380,7 +380,8 @@ abstract class restore_qtype_plugin extends restore_plugin {
|
||||
*
|
||||
* Only common stuff to all plugins, in this case:
|
||||
* - question: text and feedback
|
||||
* - question_answers: text and feedbak
|
||||
* - question_answers: text and feedback
|
||||
* - question_hints: hint
|
||||
*
|
||||
* Note each qtype will have, if needed, its own define_decode_contents method
|
||||
*/
|
||||
@@ -388,8 +389,9 @@ abstract class restore_qtype_plugin extends restore_plugin {
|
||||
|
||||
$contents = array();
|
||||
|
||||
$contents[] = new restore_decode_content('question', array('questiontext', 'generalfeedback'), 'question_created');
|
||||
$contents[] = new restore_decode_content('question_answers', array('answer', 'feedback'), 'question_answer');
|
||||
$contents[] = new restore_decode_content('question', ['questiontext', 'generalfeedback'], 'question_created');
|
||||
$contents[] = new restore_decode_content('question_answers', ['answer', 'feedback'], 'question_answer');
|
||||
$contents[] = new restore_decode_content('question_hints', ['hint'], 'question_hint');
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
@@ -300,8 +300,16 @@ class restore_root_task extends restore_task {
|
||||
$competencies->set_ui(new backup_setting_ui_checkbox($competencies, get_string('rootsettingcompetencies', 'backup')));
|
||||
$this->add_setting($competencies);
|
||||
|
||||
$customfields = new restore_customfield_setting('customfields', base_setting::IS_BOOLEAN, $defaultvalue);
|
||||
// Custom fields.
|
||||
$defaultvalue = false;
|
||||
$changeable = false;
|
||||
if (isset($rootsettings['customfield']) && $rootsettings['customfield']) { // Only enabled when available.
|
||||
$defaultvalue = true;
|
||||
$changeable = true;
|
||||
}
|
||||
$customfields = new restore_customfield_setting('customfield', base_setting::IS_BOOLEAN, $defaultvalue);
|
||||
$customfields->set_ui(new backup_setting_ui_checkbox($customfields, get_string('rootsettingcustomfield', 'backup')));
|
||||
$customfields->get_ui()->set_changeable($changeable);
|
||||
$this->add_setting($customfields);
|
||||
|
||||
// Define Content bank content.
|
||||
|
||||
+121
-115
@@ -1159,11 +1159,15 @@ class restore_groups_structure_step extends restore_structure_step {
|
||||
$groupinfo = $this->get_setting_value('groups');
|
||||
if ($groupinfo) {
|
||||
$paths[] = new restore_path_element('group', '/groups/group');
|
||||
$paths[] = new restore_path_element('groupcustomfield', '/groups/groupcustomfields/groupcustomfield');
|
||||
$paths[] = new restore_path_element('grouping', '/groups/groupings/grouping');
|
||||
$paths[] = new restore_path_element('groupingcustomfield',
|
||||
'/groups/groupings/groupingcustomfields/groupingcustomfield');
|
||||
$paths[] = new restore_path_element('grouping_group', '/groups/groupings/grouping/grouping_groups/grouping_group');
|
||||
|
||||
// Custom fields.
|
||||
if ($this->get_setting_value('customfield')) {
|
||||
$paths[] = new restore_path_element('groupcustomfield', '/groups/groupcustomfields/groupcustomfield');
|
||||
$paths[] = new restore_path_element('groupingcustomfield',
|
||||
'/groups/groupings/groupingcustomfields/groupingcustomfield');
|
||||
}
|
||||
}
|
||||
return $paths;
|
||||
}
|
||||
@@ -1235,9 +1239,11 @@ class restore_groups_structure_step extends restore_structure_step {
|
||||
*/
|
||||
public function process_groupcustomfield($data) {
|
||||
$newgroup = $this->get_mapping('group', $data['groupid']);
|
||||
$data['groupid'] = $newgroup->newitemid ?? $data['groupid'];
|
||||
$handler = \core_group\customfield\group_handler::create();
|
||||
$handler->restore_instance_data_from_backup($this->task, $data);
|
||||
if ($newgroup && $newgroup->newitemid) {
|
||||
$data['groupid'] = $newgroup->newitemid;
|
||||
$handler = \core_group\customfield\group_handler::create();
|
||||
$handler->restore_instance_data_from_backup($this->task, $data);
|
||||
}
|
||||
}
|
||||
|
||||
public function process_grouping($data) {
|
||||
@@ -1291,10 +1297,12 @@ class restore_groups_structure_step extends restore_structure_step {
|
||||
* @return void
|
||||
*/
|
||||
public function process_groupingcustomfield($data) {
|
||||
$newgroup = $this->get_mapping('grouping', $data['groupingid']);
|
||||
$data['groupingid'] = $newgroup->newitemid ?? $data['groupingid'];
|
||||
$handler = \core_group\customfield\grouping_handler::create();
|
||||
$handler->restore_instance_data_from_backup($this->task, $data);
|
||||
$newgrouping = $this->get_mapping('grouping', $data['groupingid']);
|
||||
if ($newgrouping && $newgrouping->newitemid) {
|
||||
$data['groupingid'] = $newgrouping->newitemid;
|
||||
$handler = \core_group\customfield\grouping_handler::create();
|
||||
$handler->restore_instance_data_from_backup($this->task, $data);
|
||||
}
|
||||
}
|
||||
|
||||
public function process_grouping_group($data) {
|
||||
@@ -1832,12 +1840,19 @@ class restore_course_structure_step extends restore_structure_step {
|
||||
|
||||
protected function define_structure() {
|
||||
|
||||
$paths = [];
|
||||
|
||||
$course = new restore_path_element('course', '/course');
|
||||
$category = new restore_path_element('category', '/course/category');
|
||||
$tag = new restore_path_element('tag', '/course/tags/tag');
|
||||
$customfield = new restore_path_element('customfield', '/course/customfields/customfield');
|
||||
$courseformatoptions = new restore_path_element('course_format_option', '/course/courseformatoptions/courseformatoption');
|
||||
$allowedmodule = new restore_path_element('allowed_module', '/course/allowed_modules/module');
|
||||
$paths[] = $course;
|
||||
$paths[] = new restore_path_element('category', '/course/category');
|
||||
$paths[] = new restore_path_element('tag', '/course/tags/tag');
|
||||
$paths[] = new restore_path_element('course_format_option', '/course/courseformatoptions/courseformatoption');
|
||||
$paths[] = new restore_path_element('allowed_module', '/course/allowed_modules/module');
|
||||
|
||||
// Custom fields.
|
||||
if ($this->get_setting_value('customfield')) {
|
||||
$paths[] = new restore_path_element('customfield', '/course/customfields/customfield');
|
||||
}
|
||||
|
||||
// Apply for 'format' plugins optional paths at course level
|
||||
$this->add_plugin_structure('format', $course);
|
||||
@@ -1860,7 +1875,7 @@ class restore_course_structure_step extends restore_structure_step {
|
||||
// Apply for admin tool plugins optional paths at course level.
|
||||
$this->add_plugin_structure('tool', $course);
|
||||
|
||||
return array($course, $category, $tag, $customfield, $allowedmodule, $courseformatoptions);
|
||||
return $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4921,6 +4936,12 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
/** @var array $cachedcategory store a question category */
|
||||
protected $cachedcategory = null;
|
||||
|
||||
/** @var stdClass the last question_bank_entry seen during the restore. Processed when we get to a question. */
|
||||
protected $latestqbe;
|
||||
|
||||
/** @var stdClass the last question_version seen during the restore. Processed when we get to a question. */
|
||||
protected $latestversion;
|
||||
|
||||
protected function define_structure() {
|
||||
|
||||
// Check if the backup is a pre 4.0 one.
|
||||
@@ -5046,45 +5067,25 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
}
|
||||
|
||||
/**
|
||||
* Process pre 4.0 question data where in creates the record for version and entry table.
|
||||
* Set up date to allow restore of questions from pre-4.0 backups.
|
||||
*
|
||||
* @param array $data the data from the XML file.
|
||||
* @param stdClass $data the data from the XML file.
|
||||
*/
|
||||
protected function process_question_legacy_data($data) {
|
||||
global $DB;
|
||||
$this->latestqbe = (object) [
|
||||
'id' => $data->id,
|
||||
'questioncategoryid' => $data->category,
|
||||
'ownerid' => $data->createdby,
|
||||
'idnumber' => $data->idnumber ?? null,
|
||||
];
|
||||
|
||||
$oldid = $data->id;
|
||||
// Process question bank entry.
|
||||
$entrydata = new stdClass();
|
||||
$entrydata->questioncategoryid = $data->category;
|
||||
$userid = $this->get_mappingid('user', $data->createdby);
|
||||
if ($userid) {
|
||||
$entrydata->ownerid = $userid;
|
||||
} else {
|
||||
if (!$this->task->is_samesite()) {
|
||||
$entrydata->ownerid = $this->task->get_userid();
|
||||
}
|
||||
}
|
||||
// The idnumber if it exists also needs to be unique within a category or reset it to null.
|
||||
if (isset($data->idnumber) && !$DB->record_exists('question_bank_entries',
|
||||
['idnumber' => $data->idnumber, 'questioncategoryid' => $data->category])) {
|
||||
$entrydata->idnumber = $data->idnumber;
|
||||
}
|
||||
|
||||
$newentryid = $DB->insert_record('question_bank_entries', $entrydata);
|
||||
// Process question versions.
|
||||
$versiondata = new stdClass();
|
||||
$versiondata->questionbankentryid = $newentryid;
|
||||
$versiondata->version = 1;
|
||||
// Question id is updated after inserting the question.
|
||||
$versiondata->questionid = 0;
|
||||
$versionstatus = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY;
|
||||
if ((int)$data->hidden === 1) {
|
||||
$versionstatus = \core_question\local\bank\question_version_status::QUESTION_STATUS_HIDDEN;
|
||||
}
|
||||
$versiondata->status = $versionstatus;
|
||||
$newversionid = $DB->insert_record('question_versions', $versiondata);
|
||||
$this->set_mapping('question_version_created', $oldid, $newversionid);
|
||||
$this->latestversion = (object) [
|
||||
'id' => $data->id,
|
||||
'version' => 1,
|
||||
'status' => $data->hidden ?
|
||||
\core_question\local\bank\question_version_status::QUESTION_STATUS_HIDDEN :
|
||||
\core_question\local\bank\question_version_status::QUESTION_STATUS_READY,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5093,37 +5094,9 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
* @param array $data the data from the XML file.
|
||||
*/
|
||||
protected function process_question_bank_entry($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
$questioncreated = $this->get_mappingid('question_category_created', $data->questioncategoryid) ? true : false;
|
||||
$recordexist = $DB->record_exists('question_bank_entries', ['id' => $data->id,
|
||||
'questioncategoryid' => $data->questioncategoryid]);
|
||||
// Check we have category created.
|
||||
if (!$questioncreated && $recordexist) {
|
||||
return self::SKIP_ALL_CHILDREN;
|
||||
}
|
||||
|
||||
$data->questioncategoryid = $this->get_new_parentid('question_category');
|
||||
$userid = $this->get_mappingid('user', $data->ownerid);
|
||||
if ($userid) {
|
||||
$data->ownerid = $userid;
|
||||
} else {
|
||||
if (!$this->task->is_samesite()) {
|
||||
$data->ownerid = $this->task->get_userid();
|
||||
}
|
||||
}
|
||||
|
||||
// The idnumber if it exists also needs to be unique within a category or reset it to null.
|
||||
if (!empty($data->idnumber) && $DB->record_exists('question_bank_entries',
|
||||
['idnumber' => $data->idnumber, 'questioncategoryid' => $data->questioncategoryid])) {
|
||||
unset($data->idnumber);
|
||||
}
|
||||
|
||||
$newitemid = $DB->insert_record('question_bank_entries', $data);
|
||||
$this->set_mapping('question_bank_entry', $oldid, $newitemid);
|
||||
// We can only determine the right way to process this once we get to
|
||||
// process_question and have more information, so for now just store.
|
||||
$this->latestqbe = (object) $data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5132,16 +5105,9 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
* @param array $data the data from the XML file.
|
||||
*/
|
||||
protected function process_question_versions($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
$data->questionbankentryid = $this->get_new_parentid('question_bank_entry');
|
||||
// Question id is updated after inserting the question.
|
||||
$data->questionid = 0;
|
||||
$newitemid = $DB->insert_record('question_versions', $data);
|
||||
$this->set_mapping('question_versions', $oldid, $newitemid);
|
||||
// We can only determine the right way to process this once we get to
|
||||
// process_question and have more information, so for now just store.
|
||||
$this->latestversion = (object) $data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5152,17 +5118,19 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
protected function process_question($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$data = (object) $data;
|
||||
$oldid = $data->id;
|
||||
|
||||
// Check if the backup is a pre 4.0 one.
|
||||
// Check we have one mapping for this question.
|
||||
if (!$questionmapping = $this->get_mapping('question', $oldid)) {
|
||||
// No mapping = this question doesn't need to be created/mapped.
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is a pre 4.0 backup, then there will not be a question bank entry
|
||||
// or question version in the file. So, we need to set up that data ready to be used below.
|
||||
$restoretask = $this->get_task();
|
||||
if ($restoretask->backup_release_compare('4.0', '<') || $restoretask->backup_version_compare(20220202, '<')) {
|
||||
// Check we have one mapping for this question.
|
||||
if (!$questionmapping = $this->get_mapping('question', $oldid)) {
|
||||
return; // No mapping = this question doesn't need to be created/mapped.
|
||||
}
|
||||
|
||||
// Get the mapped category (cannot use get_new_parentid() because not
|
||||
// all the categories have been created, so it is not always available
|
||||
// Instead we get the mapping for the question->parentitemid because
|
||||
@@ -5206,28 +5174,66 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
}
|
||||
}
|
||||
|
||||
$newitemid = $DB->insert_record('question', $data);
|
||||
$this->set_mapping('question', $oldid, $newitemid);
|
||||
// Also annotate them as question_created, we need
|
||||
// that later when remapping parents (keeping the old categoryid as parentid).
|
||||
$parentcatid = $this->get_old_parentid('question_category');
|
||||
$this->set_mapping('question_created', $oldid, $newitemid, false, null, $parentcatid);
|
||||
// Now update the question_versions table with the new question id. we dont need to do that for random qtypes.
|
||||
$legacyquestiondata = $this->get_mappingid('question_version_created', $oldid) ? true : false;
|
||||
if ($legacyquestiondata) {
|
||||
$parentitemid = $this->get_mappingid('question_version_created', $oldid);
|
||||
// With newitemid = 0, let's create the question.
|
||||
if (!$questionmapping->newitemid) {
|
||||
// Now we know we are inserting a question, we may need to insert the questionbankentry.
|
||||
if (empty($this->latestqbe->newid)) {
|
||||
$this->latestqbe->oldid = $this->latestqbe->id;
|
||||
|
||||
$this->latestqbe->questioncategoryid = $this->get_new_parentid('question_category');
|
||||
$userid = $this->get_mappingid('user', $this->latestqbe->ownerid);
|
||||
if ($userid) {
|
||||
$this->latestqbe->ownerid = $userid;
|
||||
} else {
|
||||
if (!$this->task->is_samesite()) {
|
||||
$this->latestqbe->ownerid = $this->task->get_userid();
|
||||
}
|
||||
}
|
||||
|
||||
// The idnumber if it exists also needs to be unique within a category or reset it to null.
|
||||
if (!empty($this->latestqbe->idnumber) && $DB->record_exists('question_bank_entries',
|
||||
['idnumber' => $this->latestqbe->idnumber, 'questioncategoryid' => $this->latestqbe->questioncategoryid])) {
|
||||
unset($this->latestqbe->idnumber);
|
||||
}
|
||||
|
||||
$this->latestqbe->newid = $DB->insert_record('question_bank_entries', $this->latestqbe);
|
||||
$this->set_mapping('question_bank_entry', $this->latestqbe->oldid, $this->latestqbe->newid);
|
||||
}
|
||||
|
||||
// Now store the question.
|
||||
$newitemid = $DB->insert_record('question', $data);
|
||||
$this->set_mapping('question', $oldid, $newitemid);
|
||||
// Also annotate them as question_created, we need
|
||||
// that later when remapping parents (keeping the old categoryid as parentid).
|
||||
$parentcatid = $this->get_old_parentid('question_category');
|
||||
$this->set_mapping('question_created', $oldid, $newitemid, false, null, $parentcatid);
|
||||
|
||||
// Also insert this question_version.
|
||||
$oldqvid = $this->latestversion->id;
|
||||
$this->latestversion->questionbankentryid = $this->latestqbe->newid;
|
||||
$this->latestversion->questionid = $newitemid;
|
||||
$newqvid = $DB->insert_record('question_versions', $this->latestversion);
|
||||
$this->set_mapping('question_versions', $oldqvid, $newqvid);
|
||||
|
||||
} else {
|
||||
$parentitemid = $this->get_new_parentid('question_versions');
|
||||
// By performing this set_mapping() we make get_old/new_parentid() to work for all the
|
||||
// children elements of the 'question' one (so qtype plugins will know the question they belong to).
|
||||
$this->set_mapping('question', $oldid, $questionmapping->newitemid);
|
||||
|
||||
// Also create the question_bank_entry and version mappings, if required.
|
||||
$newquestionversion = $DB->get_record('question_versions', ['questionid' => $questionmapping->newitemid]);
|
||||
$this->set_mapping('question_versions', $this->latestversion->id, $newquestionversion->id);
|
||||
if (empty($this->latestqbe->newid)) {
|
||||
$this->latestqbe->oldid = $this->latestqbe->id;
|
||||
$this->latestqbe->newid = $newquestionversion->questionbankentryid;
|
||||
$this->set_mapping('question_bank_entry', $this->latestqbe->oldid, $this->latestqbe->newid);
|
||||
}
|
||||
}
|
||||
$version = new stdClass();
|
||||
$version->id = $parentitemid;
|
||||
$version->questionid = $newitemid;
|
||||
$DB->update_record('question_versions', $version);
|
||||
|
||||
// Note, we don't restore any question files yet
|
||||
// as far as the CONTEXT_MODULE categories still
|
||||
// haven't their contexts to be restored to
|
||||
// The {@link restore_create_question_files}, executed in the final step
|
||||
// The {@see restore_create_question_files}, executed in the final
|
||||
// step will be in charge of restoring all the question files.
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class backup_xml_transformer_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filephp_links_replace_data_provider() {
|
||||
public static function filephp_links_replace_data_provider(): array {
|
||||
return array(
|
||||
array('http://test.test/', 'http://test.test/'),
|
||||
array('http://test.test/file.php/1', 'http://test.test/file.php/1'),
|
||||
|
||||
@@ -37,12 +37,13 @@ class restore_gradebook_structure_step_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rewrite_step_backup_file_for_legacy_freeze_provider() {
|
||||
public static function rewrite_step_backup_file_for_legacy_freeze_provider(): array {
|
||||
$fixturesdir = realpath(__DIR__ . '/fixtures/rewrite_step_backup_file_for_legacy_freeze/');
|
||||
$tests = [];
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($fixturesdir),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY);
|
||||
new \RecursiveDirectoryIterator($fixturesdir),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY,
|
||||
);
|
||||
|
||||
foreach ($iterator as $sourcefile) {
|
||||
$pattern = '/\.test$/';
|
||||
|
||||
@@ -556,6 +556,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
'backup_general_role_assignments' => 'role_assignments',
|
||||
'backup_general_activities' => 'activities',
|
||||
'backup_general_blocks' => 'blocks',
|
||||
'backup_general_files' => 'files',
|
||||
'backup_general_filters' => 'filters',
|
||||
'backup_general_comments' => 'comments',
|
||||
'backup_general_badges' => 'badges',
|
||||
@@ -566,6 +567,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
'backup_general_questionbank' => 'questionbank',
|
||||
'backup_general_groups' => 'groups',
|
||||
'backup_general_competencies' => 'competencies',
|
||||
'backup_general_customfield' => 'customfield',
|
||||
'backup_general_contentbankcontent' => 'contentbankcontent',
|
||||
'backup_general_xapistate' => 'xapistate',
|
||||
'backup_general_legacyfiles' => 'legacyfiles'
|
||||
@@ -583,6 +585,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
'backup_import_questionbank' => 'questionbank',
|
||||
'backup_import_groups' => 'groups',
|
||||
'backup_import_competencies' => 'competencies',
|
||||
'backup_import_customfield' => 'customfield',
|
||||
'backup_import_contentbankcontent' => 'contentbankcontent',
|
||||
'backup_import_legacyfiles' => 'legacyfiles'
|
||||
);
|
||||
@@ -606,6 +609,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
'backup_auto_role_assignments' => 'role_assignments',
|
||||
'backup_auto_activities' => 'activities',
|
||||
'backup_auto_blocks' => 'blocks',
|
||||
'backup_auto_files' => 'files',
|
||||
'backup_auto_filters' => 'filters',
|
||||
'backup_auto_comments' => 'comments',
|
||||
'backup_auto_badges' => 'badges',
|
||||
@@ -616,6 +620,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
'backup_auto_questionbank' => 'questionbank',
|
||||
'backup_auto_groups' => 'groups',
|
||||
'backup_auto_competencies' => 'competencies',
|
||||
'backup_auto_customfield' => 'customfield',
|
||||
'backup_auto_contentbankcontent' => 'contentbankcontent',
|
||||
'backup_auto_xapistate' => 'xapistate',
|
||||
'backup_auto_legacyfiles' => 'legacyfiles'
|
||||
|
||||
@@ -159,6 +159,7 @@ abstract class restore_controller_dbops extends restore_dbops {
|
||||
'restore_general_questionbank' => 'questionbank',
|
||||
'restore_general_groups' => 'groups',
|
||||
'restore_general_competencies' => 'competencies',
|
||||
'restore_general_customfield' => 'customfield',
|
||||
'restore_general_contentbankcontent' => 'contentbankcontent',
|
||||
'restore_general_xapistate' => 'xapistate',
|
||||
'restore_general_legacyfiles' => 'legacyfiles'
|
||||
|
||||
@@ -671,8 +671,7 @@ abstract class restore_dbops {
|
||||
$questions = self::restore_get_questions($restoreid, $category->id);
|
||||
|
||||
// Collect all the questions for this category into memory so we only talk to the DB once.
|
||||
$questioncache = $DB->get_records_sql_menu('SELECT q.id,
|
||||
q.stamp
|
||||
$questioncache = $DB->get_records_sql_menu('SELECT q.stamp, q.id
|
||||
FROM {question} q
|
||||
JOIN {question_versions} qv
|
||||
ON qv.questionid = q.id
|
||||
@@ -683,8 +682,8 @@ abstract class restore_dbops {
|
||||
WHERE qc.id = ?', array($matchcat->id));
|
||||
|
||||
foreach ($questions as $question) {
|
||||
if (isset($questioncache[$question->stamp." ".$question->version])) {
|
||||
$matchqid = $questioncache[$question->stamp." ".$question->version];
|
||||
if (isset($questioncache[$question->stamp])) {
|
||||
$matchqid = $questioncache[$question->stamp];
|
||||
} else {
|
||||
$matchqid = false;
|
||||
}
|
||||
|
||||
@@ -124,8 +124,7 @@ class restore_dbops_test extends \advanced_testcase {
|
||||
/**
|
||||
* Data provider for {@link test_precheck_user()}
|
||||
*/
|
||||
public function precheck_user_provider() {
|
||||
|
||||
public static function precheck_user_provider(): array {
|
||||
$emailmultiplier = [
|
||||
'shortmail' => 'normalusername@example.com',
|
||||
'longmail' => str_repeat('a', 100) // It's not validated, hence any string is ok.
|
||||
@@ -135,7 +134,7 @@ class restore_dbops_test extends \advanced_testcase {
|
||||
|
||||
foreach ($emailmultiplier as $emailk => $email) {
|
||||
// Get the related cases.
|
||||
$cases = $this->precheck_user_cases($email);
|
||||
$cases = self::precheck_user_cases($email);
|
||||
// Rename them (keys).
|
||||
foreach ($cases as $key => $case) {
|
||||
$providercases[$key . ' - ' . $emailk] = $case;
|
||||
@@ -150,7 +149,7 @@ class restore_dbops_test extends \advanced_testcase {
|
||||
*
|
||||
* @param string $email
|
||||
*/
|
||||
private function precheck_user_cases($email) {
|
||||
private static function precheck_user_cases($email) {
|
||||
global $CFG;
|
||||
|
||||
$baseuserarr = [
|
||||
|
||||
@@ -35,22 +35,35 @@ require_once($CFG->dirroot.'/backup/util/xml/parser/processors/grouped_parser_pr
|
||||
* TODO: Complete phpdocs
|
||||
*/
|
||||
class restore_questions_parser_processor extends grouped_parser_processor {
|
||||
/** @var string XML path in the questions.xml backup file to question categories. */
|
||||
protected const CATEGORY_PATH = '/question_categories/question_category';
|
||||
|
||||
protected $restoreid;
|
||||
protected $lastcatid;
|
||||
/** @var string XML path in the questions.xml to question elements within question_category (Moodle 4.0+). */
|
||||
protected const QUESTION_SUBPATH =
|
||||
'/question_bank_entries/question_bank_entry/question_version/question_versions/questions/question';
|
||||
|
||||
/** @var string XML path in the questions.xml to question elements within question_category (before Moodle 4.0). */
|
||||
protected const LEGACY_QUESTION_SUBPATH = '/questions/question';
|
||||
|
||||
/** @var string identifies the current restore. */
|
||||
protected string $restoreid;
|
||||
|
||||
/** @var int during the restore, this tracks the last category we saw. Any questions we see will be in here. */
|
||||
protected int $lastcatid;
|
||||
|
||||
public function __construct($restoreid) {
|
||||
$this->restoreid = $restoreid;
|
||||
$this->lastcatid = 0;
|
||||
parent::__construct(array());
|
||||
parent::__construct();
|
||||
// Set the paths we are interested on
|
||||
$this->add_path('/question_categories/question_category');
|
||||
$this->add_path('/question_categories/question_category/questions/question');
|
||||
$this->add_path(self::CATEGORY_PATH);
|
||||
$this->add_path(self::CATEGORY_PATH . self::QUESTION_SUBPATH);
|
||||
$this->add_path(self::CATEGORY_PATH . self::LEGACY_QUESTION_SUBPATH);
|
||||
}
|
||||
|
||||
protected function dispatch_chunk($data) {
|
||||
// Prepare question_category record
|
||||
if ($data['path'] == '/question_categories/question_category') {
|
||||
if ($data['path'] == self::CATEGORY_PATH) {
|
||||
$info = (object)$data['tags'];
|
||||
$itemname = 'question_category';
|
||||
$itemid = $info->id;
|
||||
@@ -58,7 +71,8 @@ class restore_questions_parser_processor extends grouped_parser_processor {
|
||||
$this->lastcatid = $itemid;
|
||||
|
||||
// Prepare question record
|
||||
} else if ($data['path'] == '/question_categories/question_category/questions/question') {
|
||||
} else if ($data['path'] == self::CATEGORY_PATH . self::QUESTION_SUBPATH ||
|
||||
$data['path'] == self::CATEGORY_PATH . self::LEGACY_QUESTION_SUBPATH) {
|
||||
$info = (object)$data['tags'];
|
||||
$itemname = 'question';
|
||||
$itemid = $info->id;
|
||||
|
||||
@@ -53,7 +53,7 @@ class restore_structure_parser_processor_test extends advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function process_cdata_data_provider() {
|
||||
public static function process_cdata_data_provider(): array {
|
||||
return array(
|
||||
array(null, null, true),
|
||||
array("$@NULL@$", null, true),
|
||||
|
||||
@@ -77,8 +77,8 @@ class badges extends system_report {
|
||||
$this->add_filters();
|
||||
$this->add_actions();
|
||||
|
||||
// Set initial sorting by name.
|
||||
$this->set_initial_sort_column('badge:namewithlink', SORT_ASC);
|
||||
$this->set_default_no_results_notice(new lang_string('nomatchingbadges', 'core_badges'));
|
||||
|
||||
// Set if report can be downloaded.
|
||||
$this->set_downloadable(false);
|
||||
@@ -157,13 +157,12 @@ class badges extends system_report {
|
||||
* unique identifier
|
||||
*/
|
||||
protected function add_filters(): void {
|
||||
$filters = [
|
||||
$this->add_filters_from_entities([
|
||||
'badge:name',
|
||||
'badge:version',
|
||||
'badge:status',
|
||||
'badge:expiry',
|
||||
];
|
||||
$this->add_filters_from_entities($filters);
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,8 +18,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace core_badges\reportbuilder\local\systemreports;
|
||||
|
||||
use core\context\system;
|
||||
use core_badges\reportbuilder\local\entities\badge;
|
||||
use core_badges\reportbuilder\local\entities\badge_issued;
|
||||
use core_reportbuilder\local\helpers\database;
|
||||
use core_reportbuilder\system_report;
|
||||
use lang_string;
|
||||
use moodle_url;
|
||||
@@ -52,11 +54,18 @@ class course_badges extends system_report {
|
||||
$this->set_main_table('badge', $entityalias);
|
||||
$this->add_entity($badgeentity);
|
||||
|
||||
$type = $this->get_parameter('type', 0, PARAM_INT);
|
||||
$courseid = $this->get_parameter('courseid', 0, PARAM_INT);
|
||||
$paramtype = database::generate_param_name();
|
||||
$context = $this->get_context();
|
||||
if ($context instanceof system) {
|
||||
$type = BADGE_TYPE_SITE;
|
||||
$this->add_base_condition_sql("{$entityalias}.type = :$paramtype", [$paramtype => $type]);
|
||||
} else {
|
||||
$type = BADGE_TYPE_COURSE;
|
||||
$paramcourseid = database::generate_param_name();
|
||||
$this->add_base_condition_sql("{$entityalias}.type = :$paramtype AND {$entityalias}.courseid = :$paramcourseid",
|
||||
[$paramtype => $type, $paramcourseid => $context->instanceid]);
|
||||
}
|
||||
|
||||
$this->add_base_condition_simple('type', $type);
|
||||
$this->add_base_condition_simple('courseid', $courseid);
|
||||
$this->add_base_condition_sql("({$entityalias}.status = " . BADGE_STATUS_ACTIVE .
|
||||
" OR {$entityalias}.status = " . BADGE_STATUS_ACTIVE_LOCKED . ")");
|
||||
|
||||
@@ -70,9 +79,12 @@ class course_badges extends system_report {
|
||||
$this->add_base_fields("{$badgeissuedalias}.uniquehash");
|
||||
|
||||
// Now we can call our helper methods to add the content we want to include in the report.
|
||||
$this->add_columns($badgeissuedalias);
|
||||
$this->add_columns();
|
||||
$this->add_filters();
|
||||
|
||||
$this->set_initial_sort_column('badge:name', SORT_ASC);
|
||||
$this->set_default_no_results_notice(new lang_string('nomatchingbadges', 'core_badges'));
|
||||
|
||||
// Set if report can be downloaded.
|
||||
$this->set_downloadable(false);
|
||||
}
|
||||
@@ -91,18 +103,17 @@ class course_badges extends system_report {
|
||||
*
|
||||
* They are provided by the entities we previously added in the {@see initialise} method, referencing each by their
|
||||
* unique identifier. If custom columns are needed just for this report, they can be defined here.
|
||||
*
|
||||
* @param string $badgeissuedalias
|
||||
*/
|
||||
public function add_columns(string $badgeissuedalias): void {
|
||||
$columns = [
|
||||
protected function add_columns(): void {
|
||||
$badgeissuedalias = $this->get_entity('badge_issued')->get_table_alias('badge_issued');
|
||||
|
||||
$this->add_columns_from_entities([
|
||||
'badge:image',
|
||||
'badge:name',
|
||||
'badge:description',
|
||||
'badge:criteria',
|
||||
'badge_issued:issued',
|
||||
];
|
||||
$this->add_columns_from_entities($columns);
|
||||
]);
|
||||
|
||||
$this->get_column('badge_issued:issued')
|
||||
->set_title(new lang_string('awardedtoyou', 'core_badges'))
|
||||
@@ -119,8 +130,6 @@ class course_badges extends system_report {
|
||||
$icon = new pix_icon('i/valid', get_string('dateearned', 'badges', $date));
|
||||
return $OUTPUT->action_icon($badgeurl, $icon, null, null, true);
|
||||
});
|
||||
|
||||
$this->set_initial_sort_column('badge:name', SORT_ASC);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,11 +139,9 @@ class course_badges extends system_report {
|
||||
* unique identifier
|
||||
*/
|
||||
protected function add_filters(): void {
|
||||
$filters = [
|
||||
$this->add_filters_from_entities([
|
||||
'badge:name',
|
||||
'badge_issued:issued',
|
||||
];
|
||||
|
||||
$this->add_filters_from_entities($filters);
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,9 @@ class recipients extends system_report {
|
||||
$this->add_filters();
|
||||
$this->add_actions();
|
||||
|
||||
$this->set_initial_sort_column('badge_issued:issued', SORT_DESC);
|
||||
$this->set_default_no_results_notice(new lang_string('nomatchingawards', 'core_badges'));
|
||||
|
||||
// Set if report can be downloaded.
|
||||
$this->set_downloadable(false);
|
||||
}
|
||||
@@ -72,7 +75,9 @@ class recipients extends system_report {
|
||||
* @return bool
|
||||
*/
|
||||
protected function can_view(): bool {
|
||||
return has_capability('moodle/badges:viewawarded', $this->get_context());
|
||||
$badgeid = $this->get_parameter('badgeid', 0, PARAM_INT);
|
||||
$badge = new \core_badges\badge($badgeid);
|
||||
return has_capability('moodle/badges:viewawarded', $badge->get_context());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,14 +86,11 @@ class recipients extends system_report {
|
||||
* They are provided by the entities we previously added in the {@see initialise} method, referencing each by their
|
||||
* unique identifier. If custom columns are needed just for this report, they can be defined here.
|
||||
*/
|
||||
public function add_columns(): void {
|
||||
$columns = [
|
||||
protected function add_columns(): void {
|
||||
$this->add_columns_from_entities([
|
||||
'user:fullnamewithlink',
|
||||
'badge_issued:issued',
|
||||
];
|
||||
|
||||
$this->add_columns_from_entities($columns);
|
||||
$this->set_initial_sort_column('badge_issued:issued', SORT_DESC);
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,12 +100,10 @@ class recipients extends system_report {
|
||||
* unique identifier
|
||||
*/
|
||||
protected function add_filters(): void {
|
||||
$filters = [
|
||||
$this->add_filters_from_entities([
|
||||
'user:fullname',
|
||||
'badge_issued:issued',
|
||||
];
|
||||
|
||||
$this->add_filters_from_entities($filters);
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -89,6 +89,8 @@ if (!has_any_capability(array(
|
||||
}
|
||||
|
||||
$PAGE->set_title($hdr);
|
||||
|
||||
/** @var core_badges_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'badges');
|
||||
|
||||
if ($delete || $archive) {
|
||||
@@ -159,8 +161,6 @@ if ($msg !== '') {
|
||||
}
|
||||
|
||||
$report = system_report_factory::create(badges::class, $PAGE->context);
|
||||
$report->set_default_no_results_notice(new lang_string('nobadges', 'badges'));
|
||||
|
||||
echo $report->output();
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user