Compare commits
259 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4bd3217ce8 | |||
| 3a71764572 | |||
| 15d05e6d76 | |||
| 96579b1904 | |||
| b5600c2b56 | |||
| 5b374f607a | |||
| f0f81cbddf | |||
| 9141121f01 | |||
| 588f9efe8c | |||
| 6e9de0d56b | |||
| 5f96398a90 | |||
| ea3bba0ac8 | |||
| fd1b952e3e | |||
| 00253d140c | |||
| ade9ea1b64 | |||
| 175e553143 | |||
| ccaa6daf95 | |||
| f3a96eb019 | |||
| f68fc730f4 | |||
| c44cd5ce91 | |||
| 65acecced1 | |||
| 3f8502225e | |||
| a7f0516ae9 | |||
| 10fef0df99 | |||
| f6f8ec2291 | |||
| 065fdf4b2d | |||
| 1ab447455b | |||
| bf301a5e81 | |||
| bbd8a07f68 | |||
| 8b2638fd56 | |||
| 97414ca1cb | |||
| a11e396945 | |||
| c13aac05cc | |||
| a4e26132e0 | |||
| 1b6873b44a | |||
| 9b0645fc15 | |||
| 2db344ac25 | |||
| 3be068cc72 | |||
| e33213647c | |||
| 289056c576 | |||
| 1e6e11d8d3 | |||
| 94a7dbf7f4 | |||
| 70d07c5947 | |||
| 8a31a02cce | |||
| a8b2acd35c | |||
| cd2a074cc2 | |||
| 660d38be15 | |||
| a87bb9848f | |||
| 376411566a | |||
| 85f4603014 | |||
| 1ae32381c5 | |||
| 966ac4af8f | |||
| 9a20fcd261 | |||
| d0931fd7d4 | |||
| d3f2f141a5 | |||
| 6f59fe694b | |||
| 2cc40431cb | |||
| cdbc789fd8 | |||
| 3e45d0801e | |||
| 348c37c98d | |||
| 57b5c36320 | |||
| cd0b2c6624 | |||
| 2ba08bbda2 | |||
| e7e806e5f9 | |||
| 9aa4e03b03 | |||
| e8e20f996d | |||
| 46861f51b7 | |||
| 6e98de58b4 | |||
| 445f79f464 | |||
| 491356530e | |||
| 943ad5a1fc | |||
| 88763543f8 | |||
| 47e3c9ad06 | |||
| 5ac62e7763 | |||
| 7eba1d5996 | |||
| 5c1dd89dd3 | |||
| fa5a4b9612 | |||
| 2da1a26439 | |||
| 88ef13a747 | |||
| ab60333d45 | |||
| 485130d7c5 | |||
| f83ab42515 | |||
| eb19752b9a | |||
| 3bb4b79a15 | |||
| 671514c6c2 | |||
| 1113c4c5b1 | |||
| 2b50abb97b | |||
| 4a844708e6 | |||
| 36f946b5db | |||
| 39def1c571 | |||
| df4c1d94f0 | |||
| 1f60d5198d | |||
| a93ceeef99 | |||
| 1be54667d6 | |||
| 5ae0bf0a12 | |||
| 8dd0ea96e5 | |||
| 42b0a371bf | |||
| 796dd551f7 | |||
| 8d8b9b7268 | |||
| cb041849a3 | |||
| e764df0dbb | |||
| a817a54e90 | |||
| 176558d2ce | |||
| f7931a5580 | |||
| d12989b797 | |||
| 1262e4539e | |||
| eb7e4a9b65 | |||
| 26e68178a8 | |||
| b1d7ea12cd | |||
| c370c0cc5e | |||
| e1d05182a6 | |||
| 2b6424c59d | |||
| 8270af1bf0 | |||
| 88e82bb634 | |||
| 5a189106ad | |||
| 6a107256e3 | |||
| 521a83352d | |||
| 66183e5320 | |||
| 5ebabad505 | |||
| 9fe9652c16 | |||
| e5b715291d | |||
| 50a7bad23e | |||
| cfcfa4b1cd | |||
| 5ec8651d54 | |||
| ff08b12ce1 | |||
| 762681f5c4 | |||
| 4d40958181 | |||
| 7f3f962c3f | |||
| aab9e18b6d | |||
| cd5c991ede | |||
| 1c70185782 | |||
| cf431667e9 | |||
| 598b4743cc | |||
| a35b341ce7 | |||
| 66f4852bff | |||
| aeace8ee75 | |||
| 38f99a1e60 | |||
| 7547dec095 | |||
| d4564b876e | |||
| 0f5cb9dbd5 | |||
| 1ecc215b3a | |||
| ecc8edd917 | |||
| 8bcec8ba5f | |||
| b26192f62f | |||
| 82c915dbc3 | |||
| 50ab3f94d5 | |||
| 5b282947d7 | |||
| 24dc478086 | |||
| 2562bbfd1b | |||
| 1716e2f2cd | |||
| acff633e39 | |||
| 65ceca6092 | |||
| c21b1143a4 | |||
| 0cd7aaebcd | |||
| 2e8b980985 | |||
| 01aa6fa7d2 | |||
| 6290196cde | |||
| ffa8c930f0 | |||
| 8679f4afdf | |||
| 1afeadb4f4 | |||
| 3fc2111a4b | |||
| d731f7e01e | |||
| 49fbe6d614 | |||
| 9ece615f6c | |||
| 42052386d1 | |||
| 0d02ded10f | |||
| aaf5c3f8b7 | |||
| 11c941f404 | |||
| 87d0aae1fb | |||
| 3e0c2a45fb | |||
| a3b84f77c7 | |||
| 149a477903 | |||
| 47cd445f67 | |||
| 5524686f71 | |||
| 20d4962c33 | |||
| 1b93c2781e | |||
| 39658c5b3a | |||
| e271f67942 | |||
| 1aef5337bd | |||
| 3ef3a9b1bc | |||
| 80c7a3a847 | |||
| c5b16d9afb | |||
| 4fb2a4dd60 | |||
| 5ab2997d89 | |||
| 16efbcaa01 | |||
| 3f020e662d | |||
| ef01def984 | |||
| ce1ef8bda0 | |||
| 8adf0918ce | |||
| 86e830eac4 | |||
| 60fb2c1232 | |||
| 605a610702 | |||
| 55e6c1b588 | |||
| e792dbbe0b | |||
| 09880d7d78 | |||
| 426e34af13 | |||
| 161d14cd92 | |||
| 204da574bd | |||
| a7f0f4af47 | |||
| cec04e64a1 | |||
| 371c836be1 | |||
| 97f35300f7 | |||
| 2870ea8556 | |||
| 1c2e8c3abb | |||
| 125ff0d462 | |||
| 23bde28300 | |||
| f5aa88ec02 | |||
| 9f9fa01a91 | |||
| 5bf6da6331 | |||
| 69751fcd69 | |||
| 5c969d2370 | |||
| 7c959f479b | |||
| d43cec5bb3 | |||
| a47729dc17 | |||
| 8ffd4c4bb1 | |||
| a3ab626df1 | |||
| fd103caa83 | |||
| 12d87a9b65 | |||
| cd54f46df1 | |||
| 49e66dfc5d | |||
| c36c98448d | |||
| 5e7d431426 | |||
| 3b4b95d431 | |||
| 42079bb48d | |||
| c294a22dae | |||
| bde5487a56 | |||
| c0b2343245 | |||
| ae500b5728 | |||
| b311baf0bd | |||
| d1c223071a | |||
| 14f9c08355 | |||
| 9ec7e01527 | |||
| ce20b2f255 | |||
| 85bd222b2f | |||
| cf3d932d74 | |||
| 0b47dfec7c | |||
| 8036733091 | |||
| a74e15c66b | |||
| b7e1d77184 | |||
| 5379d34827 | |||
| 50e813478a | |||
| 4f699801b9 | |||
| 7beb6d7e82 | |||
| 1f1406d68c | |||
| 17924add45 | |||
| 56293e0de4 | |||
| 653c0937c6 | |||
| 9fcb0eca01 | |||
| ff87bb5101 | |||
| a271d9efc9 | |||
| 3e18e85dce | |||
| 92fdfe834f | |||
| f7c18e4e4b | |||
| 2698647bcd | |||
| 803c3d8977 | |||
| 62e776673a | |||
| 89c30cecd8 | |||
| a5ac414521 | |||
| 1d848a78cf |
@@ -128,7 +128,7 @@ jobs:
|
||||
|
||||
- name: Setting up redis service
|
||||
run: |
|
||||
choco install redis-64 --version 3.0.503 --no-progress
|
||||
choco install redis --version 5.0.7 --no-progress
|
||||
nssm install redis redis-server
|
||||
nssm start redis
|
||||
|
||||
|
||||
@@ -6,6 +6,82 @@ More detailed information on key changes can be found in the [Developer update n
|
||||
|
||||
The format of this change log follows the advice given at [Keep a CHANGELOG](https://keepachangelog.com).
|
||||
|
||||
## 4.5.1
|
||||
|
||||
### core
|
||||
|
||||
#### Added
|
||||
|
||||
- `\core\output\activity_header` now uses the `is_title_allowed()` method when setting the title in the constructor.
|
||||
|
||||
This method has been improved to give priority to the 'notitle' option in the theme config for the current page layout, over the top-level option in the theme.
|
||||
|
||||
For example, the Boost theme sets `$THEME->activityheaderconfig['notitle'] = true;` by default, but in its `secure` pagelayout, it has `'notitle' = false`.
|
||||
This prevents display of the title in all layouts except `secure`.
|
||||
|
||||
For more information see [MDL-75610](https://tracker.moodle.org/browse/MDL-75610)
|
||||
|
||||
#### Changed
|
||||
|
||||
- All uses of the following PHPUnit methods have been removed as these methods are
|
||||
deprecated upstream without direct replacement:
|
||||
|
||||
- `withConsecutive`
|
||||
- `willReturnConsecutive`
|
||||
- `onConsecutive`
|
||||
|
||||
Any plugin using these methods must update their uses.
|
||||
|
||||
For more information see [MDL-81308](https://tracker.moodle.org/browse/MDL-81308)
|
||||
|
||||
### core_courseformat
|
||||
|
||||
#### Added
|
||||
|
||||
- Add core_courseformat\base::invalidate_all_session_caches to reset course editor cache for all users when course is changed. This method can be used as an alternative to core_courseformat\base::session_cache_reset for resetting the cache for the current user in case the change in the course should be reflected for all users.
|
||||
|
||||
For more information see [MDL-83185](https://tracker.moodle.org/browse/MDL-83185)
|
||||
|
||||
### core_enrol
|
||||
|
||||
#### Changed
|
||||
|
||||
- The `after_user_enrolled` hook now contains a `roleid` property to allow for listeners to determine which role was assigned during user enrolment (if any)
|
||||
|
||||
The base enrolment `enrol_plugin::send_course_welcome_message_to_user` method also now accepts a `$roleid` parameter in order to correctly populate the `courserole` placeholder
|
||||
|
||||
For more information see [MDL-83432](https://tracker.moodle.org/browse/MDL-83432)
|
||||
|
||||
### core_form
|
||||
|
||||
#### Changed
|
||||
|
||||
- The `cohort` form element now accepts new `includes` option, which is passed to the corresponding external service to determine which cohorts to return (self, parents, all)
|
||||
|
||||
For more information see [MDL-83641](https://tracker.moodle.org/browse/MDL-83641)
|
||||
|
||||
### core_reportbuilder
|
||||
|
||||
#### Changed
|
||||
|
||||
- The `get_active_conditions` method of the base report class has a new `$checkavailable` parameter to determine whether to check the returned conditions availability
|
||||
|
||||
For more information see [MDL-82809](https://tracker.moodle.org/browse/MDL-82809)
|
||||
|
||||
### mod_quiz
|
||||
|
||||
#### Changed
|
||||
|
||||
- The `\mod_quiz\attempt_walkthrough_from_csv_test` unit test has been marked as final and should not be extended by other tests.
|
||||
|
||||
All shared functionality has been moved to a new autoloadable test-case:
|
||||
`\mod_quiz\tests\attempt_walkthrough_testcase`.
|
||||
|
||||
To support this testcase the existing `$files` instance property should be replaced with a new static method, `::get_test_files`.
|
||||
Both the existing instance property and the new static method can co-exist.
|
||||
|
||||
For more information see [MDL-81521](https://tracker.moodle.org/browse/MDL-81521)
|
||||
|
||||
## 4.5
|
||||
|
||||
### core
|
||||
|
||||
@@ -105,10 +105,9 @@ class task_log extends base {
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_fields("{$tablealias}.classname, {$tablealias}.id")
|
||||
->add_field("{$tablealias}.classname")
|
||||
->set_is_sortable(true)
|
||||
->add_callback(static function($value, stdClass $row): string {
|
||||
$classname = $row->classname;
|
||||
->add_callback(static function(string $classname): string {
|
||||
$output = '';
|
||||
if (class_exists($classname)) {
|
||||
$task = new $classname;
|
||||
@@ -119,7 +118,6 @@ class task_log extends base {
|
||||
$output .= \html_writer::tag('div', "\\{$classname}", [
|
||||
'class' => 'small text-muted',
|
||||
]);
|
||||
$output = \html_writer::link(new \moodle_url('/admin/tasklogs.php', ['logid' => $row->id]), $output);
|
||||
return $output;
|
||||
});
|
||||
|
||||
|
||||
@@ -20,10 +20,12 @@ use context_system;
|
||||
use core_admin\reportbuilder\local\entities\task_log;
|
||||
use core_reportbuilder\local\entities\user;
|
||||
use core_reportbuilder\local\report\action;
|
||||
use core_reportbuilder\system_report;
|
||||
use html_writer;
|
||||
use lang_string;
|
||||
use moodle_url;
|
||||
use pix_icon;
|
||||
use core_reportbuilder\system_report;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Task logs system report class implementation
|
||||
@@ -89,7 +91,9 @@ class task_logs extends system_report {
|
||||
* unique identifier
|
||||
*/
|
||||
public function add_columns(): void {
|
||||
$columns = [
|
||||
$entitymainalias = $this->get_entity('task_log')->get_table_alias('task_log');
|
||||
|
||||
$this->add_columns_from_entities([
|
||||
'task_log:name',
|
||||
'task_log:type',
|
||||
'user:fullname',
|
||||
@@ -99,14 +103,18 @@ class task_logs extends system_report {
|
||||
'task_log:pid',
|
||||
'task_log:database',
|
||||
'task_log:result',
|
||||
];
|
||||
]);
|
||||
|
||||
$this->add_columns_from_entities($columns);
|
||||
// Wrap the task name in a link.
|
||||
$this->get_column('task_log:name')
|
||||
->add_field("{$entitymainalias}.id")
|
||||
->add_callback(static function(string $output, stdClass $row): string {
|
||||
return html_writer::link(new moodle_url('/admin/tasklogs.php', ['logid' => $row->id]), $output);
|
||||
});
|
||||
|
||||
// It's possible to override the display name of a column, if you don't want to use the value provided by the entity.
|
||||
if ($column = $this->get_column('user:fullname')) {
|
||||
$column->set_title(new lang_string('user', 'admin'));
|
||||
}
|
||||
// Rename the user fullname column.
|
||||
$this->get_column('user:fullname')
|
||||
->set_title(new lang_string('user', 'admin'));
|
||||
|
||||
// It's possible to set a default initial sort direction for one column.
|
||||
$this->set_initial_sort_column('task_log:starttime', SORT_DESC);
|
||||
@@ -119,16 +127,14 @@ class task_logs extends system_report {
|
||||
* unique identifier
|
||||
*/
|
||||
protected function add_filters(): void {
|
||||
$filters = [
|
||||
$this->add_filters_from_entities([
|
||||
'task_log:name',
|
||||
'task_log:type',
|
||||
'task_log:output',
|
||||
'task_log:result',
|
||||
'task_log:timestart',
|
||||
'task_log:duration',
|
||||
];
|
||||
|
||||
$this->add_filters_from_entities($filters);
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -368,7 +368,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,
|
||||
@@ -531,26 +531,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,
|
||||
@@ -559,7 +565,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,
|
||||
@@ -567,20 +575,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,
|
||||
@@ -589,7 +603,6 @@ class manager_test extends \advanced_testcase {
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test the behaviour of delete_preset() method when the preset id doesn't exist.
|
||||
*
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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"
|
||||
@@ -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');
|
||||
|
||||
@@ -51,5 +51,8 @@ function xmldb_tool_cohortroles_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,5 +36,8 @@ function xmldb_tool_customlang_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -106,5 +106,8 @@ function xmldb_tool_dataprivacy_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -41,5 +41,8 @@ function xmldb_tool_log_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -35,5 +35,8 @@ function xmldb_logstore_database_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -35,5 +35,8 @@ function xmldb_logstore_standard_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -142,17 +142,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);
|
||||
@@ -188,6 +185,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']);
|
||||
@@ -263,6 +262,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']);
|
||||
@@ -270,6 +270,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']);
|
||||
@@ -378,6 +379,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 = 2024100700; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2024100701; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2024100100; // 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;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -51,5 +51,8 @@ function xmldb_factor_auth_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -73,5 +73,8 @@ function xmldb_factor_sms_upgrade(int $oldversion): bool {
|
||||
upgrade_plugin_savepoint(true, 2024082201, 'factor', 'sms');
|
||||
}
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ $string['managefactor'] = 'Manage SMS';
|
||||
$string['managefactorbutton'] = 'Manage';
|
||||
$string['manageinfo'] = 'You are using \'{$a}\' to authenticate.';
|
||||
$string['notification:smsgatewaymigration'] = 'SMS settings have moved';
|
||||
$string['notification:smsgatewaymigrationinfo'] = 'A new SMS subsystem is now available for managing and configuring all SMS-related functions. Your existing SMS configurations have been seamlessly migrated. You can find and manage them on the new <a href="{$a}">SMS Gateways page</a>.';
|
||||
$string['notification:smsgatewaymigrationinfo'] = 'A new SMS subsystem is now available for managing and configuring all SMS-related functions. Your existing SMS configurations have been migrated to the page <a href="{$a}">SMS gateways</a>.';
|
||||
$string['logintitle'] = 'Enter the verification code sent to your mobile';
|
||||
$string['phonehelp'] = 'Enter your mobile number (including country code) to receive a verification code.';
|
||||
$string['pluginname'] = 'SMS mobile phone';
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -276,7 +276,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)];
|
||||
|
||||
@@ -39,5 +39,8 @@ function xmldb_factor_totp_upgrade($oldversion): bool {
|
||||
upgrade_plugin_savepoint(true, 2024081600, 'factor', 'totp');
|
||||
}
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -41,5 +41,8 @@ function xmldb_tool_mobile_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,5 +41,8 @@ function xmldb_tool_monitor_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,5 +41,8 @@ function xmldb_tool_moodlenet_upgrade(int $oldversion) {
|
||||
// Automatically generated Moodle v4.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -42,5 +42,8 @@ function xmldb_tool_policy_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -176,7 +176,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],
|
||||
|
||||
@@ -176,7 +176,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')
|
||||
|
||||
@@ -52,5 +52,8 @@ function xmldb_tool_usertours_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.5.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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'),
|
||||
]),
|
||||
);
|
||||
|
||||
|
||||
@@ -527,14 +527,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')
|
||||
@@ -554,7 +570,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.
|
||||
@@ -563,9 +579,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();
|
||||
}
|
||||
@@ -764,9 +790,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) {
|
||||
|
||||
@@ -72,6 +72,14 @@ abstract class provider {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the request is allowed by the rate limiter.
|
||||
*
|
||||
* @param aiactions\base $action The action to check.
|
||||
* @return array|bool True on success, array of error details on failure.
|
||||
*/
|
||||
abstract public function is_request_allowed(aiactions\base $action): array|bool;
|
||||
|
||||
/**
|
||||
* Check if a provider has the minimal configuration to work.
|
||||
*
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
define("aiplacement_courseassist/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={ELEMENTS:{AIDRAWER:"#ai-drawer",AIDRAWER_BODY:"#ai-drawer .ai-drawer-body",PAGE:"#page",MAIN_REGION:'[role="main"]'},ACTIONS:{SUMMARY:'[data-action="course-summarise"]',RETRY:'[data-action="course-summarise-retry"]',DECLINE:'[data-action="course-summarise-policy-decline"]',ACCEPT:'.ai-policy-block [data-action="accept"]',REGENERATE:'[data-action="course-summarise-regenerate"]',CANCEL:'.ai-policy-block [data-action="decline"]'}},_exports.default}));
|
||||
define("aiplacement_courseassist/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={ELEMENTS:{AIDRAWER:"#ai-drawer",AIDRAWER_BODY:"#ai-drawer .ai-drawer-body",PAGE:"#page",MAIN_REGION:'[role="main"]'},ACTIONS:{SUMMARY:'[data-action="course-summarise"]',RETRY:'[data-action="course-summarise-retry"]',DECLINE:'.ai-policy-block [data-action="decline"]',ACCEPT:'.ai-policy-block [data-action="accept"]',REGENERATE:'[data-action="course-summarise-regenerate"]',CANCEL:'[data-action="course-summarise-cancel"]'}},_exports.default}));
|
||||
|
||||
//# sourceMappingURL=selectors.min.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Define all of the selectors we will be using on the AI Course assistant.\n *\n * @module aiplacement_courseassist/selectors\n * @copyright 2024 Huong Nguyen <huongnv13@gmail.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default {\n ELEMENTS: {\n AIDRAWER: '#ai-drawer',\n AIDRAWER_BODY: '#ai-drawer .ai-drawer-body',\n PAGE: '#page',\n MAIN_REGION: '[role=\"main\"]',\n },\n ACTIONS: {\n SUMMARY: '[data-action=\"course-summarise\"]',\n RETRY: '[data-action=\"course-summarise-retry\"]',\n DECLINE: '[data-action=\"course-summarise-policy-decline\"]',\n ACCEPT: '.ai-policy-block [data-action=\"accept\"]',\n REGENERATE: '[data-action=\"course-summarise-regenerate\"]',\n CANCEL: '.ai-policy-block [data-action=\"decline\"]',\n }\n};\n"],"names":["ELEMENTS","AIDRAWER","AIDRAWER_BODY","PAGE","MAIN_REGION","ACTIONS","SUMMARY","RETRY","DECLINE","ACCEPT","REGENERATE","CANCEL"],"mappings":"oLAsBe,CACXA,SAAU,CACNC,SAAU,aACVC,cAAe,6BACfC,KAAM,QACNC,YAAa,iBAEjBC,QAAS,CACLC,QAAS,mCACTC,MAAO,yCACPC,QAAS,kDACTC,OAAQ,0CACRC,WAAY,8CACZC,OAAQ"}
|
||||
{"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Define all of the selectors we will be using on the AI Course assistant.\n *\n * @module aiplacement_courseassist/selectors\n * @copyright 2024 Huong Nguyen <huongnv13@gmail.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default {\n ELEMENTS: {\n AIDRAWER: '#ai-drawer',\n AIDRAWER_BODY: '#ai-drawer .ai-drawer-body',\n PAGE: '#page',\n MAIN_REGION: '[role=\"main\"]',\n },\n ACTIONS: {\n SUMMARY: '[data-action=\"course-summarise\"]',\n RETRY: '[data-action=\"course-summarise-retry\"]',\n DECLINE: '.ai-policy-block [data-action=\"decline\"]',\n ACCEPT: '.ai-policy-block [data-action=\"accept\"]',\n REGENERATE: '[data-action=\"course-summarise-regenerate\"]',\n CANCEL: '[data-action=\"course-summarise-cancel\"]',\n }\n};\n"],"names":["ELEMENTS","AIDRAWER","AIDRAWER_BODY","PAGE","MAIN_REGION","ACTIONS","SUMMARY","RETRY","DECLINE","ACCEPT","REGENERATE","CANCEL"],"mappings":"oLAsBe,CACXA,SAAU,CACNC,SAAU,aACVC,cAAe,6BACfC,KAAM,QACNC,YAAa,iBAEjBC,QAAS,CACLC,QAAS,mCACTC,MAAO,yCACPC,QAAS,2CACTC,OAAQ,0CACRC,WAAY,8CACZC,OAAQ"}
|
||||
@@ -30,9 +30,9 @@ export default {
|
||||
ACTIONS: {
|
||||
SUMMARY: '[data-action="course-summarise"]',
|
||||
RETRY: '[data-action="course-summarise-retry"]',
|
||||
DECLINE: '[data-action="course-summarise-policy-decline"]',
|
||||
DECLINE: '.ai-policy-block [data-action="decline"]',
|
||||
ACCEPT: '.ai-policy-block [data-action="accept"]',
|
||||
REGENERATE: '[data-action="course-summarise-regenerate"]',
|
||||
CANCEL: '.ai-policy-block [data-action="decline"]',
|
||||
CANCEL: '[data-action="course-summarise-cancel"]',
|
||||
}
|
||||
};
|
||||
|
||||
@@ -27,9 +27,9 @@ $string['courseassist:summarise_text'] = 'Summarise text';
|
||||
$string['copy'] = 'Copy';
|
||||
$string['generatefailtitle'] = 'Something went wrong';
|
||||
$string['generating'] = 'Generating your response';
|
||||
$string['nocourseassist'] = 'AI summary is not available for this context';
|
||||
$string['pluginname'] = 'Course Assistance Placement';
|
||||
$string['privacy:metadata'] = 'The Course Assistance placement plugin does not store any personal data.';
|
||||
$string['nocourseassist'] = 'An AI-generated summary is not available for this context.';
|
||||
$string['pluginname'] = 'Course assistance placement';
|
||||
$string['privacy:metadata'] = 'The Course assistance placement plugin does not store any personal data.';
|
||||
$string['regenerate'] = 'Regenerate';
|
||||
$string['summarise'] = 'Summarise';
|
||||
$string['summarise_tooltips'] = 'Create an AI-generated summary of the page content';
|
||||
|
||||
@@ -28,7 +28,6 @@ Feature: AI Course assist summarise
|
||||
And I enable "openai" "aiprovider" plugin
|
||||
And the following config values are set as admin:
|
||||
| apikey | 123 | aiprovider_openai |
|
||||
| orgid | abc | aiprovider_openai |
|
||||
And I enable "courseassist" "aiplacement" plugin
|
||||
|
||||
@javascript
|
||||
|
||||
@@ -47,7 +47,6 @@ final class utils_test extends \advanced_testcase {
|
||||
|
||||
set_config('enabled', 1, 'aiprovider_openai');
|
||||
set_config('apikey', '123', 'aiprovider_openai');
|
||||
set_config('orgid', 'abc', 'aiprovider_openai');
|
||||
|
||||
// Plugin is not enabled.
|
||||
$this->setUser($user1);
|
||||
|
||||
@@ -22,15 +22,15 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['generatecontent'] = 'Generate AI Content';
|
||||
$string['generatecontent'] = 'Generate AI content';
|
||||
$string['generateimage'] = 'AI generate image';
|
||||
$string['generateimagesetting'] = 'Enable generate image';
|
||||
$string['generateimagesetting_desc'] = 'Enable or disable the generation of images from a text prompt.';
|
||||
$string['generatetext'] = 'AI generate text';
|
||||
$string['generatetextsetting'] = 'Enable generate text';
|
||||
$string['generatetextsetting_desc'] = 'Enable or disable the generation of text from a text prompt.';
|
||||
$string['noeditor'] = 'HTML Text Editor Placement is not available for this context';
|
||||
$string['pluginname'] = 'HTML Text Editor Placement';
|
||||
$string['privacy:metadata'] = 'The HTML text editor placement plugin does not store any personal data.';
|
||||
$string['editor:generate_image'] = 'Generate AI Images in HTML Text Editor';
|
||||
$string['editor:generate_text'] = 'Generate AI Text in HTML Text Editor';
|
||||
$string['noeditor'] = 'Text editor placement is not available for this context.';
|
||||
$string['pluginname'] = 'Text editor placement';
|
||||
$string['privacy:metadata'] = 'The Text editor placement plugin does not store any personal data.';
|
||||
$string['editor:generate_image'] = 'Generate AI images in text editor';
|
||||
$string['editor:generate_text'] = 'Generate AI text in text editor';
|
||||
|
||||
@@ -20,7 +20,7 @@ use core_ai\aiactions\generate_image;
|
||||
use core_ai\aiactions\generate_text;
|
||||
|
||||
/**
|
||||
* HTML Text Editor Placement utils test.
|
||||
* Text editor placement utils test.
|
||||
*
|
||||
* @package aiplacement_editor
|
||||
* @copyright 2024 Huong Nguyen <huongnv13@gmail.com>
|
||||
@@ -73,7 +73,6 @@ final class utils_test extends \advanced_testcase {
|
||||
|
||||
set_config('enabled', 1, 'aiprovider_openai');
|
||||
set_config('apikey', '123', 'aiprovider_openai');
|
||||
set_config('orgid', 'abc', 'aiprovider_openai');
|
||||
|
||||
// Plugin is not enabled.
|
||||
$this->setUser($this->users[1]);
|
||||
|
||||
@@ -100,12 +100,7 @@ class provider extends \core_ai\provider {
|
||||
->withAddedHeader('api-key', $this->apikey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the request is allowed by the rate limiter.
|
||||
*
|
||||
* @param aiactions\base $action The action to check.
|
||||
* @return array|bool True on success, array of error details on failure.
|
||||
*/
|
||||
#[\Override]
|
||||
public function is_request_allowed(aiactions\base $action): array|bool {
|
||||
$ratelimiter = \core\di::get(rate_limiter::class);
|
||||
$component = \core\component::get_component_from_classname(get_class($this));
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
$string['action_apiversion'] = 'API version';
|
||||
$string['action_deployment'] = 'Deployment ID';
|
||||
$string['action_deployment_desc'] = 'The deployment ID that relates to the API endpoint the provider uses for this action.';
|
||||
$string['action_systeminstruction'] = 'System Instruction';
|
||||
$string['action_systeminstruction'] = 'System instruction';
|
||||
$string['action_systeminstruction_desc'] = 'This instruction is sent to the AI model along with the user\'s prompt. Editing this instruction is not recommended unless absolutely required.';
|
||||
$string['apikey'] = 'Azure AI API key';
|
||||
$string['apikey_desc'] = 'Enter your Azure AI API key.';
|
||||
@@ -36,15 +36,15 @@ $string['enableglobalratelimit_desc'] = 'Limit the number of requests that the A
|
||||
$string['enableuserratelimit'] = 'Set user rate limit';
|
||||
$string['enableuserratelimit_desc'] = 'Limit the number of requests each user can make to the Azure AI API provider every hour.';
|
||||
$string['endpoint'] = 'Azure AI API endpoint';
|
||||
$string['endpoint_desc'] = 'Enter the endpoint URL for your Azure AI API, in the following format: https://YOUR_RESOURCE_NAME.azureai.azure.com/azureai/deployments';
|
||||
$string['endpoint_desc'] = 'Enter the endpoint URL for your Azure AI API in the following format: https://YOUR_RESOURCE_NAME.openai.azure.com';
|
||||
$string['globalratelimit'] = 'Maximum number of site-wide requests';
|
||||
$string['globalratelimit_desc'] = 'The number of site-wide requests allowed per hour.';
|
||||
$string['pluginname'] = 'Azure AI API Provider';
|
||||
$string['privacy:metadata'] = 'The Azure Ai API provider plugin does not store any personal data.';
|
||||
$string['pluginname'] = 'Azure AI API provider';
|
||||
$string['privacy:metadata'] = 'The Azure AI API provider plugin does not store any personal data.';
|
||||
$string['privacy:metadata:aiprovider_azureai:externalpurpose'] = 'This information is sent to the Azure API in order for a response to be generated. Your Azure AI account settings may change how Microsoft stores and retains this data. No user data is explicitly sent to Microsoft or stored in Moodle LMS by this plugin.';
|
||||
$string['privacy:metadata:aiprovider_azureai:model'] = 'The model used to generate the response.';
|
||||
$string['privacy:metadata:aiprovider_azureai:numberimages'] = 'The number of images used in the response. When generating images.';
|
||||
$string['privacy:metadata:aiprovider_azureai:numberimages'] = 'When generating images the number of images used in the response.';
|
||||
$string['privacy:metadata:aiprovider_azureai:prompttext'] = 'The user entered text prompt used to generate the response.';
|
||||
$string['privacy:metadata:aiprovider_azureai:responseformat'] = 'The format of the response. When generating images.';
|
||||
$string['privacy:metadata:aiprovider_azureai:responseformat'] = 'When generating images the format of the response.';
|
||||
$string['userratelimit'] = 'Maximum number of requests per user';
|
||||
$string['userratelimit_desc'] = 'The number of requests allowed per hour, per user.';
|
||||
|
||||
@@ -102,12 +102,7 @@ class provider extends \core_ai\provider {
|
||||
->withAddedHeader('OpenAI-Organization', $this->orgid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the request is allowed by the rate limiter.
|
||||
*
|
||||
* @param aiactions\base $action The action to check.
|
||||
* @return array|bool True on success, array of error details on failure.
|
||||
*/
|
||||
#[\Override]
|
||||
public function is_request_allowed(aiactions\base $action): array|bool {
|
||||
$ratelimiter = \core\di::get(rate_limiter::class);
|
||||
$component = \core\component::get_component_from_classname(get_class($this));
|
||||
@@ -214,6 +209,6 @@ class provider extends \core_ai\provider {
|
||||
* @return bool Return true if configured.
|
||||
*/
|
||||
public function is_provider_configured(): bool {
|
||||
return !empty($this->apikey) && !empty($this->orgid);
|
||||
return !empty($this->apikey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ $string['action:summarise_text:model_desc'] = 'The model used to summarise the p
|
||||
$string['action:summarise_text:systeminstruction'] = 'System instruction';
|
||||
$string['action:summarise_text:systeminstruction_desc'] = 'This instruction is sent to the AI model along with the user\'s prompt. Editing this instruction is not recommended unless absolutely required.';
|
||||
$string['apikey'] = 'OpenAI API key';
|
||||
$string['apikey_desc'] = 'Get a key from your <a href="https://platform.openai.com/account/api-keys" target="_blank">OpenAI API keys</a>.';
|
||||
$string['apikey_desc'] = 'Get a key from <a href="https://platform.openai.com/account/api-keys">OpenAI Platform API keys</a>.';
|
||||
$string['enableglobalratelimit'] = 'Set site-wide rate limit';
|
||||
$string['enableglobalratelimit_desc'] = 'Limit the number of requests that the OpenAI API provider can receive across the entire site every hour.';
|
||||
$string['enableuserratelimit'] = 'Set user rate limit';
|
||||
@@ -44,13 +44,13 @@ $string['enableuserratelimit_desc'] = 'Limit the number of requests each user ca
|
||||
$string['globalratelimit'] = 'Maximum number of site-wide requests';
|
||||
$string['globalratelimit_desc'] = 'The number of site-wide requests allowed per hour.';
|
||||
$string['orgid'] = 'OpenAI organization ID';
|
||||
$string['orgid_desc'] = 'Get your OpenAI organization ID from your <a href="https://platform.openai.com/account/org-settings" target="_blank">OpenAI account</a>.';
|
||||
$string['pluginname'] = 'OpenAI API Provider';
|
||||
$string['orgid_desc'] = 'Get an OpenAI organization ID from your <a href="https://platform.openai.com/account/org-settings">OpenAI Platform account</a>.';
|
||||
$string['pluginname'] = 'OpenAI API provider';
|
||||
$string['privacy:metadata'] = 'The OpenAI API provider plugin does not store any personal data.';
|
||||
$string['privacy:metadata:aiprovider_openai:externalpurpose'] = 'This information is sent to the OpenAI API in order for a response to be generated. Your OpenAI account settings may change how OpenAI stores and retains this data. No user data is explicitly sent to OpenAI or stored in Moodle LMS by this plugin.';
|
||||
$string['privacy:metadata:aiprovider_openai:model'] = 'The model used to generate the response.';
|
||||
$string['privacy:metadata:aiprovider_openai:numberimages'] = 'The number of images used in the response. When generating images.';
|
||||
$string['privacy:metadata:aiprovider_openai:numberimages'] = 'When generating images the number of images used in the response.';
|
||||
$string['privacy:metadata:aiprovider_openai:prompttext'] = 'The user entered text prompt used to generate the response.';
|
||||
$string['privacy:metadata:aiprovider_openai:responseformat'] = 'The format of the response. When generating images.';
|
||||
$string['privacy:metadata:aiprovider_openai:responseformat'] = 'When generating images the format of the response.';
|
||||
$string['userratelimit'] = 'Maximum number of requests per user';
|
||||
$string['userratelimit_desc'] = 'The number of requests allowed per hour, per user.';
|
||||
|
||||
@@ -121,15 +121,8 @@ final class provider_test extends \advanced_testcase {
|
||||
$provider = new \aiprovider_openai\provider();
|
||||
$this->assertFalse($provider->is_provider_configured());
|
||||
|
||||
// Partially configured values.
|
||||
set_config('apikey', '123', 'aiprovider_openai');
|
||||
set_config('orgid', '', 'aiprovider_openai');
|
||||
$provider = new \aiprovider_openai\provider();
|
||||
$this->assertFalse($provider->is_provider_configured());
|
||||
|
||||
// Properly configured values.
|
||||
set_config('apikey', '123', 'aiprovider_openai');
|
||||
set_config('orgid', 'abc', 'aiprovider_openai');
|
||||
$provider = new \aiprovider_openai\provider();
|
||||
$this->assertTrue($provider->is_provider_configured());
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ final class ai_image_test extends \advanced_testcase {
|
||||
$height = 20;
|
||||
|
||||
// Test for black image.
|
||||
$imagepath = __DIR__ . '/fixtures/black.png'; // Get the test image from the fixtures file.
|
||||
$imagepath = self::get_fixture_path(__NAMESPACE__, 'black.png'); // Get the test image from the fixtures file.
|
||||
$image = new ai_image($imagepath);
|
||||
// We're working with a private method here, so we need to use reflection.
|
||||
$method = new \ReflectionMethod($image, 'get_predominant_color');
|
||||
@@ -47,7 +47,7 @@ final class ai_image_test extends \advanced_testcase {
|
||||
$this->assertEquals(0, $color['blue']);
|
||||
|
||||
// Test for white image.
|
||||
$imagepath = __DIR__ . '/fixtures/white.png';
|
||||
$imagepath = self::get_fixture_path(__NAMESPACE__, 'white.png');
|
||||
$image = new ai_image($imagepath);
|
||||
// We're working with a private method here, so we need to use reflection.
|
||||
$method = new \ReflectionMethod($image, 'get_predominant_color');
|
||||
@@ -58,7 +58,7 @@ final class ai_image_test extends \advanced_testcase {
|
||||
$this->assertEquals(255, $color['blue']);
|
||||
|
||||
// Test for grey image.
|
||||
$imagepath = __DIR__ . '/fixtures/grey.png';
|
||||
$imagepath = self::get_fixture_path(__NAMESPACE__, 'grey.png');
|
||||
$image = new ai_image($imagepath);
|
||||
// We're working with a private method here, so we need to use reflection.
|
||||
$method = new \ReflectionMethod($image, 'get_predominant_color');
|
||||
@@ -75,7 +75,7 @@ final class ai_image_test extends \advanced_testcase {
|
||||
public function test_is_color_dark(): void {
|
||||
// Load an image as it is required for class instantiation.
|
||||
// The color of the image is not important for this test.
|
||||
$imagepath = __DIR__ . '/fixtures/black.png';
|
||||
$imagepath = self::get_fixture_path(__NAMESPACE__, 'black.png');
|
||||
$image = new ai_image($imagepath);
|
||||
// We're working with a private method here, so we need to use reflection.
|
||||
$method = new \ReflectionMethod($image, 'is_color_dark');
|
||||
@@ -92,7 +92,7 @@ final class ai_image_test extends \advanced_testcase {
|
||||
|
||||
$this->assertFalse($result);
|
||||
|
||||
$imagepath = __DIR__ . '/fixtures/grey.png';
|
||||
$imagepath = self::get_fixture_path(__NAMESPACE__, 'grey.png');
|
||||
$image = new ai_image($imagepath);
|
||||
// We're working with a private method here, so we need to use reflection.
|
||||
$method = new \ReflectionMethod($image, 'is_color_dark');
|
||||
|
||||
@@ -8,44 +8,43 @@ Feature: An administrator can manage AI subsystem settings
|
||||
Scenario: An administrator can control the enabled state of AI Provider plugins using JavaScript
|
||||
Given I am logged in as "admin"
|
||||
And I navigate to "AI > AI providers" in site administration
|
||||
When I toggle the "Enable OpenAI API Provider" admin switch "on"
|
||||
And I should see "OpenAI API Provider enabled."
|
||||
When I toggle the "Enable OpenAI API provider" admin switch "on"
|
||||
And I should see "OpenAI API provider enabled."
|
||||
And I reload the page
|
||||
And I should see "Disable OpenAI API Provider"
|
||||
And I toggle the "Disable OpenAI API Provider" admin switch "off"
|
||||
Then I should see "OpenAI API Provider disabled."
|
||||
And I should see "Disable OpenAI API provider"
|
||||
And I toggle the "Disable OpenAI API provider" admin switch "off"
|
||||
Then I should see "OpenAI API provider disabled."
|
||||
|
||||
@javascript
|
||||
Scenario: An administrator can control the enabled state of AI Placement plugins using JavaScript
|
||||
Scenario: An administrator can control the enabled state of AI placement plugins using JavaScript
|
||||
Given I am logged in as "admin"
|
||||
And I navigate to "AI > AI placements" in site administration
|
||||
When I toggle the "Enable HTML Text Editor Placement" admin switch "on"
|
||||
And I should see "HTML Text Editor Placement enabled."
|
||||
When I toggle the "Enable Text editor placement" admin switch "on"
|
||||
And I should see "Text editor placement enabled."
|
||||
And I reload the page
|
||||
And I should see "Disable HTML Text Editor Placement"
|
||||
And I toggle the "Disable HTML Text Editor Placement" admin switch "off"
|
||||
Then I should see "HTML Text Editor Placement disabled."
|
||||
And I should see "Disable Text editor placement"
|
||||
And I toggle the "Disable Text editor placement" admin switch "off"
|
||||
Then I should see "Text editor placement disabled."
|
||||
|
||||
@javascript
|
||||
Scenario: Placement actions should be available when an Administrator enables AI Providers using JavaScript
|
||||
Given I am logged in as "admin"
|
||||
And I navigate to "AI > AI providers" in site administration
|
||||
When I toggle the "Enable OpenAI API Provider" admin switch "on"
|
||||
And I should see "OpenAI API Provider enabled."
|
||||
When I toggle the "Enable OpenAI API provider" admin switch "on"
|
||||
And I should see "OpenAI API provider enabled."
|
||||
And the following config values are set as admin:
|
||||
| apikey | 123 | aiprovider_openai |
|
||||
| orgid | abc | aiprovider_openai |
|
||||
And I navigate to "AI > AI placements" in site administration
|
||||
And I click on the "Settings" link in the table row containing "HTML Text Editor Placement"
|
||||
And I click on the "Settings" link in the table row containing "Text editor placement"
|
||||
Then I should not see "This action is unavailable."
|
||||
|
||||
@javascript
|
||||
Scenario: Placement actions should not be available when an Administrator disables AI Providers using JavaScript
|
||||
Given I am logged in as "admin"
|
||||
And I navigate to "AI > AI providers" in site administration
|
||||
When I toggle the "Enable OpenAI API Provider" admin switch "off"
|
||||
When I toggle the "Enable OpenAI API provider" admin switch "off"
|
||||
And I navigate to "AI > AI placements" in site administration
|
||||
And I click on the "Settings" link in the table row containing "HTML Text Editor Placement"
|
||||
And I click on the "Settings" link in the table row containing "Text editor placement"
|
||||
And I should see "This action is unavailable." in the table row containing "Generate text"
|
||||
Then I should see "This action is unavailable." in the table row containing "Generate image"
|
||||
|
||||
@@ -53,14 +52,13 @@ Feature: An administrator can manage AI subsystem settings
|
||||
Scenario: Placement actions should not be available for enabled Providers when an Administrator disables an Action using JavaScript
|
||||
Given I am logged in as "admin"
|
||||
And I navigate to "AI > AI providers" in site administration
|
||||
When I toggle the "Enable OpenAI API Provider" admin switch "on"
|
||||
And I should see "OpenAI API Provider enabled."
|
||||
When I toggle the "Enable OpenAI API provider" admin switch "on"
|
||||
And I should see "OpenAI API provider enabled."
|
||||
And the following config values are set as admin:
|
||||
| apikey | 123 | aiprovider_openai |
|
||||
| orgid | abc | aiprovider_openai |
|
||||
And I click on the "Settings" link in the table row containing "OpenAI API Provider"
|
||||
And I click on the "Settings" link in the table row containing "OpenAI API provider"
|
||||
And I toggle the "Generate text" admin switch "off"
|
||||
And I navigate to "AI > AI placements" in site administration
|
||||
And I click on the "Settings" link in the table row containing "HTML Text Editor Placement"
|
||||
And I click on the "Settings" link in the table row containing "Text editor placement"
|
||||
And I should see "This action is unavailable." in the table row containing "Generate text"
|
||||
Then I should not see "This action is unavailable." in the table row containing "Generate image"
|
||||
|
||||
@@ -75,7 +75,6 @@ final class manager_test extends \advanced_testcase {
|
||||
$this->resetAfterTest();
|
||||
set_config('enabled', 1, 'aiprovider_openai');
|
||||
set_config('apikey', '123', 'aiprovider_openai');
|
||||
set_config('orgid', 'abc', 'aiprovider_openai');
|
||||
|
||||
$manager = \core\di::get(manager::class);
|
||||
$actions = [
|
||||
@@ -144,7 +143,6 @@ final class manager_test extends \advanced_testcase {
|
||||
// Enable the providers.
|
||||
set_config('enabled', 1, 'aiprovider_openai');
|
||||
set_config('apikey', '123', 'aiprovider_openai');
|
||||
set_config('orgid', 'abc', 'aiprovider_openai');
|
||||
set_config('enabled', 1, 'aiprovider_azureai');
|
||||
set_config('apikey', '123', 'aiprovider_azureai');
|
||||
set_config('endpoint', 'abc', 'aiprovider_azureai');
|
||||
@@ -420,7 +418,6 @@ final class manager_test extends \advanced_testcase {
|
||||
$manager = \core_plugin_manager::resolve_plugininfo_class('aiprovider');
|
||||
$manager::enable_plugin('openai', 1);
|
||||
set_config('apikey', '123', 'aiprovider_openai');
|
||||
set_config('orgid', 'abc', 'aiprovider_openai');
|
||||
|
||||
// Should now be available.
|
||||
$result = manager::is_action_available($action);
|
||||
|
||||
@@ -1530,4 +1530,22 @@ final class provider_test extends \advanced_testcase {
|
||||
|
||||
$this->assertEquals(get_string('pluginname', 'aiprovider_openai'), $provider->get_name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the is_request_allowed method of the provider abstract class.
|
||||
*/
|
||||
public function test_is_request_allowed(): void {
|
||||
|
||||
$stub = $this->getMockBuilder(\core_ai\provider::class)
|
||||
->onlyMethods(['is_request_allowed'])
|
||||
->getMockForAbstractClass();
|
||||
|
||||
$stub->expects($this->once())
|
||||
->method('is_request_allowed')
|
||||
->willReturn(true);
|
||||
|
||||
$actionmock = $this->createMock(\core_ai\aiactions\base::class);
|
||||
|
||||
$this->assertTrue($stub->is_request_allowed($actionmock));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -788,7 +788,7 @@ class manager {
|
||||
if (preg_match('~^\\\\mod_([^\\\\]+)\\\\~', $indicator, $matches)) {
|
||||
if (!$allmodules) {
|
||||
// The first time, get all modules.
|
||||
$allmodules = \core\plugin_manager::instance()->get_plugins_of_type('mod');
|
||||
$allmodules = \core\plugin_manager::instance()->get_present_plugins('mod');
|
||||
}
|
||||
if (!array_key_exists($matches[1], $allmodules)) {
|
||||
// Module does not exist, so skip indicator.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user